cb6f8eff0f9787b818b6fe94b8dc3fbc9502d769
[metze/wireshark/wip.git] / ui / qt / main_window_slots.cpp
1 /* main_window_slots.cpp
2  *
3  * Wireshark - Network traffic analyzer
4  * By Gerald Combs <gerald@wireshark.org>
5  * Copyright 1998 Gerald Combs
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #include <config.h>
23
24 // Qt 5.5.0 + Visual C++ 2013
25 #ifdef _MSC_VER
26 #pragma warning(push)
27 #pragma warning(disable:4996)
28 #endif
29
30 #include "main_window.h"
31 #include <ui_main_window.h>
32
33 #ifdef _WIN32
34 #include <windows.h>
35 #endif
36
37 #ifdef HAVE_LIBPCAP
38 #include "ui/capture.h"
39 #endif
40
41 #include "color_filters.h"
42
43 #include "wsutil/file_util.h"
44 #include "wsutil/filesystem.h"
45 #include "wsutil/str_util.h"
46
47 #include "epan/addr_resolv.h"
48 #include "epan/dissector_filters.h"
49 #include "epan/column.h"
50 #include "epan/dfilter/dfilter-macro.h"
51 #include "epan/epan_dissect.h"
52 #include "epan/filter_expressions.h"
53 #include "epan/prefs.h"
54 #include "epan/uat.h"
55 #include "epan/value_string.h"
56
57 #ifdef HAVE_LUA
58 #include <epan/wslua/init_wslua.h>
59 #endif
60
61 #include "ui/alert_box.h"
62 #ifdef HAVE_LIBPCAP
63 #include "ui/capture_ui_utils.h"
64 #endif
65
66 #include "ui/capture_globals.h"
67 #include "ui/help_url.h"
68 #include "ui/main_statusbar.h"
69 #include "ui/preference_utils.h"
70 #include "ui/recent.h"
71 #include "ui/recent_utils.h"
72 #include "ui/ssl_key_export.h"
73 #include "ui/ui_util.h"
74 #include "ui/qt/simple_dialog.h"
75
76 #ifdef HAVE_SOFTWARE_UPDATE
77 #include "ui/software_update.h"
78 #endif
79
80 #include "about_dialog.h"
81 #include "bluetooth_att_server_attributes_dialog.h"
82 #include "bluetooth_devices_dialog.h"
83 #include "bluetooth_hci_summary_dialog.h"
84 #include "capture_file_dialog.h"
85 #include "capture_file_properties_dialog.h"
86 #include "color_utils.h"
87 #include "coloring_rules_dialog.h"
88 #include "conversation_dialog.h"
89 #include "conversation_hash_tables_dialog.h"
90 #include "enabled_protocols_dialog.h"
91 #include "decode_as_dialog.h"
92 #include "display_filter_edit.h"
93 #include "display_filter_expression_dialog.h"
94 #include "dissector_tables_dialog.h"
95 #include "endpoint_dialog.h"
96 #include "expert_info_dialog.h"
97 #include "export_object_dialog.h"
98 #include "export_pdu_dialog.h"
99 #if HAVE_EXTCAP
100 #include "extcap_options_dialog.h"
101 #endif
102 #include "filter_action.h"
103 #include "filter_dialog.h"
104 #include "funnel_statistics.h"
105 #include "gsm_map_summary_dialog.h"
106 #include "iax2_analysis_dialog.h"
107 #include "io_graph_dialog.h"
108 #include "lbm_stream_dialog.h"
109 #include "lbm_uimflow_dialog.h"
110 #include "lbm_lbtrm_transport_dialog.h"
111 #include "lbm_lbtru_transport_dialog.h"
112 #include "lte_mac_statistics_dialog.h"
113 #include "lte_rlc_statistics_dialog.h"
114 #include "lte_rlc_graph_dialog.h"
115 #include "mtp3_summary_dialog.h"
116 #include "multicast_statistics_dialog.h"
117 #include "packet_comment_dialog.h"
118 #include "packet_dialog.h"
119 #include "packet_list.h"
120 #include "preferences_dialog.h"
121 #include "print_dialog.h"
122 #include "profile_dialog.h"
123 #include "protocol_hierarchy_dialog.h"
124 #include "qt_ui_utils.h"
125 #include "resolved_addresses_dialog.h"
126 #include "rpc_service_response_time_dialog.h"
127 #include "rtp_stream_dialog.h"
128 #include "rtp_analysis_dialog.h"
129 #include "sctp_all_assocs_dialog.h"
130 #include "sctp_assoc_analyse_dialog.h"
131 #include "sctp_graph_dialog.h"
132 #include "sequence_dialog.h"
133 #include "stats_tree_dialog.h"
134 #include "stock_icon.h"
135 #include "supported_protocols_dialog.h"
136 #include "tap_parameter_dialog.h"
137 #include "tcp_stream_dialog.h"
138 #include "time_shift_dialog.h"
139 #include "uat_dialog.h"
140 #include "voip_calls_dialog.h"
141 #include "wireshark_application.h"
142 #include "wlan_statistics_dialog.h"
143
144 #include <QClipboard>
145 #include <QFileInfo>
146 #include <QMessageBox>
147 #include <QMetaObject>
148 #include <QToolBar>
149 #include <QDesktopServices>
150 #include <QUrl>
151 #include <QDebug>
152
153 //
154 // Public slots
155 //
156
157 static const char *dfe_property_ = "display filter expression"; //TODO : Fix Translate
158
159 // We're too lazy to sublcass QAction.
160 static const char *color_number_property_ = "color number";
161
162 bool MainWindow::openCaptureFile(QString cf_path, QString read_filter, unsigned int type)
163 {
164     QString file_name = "";
165     dfilter_t *rfcode = NULL;
166     gchar *err_msg;
167     int err;
168     gboolean name_param;
169
170     // was a file name given as function parameter?
171     name_param = !cf_path.isEmpty();
172
173     for (;;) {
174
175         if (cf_path.isEmpty()) {
176             CaptureFileDialog open_dlg(this, capture_file_.capFile(), read_filter);
177
178             switch (prefs.gui_fileopen_style) {
179
180             case FO_STYLE_LAST_OPENED:
181                 /* The user has specified that we should start out in the last directory
182                    we looked in.  If we've already opened a file, use its containing
183                    directory, if we could determine it, as the directory, otherwise
184                    use the "last opened" directory saved in the preferences file if
185                    there was one. */
186                 /* This is now the default behaviour in file_selection_new() */
187                 break;
188
189             case FO_STYLE_SPECIFIED:
190                 /* The user has specified that we should always start out in a
191                    specified directory; if they've specified that directory,
192                    start out by showing the files in that dir. */
193                 if (prefs.gui_fileopen_dir[0] != '\0')
194                     open_dlg.setDirectory(prefs.gui_fileopen_dir);
195                 break;
196             }
197
198             if (open_dlg.open(file_name, type)) {
199                 cf_path = file_name;
200             } else {
201                 return false;
202             }
203         }
204
205         if (!testCaptureFileClose(false)) {
206             return false;
207         }
208
209         if (dfilter_compile(read_filter.toUtf8().constData(), &rfcode, &err_msg)) {
210             cf_set_rfcode(CaptureFile::globalCapFile(), rfcode);
211         } else {
212             /* Not valid.  Tell the user, and go back and run the file
213                selection box again once they dismiss the alert. */
214             //bad_dfilter_alert_box(top_level, read_filter->str);
215             QMessageBox::warning(this, tr("Invalid Display Filter"),
216                     QString("The filter expression ") +
217                     read_filter +
218                     QString(" isn't a valid display filter. (") +
219                     err_msg + QString(")."),
220                     QMessageBox::Ok);
221
222             if (!name_param) {
223                 // go back to the selection dialogue only if the file
224                 // was selected from this dialogue
225                 cf_path.clear();
226                 continue;
227             }
228         }
229
230         /* Try to open the capture file. This closes the current file if it succeeds. */
231         CaptureFile::globalCapFile()->window = this;
232         if (cf_open(CaptureFile::globalCapFile(), cf_path.toUtf8().constData(), type, FALSE, &err) != CF_OK) {
233             /* We couldn't open it; don't dismiss the open dialog box,
234                just leave it around so that the user can, after they
235                dismiss the alert box popped up for the open error,
236                try again. */
237             CaptureFile::globalCapFile()->window = NULL;
238             if (rfcode != NULL)
239                 dfilter_free(rfcode);
240             cf_path.clear();
241             continue;
242         }
243
244         switch (cf_read(CaptureFile::globalCapFile(), FALSE)) {
245
246         case CF_READ_OK:
247         case CF_READ_ERROR:
248             /* Just because we got an error, that doesn't mean we were unable
249                to read any of the file; we handle what we could get from the
250                file. */
251             break;
252
253         case CF_READ_ABORTED:
254             /* The user bailed out of re-reading the capture file; the
255                capture file has been closed - just free the capture file name
256                string and return (without changing the last containing
257                directory). */
258             capture_file_.setCapFile(NULL);
259             return false;
260         }
261         break;
262     }
263     // get_dirname overwrites its path. Hopefully this isn't a problem.
264     wsApp->setLastOpenDir(get_dirname(cf_path.toUtf8().data()));
265
266     main_ui_->statusBar->showExpert();
267
268     return true;
269 }
270
271 void MainWindow::filterPackets(QString new_filter, bool force)
272 {
273     cf_status_t cf_status;
274
275     cf_status = cf_filter_packets(CaptureFile::globalCapFile(), new_filter.toUtf8().data(), force);
276
277     if (cf_status == CF_OK) {
278         emit displayFilterSuccess(true);
279         if (new_filter.length() > 0) {
280             int index = df_combo_box_->findText(new_filter);
281             if (index == -1) {
282                 df_combo_box_->insertItem(0, new_filter);
283                 df_combo_box_->setCurrentIndex(0);
284             } else {
285                 df_combo_box_->setCurrentIndex(index);
286             }
287         } else {
288             df_combo_box_->lineEdit()->clear();
289         }
290     } else {
291         emit displayFilterSuccess(false);
292     }
293     if (packet_list_) {
294         packet_list_->resetColumns();
295     }
296 }
297
298 // A new layout should be applied when it differs from the old layout AND
299 // at the following times:
300 // - At startup
301 // - When the preferences change
302 // - When the profile changes
303 void MainWindow::layoutPanes()
304 {
305     QVector<unsigned> new_layout = QVector<unsigned>() << prefs.gui_layout_type
306                                                        << prefs.gui_layout_content_1
307                                                        << prefs.gui_layout_content_2
308                                                        << prefs.gui_layout_content_3
309                                                        << recent.packet_list_show
310                                                        << recent.tree_view_show
311                                                        << recent.byte_view_show;
312
313     if (cur_layout_ == new_layout) return;
314
315     QSplitter *parents[3];
316     int current_row = capture_file_.currentRow();
317
318     // Reparent all widgets and add them back in the proper order below.
319     // This hides each widget as well.
320     packet_list_->freeze(); // Clears tree and byte view tabs.
321     packet_list_->setParent(main_ui_->mainStack);
322     proto_tree_->setParent(main_ui_->mainStack);
323     byte_view_tab_->setParent(main_ui_->mainStack);
324     empty_pane_.setParent(main_ui_->mainStack);
325     extra_split_.setParent(main_ui_->mainStack);
326
327     // XXX We should try to preserve geometries if we can, e.g. by
328     // checking to see if the layout type is the same.
329     switch(prefs.gui_layout_type) {
330     case(layout_type_2):
331     case(layout_type_1):
332         extra_split_.setOrientation(Qt::Horizontal);
333         /* Fall Through */
334     case(layout_type_5):
335         master_split_.setOrientation(Qt::Vertical);
336         break;
337
338     case(layout_type_4):
339     case(layout_type_3):
340         extra_split_.setOrientation(Qt::Vertical);
341         /* Fall Through */
342     case(layout_type_6):
343         master_split_.setOrientation(Qt::Horizontal);
344         break;
345
346     default:
347         g_assert_not_reached();
348     }
349
350     switch(prefs.gui_layout_type) {
351     case(layout_type_5):
352     case(layout_type_6):
353         parents[0] = &master_split_;
354         parents[1] = &master_split_;
355         parents[2] = &master_split_;
356         break;
357     case(layout_type_2):
358     case(layout_type_4):
359         parents[0] = &master_split_;
360         parents[1] = &extra_split_;
361         parents[2] = &extra_split_;
362         break;
363     case(layout_type_1):
364     case(layout_type_3):
365         parents[0] = &extra_split_;
366         parents[1] = &extra_split_;
367         parents[2] = &master_split_;
368         break;
369     default:
370         g_assert_not_reached();
371     }
372
373     if (parents[0] == &extra_split_) {
374         master_split_.addWidget(&extra_split_);
375     }
376
377     parents[0]->addWidget(getLayoutWidget(prefs.gui_layout_content_1));
378
379     if (parents[2] == &extra_split_) {
380         master_split_.addWidget(&extra_split_);
381     }
382
383     parents[1]->addWidget(getLayoutWidget(prefs.gui_layout_content_2));
384     parents[2]->addWidget(getLayoutWidget(prefs.gui_layout_content_3));
385
386     const QList<QWidget *> ms_children = master_split_.findChildren<QWidget *>();
387
388     extra_split_.setVisible(ms_children.contains(&extra_split_));
389     packet_list_->setVisible(ms_children.contains(packet_list_) && recent.packet_list_show);
390     proto_tree_->setVisible(ms_children.contains(proto_tree_) && recent.tree_view_show);
391     byte_view_tab_->setVisible(ms_children.contains(byte_view_tab_) && recent.byte_view_show);
392
393     packet_list_->thaw();
394     cf_select_packet(capture_file_.capFile(), current_row);  // XXX Doesn't work for row 0?
395     cur_layout_ = new_layout;
396 }
397
398 // The recent layout geometry should be applied after the layout has been
399 // applied AND at the following times:
400 // - At startup
401 // - When the profile changes
402 void MainWindow::applyRecentPaneGeometry()
403 {
404     // XXX This shrinks slightly each time the application is run. For some
405     // reason the master_split_ geometry is two pixels shorter when
406     // saveWindowGeometry is invoked.
407
408     // This is also an awful lot of trouble to go through to reuse the GTK+
409     // pane settings. We might want to add gui.geometry_main_master_sizes
410     // and gui.geometry_main_extra_sizes and save QSplitter::saveState in
411     // each.
412
413     // Force a geometry recalculation
414     QWidget *cur_w = main_ui_->mainStack->currentWidget();
415     main_ui_->mainStack->setCurrentWidget(&master_split_);
416     QRect geom = master_split_.geometry();
417     QList<int> master_sizes = master_split_.sizes();
418     QList<int> extra_sizes = extra_split_.sizes();
419     main_ui_->mainStack->setCurrentWidget(cur_w);
420
421     int master_last_size = master_split_.orientation() == Qt::Vertical ? geom.height() : geom.width();
422     int extra_last_size = extra_split_.orientation() == Qt::Vertical ? geom.height() : geom.width();
423
424     if (recent.gui_geometry_main_upper_pane > 0) {
425         master_sizes[0] = recent.gui_geometry_main_upper_pane + 1; // Add back mystery pixel
426         master_last_size -= recent.gui_geometry_main_upper_pane + master_split_.handleWidth();
427     }
428
429     if (recent.gui_geometry_main_lower_pane > 0) {
430         if (master_sizes.length() > 2) {
431             master_sizes[1] = recent.gui_geometry_main_lower_pane + 1; // Add back mystery pixel
432             master_last_size -= recent.gui_geometry_main_lower_pane + master_split_.handleWidth();
433         } else if (extra_sizes.length() > 0) {
434             extra_sizes[0] = recent.gui_geometry_main_lower_pane; // No mystery pixel
435             extra_last_size -= recent.gui_geometry_main_lower_pane + extra_split_.handleWidth();
436             extra_sizes.last() = extra_last_size;
437         }
438     }
439
440     master_sizes.last() = master_last_size;
441
442     master_split_.setSizes(master_sizes);
443     extra_split_.setSizes(extra_sizes);
444 }
445
446 void MainWindow::layoutToolbars()
447 {
448     Qt::ToolButtonStyle tbstyle = Qt::ToolButtonIconOnly;
449     switch (prefs.gui_toolbar_main_style) {
450     case TB_STYLE_TEXT:
451         tbstyle = Qt::ToolButtonTextOnly;
452         break;
453     case TB_STYLE_BOTH:
454         tbstyle = Qt::ToolButtonTextUnderIcon;
455         break;
456     }
457
458     main_ui_->mainToolBar->setToolButtonStyle(tbstyle);
459
460     main_ui_->mainToolBar->setVisible(recent.main_toolbar_show);
461     main_ui_->displayFilterToolBar->setVisible(recent.filter_toolbar_show);
462     main_ui_->wirelessToolBar->setVisible(recent.wireless_toolbar_show);
463     main_ui_->statusBar->setVisible(recent.statusbar_show);
464 }
465
466 void MainWindow::updatePreferenceActions()
467 {
468     main_ui_->actionViewNameResolutionPhysical->setChecked(gbl_resolv_flags.mac_name);
469     main_ui_->actionViewNameResolutionNetwork->setChecked(gbl_resolv_flags.network_name);
470     main_ui_->actionViewNameResolutionTransport->setChecked(gbl_resolv_flags.transport_name);
471
472     // Should this be a "recent" setting?
473     main_ui_->actionGoAutoScroll->setChecked(prefs.capture_auto_scroll);
474 }
475
476 void MainWindow::updateRecentActions()
477 {
478     main_ui_->actionViewMainToolbar->setChecked(recent.main_toolbar_show);
479     main_ui_->actionViewFilterToolbar->setChecked(recent.filter_toolbar_show);
480     main_ui_->actionViewWirelessToolbar->setChecked(recent.wireless_toolbar_show);
481     main_ui_->actionViewStatusBar->setChecked(recent.statusbar_show);
482     main_ui_->actionViewPacketList->setChecked(recent.packet_list_show);
483     main_ui_->actionViewPacketDetails->setChecked(recent.tree_view_show);
484     main_ui_->actionViewPacketBytes->setChecked(recent.byte_view_show);
485
486     foreach (QAction* tda, td_actions.keys()) {
487         if (recent.gui_time_format == td_actions[tda]) {
488             tda->setChecked(true);
489         }
490     }
491     foreach (QAction* tpa, tp_actions.keys()) {
492         if (recent.gui_time_precision == tp_actions[tpa]) {
493             tpa->setChecked(true);
494         }
495     }
496     main_ui_->actionViewTimeDisplaySecondsWithHoursAndMinutes->setChecked(recent.gui_seconds_format == TS_SECONDS_HOUR_MIN_SEC);
497
498     main_ui_->actionViewColorizePacketList->setChecked(recent.packet_list_colorize);
499 }
500
501 void MainWindow::filterAction(QString &action_filter, FilterAction::Action action, FilterAction::ActionType type)
502 {
503     QString cur_filter, new_filter;
504
505     if (!df_combo_box_) return;
506     cur_filter = df_combo_box_->lineEdit()->text();
507
508     switch (type) {
509     case FilterAction::ActionTypePlain:
510         new_filter = action_filter;
511         break;
512     case FilterAction::ActionTypeAnd:
513         if (cur_filter.length()) {
514             new_filter = "(" + cur_filter + ") && (" + action_filter + ")";
515         } else {
516             new_filter = action_filter;
517         }
518         break;
519     case FilterAction::ActionTypeOr:
520         if (cur_filter.length()) {
521             new_filter = "(" + cur_filter + ") || (" + action_filter + ")";
522         } else {
523             new_filter = action_filter;
524         }
525         break;
526     case FilterAction::ActionTypeNot:
527         new_filter = "!(" + action_filter + ")";
528         break;
529     case FilterAction::ActionTypeAndNot:
530         if (cur_filter.length()) {
531             new_filter = "(" + cur_filter + ") && !(" + action_filter + ")";
532         } else {
533             new_filter = "!(" + action_filter + ")";
534         }
535         break;
536     case FilterAction::ActionTypeOrNot:
537         if (cur_filter.length()) {
538             new_filter = "(" + cur_filter + ") || !(" + action_filter + ")";
539         } else {
540             new_filter = "!(" + action_filter + ")";
541         }
542         break;
543     default:
544         g_assert_not_reached();
545         break;
546     }
547
548     switch(action) {
549     case FilterAction::ActionApply:
550         df_combo_box_->lineEdit()->setText(new_filter);
551         df_combo_box_->applyDisplayFilter();
552         break;
553     case FilterAction::ActionPrepare:
554         df_combo_box_->lineEdit()->setText(new_filter);
555         df_combo_box_->lineEdit()->setFocus();
556         break;
557     case FilterAction::ActionWebLookup:
558     {
559         QString url = QString("https://www.google.com/search?q=") + new_filter;
560         QDesktopServices::openUrl(QUrl(url));
561         break;
562     }
563     case FilterAction::ActionCopy:
564         wsApp->clipboard()->setText(new_filter);
565         break;
566     default:
567         qDebug() << "FIX FilterAction::Action" << action << "not implemented";
568         break;
569     }
570 }
571
572 // Capture callbacks
573
574 void MainWindow::captureCapturePrepared(capture_session *) {
575 #ifdef HAVE_LIBPCAP
576     setTitlebarForCaptureInProgress();
577
578     setWindowIcon(wsApp->captureIcon());
579
580     /* Disable menu items that make no sense if you're currently running
581        a capture. */
582     setForCaptureInProgress(true);
583 //    set_capture_if_dialog_for_capture_in_progress(TRUE);
584
585 //    /* Don't set up main window for a capture file. */
586 //    main_set_for_capture_file(FALSE);
587     main_ui_->mainStack->setCurrentWidget(&master_split_);
588 #endif // HAVE_LIBPCAP
589 }
590
591 void MainWindow::captureCaptureUpdateStarted(capture_session *) {
592 #ifdef HAVE_LIBPCAP
593
594     /* We've done this in "prepared" above, but it will be cleared while
595        switching to the next multiple file. */
596     setTitlebarForCaptureInProgress();
597
598     setForCaptureInProgress(true);
599
600     setForCapturedPackets(true);
601 #endif // HAVE_LIBPCAP
602 }
603 void MainWindow::captureCaptureUpdateFinished(capture_session *) {
604 #ifdef HAVE_LIBPCAP
605
606     /* The capture isn't stopping any more - it's stopped. */
607     capture_stopping_ = false;
608
609     /* Update the main window as appropriate */
610     updateForUnsavedChanges();
611
612     /* Enable menu items that make sense if you're not currently running
613      a capture. */
614     setForCaptureInProgress(false);
615
616     setWindowIcon(wsApp->normalIcon());
617
618     if (global_capture_opts.quit_after_cap) {
619         // Command line asked us to quit after capturing.
620         // Don't pop up a dialog to ask for unsaved files etc.
621         exit(0);
622     }
623 #endif // HAVE_LIBPCAP
624 }
625 void MainWindow::captureCaptureFixedStarted(capture_session *) {
626 #ifdef HAVE_LIBPCAP
627 #endif // HAVE_LIBPCAP
628 }
629 void MainWindow::captureCaptureFixedFinished(capture_session *) {
630 #ifdef HAVE_LIBPCAP
631
632     /* The capture isn't stopping any more - it's stopped. */
633     capture_stopping_ = false;
634
635     /* Enable menu items that make sense if you're not currently running
636      a capture. */
637     setForCaptureInProgress(false);
638
639     setWindowIcon(wsApp->normalIcon());
640
641     if (global_capture_opts.quit_after_cap) {
642         // Command line asked us to quit after capturing.
643         // Don't pop up a dialog to ask for unsaved files etc.
644         exit(0);
645     }
646 #endif // HAVE_LIBPCAP
647 }
648 void MainWindow::captureCaptureStopping(capture_session *) {
649 #ifdef HAVE_LIBPCAP
650
651     capture_stopping_ = true;
652     setMenusForCaptureStopping();
653 #endif // HAVE_LIBPCAP
654 }
655 void MainWindow::captureCaptureFailed(capture_session *) {
656 #ifdef HAVE_LIBPCAP
657     /* Capture isn't stopping any more. */
658     capture_stopping_ = false;
659
660     setForCaptureInProgress(false);
661     main_ui_->mainStack->setCurrentWidget(main_welcome_);
662
663     setWindowIcon(wsApp->normalIcon());
664
665     if (global_capture_opts.quit_after_cap) {
666         // Command line asked us to quit after capturing.
667         // Don't pop up a dialog to ask for unsaved files etc.
668         exit(0);
669     }
670 #endif // HAVE_LIBPCAP
671 }
672
673
674 // Callbacks from cfile.c and file.c via CaptureFile::captureFileCallback
675
676 void MainWindow::captureFileOpened() {
677     if (capture_file_.window() != this) return;
678
679     file_set_dialog_.fileOpened(capture_file_.capFile());
680     setMenusForFileSet(true);
681     emit setCaptureFile(capture_file_.capFile());
682 }
683
684 void MainWindow::captureFileReadStarted(const QString &action) {
685 //    tap_param_dlg_update();
686
687     /* Set up main window for a capture file. */
688 //    main_set_for_capture_file(TRUE);
689
690     main_ui_->statusBar->popFileStatus();
691     QString msg = QString(tr("%1: %2")).arg(action).arg(capture_file_.fileName());
692     QString msgtip = QString();
693     main_ui_->statusBar->pushFileStatus(msg, msgtip);
694     main_ui_->mainStack->setCurrentWidget(&master_split_);
695     main_ui_->actionAnalyzeReloadLuaPlugins->setEnabled(false);
696
697     WiresharkApplication::processEvents();
698 }
699
700 void MainWindow::captureFileReadFinished() {
701     gchar *dir_path;
702
703     if (!capture_file_.capFile()->is_tempfile && capture_file_.capFile()->filename) {
704         /* Add this filename to the list of recent files in the "Recent Files" submenu */
705         add_menu_recent_capture_file(capture_file_.capFile()->filename);
706
707         /* Remember folder for next Open dialog and save it in recent */
708         dir_path = get_dirname(g_strdup(capture_file_.capFile()->filename));
709         wsApp->setLastOpenDir(dir_path);
710         g_free(dir_path);
711     }
712
713     /* Update the appropriate parts of the main window. */
714     updateForUnsavedChanges();
715
716     /* Enable menu items that make sense if you have some captured packets. */
717     setForCapturedPackets(true);
718
719     main_ui_->statusBar->setFileName(capture_file_);
720     main_ui_->actionAnalyzeReloadLuaPlugins->setEnabled(true);
721
722     packet_list_->captureFileReadFinished();
723
724     emit setDissectedCaptureFile(capture_file_.capFile());
725 }
726
727 void MainWindow::captureFileRetapStarted()
728 {
729     // XXX Push a status message?
730     freeze();
731 }
732
733 void MainWindow::captureFileRetapFinished()
734 {
735     thaw();
736 }
737
738 void MainWindow::captureFileFlushTapsData()
739 {
740     draw_tap_listeners(FALSE);
741 }
742
743 void MainWindow::captureFileClosing() {
744     setMenusForCaptureFile(true);
745     setForCapturedPackets(false);
746     setForCaptureInProgress(false);
747
748     // Reset expert information indicator
749     main_ui_->statusBar->captureFileClosing();
750     main_ui_->searchFrame->animatedHide();
751 //    gtk_widget_show(expert_info_none);
752     emit setCaptureFile(NULL);
753     emit setDissectedCaptureFile(NULL);
754 }
755
756 void MainWindow::captureFileClosed() {
757     packets_bar_update();
758
759     file_set_dialog_.fileClosed();
760     setMenusForFileSet(false);
761     setWindowModified(false);
762
763     // Reset expert information indicator
764     main_ui_->statusBar->captureFileClosing();
765
766     main_ui_->statusBar->popFileStatus();
767
768     setDefaultWindowTitle();
769     setWindowIcon(wsApp->normalIcon());
770     setMenusForSelectedPacket();
771     setMenusForSelectedTreeRow();
772
773     if (!global_capture_opts.multi_files_on)
774         main_ui_->mainStack->setCurrentWidget(main_welcome_);
775 }
776
777 void MainWindow::captureFileSaveStarted(const QString &file_path)
778 {
779     QFileInfo file_info(file_path);
780     main_ui_->statusBar->popFileStatus();
781     main_ui_->statusBar->pushFileStatus(tr("Saving %1" UTF8_HORIZONTAL_ELLIPSIS).arg(file_info.baseName()));
782 }
783
784 void MainWindow::filterExpressionsChanged()
785 {
786     // Recreate filter buttons
787     foreach (QAction *act, main_ui_->displayFilterToolBar->actions()) {
788         // Permanent actions shouldn't have data
789         if (act->property(dfe_property_).isValid()) {
790             main_ui_->displayFilterToolBar->removeAction(act);
791             delete act;
792         }
793     }
794
795     // XXX Add a context menu for removing and changing buttons.
796     for (struct filter_expression *fe = *pfilter_expression_head; fe != NULL; fe = fe->next) {
797         if (!fe->enabled) continue;
798         QAction *dfb_action = new QAction(fe->label, main_ui_->displayFilterToolBar);
799         dfb_action->setToolTip(fe->expression);
800         dfb_action->setData(fe->expression);
801         dfb_action->setProperty(dfe_property_, true);
802         main_ui_->displayFilterToolBar->addAction(dfb_action);
803         connect(dfb_action, SIGNAL(triggered()), this, SLOT(displayFilterButtonClicked()));
804     }
805 }
806
807 //
808 // Private slots
809 //
810
811 // ui/gtk/capture_dlg.c:start_capture_confirmed
812
813 void MainWindow::startCapture() {
814 #ifdef HAVE_LIBPCAP
815     interface_options interface_opts;
816     guint i;
817
818     /* did the user ever select a capture interface before? */
819     if(global_capture_opts.num_selected == 0) {
820         QString msg = QString(tr("No interface selected"));
821         main_ui_->statusBar->pushTemporaryStatus(msg);
822         main_ui_->actionCaptureStart->setChecked(false);
823         return;
824     }
825
826     // Ideally we should have disabled the start capture
827     // toolbar buttons and menu items. This may not be the
828     // case, e.g. with QtMacExtras.
829     if(!capture_filter_valid_) {
830         QString msg = QString(tr("Invalid capture filter"));
831         main_ui_->statusBar->pushTemporaryStatus(msg);
832         main_ui_->actionCaptureStart->setChecked(false);
833         return;
834     }
835
836     main_ui_->mainStack->setCurrentWidget(&master_split_);
837
838     /* XXX - we might need to init other pref data as well... */
839
840     /* XXX - can this ever happen? */
841     if (cap_session_.state != CAPTURE_STOPPED)
842       return;
843
844     /* close the currently loaded capture file */
845     cf_close((capture_file *) cap_session_.cf);
846
847     /* Copy the selected interfaces to the set of interfaces to use for
848        this capture. */
849     collect_ifaces(&global_capture_opts);
850
851     CaptureFile::globalCapFile()->window = this;
852     if (capture_start(&global_capture_opts, &cap_session_, &info_data_, main_window_update)) {
853         capture_options *capture_opts = cap_session_.capture_opts;
854         GString *interface_names;
855
856         /* enable autoscroll timer as needed. */
857         packet_list_->setVerticalAutoScroll(main_ui_->actionGoAutoScroll->isChecked());
858
859         /* Add "interface name<live capture in progress>" on main status bar */
860         interface_names = get_iface_list_string(capture_opts, 0);
861         if (strlen (interface_names->str) > 0) {
862             g_string_append(interface_names, ":");
863         }
864         g_string_append(interface_names, " ");
865
866         main_ui_->statusBar->popFileStatus();
867         QString msg = QString().sprintf("%s<live capture in progress>", interface_names->str);
868         QString msgtip = QString().sprintf("to file: %s", (capture_opts->save_file) ? capture_opts->save_file : "");
869         main_ui_->statusBar->pushFileStatus(msg, msgtip);
870         g_string_free(interface_names, TRUE);
871
872         /* The capture succeeded, which means the capture filter syntax is
873          valid; add this capture filter to the recent capture filter list. */
874         for (i = 0; i < global_capture_opts.ifaces->len; i++) {
875             interface_opts = g_array_index(global_capture_opts.ifaces, interface_options, i);
876             if (interface_opts.cfilter) {
877 //              cfilter_combo_add_recent(interface_opts.cfilter);
878             }
879         }
880     } else {
881         CaptureFile::globalCapFile()->window = NULL;
882     }
883 #endif // HAVE_LIBPCAP
884 }
885
886 // Copied from ui/gtk/gui_utils.c
887 void MainWindow::pipeTimeout() {
888 #ifdef _WIN32
889     HANDLE handle;
890     DWORD avail = 0;
891     gboolean result, result1;
892     DWORD childstatus;
893     gint iterations = 0;
894
895
896     /* try to read data from the pipe only 5 times, to avoid blocking */
897     while(iterations < 5) {
898         /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: new iteration");*/
899
900         /* Oddly enough although Named pipes don't work on win9x,
901            PeekNamedPipe does !!! */
902         handle = (HANDLE) _get_osfhandle (pipe_source_);
903         result = PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL);
904
905         /* Get the child process exit status */
906         result1 = GetExitCodeProcess((HANDLE)*(pipe_child_process_),
907                                      &childstatus);
908
909         /* If the Peek returned an error, or there are bytes to be read
910            or the childwatcher thread has terminated then call the normal
911            callback */
912         if (!result || avail > 0 || childstatus != STILL_ACTIVE) {
913
914             /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: data avail");*/
915
916             /* And call the real handler */
917             if (!pipe_input_cb_(pipe_source_, pipe_user_data_)) {
918                 g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: input pipe closed, iterations: %u", iterations);
919                 /* pipe closed, return false so that the old timer is not run again */
920                 delete pipe_timer_;
921                 return;
922             }
923         }
924         else {
925             /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: no data avail");*/
926             /* No data, stop now */
927             break;
928         }
929
930         iterations++;
931     }
932 #endif // _WIN32
933 }
934
935 void MainWindow::pipeActivated(int source) {
936 #ifdef _WIN32
937     Q_UNUSED(source);
938 #else
939     g_assert(source == pipe_source_);
940
941     pipe_notifier_->setEnabled(false);
942     if (pipe_input_cb_(pipe_source_, pipe_user_data_)) {
943         pipe_notifier_->setEnabled(true);
944     } else {
945         delete pipe_notifier_;
946     }
947 #endif // _WIN32
948 }
949
950 void MainWindow::pipeNotifierDestroyed() {
951 #ifdef _WIN32
952     pipe_timer_ = NULL;
953 #else
954     pipe_notifier_ = NULL;
955 #endif // _WIN32
956 }
957
958 void MainWindow::stopCapture() {
959 //#ifdef HAVE_AIRPCAP
960 //  if (airpcap_if_active)
961 //    airpcap_set_toolbar_stop_capture(airpcap_if_active);
962 //#endif
963
964 #ifdef HAVE_LIBPCAP
965     capture_stop(&cap_session_);
966 #endif // HAVE_LIBPCAP
967
968     /* Pop the "<live capture in progress>" message off the status bar. */
969     main_ui_->statusBar->setFileName(capture_file_);
970
971     /* disable autoscroll timer if any. */
972     packet_list_->setVerticalAutoScroll(false);
973 }
974
975 // Keep focus rects from showing through the welcome screen. Primarily for
976 // OS X.
977 void MainWindow::mainStackChanged(int)
978 {
979     for (int i = 0; i < main_ui_->mainStack->count(); i++) {
980         main_ui_->mainStack->widget(i)->setEnabled(i == main_ui_->mainStack->currentIndex());
981     }
982 }
983
984 // XXX - Copied from ui/gtk/menus.c
985
986 /**
987  * Add the capture filename (with an absolute path) to the "Recent Files" menu.
988  */
989 // XXX - We should probably create a RecentFile class.
990 void MainWindow::updateRecentFiles() {
991     QAction *ra;
992     QMenu *recentMenu = main_ui_->menuOpenRecentCaptureFile;
993     QString action_cf_name;
994
995     if (!recentMenu) {
996         return;
997     }
998
999     recentMenu->clear();
1000
1001     /* Iterate through the actions in menuOpenRecentCaptureFile,
1002      * removing special items, a maybe duplicate entry and every item above count_max */
1003     int shortcut = Qt::Key_0;
1004     foreach (recent_item_status *ri, wsApp->recentItems()) {
1005         // Add the new item
1006         ra = new QAction(recentMenu);
1007         ra->setData(ri->filename);
1008         // XXX - Needs get_recent_item_status or equivalent
1009         ra->setEnabled(ri->accessible);
1010         recentMenu->insertAction(NULL, ra);
1011         action_cf_name = ra->data().toString();
1012         if (shortcut <= Qt::Key_9) {
1013             ra->setShortcut(Qt::META | shortcut);
1014             shortcut++;
1015         }
1016         ra->setText(action_cf_name);
1017         connect(ra, SIGNAL(triggered()), this, SLOT(recentActionTriggered()));
1018     }
1019
1020     if (recentMenu->actions().count() > 0) {
1021         // Separator + "Clear"
1022         // XXX - Do we really need this?
1023         ra = new QAction(recentMenu);
1024         ra->setSeparator(true);
1025         recentMenu->insertAction(NULL, ra);
1026
1027         ra = new QAction(recentMenu);
1028         ra->setText(tr("Clear Menu"));
1029         recentMenu->insertAction(NULL, ra);
1030         connect(ra, SIGNAL(triggered()), wsApp, SLOT(clearRecentItems()));
1031     } else {
1032         if (main_ui_->actionDummyNoFilesFound) {
1033             recentMenu->addAction(main_ui_->actionDummyNoFilesFound);
1034         }
1035     }
1036 }
1037
1038 void MainWindow::recentActionTriggered() {
1039     QAction *ra = qobject_cast<QAction*>(sender());
1040
1041     if (ra) {
1042         QString cfPath = ra->data().toString();
1043         openCaptureFile(cfPath);
1044     }
1045 }
1046
1047 void MainWindow::setMenusForSelectedPacket()
1048 {
1049     gboolean is_ip = FALSE, is_tcp = FALSE, is_udp = FALSE, is_sctp = FALSE, is_ssl = FALSE, is_rtp = FALSE, is_lte_rlc = FALSE;
1050
1051     /* Making the menu context-sensitive allows for easier selection of the
1052        desired item and has the added benefit, with large captures, of
1053        avoiding needless looping through huge lists for marked, ignored,
1054        or time-referenced packets. */
1055
1056     /* We have one or more items in the packet list */
1057     bool have_frames = false;
1058     /* A frame is selected */
1059     bool frame_selected = false;
1060     /* We have marked frames.  (XXX - why check frame_selected?) */
1061     bool have_marked = false;
1062     /* We have a marked frame other than the current frame (i.e.,
1063        we have at least one marked frame, and either there's more
1064        than one marked frame or the current frame isn't marked). */
1065     bool another_is_marked = false;
1066     /* One or more frames are hidden by a display filter */
1067     bool have_filtered = false;
1068     /* One or more frames have been ignored */
1069     bool have_ignored = false;
1070     bool have_time_ref = false;
1071     /* We have a time reference frame other than the current frame (i.e.,
1072        we have at least one time reference frame, and either there's more
1073        than one time reference frame or the current frame isn't a
1074        time reference frame). (XXX - why check frame_selected?) */
1075     bool another_is_time_ref = false;
1076     /* We have a valid filter expression */
1077     bool have_filter_expr = false;
1078
1079     QList<QAction *> cc_actions = QList<QAction *>()
1080             << main_ui_->actionViewColorizeConversation1 << main_ui_->actionViewColorizeConversation2
1081             << main_ui_->actionViewColorizeConversation3 << main_ui_->actionViewColorizeConversation4
1082             << main_ui_->actionViewColorizeConversation5 << main_ui_->actionViewColorizeConversation6
1083             << main_ui_->actionViewColorizeConversation7 << main_ui_->actionViewColorizeConversation8
1084             << main_ui_->actionViewColorizeConversation9 << main_ui_->actionViewColorizeConversation10;
1085
1086     if (capture_file_.capFile()) {
1087         frame_selected = capture_file_.capFile()->current_frame != NULL;
1088         have_frames = capture_file_.capFile()->count > 0;
1089         have_marked = frame_selected && capture_file_.capFile()->marked_count > 0;
1090         another_is_marked = have_marked &&
1091                 !(capture_file_.capFile()->marked_count == 1 && capture_file_.capFile()->current_frame->flags.marked);
1092         have_filtered = capture_file_.capFile()->displayed_count > 0 && capture_file_.capFile()->displayed_count != capture_file_.capFile()->count;
1093         have_ignored = capture_file_.capFile()->ignored_count > 0;
1094         have_time_ref = capture_file_.capFile()->ref_time_count > 0;
1095         another_is_time_ref = frame_selected && have_time_ref &&
1096                 !(capture_file_.capFile()->ref_time_count == 1 && capture_file_.capFile()->current_frame->flags.ref_time);
1097
1098         if (capture_file_.capFile()->edt)
1099         {
1100             proto_get_frame_protocols(capture_file_.capFile()->edt->pi.layers,
1101                                       &is_ip, &is_tcp, &is_udp, &is_sctp,
1102                                       &is_ssl, &is_rtp, &is_lte_rlc);
1103         }
1104     }
1105
1106     have_filter_expr = !packet_list_->getFilterFromRowAndColumn().isEmpty();
1107
1108     main_ui_->actionEditMarkPacket->setEnabled(frame_selected);
1109     main_ui_->actionEditMarkAllDisplayed->setEnabled(have_frames);
1110     /* Unlike un-ignore, do not allow unmark of all frames when no frames are displayed  */
1111     main_ui_->actionEditUnmarkAllDisplayed->setEnabled(have_marked);
1112     main_ui_->actionEditNextMark->setEnabled(another_is_marked);
1113     main_ui_->actionEditPreviousMark->setEnabled(another_is_marked);
1114
1115 #ifdef WANT_PACKET_EDITOR
1116 //    set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/EditMenu/EditPacket",
1117 //                         frame_selected);
1118 #endif // WANT_PACKET_EDITOR
1119     main_ui_->actionEditPacketComment->setEnabled(frame_selected && wtap_dump_can_write(capture_file_.capFile()->linktypes, WTAP_COMMENT_PER_PACKET));
1120
1121     main_ui_->actionEditIgnorePacket->setEnabled(frame_selected);
1122     main_ui_->actionEditIgnoreAllDisplayed->setEnabled(have_filtered);
1123     /* Allow un-ignore of all frames even with no frames currently displayed */
1124     main_ui_->actionEditUnignoreAllDisplayed->setEnabled(have_ignored);
1125
1126     main_ui_->actionEditSetTimeReference->setEnabled(frame_selected);
1127     main_ui_->actionEditUnsetAllTimeReferences->setEnabled(have_time_ref);
1128     main_ui_->actionEditNextTimeReference->setEnabled(another_is_time_ref);
1129     main_ui_->actionEditPreviousTimeReference->setEnabled(another_is_time_ref);
1130     main_ui_->actionEditTimeShift->setEnabled(have_frames);
1131
1132     main_ui_->actionGoGoToLinkedPacket->setEnabled(false);
1133
1134     main_ui_->actionAnalyzeAAFSelected->setEnabled(have_filter_expr);
1135     main_ui_->actionAnalyzeAAFNotSelected->setEnabled(have_filter_expr);
1136     main_ui_->actionAnalyzeAAFAndSelected->setEnabled(have_filter_expr);
1137     main_ui_->actionAnalyzeAAFOrSelected->setEnabled(have_filter_expr);
1138     main_ui_->actionAnalyzeAAFAndNotSelected->setEnabled(have_filter_expr);
1139     main_ui_->actionAnalyzeAAFOrNotSelected->setEnabled(have_filter_expr);
1140
1141     main_ui_->actionAnalyzePAFSelected->setEnabled(have_filter_expr);
1142     main_ui_->actionAnalyzePAFNotSelected->setEnabled(have_filter_expr);
1143     main_ui_->actionAnalyzePAFAndSelected->setEnabled(have_filter_expr);
1144     main_ui_->actionAnalyzePAFOrSelected->setEnabled(have_filter_expr);
1145     main_ui_->actionAnalyzePAFAndNotSelected->setEnabled(have_filter_expr);
1146     main_ui_->actionAnalyzePAFOrNotSelected->setEnabled(have_filter_expr);
1147
1148     main_ui_->actionAnalyzeFollowTCPStream->setEnabled(is_tcp);
1149     main_ui_->actionAnalyzeFollowUDPStream->setEnabled(is_udp);
1150     main_ui_->actionAnalyzeFollowSSLStream->setEnabled(is_ssl);
1151
1152     foreach (QAction *cc_action, cc_actions) {
1153         cc_action->setEnabled(frame_selected);
1154     }
1155     main_ui_->actionViewColorizeNewConversationRule->setEnabled(frame_selected);
1156
1157     main_ui_->actionViewColorizeResetColorization->setEnabled(tmp_color_filters_used());
1158
1159     main_ui_->actionViewColorizeNewConversationRule->setEnabled(frame_selected);
1160
1161     main_ui_->actionViewShowPacketInNewWindow->setEnabled(frame_selected);
1162     main_ui_->actionViewEditResolvedName->setEnabled(frame_selected && is_ip);
1163
1164     main_ui_->menuConversationFilter->clear();
1165
1166     packet_list_->conversationMenu()->clear();
1167     packet_list_->colorizeMenu()->clear();
1168
1169     for (GList *conv_filter_list_entry = conv_filter_list; conv_filter_list_entry; conv_filter_list_entry = g_list_next(conv_filter_list_entry)) {
1170         // Main menu items
1171         conversation_filter_t* conv_filter = (conversation_filter_t *)conv_filter_list_entry->data;
1172         QAction *conv_action = main_ui_->menuConversationFilter->addAction(conv_filter->display_name);
1173
1174         bool enable = false;
1175         QString filter;
1176         if (capture_file_.capFile() && capture_file_.capFile()->edt) {
1177             enable = conv_filter->is_filter_valid(&capture_file_.capFile()->edt->pi);
1178             filter = gchar_free_to_qstring(conv_filter->build_filter_string(&capture_file_.capFile()->edt->pi));
1179         }
1180         conv_action->setEnabled(enable);
1181         conv_action->setData(filter);
1182         connect(conv_action, SIGNAL(triggered()), this, SLOT(applyConversationFilter()));
1183
1184         // Packet list context menu items
1185         packet_list_->conversationMenu()->addAction(conv_action);
1186
1187         QMenu *submenu = packet_list_->colorizeMenu()->addMenu(conv_action->text());
1188         int i = 1;
1189         foreach (QAction *cc_action, cc_actions) {
1190             QAction *colorize_action = submenu->addAction(cc_action->icon(), cc_action->text());
1191             colorize_action->setProperty(color_number_property_, i++);
1192             colorize_action->setData(filter);
1193             colorize_action->setEnabled(enable);
1194             connect(colorize_action, SIGNAL(triggered()), this, SLOT(colorizeWithFilter()));
1195         }
1196
1197         QAction *conv_rule_action = submenu->addAction(main_ui_->actionViewColorizeNewConversationRule->text());
1198         conv_rule_action->setData(conv_action->data());
1199         conv_rule_action->setEnabled(enable);
1200         connect(conv_rule_action, SIGNAL(triggered()), this, SLOT(colorizeWithFilter()));
1201     }
1202
1203 //    set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/ViewMenu/NameResolution/ResolveName",
1204 //                         frame_selected && (gbl_resolv_flags.mac_name || gbl_resolv_flags.network_name ||
1205 //                                            gbl_resolv_flags.transport_name || gbl_resolv_flags.concurrent_dns));
1206 //    set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/ToolsMenu/FirewallACLRules",
1207 //                         frame_selected);
1208     main_ui_->menuTcpStreamGraphs->setEnabled(is_tcp);
1209     main_ui_->actionSCTPAnalyseThisAssociation->setEnabled(is_sctp);
1210     main_ui_->actionSCTPShowAllAssociations->setEnabled(is_sctp);
1211     main_ui_->actionSCTPFilterThisAssociation->setEnabled(is_sctp);
1212     main_ui_->actionTelephonyRTPStreamAnalysis->setEnabled(is_rtp);
1213     main_ui_->actionTelephonyLteRlcGraph->setEnabled(is_lte_rlc);
1214 }
1215
1216 void MainWindow::setMenusForSelectedTreeRow(field_info *fi) {
1217
1218     bool can_match_selected = false;
1219     bool is_framenum = false;
1220     bool have_field_info = false;
1221     bool have_subtree = false;
1222     bool can_open_url = false;
1223     QString field_filter;
1224     int field_id = -1;
1225
1226     QList<QAction *> cc_actions = QList<QAction *>()
1227             << main_ui_->actionViewColorizeConversation1 << main_ui_->actionViewColorizeConversation2
1228             << main_ui_->actionViewColorizeConversation3 << main_ui_->actionViewColorizeConversation4
1229             << main_ui_->actionViewColorizeConversation5 << main_ui_->actionViewColorizeConversation6
1230             << main_ui_->actionViewColorizeConversation7 << main_ui_->actionViewColorizeConversation8
1231             << main_ui_->actionViewColorizeConversation9 << main_ui_->actionViewColorizeConversation10;
1232
1233     if (capture_file_.capFile()) {
1234         capture_file_.capFile()->finfo_selected = fi;
1235
1236         if (fi && fi->tree_type != -1) {
1237             have_subtree = true;
1238         }
1239     }
1240
1241     if (capture_file_.capFile() != NULL && fi != NULL) {
1242         header_field_info *hfinfo = fi->hfinfo;
1243         int linked_frame = -1;
1244
1245         have_field_info = true;
1246         can_match_selected = proto_can_match_selected(capture_file_.capFile()->finfo_selected, capture_file_.capFile()->edt);
1247         if (hfinfo && hfinfo->type == FT_FRAMENUM) {
1248             is_framenum = true;
1249             linked_frame = fvalue_get_uinteger(&fi->value);
1250         }
1251
1252         char *tmp_field = proto_construct_match_selected_string(fi, capture_file_.capFile()->edt);
1253         field_filter = QString(tmp_field);
1254         wmem_free(NULL, tmp_field);
1255
1256         field_id = fi->hfinfo->id;
1257         /* if the selected field isn't a protocol, get its parent */
1258         if (!proto_registrar_is_protocol(field_id)) {
1259             field_id = proto_registrar_get_parent(fi->hfinfo->id);
1260         }
1261
1262         if (field_id >= 0) {
1263             can_open_url = true;
1264             main_ui_->actionContextWikiProtocolPage->setData(field_id);
1265             main_ui_->actionContextFilterFieldReference->setData(field_id);
1266         } else {
1267             main_ui_->actionContextWikiProtocolPage->setData(QVariant());
1268             main_ui_->actionContextFilterFieldReference->setData(QVariant());
1269         }
1270
1271         if (linked_frame > 0) {
1272             main_ui_->actionGoGoToLinkedPacket->setData(linked_frame);
1273         } else {
1274             main_ui_->actionGoGoToLinkedPacket->setData(QVariant());
1275         }
1276     }
1277
1278     // Always enable / disable the following items.
1279     main_ui_->actionFileExportPacketBytes->setEnabled(have_field_info);
1280
1281     main_ui_->actionCopyAllVisibleItems->setEnabled(capture_file_.capFile() != NULL);
1282     main_ui_->actionCopyAllVisibleSelectedTreeItems->setEnabled(can_match_selected);
1283     main_ui_->actionEditCopyDescription->setEnabled(can_match_selected);
1284     main_ui_->actionEditCopyFieldName->setEnabled(can_match_selected);
1285     main_ui_->actionEditCopyValue->setEnabled(can_match_selected);
1286     main_ui_->actionEditCopyAsFilter->setEnabled(can_match_selected);
1287
1288     main_ui_->actionViewExpandSubtrees->setEnabled(have_subtree);
1289
1290     main_ui_->actionGoGoToLinkedPacket->setEnabled(is_framenum);
1291
1292     main_ui_->actionAnalyzeCreateAColumn->setEnabled(can_match_selected);
1293
1294     main_ui_->actionContextShowLinkedPacketInNewWindow->setEnabled(is_framenum);
1295
1296     main_ui_->actionContextWikiProtocolPage->setEnabled(can_open_url);
1297     main_ui_->actionContextFilterFieldReference->setEnabled(can_open_url);
1298
1299
1300     // Only enable / disable the following items if we have focus so that we
1301     // don't clobber anything we may have set in setMenusForSelectedPacket.
1302     if (!proto_tree_ || !proto_tree_->hasFocus()) return;
1303
1304     main_ui_->menuConversationFilter->clear();
1305     for (GList *conv_filter_list_entry = conv_filter_list; conv_filter_list_entry; conv_filter_list_entry = g_list_next(conv_filter_list_entry)) {
1306         conversation_filter_t* conv_filter = (conversation_filter_t *)conv_filter_list_entry->data;
1307         QAction *conv_action = main_ui_->menuConversationFilter->addAction(conv_filter->display_name);
1308
1309         bool enable = false;
1310         QString filter;
1311         if (fi && capture_file_.capFile() && capture_file_.capFile()->edt) {
1312             enable = conv_filter->is_filter_valid(&capture_file_.capFile()->edt->pi);
1313             filter = conv_filter->build_filter_string(&capture_file_.capFile()->edt->pi);
1314         }
1315         conv_action->setEnabled(enable);
1316         conv_action->setData(filter);
1317         connect(conv_action, SIGNAL(triggered()), this, SLOT(applyConversationFilter()));
1318     }
1319
1320     proto_tree_->colorizeMenu()->clear();
1321     int i = 1;
1322     foreach (QAction *cc_action, cc_actions) {
1323         QAction *colorize_action = proto_tree_->colorizeMenu()->addAction(cc_action->icon(), cc_action->text());
1324         colorize_action->setProperty(color_number_property_, i++);
1325         colorize_action->setData(field_filter);
1326         colorize_action->setEnabled(!field_filter.isEmpty());
1327         connect(colorize_action, SIGNAL(triggered()), this, SLOT(colorizeWithFilter()));
1328     }
1329
1330     QAction *conv_rule_action = proto_tree_->colorizeMenu()->addAction(main_ui_->actionViewColorizeNewConversationRule->text());
1331     conv_rule_action->setData(field_filter);
1332     conv_rule_action->setEnabled(!field_filter.isEmpty());
1333     connect(conv_rule_action, SIGNAL(triggered()), this, SLOT(colorizeWithFilter()));
1334
1335 //    set_menu_sensitivity(ui_manager_tree_view_menu, "/TreeViewPopup/ResolveName",
1336 //                         frame_selected && (gbl_resolv_flags.mac_name || gbl_resolv_flags.network_name ||
1337 //                                            gbl_resolv_flags.transport_name || gbl_resolv_flags.concurrent_dns));
1338
1339
1340     main_ui_->actionAnalyzeAAFSelected->setEnabled(can_match_selected);
1341     main_ui_->actionAnalyzeAAFNotSelected->setEnabled(can_match_selected);
1342     main_ui_->actionAnalyzeAAFAndSelected->setEnabled(can_match_selected);
1343     main_ui_->actionAnalyzeAAFOrSelected->setEnabled(can_match_selected);
1344     main_ui_->actionAnalyzeAAFAndNotSelected->setEnabled(can_match_selected);
1345     main_ui_->actionAnalyzeAAFOrNotSelected->setEnabled(can_match_selected);
1346
1347     main_ui_->actionAnalyzePAFSelected->setEnabled(can_match_selected);
1348     main_ui_->actionAnalyzePAFNotSelected->setEnabled(can_match_selected);
1349     main_ui_->actionAnalyzePAFAndSelected->setEnabled(can_match_selected);
1350     main_ui_->actionAnalyzePAFOrSelected->setEnabled(can_match_selected);
1351     main_ui_->actionAnalyzePAFAndNotSelected->setEnabled(can_match_selected);
1352     main_ui_->actionAnalyzePAFOrNotSelected->setEnabled(can_match_selected);
1353 }
1354
1355 void MainWindow::interfaceSelectionChanged()
1356 {
1357 #ifdef HAVE_LIBPCAP
1358     // XXX This doesn't disable the toolbar button when using
1359     // QtMacExtras.
1360     if (global_capture_opts.num_selected > 0 && capture_filter_valid_) {
1361         main_ui_->actionCaptureStart->setEnabled(true);
1362     } else {
1363         main_ui_->actionCaptureStart->setEnabled(false);
1364     }
1365 #endif // HAVE_LIBPCAP
1366 }
1367
1368 void MainWindow::captureFilterSyntaxChanged(bool valid)
1369 {
1370     capture_filter_valid_ = valid;
1371     interfaceSelectionChanged();
1372 }
1373
1374 void MainWindow::startInterfaceCapture(bool valid)
1375 {
1376     capture_filter_valid_ = valid;
1377     startCapture();
1378 }
1379
1380 void MainWindow::redissectPackets()
1381 {
1382     if (capture_file_.capFile()) {
1383         cf_redissect_packets(capture_file_.capFile());
1384         main_ui_->statusBar->expertUpdate();
1385     }
1386
1387     proto_free_deregistered_fields();
1388 }
1389
1390 void MainWindow::checkDisplayFilter()
1391 {
1392     if (!df_combo_box_->checkDisplayFilter()) {
1393         g_free(CaptureFile::globalCapFile()->dfilter);
1394         CaptureFile::globalCapFile()->dfilter = NULL;
1395     }
1396 }
1397
1398 void MainWindow::fieldsChanged()
1399 {
1400     color_filters_reload();
1401     tap_listeners_dfilter_recompile();
1402
1403     emit checkDisplayFilter();
1404
1405     if (have_custom_cols(&CaptureFile::globalCapFile()->cinfo)) {
1406         // Recreate packet list columns according to new/changed/deleted fields
1407         packet_list_->fieldsChanged(CaptureFile::globalCapFile());
1408     }
1409
1410     emit reloadFields();
1411 }
1412
1413 void MainWindow::showAccordionFrame(AccordionFrame *show_frame, bool toggle)
1414 {
1415     QList<AccordionFrame *>frame_list = QList<AccordionFrame *>()
1416             << main_ui_->goToFrame << main_ui_->searchFrame
1417             << main_ui_->addressEditorFrame << main_ui_->columnEditorFrame
1418             << main_ui_->preferenceEditorFrame;
1419
1420     frame_list.removeAll(show_frame);
1421     foreach (AccordionFrame *af, frame_list) af->animatedHide();
1422
1423     if (toggle) {
1424         if (show_frame->isVisible()) {
1425             show_frame->animatedHide();
1426             return;
1427         }
1428     }
1429     show_frame->animatedShow();
1430 }
1431
1432 void MainWindow::showColumnEditor(int column)
1433 {
1434     previous_focus_ = wsApp->focusWidget();
1435     connect(previous_focus_, SIGNAL(destroyed()), this, SLOT(resetPreviousFocus()));
1436     showAccordionFrame(main_ui_->columnEditorFrame);
1437     main_ui_->columnEditorFrame->editColumn(column);
1438 }
1439
1440 void MainWindow::showPreferenceEditor()
1441 {
1442     showAccordionFrame(main_ui_->preferenceEditorFrame);
1443 }
1444
1445 void MainWindow::initViewColorizeMenu()
1446 {
1447     QList<QAction *> cc_actions = QList<QAction *>()
1448             << main_ui_->actionViewColorizeConversation1 << main_ui_->actionViewColorizeConversation2
1449             << main_ui_->actionViewColorizeConversation3 << main_ui_->actionViewColorizeConversation4
1450             << main_ui_->actionViewColorizeConversation5 << main_ui_->actionViewColorizeConversation6
1451             << main_ui_->actionViewColorizeConversation7 << main_ui_->actionViewColorizeConversation8
1452             << main_ui_->actionViewColorizeConversation9 << main_ui_->actionViewColorizeConversation10;
1453
1454     guint8 color_num = 1;
1455
1456     foreach (QAction *cc_action, cc_actions) {
1457         cc_action->setData(color_num);
1458         connect(cc_action, SIGNAL(triggered()), this, SLOT(colorizeConversation()));
1459
1460         const color_filter_t *colorf = color_filters_tmp_color(color_num);
1461         if (colorf) {
1462             QColor bg = ColorUtils::fromColorT(colorf->bg_color);
1463             QColor fg = ColorUtils::fromColorT(colorf->fg_color);
1464             cc_action->setIcon(StockIcon::colorIcon(bg.rgb(), fg.rgb(), QString::number(color_num)));
1465         }
1466         color_num++;
1467     }
1468
1469 #ifdef Q_OS_MAC
1470     // Spotlight uses Cmd+Space
1471     main_ui_->actionViewColorizeResetColorization->setShortcut(QKeySequence("Meta+Space"));
1472 #endif
1473 }
1474
1475 void MainWindow::addStatsPluginsToMenu() {
1476     GList          *cfg_list = stats_tree_get_cfg_list();
1477     GList          *iter = g_list_first(cfg_list);
1478     QAction        *stats_tree_action;
1479     QMenu          *parent_menu;
1480     bool            first_item = true;
1481
1482     while (iter) {
1483         stats_tree_cfg *cfg = (stats_tree_cfg*)iter->data;
1484         if (cfg->plugin) {
1485             if (first_item) {
1486                 main_ui_->menuStatistics->addSeparator();
1487                 first_item = false;
1488             }
1489
1490             parent_menu = main_ui_->menuStatistics;
1491             // gtk/main_menubar.c compresses double slashes, hence SkipEmptyParts
1492             QStringList cfg_name_parts = QString(cfg->name).split("/", QString::SkipEmptyParts);
1493             if (cfg_name_parts.isEmpty()) continue;
1494
1495             QString stat_name = cfg_name_parts.takeLast();
1496             if (!cfg_name_parts.isEmpty()) {
1497                 QString menu_name = cfg_name_parts.join("/");
1498                 parent_menu = findOrAddMenu(parent_menu, menu_name);
1499             }
1500
1501             stats_tree_action = new QAction(stat_name, this);
1502             stats_tree_action->setData(cfg->abbr);
1503             parent_menu->addAction(stats_tree_action);
1504             connect(stats_tree_action, SIGNAL(triggered()), this, SLOT(actionStatisticsPlugin_triggered()));
1505         }
1506         iter = g_list_next(iter);
1507     }
1508     g_list_free(cfg_list);
1509 }
1510
1511 void MainWindow::setFeaturesEnabled(bool enabled)
1512 {
1513     main_ui_->menuBar->setEnabled(enabled);
1514     main_ui_->mainToolBar->setEnabled(enabled);
1515     main_ui_->displayFilterToolBar->setEnabled(enabled);
1516     if(enabled)
1517     {
1518         main_ui_->statusBar->clearMessage();
1519     }
1520     else
1521     {
1522         main_ui_->statusBar->showMessage(tr("Please wait while Wireshark is initializing" UTF8_HORIZONTAL_ELLIPSIS));
1523     }
1524 }
1525
1526 // Display Filter Toolbar
1527
1528 void MainWindow::on_actionDisplayFilterExpression_triggered()
1529 {
1530     DisplayFilterExpressionDialog *dfe_dialog = new DisplayFilterExpressionDialog(this);
1531
1532     connect(dfe_dialog, SIGNAL(insertDisplayFilter(QString)),
1533             df_combo_box_->lineEdit(), SLOT(insertFilter(const QString &)));
1534
1535     dfe_dialog->show();
1536 }
1537
1538 void MainWindow::on_actionNewDisplayFilterExpression_triggered()
1539 {
1540     main_ui_->filterExpressionFrame->addExpression(df_combo_box_->lineEdit()->text());
1541     showAccordionFrame(main_ui_->filterExpressionFrame);
1542 }
1543
1544 // On Qt4 + OS X with unifiedTitleAndToolBarOnMac set it's possible to make
1545 // the main window obnoxiously wide.
1546
1547 void MainWindow::displayFilterButtonClicked()
1548 {
1549     QAction *dfb_action = qobject_cast<QAction*>(sender());
1550
1551     if (dfb_action) {
1552         df_combo_box_->lineEdit()->setText(dfb_action->data().toString());
1553         df_combo_box_->applyDisplayFilter();
1554         df_combo_box_->lineEdit()->setFocus();
1555     }
1556 }
1557
1558 void MainWindow::openStatCommandDialog(const QString &menu_path, const char *arg, void *userdata)
1559 {
1560     QString slot = QString("statCommand%1").arg(menu_path);
1561     QMetaObject::invokeMethod(this, slot.toLatin1().constData(), Q_ARG(const char *, arg), Q_ARG(void *, userdata));
1562 }
1563
1564 void MainWindow::openTapParameterDialog(const QString cfg_str, const QString arg, void *userdata)
1565 {
1566     TapParameterDialog *tp_dialog = TapParameterDialog::showTapParameterStatistics(*this, capture_file_, cfg_str, arg, userdata);
1567     if (!tp_dialog) return;
1568
1569     connect(tp_dialog, SIGNAL(filterAction(QString&,FilterAction::Action,FilterAction::ActionType)),
1570             this, SLOT(filterAction(QString&,FilterAction::Action,FilterAction::ActionType)));
1571     connect(tp_dialog, SIGNAL(updateFilter(QString)),
1572             df_combo_box_->lineEdit(), SLOT(setText(QString)));
1573     tp_dialog->show();
1574 }
1575
1576 void MainWindow::openTapParameterDialog()
1577 {
1578     QAction *tpa = qobject_cast<QAction *>(QObject::sender());
1579     if (!tpa) return;
1580
1581     const QString cfg_str = tpa->data().toString();
1582     openTapParameterDialog(cfg_str, NULL, NULL);
1583 }
1584
1585 // File Menu
1586
1587 void MainWindow::on_actionFileOpen_triggered()
1588 {
1589     openCaptureFile();
1590 }
1591
1592 void MainWindow::on_actionFileMerge_triggered()
1593 {
1594     mergeCaptureFile();
1595 }
1596
1597 void MainWindow::on_actionFileImportFromHexDump_triggered()
1598 {
1599     importCaptureFile();
1600 }
1601
1602 void MainWindow::on_actionFileClose_triggered() {
1603     if (testCaptureFileClose())
1604         main_ui_->mainStack->setCurrentWidget(main_welcome_);
1605 }
1606
1607 void MainWindow::on_actionFileSave_triggered()
1608 {
1609     saveCaptureFile(capture_file_.capFile(), FALSE);
1610 }
1611
1612 void MainWindow::on_actionFileSaveAs_triggered()
1613 {
1614     saveAsCaptureFile(capture_file_.capFile());
1615 }
1616
1617 void MainWindow::on_actionFileSetListFiles_triggered()
1618 {
1619     file_set_dialog_.show();
1620 }
1621
1622 void MainWindow::on_actionFileSetNextFile_triggered()
1623 {
1624     fileset_entry *entry = fileset_get_next();
1625
1626     if (entry) {
1627         QString new_cf_path = entry->fullname;
1628         openCaptureFile(new_cf_path);
1629     }
1630 }
1631
1632 void MainWindow::on_actionFileSetPreviousFile_triggered()
1633 {
1634     fileset_entry *entry = fileset_get_previous();
1635
1636     if (entry) {
1637         QString new_cf_path = entry->fullname;
1638         openCaptureFile(new_cf_path);
1639     }
1640 }
1641
1642 void MainWindow::on_actionFileExportPackets_triggered()
1643 {
1644     exportSelectedPackets();
1645 }
1646
1647 void MainWindow::on_actionFileExportAsPlainText_triggered()
1648 {
1649     exportDissections(export_type_text);
1650 }
1651
1652 void MainWindow::on_actionFileExportAsCSV_triggered()
1653 {
1654     exportDissections(export_type_csv);
1655 }
1656
1657 void MainWindow::on_actionFileExportAsCArrays_triggered()
1658 {
1659     exportDissections(export_type_carrays);
1660 }
1661
1662 void MainWindow::on_actionFileExportAsPSML_triggered()
1663 {
1664     exportDissections(export_type_psml);
1665 }
1666
1667 void MainWindow::on_actionFileExportAsPDML_triggered()
1668 {
1669     exportDissections(export_type_pdml);
1670 }
1671
1672 void MainWindow::on_actionFileExportPacketBytes_triggered()
1673 {
1674     QString file_name;
1675
1676     if (!capture_file_.capFile() || !capture_file_.capFile()->finfo_selected) return;
1677
1678     file_name = QFileDialog::getSaveFileName(this,
1679                                              wsApp->windowTitleString(tr("Export Selected Packet Bytes")),
1680                                              wsApp->lastOpenDir().canonicalPath(),
1681                                              tr("Raw data (*.bin *.dat *.raw);;Any File (*.*)")
1682                                              );
1683
1684     if (file_name.length() > 0) {
1685         const guint8 *data_p;
1686         int fd;
1687
1688         data_p = tvb_get_ptr(capture_file_.capFile()->finfo_selected->ds_tvb, 0, -1) +
1689                 capture_file_.capFile()->finfo_selected->start;
1690         fd = ws_open(file_name.toUtf8().constData(), O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0666);
1691         if (fd == -1) {
1692             open_failure_alert_box(file_name.toUtf8().constData(), errno, TRUE);
1693             return;
1694         }
1695         if (ws_write(fd, data_p, capture_file_.capFile()->finfo_selected->length) < 0) {
1696             write_failure_alert_box(file_name.toUtf8().constData(), errno);
1697             ws_close(fd);
1698             return;
1699         }
1700         if (ws_close(fd) < 0) {
1701             write_failure_alert_box(file_name.toUtf8().constData(), errno);
1702             return;
1703         }
1704
1705         /* Save the directory name for future file dialogs. */
1706         wsApp->setLastOpenDir(&file_name);
1707     }
1708 }
1709 void MainWindow::on_actionFileExportPDU_triggered()
1710 {
1711     ExportPDUDialog *exportpdu_dialog = new ExportPDUDialog(this);
1712
1713     if (exportpdu_dialog->isMinimized() == true)
1714     {
1715         exportpdu_dialog->showNormal();
1716     }
1717     else
1718     {
1719         exportpdu_dialog->show();
1720     }
1721
1722     exportpdu_dialog->raise();
1723     exportpdu_dialog->activateWindow();
1724 }
1725
1726 void MainWindow::on_actionFileExportSSLSessionKeys_triggered()
1727 {
1728     QString file_name;
1729     QString save_title;
1730     int keylist_len;
1731
1732     keylist_len = ssl_session_key_count();
1733     /* don't show up the dialog, if no data has to be saved */
1734     if (keylist_len < 1) {
1735         /* shouldn't happen as the menu item should have been greyed out */
1736         QMessageBox::warning(
1737                     this,
1738                     tr("No Keys"),
1739                     tr("There are no SSL Session Keys to save."),
1740                     QMessageBox::Ok
1741                     );
1742         return;
1743     }
1744
1745     save_title.append(wsApp->windowTitleString(tr("Export SSL Session Keys (%1 key%2").
1746             arg(keylist_len).arg(plurality(keylist_len, "", "s"))));
1747     file_name = QFileDialog::getSaveFileName(this,
1748                                              save_title,
1749                                              wsApp->lastOpenDir().canonicalPath(),
1750                                              tr("SSL Session Keys (*.keys *.txt);;Any File (*.*)")
1751                                              );
1752     if (file_name.length() > 0) {
1753         gchar *keylist;
1754         int fd;
1755
1756         keylist = ssl_export_sessions();
1757         fd = ws_open(file_name.toUtf8().constData(), O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0666);
1758         if (fd == -1) {
1759             open_failure_alert_box(file_name.toUtf8().constData(), errno, TRUE);
1760             g_free(keylist);
1761             return;
1762         }
1763         /*
1764          * Thanks, Microsoft, for not using size_t for the third argument to
1765          * _write().  Presumably this string will be <= 4GiB long....
1766          */
1767         if (ws_write(fd, keylist, (unsigned int)strlen(keylist)) < 0) {
1768             write_failure_alert_box(file_name.toUtf8().constData(), errno);
1769             ws_close(fd);
1770             g_free(keylist);
1771             return;
1772         }
1773         if (ws_close(fd) < 0) {
1774             write_failure_alert_box(file_name.toUtf8().constData(), errno);
1775             g_free(keylist);
1776             return;
1777         }
1778
1779         /* Save the directory name for future file dialogs. */
1780         wsApp->setLastOpenDir(&file_name);
1781         g_free(keylist);
1782     }
1783 }
1784
1785 void MainWindow::on_actionFileExportObjectsDICOM_triggered()
1786 {
1787     new ExportObjectDialog(*this, capture_file_, ExportObjectDialog::Dicom);
1788 }
1789
1790 void MainWindow::on_actionStatisticsHpfeeds_triggered()
1791 {
1792     openStatisticsTreeDialog("hpfeeds");
1793 }
1794
1795 void MainWindow::on_actionFileExportObjectsHTTP_triggered()
1796 {
1797     new ExportObjectDialog(*this, capture_file_, ExportObjectDialog::Http);
1798 }
1799
1800 void MainWindow::on_actionFileExportObjectsSMB_triggered()
1801 {
1802     new ExportObjectDialog(*this, capture_file_, ExportObjectDialog::Smb);
1803 }
1804
1805 void MainWindow::on_actionFileExportObjectsTFTP_triggered()
1806 {
1807     new ExportObjectDialog(*this, capture_file_, ExportObjectDialog::Tftp);
1808 }
1809
1810 void MainWindow::on_actionFilePrint_triggered()
1811 {
1812     PrintDialog pdlg(this, capture_file_.capFile());
1813
1814     pdlg.exec();
1815 }
1816
1817 // Edit Menu
1818
1819 void MainWindow::recursiveCopyProtoTreeItems(QTreeWidgetItem *item, QString &clip, int ident_level) {
1820     if (!item->isExpanded()) return;
1821
1822     for (int i_item = 0; i_item < item->childCount(); i_item += 1) {
1823         clip.append(QString("    ").repeated(ident_level));
1824         clip.append(item->child(i_item)->text(0));
1825         clip.append("\n");
1826
1827         recursiveCopyProtoTreeItems(item->child(i_item), clip, ident_level + 1);
1828     }
1829 }
1830
1831 // XXX This should probably be somewhere else.
1832 void MainWindow::actionEditCopyTriggered(MainWindow::CopySelected selection_type)
1833 {
1834     char label_str[ITEM_LABEL_LENGTH];
1835     QString clip;
1836
1837     if (!capture_file_.capFile()) return;
1838
1839     field_info *finfo_selected = capture_file_.capFile()->finfo_selected;
1840
1841     switch(selection_type) {
1842     case CopySelectedDescription:
1843         if (finfo_selected && finfo_selected->rep
1844                 && strlen (finfo_selected->rep->representation) > 0) {
1845             clip.append(finfo_selected->rep->representation);
1846         }
1847         break;
1848     case CopySelectedFieldName:
1849         if (finfo_selected && finfo_selected->hfinfo->abbrev != 0) {
1850             clip.append(finfo_selected->hfinfo->abbrev);
1851         }
1852         break;
1853     case CopySelectedValue:
1854         if (finfo_selected && capture_file_.capFile()->edt != 0) {
1855             gchar* field_str = get_node_field_value(finfo_selected, capture_file_.capFile()->edt);
1856             clip.append(field_str);
1857             g_free(field_str);
1858         }
1859         break;
1860     case CopyAllVisibleItems:
1861         for (int i_item = 0; i_item < proto_tree_->topLevelItemCount(); i_item += 1) {
1862             clip.append(proto_tree_->topLevelItem(i_item)->text(0));
1863             clip.append("\n");
1864
1865             recursiveCopyProtoTreeItems(proto_tree_->topLevelItem(i_item), clip, 1);
1866         }
1867
1868         break;
1869     case CopyAllVisibleSelectedTreeItems:
1870         if (proto_tree_->selectedItems().count() > 0) {
1871             clip.append(proto_tree_->currentItem()->text(0));
1872             clip.append("\n");
1873
1874             recursiveCopyProtoTreeItems(proto_tree_->currentItem(), clip, 1);
1875         }
1876         break;
1877     }
1878
1879     if (clip.length() == 0) {
1880         /* If no representation then... Try to read the value */
1881         proto_item_fill_label(capture_file_.capFile()->finfo_selected, label_str);
1882         clip.append(label_str);
1883     }
1884
1885     if (clip.length()) {
1886         wsApp->clipboard()->setText(clip);
1887     } else {
1888         QString err = tr("Couldn't copy text. Try another item.");
1889         main_ui_->statusBar->pushTemporaryStatus(err);
1890     }
1891 }
1892
1893 void MainWindow::on_actionCopyAllVisibleItems_triggered()
1894 {
1895     actionEditCopyTriggered(CopyAllVisibleItems);
1896 }
1897
1898 void MainWindow::on_actionCopyAllVisibleSelectedTreeItems_triggered()
1899 {
1900     actionEditCopyTriggered(CopyAllVisibleSelectedTreeItems);
1901 }
1902
1903 void MainWindow::on_actionEditCopyDescription_triggered()
1904 {
1905     actionEditCopyTriggered(CopySelectedDescription);
1906 }
1907
1908 void MainWindow::on_actionEditCopyFieldName_triggered()
1909 {
1910     actionEditCopyTriggered(CopySelectedFieldName);
1911 }
1912
1913 void MainWindow::on_actionEditCopyValue_triggered()
1914 {
1915     actionEditCopyTriggered(CopySelectedValue);
1916 }
1917
1918 void MainWindow::on_actionEditCopyAsFilter_triggered()
1919 {
1920     matchFieldFilter(FilterAction::ActionCopy, FilterAction::ActionTypePlain);
1921 }
1922
1923 void MainWindow::on_actionEditFindPacket_triggered()
1924 {
1925     if (packet_list_->model()->rowCount() < 1) {
1926         return;
1927     }
1928     previous_focus_ = wsApp->focusWidget();
1929     connect(previous_focus_, SIGNAL(destroyed()), this, SLOT(resetPreviousFocus()));
1930     showAccordionFrame(main_ui_->searchFrame, true);
1931     if (main_ui_->searchFrame->isVisible()) {
1932         main_ui_->searchFrame->setFocus();
1933     }
1934 }
1935
1936 void MainWindow::on_actionEditFindNext_triggered()
1937 {
1938     main_ui_->searchFrame->findNext();
1939 }
1940
1941 void MainWindow::on_actionEditFindPrevious_triggered()
1942 {
1943     main_ui_->searchFrame->findPrevious();
1944 }
1945
1946 void MainWindow::on_actionEditMarkPacket_triggered()
1947 {
1948     freeze();
1949     packet_list_->markFrame();
1950     thaw();
1951 }
1952
1953 void MainWindow::on_actionEditMarkAllDisplayed_triggered()
1954 {
1955     freeze();
1956     packet_list_->markAllDisplayedFrames(true);
1957     thaw();
1958 }
1959
1960 void MainWindow::on_actionEditUnmarkAllDisplayed_triggered()
1961 {
1962     freeze();
1963     packet_list_->markAllDisplayedFrames(false);
1964     thaw();
1965 }
1966
1967 void MainWindow::on_actionEditNextMark_triggered()
1968 {
1969     if (capture_file_.capFile())
1970         cf_find_packet_marked(capture_file_.capFile(), SD_FORWARD);
1971 }
1972
1973 void MainWindow::on_actionEditPreviousMark_triggered()
1974 {
1975     if (capture_file_.capFile())
1976         cf_find_packet_marked(capture_file_.capFile(), SD_BACKWARD);
1977 }
1978
1979 void MainWindow::on_actionEditIgnorePacket_triggered()
1980 {
1981     freeze();
1982     packet_list_->ignoreFrame();
1983     thaw();
1984 }
1985
1986 void MainWindow::on_actionEditIgnoreAllDisplayed_triggered()
1987 {
1988     freeze();
1989     packet_list_->ignoreAllDisplayedFrames(true);
1990     thaw();
1991 }
1992
1993 void MainWindow::on_actionEditUnignoreAllDisplayed_triggered()
1994 {
1995     freeze();
1996     packet_list_->ignoreAllDisplayedFrames(false);
1997     thaw();
1998 }
1999
2000 void MainWindow::on_actionEditSetTimeReference_triggered()
2001 {
2002     packet_list_->setTimeReference();
2003 }
2004
2005 void MainWindow::on_actionEditUnsetAllTimeReferences_triggered()
2006 {
2007     packet_list_->unsetAllTimeReferences();
2008 }
2009
2010 void MainWindow::on_actionEditNextTimeReference_triggered()
2011 {
2012     if (!capture_file_.capFile()) return;
2013     cf_find_packet_time_reference(capture_file_.capFile(), SD_FORWARD);
2014 }
2015
2016 void MainWindow::on_actionEditPreviousTimeReference_triggered()
2017 {
2018     if (!capture_file_.capFile()) return;
2019     cf_find_packet_time_reference(capture_file_.capFile(), SD_BACKWARD);
2020 }
2021
2022 void MainWindow::on_actionEditTimeShift_triggered()
2023 {
2024     TimeShiftDialog ts_dialog(this, capture_file_.capFile());
2025     connect(this, SIGNAL(setCaptureFile(capture_file*)),
2026             &ts_dialog, SLOT(setCaptureFile(capture_file*)));
2027     connect(&ts_dialog, SIGNAL(timeShifted()), packet_list_, SLOT(applyTimeShift()));
2028     ts_dialog.exec();
2029 }
2030
2031 void MainWindow::on_actionEditPacketComment_triggered()
2032 {
2033     PacketCommentDialog pc_dialog(this, packet_list_->packetComment());
2034     if (pc_dialog.exec() == QDialog::Accepted) {
2035         packet_list_->setPacketComment(pc_dialog.text());
2036         updateForUnsavedChanges();
2037     }
2038 }
2039
2040 void MainWindow::on_actionEditConfigurationProfiles_triggered()
2041 {
2042     ProfileDialog cp_dialog;
2043
2044     cp_dialog.exec();
2045 }
2046
2047 void MainWindow::showPreferencesDialog(PreferencesDialog::PreferencesPane start_pane)
2048 {
2049     PreferencesDialog pref_dialog(this);
2050
2051     pref_dialog.setPane(start_pane);
2052     pref_dialog.exec();
2053
2054     // Emitting PacketDissectionChanged directly from a QDialog can cause
2055     // problems on OS X.
2056     wsApp->flushAppSignals();
2057 }
2058
2059 void MainWindow::showPreferencesDialog(QString module_name)
2060 {
2061     PreferencesDialog pref_dialog(this);
2062
2063     pref_dialog.setPane(module_name);
2064     pref_dialog.exec();
2065
2066     // Emitting PacketDissectionChanged directly from a QDialog can cause
2067     // problems on OS X.
2068     wsApp->flushAppSignals();
2069 }
2070
2071 void MainWindow::on_actionEditPreferences_triggered()
2072 {
2073     showPreferencesDialog();
2074 }
2075
2076 // View Menu
2077
2078 void MainWindow::showHideMainWidgets(QAction *action)
2079 {
2080     if (!action) {
2081         return;
2082     }
2083     bool show = action->isChecked();
2084     QWidget *widget = action->data().value<QWidget*>();
2085
2086     // We may have come from the toolbar context menu, so check/uncheck each
2087     // action as well.
2088     if (widget == main_ui_->mainToolBar) {
2089         recent.main_toolbar_show = show;
2090         main_ui_->actionViewMainToolbar->setChecked(show);
2091     } else if (widget == main_ui_->displayFilterToolBar) {
2092         recent.filter_toolbar_show = show;
2093         main_ui_->actionViewFilterToolbar->setChecked(show);
2094      } else if (widget == main_ui_->wirelessToolBar) {
2095         recent.wireless_toolbar_show = show;
2096         main_ui_->actionViewWirelessToolbar->setChecked(show);
2097     } else if (widget == main_ui_->statusBar) {
2098         recent.statusbar_show = show;
2099         main_ui_->actionViewStatusBar->setChecked(show);
2100     } else if (widget == packet_list_) {
2101         recent.packet_list_show = show;
2102         main_ui_->actionViewPacketList->setChecked(show);
2103     } else if (widget == proto_tree_) {
2104         recent.tree_view_show = show;
2105         main_ui_->actionViewPacketDetails->setChecked(show);
2106     } else if (widget == byte_view_tab_) {
2107         recent.byte_view_show = show;
2108         main_ui_->actionViewPacketBytes->setChecked(show);
2109     }
2110
2111     if (widget) {
2112         widget->setVisible(show);
2113     }
2114 }
2115
2116 Q_DECLARE_METATYPE(ts_type)
2117
2118 void MainWindow::setTimestampFormat(QAction *action)
2119 {
2120     if (!action) {
2121         return;
2122     }
2123     ts_type tsf = action->data().value<ts_type>();
2124     if (recent.gui_time_format != tsf) {
2125         timestamp_set_type(tsf);
2126         recent.gui_time_format = tsf;
2127         if (capture_file_.capFile()) {
2128             /* This call adjusts column width */
2129             cf_timestamp_auto_precision(capture_file_.capFile());
2130         }
2131         if (packet_list_) {
2132             packet_list_->resetColumns();
2133         }
2134     }
2135 }
2136
2137 Q_DECLARE_METATYPE(ts_precision)
2138
2139 void MainWindow::setTimestampPrecision(QAction *action)
2140 {
2141     if (!action) {
2142         return;
2143     }
2144     ts_precision tsp = action->data().value<ts_precision>();
2145     if (recent.gui_time_precision != tsp) {
2146         /* the actual precision will be set in packet_list_queue_draw() below */
2147         timestamp_set_precision(tsp);
2148         recent.gui_time_precision = tsp;
2149         if (capture_file_.capFile()) {
2150             /* This call adjusts column width */
2151             cf_timestamp_auto_precision(capture_file_.capFile());
2152         }
2153         if (packet_list_) {
2154             packet_list_->resetColumns();
2155         }
2156     }
2157 }
2158
2159 void MainWindow::on_actionViewTimeDisplaySecondsWithHoursAndMinutes_triggered(bool checked)
2160 {
2161     if (checked) {
2162         recent.gui_seconds_format = TS_SECONDS_HOUR_MIN_SEC;
2163     } else {
2164         recent.gui_seconds_format = TS_SECONDS_DEFAULT;
2165     }
2166     timestamp_set_seconds_type(recent.gui_seconds_format);
2167
2168     if (capture_file_.capFile()) {
2169         /* This call adjusts column width */
2170         cf_timestamp_auto_precision(capture_file_.capFile());
2171     }
2172     if (packet_list_) {
2173         packet_list_->resetColumns();
2174     }
2175 }
2176
2177 void MainWindow::on_actionViewEditResolvedName_triggered()
2178 {
2179 //    int column = packet_list_->selectedColumn();
2180     int column = -1;
2181
2182     if (packet_list_->currentIndex().isValid()) {
2183         column = packet_list_->currentIndex().column();
2184     }
2185
2186     main_ui_->addressEditorFrame->editAddresses(capture_file_, column);
2187     showAccordionFrame(main_ui_->addressEditorFrame);
2188 }
2189
2190 void MainWindow::setNameResolution()
2191 {
2192     gbl_resolv_flags.mac_name = main_ui_->actionViewNameResolutionPhysical->isChecked() ? TRUE : FALSE;
2193     gbl_resolv_flags.network_name = main_ui_->actionViewNameResolutionNetwork->isChecked() ? TRUE : FALSE;
2194     gbl_resolv_flags.transport_name = main_ui_->actionViewNameResolutionTransport->isChecked() ? TRUE : FALSE;
2195
2196     if (packet_list_) {
2197         packet_list_->resetColumns();
2198     }
2199 }
2200
2201 void MainWindow::on_actionViewNameResolutionPhysical_triggered()
2202 {
2203     setNameResolution();
2204 }
2205
2206 void MainWindow::on_actionViewNameResolutionNetwork_triggered()
2207 {
2208     setNameResolution();
2209 }
2210
2211 void MainWindow::on_actionViewNameResolutionTransport_triggered()
2212 {
2213     setNameResolution();
2214 }
2215
2216 void MainWindow::zoomText()
2217 {
2218     // Scale by 10%, rounding to nearest half point, minimum 1 point.
2219     // XXX Small sizes repeat. It might just be easier to create a map of multipliers.
2220     mono_font_ = QFont(wsApp->monospaceFont());
2221     qreal zoom_size = wsApp->monospaceFont().pointSize() * 2 * qPow(1.1, recent.gui_zoom_level);
2222     zoom_size = qRound(zoom_size) / 2.0;
2223     zoom_size = qMax(zoom_size, 1.0);
2224     mono_font_.setPointSizeF(zoom_size);
2225     emit monospaceFontChanged(mono_font_);
2226 }
2227
2228 void MainWindow::on_actionViewZoomIn_triggered()
2229 {
2230     recent.gui_zoom_level++;
2231     zoomText();
2232 }
2233
2234 void MainWindow::on_actionViewZoomOut_triggered()
2235 {
2236     recent.gui_zoom_level--;
2237     zoomText();
2238 }
2239
2240 void MainWindow::on_actionViewNormalSize_triggered()
2241 {
2242     recent.gui_zoom_level = 0;
2243     zoomText();
2244 }
2245
2246 void MainWindow::on_actionViewColorizePacketList_triggered(bool checked) {
2247     recent.packet_list_colorize = checked;
2248     color_filters_enable(checked);
2249     packet_list_->packetListModel()->resetColorized();
2250 }
2251
2252 void MainWindow::on_actionViewColoringRules_triggered()
2253 {
2254     ColoringRulesDialog coloring_rules_dialog(this);
2255     connect(&coloring_rules_dialog, SIGNAL(accepted()),
2256             packet_list_, SLOT(recolorPackets()));
2257     coloring_rules_dialog.exec();
2258 }
2259
2260 // actionViewColorizeConversation1 - 10
2261 void MainWindow::colorizeConversation(bool create_rule)
2262 {
2263     QAction *cc_action = qobject_cast<QAction *>(sender());
2264     if (!cc_action) return;
2265
2266     if (capture_file_.capFile() && capture_file_.capFile()->current_frame) {
2267         packet_info *pi = &capture_file_.capFile()->edt->pi;
2268         guint8 cc_num = cc_action->data().toUInt();
2269         gchar *filter = NULL;
2270
2271         const conversation_filter_t *color_filter = find_conversation_filter("tcp");
2272         if ((color_filter != NULL) && (color_filter->is_filter_valid(pi)))
2273             filter = color_filter->build_filter_string(pi);
2274         if (filter == NULL) {
2275             color_filter = find_conversation_filter("udp");
2276             if ((color_filter != NULL) && (color_filter->is_filter_valid(pi)))
2277                 filter = color_filter->build_filter_string(pi);
2278         }
2279         if (filter == NULL) {
2280             color_filter = find_conversation_filter("ip");
2281             if ((color_filter != NULL) && (color_filter->is_filter_valid(pi)))
2282                 filter = color_filter->build_filter_string(pi);
2283         }
2284         if (filter == NULL) {
2285             color_filter = find_conversation_filter("ipv6");
2286             if ((color_filter != NULL) && (color_filter->is_filter_valid(pi)))
2287                 filter = color_filter->build_filter_string(pi);
2288         }
2289         if (filter == NULL) {
2290             color_filter = find_conversation_filter("eth");
2291             if ((color_filter != NULL) && (color_filter->is_filter_valid(pi)))
2292                 filter = color_filter->build_filter_string(pi);
2293         }
2294         if( filter == NULL ) {
2295             main_ui_->statusBar->pushTemporaryStatus(tr("Unable to build conversation filter."));
2296             return;
2297         }
2298
2299         if (create_rule) {
2300             ColoringRulesDialog coloring_rules_dialog(this, filter);
2301             connect(&coloring_rules_dialog, SIGNAL(accepted()),
2302                     packet_list_, SLOT(recolorPackets()));
2303             coloring_rules_dialog.exec();
2304         } else {
2305             color_filters_set_tmp(cc_num, filter, FALSE);
2306             packet_list_->recolorPackets();
2307         }
2308     }
2309     setMenusForSelectedPacket();
2310 }
2311
2312 void MainWindow::colorizeWithFilter()
2313 {
2314     QAction *colorize_action = qobject_cast<QAction *>(sender());
2315     if (!colorize_action) return;
2316
2317     QString filter = colorize_action->data().toString();
2318     if (filter.isEmpty()) return;
2319
2320     bool ok = false;
2321     int color_number = colorize_action->property(color_number_property_).toInt(&ok);
2322
2323     if (ok) {
2324         // Assume "Color X"
2325         color_filters_set_tmp(color_number, filter.toUtf8().constData(), FALSE);
2326         packet_list_->recolorPackets();
2327     } else {
2328         // New coloring rule
2329         ColoringRulesDialog coloring_rules_dialog(window(), filter);
2330         connect(&coloring_rules_dialog, SIGNAL(accepted()),
2331                 packet_list_, SLOT(recolorPackets()));
2332         coloring_rules_dialog.exec();
2333     }
2334     main_ui_->actionViewColorizeResetColorization->setEnabled(tmp_color_filters_used());
2335 }
2336
2337 void MainWindow::on_actionViewColorizeResetColorization_triggered()
2338 {
2339     color_filters_reset_tmp();
2340     packet_list_->recolorPackets();
2341     setMenusForSelectedPacket();
2342 }
2343
2344 void MainWindow::on_actionViewColorizeNewConversationRule_triggered()
2345 {
2346     colorizeConversation(true);
2347 }
2348
2349 void MainWindow::on_actionViewResizeColumns_triggered()
2350 {
2351     for (int col = 0; col < packet_list_->packetListModel()->columnCount(); col++) {
2352         packet_list_->resizeColumnToContents(col);
2353         recent_set_column_width(col, packet_list_->columnWidth(col));
2354     }
2355 }
2356
2357 void MainWindow::openPacketDialog(bool from_reference)
2358 {
2359     frame_data * fdata;
2360
2361     /* Find the frame for which we're popping up a dialog */
2362     if(from_reference) {
2363         guint32 framenum = fvalue_get_uinteger(&(capture_file_.capFile()->finfo_selected->value));
2364         if (framenum == 0)
2365             return;
2366
2367         fdata = frame_data_sequence_find(capture_file_.capFile()->frames, framenum);
2368     } else {
2369         fdata = capture_file_.capFile()->current_frame;
2370     }
2371
2372     /* If we have a frame, pop up the dialog */
2373     if (fdata) {
2374         PacketDialog *packet_dialog = new PacketDialog(*this, capture_file_, fdata);
2375
2376         connect(this, SIGNAL(monospaceFontChanged(QFont)),
2377                 packet_dialog, SIGNAL(monospaceFontChanged(QFont)));
2378         connect(this, SIGNAL(closePacketDialogs()),
2379                 packet_dialog, SLOT(close()));
2380         zoomText(); // Emits monospaceFontChanged
2381
2382         packet_dialog->show();
2383     }
2384 }
2385
2386 void MainWindow::on_actionViewInternalsConversationHashTables_triggered()
2387 {
2388     ConversationHashTablesDialog *conversation_hash_tables_dlg = new ConversationHashTablesDialog(this);
2389     conversation_hash_tables_dlg->show();
2390 }
2391
2392 void MainWindow::on_actionViewInternalsDissectorTables_triggered()
2393 {
2394     DissectorTablesDialog *dissector_tables_dlg = new DissectorTablesDialog(this);
2395     dissector_tables_dlg->show();
2396 }
2397
2398 void MainWindow::on_actionViewInternalsSupportedProtocols_triggered()
2399 {
2400     SupportedProtocolsDialog *supported_protocols_dlg = new SupportedProtocolsDialog(this);
2401     supported_protocols_dlg->show();
2402 }
2403
2404 void MainWindow::on_actionViewShowPacketInNewWindow_triggered()
2405 {
2406     openPacketDialog();
2407 }
2408
2409 // This is only used in ProtoTree. Defining it here makes more sense.
2410 void MainWindow::on_actionContextShowLinkedPacketInNewWindow_triggered()
2411 {
2412     openPacketDialog(true);
2413 }
2414
2415 void MainWindow::on_actionViewReload_triggered()
2416 {
2417     cf_reload(CaptureFile::globalCapFile());
2418 }
2419
2420 void MainWindow::on_actionViewReload_as_File_Format_or_Capture_triggered()
2421 {
2422     capture_file *cf = CaptureFile::globalCapFile();
2423
2424     if (cf->open_type == WTAP_TYPE_AUTO)
2425         cf->open_type = open_info_name_to_type("MIME Files Format");
2426     else /* TODO: This should be latest format chosen by user */
2427         cf->open_type = WTAP_TYPE_AUTO;
2428
2429     cf_reload(cf);
2430 }
2431
2432
2433 // Expand / collapse slots in proto_tree
2434
2435 // Go Menu
2436
2437 // Analyze Menu
2438
2439 void MainWindow::matchFieldFilter(FilterAction::Action action, FilterAction::ActionType filter_type)
2440 {
2441     QString field_filter;
2442
2443     if (packet_list_->contextMenuActive() || packet_list_->hasFocus()) {
2444         field_filter = packet_list_->getFilterFromRowAndColumn();
2445     } else if (capture_file_.capFile() && capture_file_.capFile()->finfo_selected) {
2446         char *tmp_field = proto_construct_match_selected_string(capture_file_.capFile()->finfo_selected,
2447                                                        capture_file_.capFile()->edt);
2448         field_filter = QString(tmp_field);
2449         wmem_free(NULL, tmp_field);
2450     }
2451
2452     if (field_filter.isEmpty()) {
2453         QString err = tr("No filter available. Try another ");
2454         err.append(packet_list_->contextMenuActive() ? "column" : "item");
2455         err.append(".");
2456         main_ui_->statusBar->pushTemporaryStatus(err);
2457         return;
2458     }
2459
2460     filterAction(field_filter, action, filter_type);
2461 }
2462
2463 static FilterDialog *display_filter_dlg_ = NULL;
2464 void MainWindow::on_actionAnalyzeDisplayFilters_triggered()
2465 {
2466     if (!display_filter_dlg_) {
2467         display_filter_dlg_ = new FilterDialog(this, FilterDialog::DisplayFilter);
2468     }
2469     display_filter_dlg_->show();
2470     display_filter_dlg_->raise();
2471     display_filter_dlg_->activateWindow();
2472 }
2473
2474 struct epan_uat;
2475 void MainWindow::on_actionAnalyzeDisplayFilterMacros_triggered()
2476 {
2477     struct epan_uat* dfm_uat;
2478     dfilter_macro_get_uat(&dfm_uat);
2479     UatDialog uat_dlg(parentWidget(), dfm_uat);
2480
2481     uat_dlg.exec();
2482     // Emitting PacketDissectionChanged directly from a QDialog can cause
2483     // problems on OS X.
2484     wsApp->flushAppSignals();
2485 }
2486
2487 void MainWindow::on_actionAnalyzeCreateAColumn_triggered()
2488 {
2489     gint colnr = 0;
2490
2491     if ( capture_file_.capFile() != 0 && capture_file_.capFile()->finfo_selected != 0 )
2492     {
2493         colnr = column_prefs_add_custom(COL_CUSTOM, capture_file_.capFile()->finfo_selected->hfinfo->name,
2494                     capture_file_.capFile()->finfo_selected->hfinfo->abbrev,0);
2495
2496         packet_list_->columnsChanged();
2497         packet_list_->resizeColumnToContents(colnr);
2498
2499         prefs_main_write();
2500     }
2501 }
2502
2503 void MainWindow::applyConversationFilter()
2504 {
2505     QAction *cfa = qobject_cast<QAction*>(sender());
2506     if (!cfa) return;
2507
2508     QString new_filter = cfa->data().toString();
2509     if (new_filter.isEmpty()) return;
2510
2511     df_combo_box_->lineEdit()->setText(new_filter);
2512     df_combo_box_->applyDisplayFilter();
2513 }
2514
2515 // XXX We could probably create the analyze and prepare actions
2516 // dynamically using FilterActions and consolidate the methods
2517 // below into one callback.
2518 void MainWindow::on_actionAnalyzeAAFSelected_triggered()
2519 {
2520     matchFieldFilter(FilterAction::ActionApply, FilterAction::ActionTypePlain);
2521 }
2522
2523 void MainWindow::on_actionAnalyzeAAFNotSelected_triggered()
2524 {
2525     matchFieldFilter(FilterAction::ActionApply, FilterAction::ActionTypeNot);
2526 }
2527
2528 void MainWindow::on_actionAnalyzeAAFAndSelected_triggered()
2529 {
2530     matchFieldFilter(FilterAction::ActionApply, FilterAction::ActionTypeAnd);
2531 }
2532
2533 void MainWindow::on_actionAnalyzeAAFOrSelected_triggered()
2534 {
2535     matchFieldFilter(FilterAction::ActionApply, FilterAction::ActionTypeOr);
2536 }
2537
2538 void MainWindow::on_actionAnalyzeAAFAndNotSelected_triggered()
2539 {
2540     matchFieldFilter(FilterAction::ActionApply, FilterAction::ActionTypeAndNot);
2541 }
2542
2543 void MainWindow::on_actionAnalyzeAAFOrNotSelected_triggered()
2544 {
2545     matchFieldFilter(FilterAction::ActionApply, FilterAction::ActionTypeOrNot);
2546 }
2547
2548 void MainWindow::on_actionAnalyzePAFSelected_triggered()
2549 {
2550     matchFieldFilter(FilterAction::ActionPrepare, FilterAction::ActionTypePlain);
2551 }
2552
2553 void MainWindow::on_actionAnalyzePAFNotSelected_triggered()
2554 {
2555     matchFieldFilter(FilterAction::ActionPrepare, FilterAction::ActionTypeNot);
2556 }
2557
2558 void MainWindow::on_actionAnalyzePAFAndSelected_triggered()
2559 {
2560     matchFieldFilter(FilterAction::ActionPrepare, FilterAction::ActionTypeAnd);
2561 }
2562
2563 void MainWindow::on_actionAnalyzePAFOrSelected_triggered()
2564 {
2565     matchFieldFilter(FilterAction::ActionPrepare, FilterAction::ActionTypeOr);
2566 }
2567
2568 void MainWindow::on_actionAnalyzePAFAndNotSelected_triggered()
2569 {
2570     matchFieldFilter(FilterAction::ActionPrepare, FilterAction::ActionTypeAndNot);
2571 }
2572
2573 void MainWindow::on_actionAnalyzePAFOrNotSelected_triggered()
2574 {
2575     matchFieldFilter(FilterAction::ActionPrepare, FilterAction::ActionTypeOrNot);
2576 }
2577
2578 void MainWindow::on_actionAnalyzeEnabledProtocols_triggered()
2579 {
2580     EnabledProtocolsDialog enable_proto_dialog(this);
2581     enable_proto_dialog.exec();
2582
2583     // Emitting PacketDissectionChanged directly from a QDialog can cause
2584     // problems on OS X.
2585     wsApp->flushAppSignals();
2586 }
2587
2588 void MainWindow::on_actionAnalyzeDecodeAs_triggered()
2589 {
2590     QAction *da_action = qobject_cast<QAction*>(sender());
2591     bool create_new = false;
2592     if (da_action && da_action->data().toBool() == true) {
2593         create_new = true;
2594     }
2595
2596     DecodeAsDialog da_dialog(this, capture_file_.capFile(), create_new);
2597     connect(this, SIGNAL(setCaptureFile(capture_file*)),
2598             &da_dialog, SLOT(setCaptureFile(capture_file*)));
2599     da_dialog.exec();
2600
2601     // Emitting PacketDissectionChanged directly from a QDialog can cause
2602     // problems on OS X.
2603     wsApp->flushAppSignals();
2604 }
2605
2606 void MainWindow::on_actionAnalyzeReloadLuaPlugins_triggered()
2607 {
2608 #ifdef HAVE_LUA
2609     if (wsApp->isReloadingLua())
2610         return;
2611
2612     wsApp->setReloadingLua(true);
2613
2614     wslua_reload_plugins(NULL, NULL);
2615     funnel_statistics_reload_menus();
2616     reloadDynamicMenus();
2617     closePacketDialogs();
2618
2619     // Preferences may have been deleted so close all widgets using prefs
2620     proto_tree_->closeContextMenu();
2621     main_ui_->preferenceEditorFrame->animatedHide();
2622
2623     char *gdp_path, *dp_path;
2624     wsApp->readConfigurationFiles(&gdp_path, &dp_path, true);
2625
2626     fieldsChanged();
2627     redissectPackets();
2628
2629     wsApp->setReloadingLua(false);
2630     SimpleDialog::displayQueuedMessages();
2631 #endif
2632 }
2633
2634 void MainWindow::openFollowStreamDialog(follow_type_t type) {
2635     FollowStreamDialog *fsd = new FollowStreamDialog(*this, capture_file_, type);
2636     connect(fsd, SIGNAL(updateFilter(QString, bool)), this, SLOT(filterPackets(QString, bool)));
2637     connect(fsd, SIGNAL(goToPacket(int)), packet_list_, SLOT(goToPacket(int)));
2638
2639     fsd->show();
2640     fsd->follow(getFilter());
2641 }
2642
2643 void MainWindow::on_actionAnalyzeFollowTCPStream_triggered()
2644 {
2645     openFollowStreamDialog(FOLLOW_TCP);
2646 }
2647
2648 void MainWindow::on_actionAnalyzeFollowUDPStream_triggered()
2649 {
2650     openFollowStreamDialog(FOLLOW_UDP);
2651 }
2652
2653 void MainWindow::on_actionAnalyzeFollowSSLStream_triggered()
2654 {
2655     openFollowStreamDialog(FOLLOW_SSL);
2656 }
2657
2658 void MainWindow::openSCTPAllAssocsDialog()
2659 {
2660     SCTPAllAssocsDialog *sctp_dialog = new SCTPAllAssocsDialog(this, capture_file_.capFile());
2661     connect(sctp_dialog, SIGNAL(filterPackets(QString,bool)),
2662             this, SLOT(filterPackets(QString,bool)));
2663     connect(this, SIGNAL(setCaptureFile(capture_file*)),
2664             sctp_dialog, SLOT(setCaptureFile(capture_file*)));
2665     sctp_dialog->fillTable();
2666
2667     if (sctp_dialog->isMinimized() == true)
2668     {
2669         sctp_dialog->showNormal();
2670     }
2671     else
2672     {
2673         sctp_dialog->show();
2674     }
2675
2676     sctp_dialog->raise();
2677     sctp_dialog->activateWindow();
2678 }
2679
2680 void MainWindow::on_actionSCTPShowAllAssociations_triggered()
2681 {
2682     openSCTPAllAssocsDialog();
2683 }
2684
2685 void MainWindow::on_actionSCTPAnalyseThisAssociation_triggered()
2686 {
2687     SCTPAssocAnalyseDialog *sctp_analyse = new SCTPAssocAnalyseDialog(this, NULL, capture_file_.capFile());
2688     connect(sctp_analyse, SIGNAL(filterPackets(QString,bool)),
2689             this, SLOT(filterPackets(QString,bool)));
2690
2691     if (sctp_analyse->isMinimized() == true)
2692     {
2693         sctp_analyse->showNormal();
2694     }
2695     else
2696     {
2697         sctp_analyse->show();
2698     }
2699
2700     sctp_analyse->raise();
2701     sctp_analyse->activateWindow();
2702 }
2703
2704 void MainWindow::on_actionSCTPFilterThisAssociation_triggered()
2705 {
2706     sctp_assoc_info_t* assoc = SCTPAssocAnalyseDialog::findAssocForPacket(capture_file_.capFile());
2707     if (assoc) {
2708         QString newFilter = QString("sctp.assoc_index==%1").arg(assoc->assoc_id);
2709         assoc = NULL;
2710         emit filterPackets(newFilter, false);
2711     }
2712 }
2713
2714 // -z wlan,stat
2715 void MainWindow::statCommandWlanStatistics(const char *arg, void *)
2716 {
2717     WlanStatisticsDialog *wlan_stats_dlg = new WlanStatisticsDialog(*this, capture_file_, arg);
2718     connect(wlan_stats_dlg, SIGNAL(filterAction(QString&,FilterAction::Action,FilterAction::ActionType)),
2719             this, SLOT(filterAction(QString&,FilterAction::Action,FilterAction::ActionType)));
2720     wlan_stats_dlg->show();
2721 }
2722
2723 void MainWindow::on_actionWirelessWlanStatistics_triggered()
2724 {
2725     statCommandWlanStatistics(NULL, NULL);
2726 }
2727
2728 // -z expert
2729 void MainWindow::statCommandExpertInfo(const char *, void *)
2730 {
2731     ExpertInfoDialog *expert_dialog = new ExpertInfoDialog(*this, capture_file_);
2732     const DisplayFilterEdit *df_edit = dynamic_cast<DisplayFilterEdit *>(df_combo_box_->lineEdit());
2733
2734     expert_dialog->setDisplayFilter(df_edit->text());
2735
2736     connect(expert_dialog, SIGNAL(goToPacket(int, int)),
2737             packet_list_, SLOT(goToPacket(int, int)));
2738     connect(expert_dialog, SIGNAL(filterAction(QString&,FilterAction::Action,FilterAction::ActionType)),
2739             this, SLOT(filterAction(QString&,FilterAction::Action,FilterAction::ActionType)));
2740
2741     expert_dialog->show();
2742 }
2743
2744 void MainWindow::on_actionAnalyzeExpertInfo_triggered()
2745 {
2746     statCommandExpertInfo(NULL, NULL);
2747 }
2748
2749
2750 // Next / previous / first / last slots in packet_list
2751
2752 // Statistics Menu
2753
2754 void MainWindow::on_actionStatisticsFlowGraph_triggered()
2755 {
2756     SequenceDialog *sequence_dialog = new SequenceDialog(*this, capture_file_);
2757     connect(sequence_dialog, SIGNAL(goToPacket(int)),
2758             packet_list_, SLOT(goToPacket(int)));
2759     sequence_dialog->show();
2760 }
2761
2762 void MainWindow::openTcpStreamDialog(int graph_type)
2763 {
2764     TCPStreamDialog *stream_dialog = new TCPStreamDialog(this, capture_file_.capFile(), (tcp_graph_type)graph_type);
2765     connect(stream_dialog, SIGNAL(goToPacket(int)),
2766             packet_list_, SLOT(goToPacket(int)));
2767     connect(this, SIGNAL(setCaptureFile(capture_file*)),
2768             stream_dialog, SLOT(setCaptureFile(capture_file*)));
2769     stream_dialog->show();
2770 }
2771
2772 void MainWindow::on_actionStatisticsTcpStreamStevens_triggered()
2773 {
2774     openTcpStreamDialog(GRAPH_TSEQ_STEVENS);
2775 }
2776
2777 void MainWindow::on_actionStatisticsTcpStreamTcptrace_triggered()
2778 {
2779     openTcpStreamDialog(GRAPH_TSEQ_TCPTRACE);
2780 }
2781
2782 void MainWindow::on_actionStatisticsTcpStreamThroughput_triggered()
2783 {
2784     openTcpStreamDialog(GRAPH_THROUGHPUT);
2785 }
2786
2787 void MainWindow::on_actionStatisticsTcpStreamRoundTripTime_triggered()
2788 {
2789     openTcpStreamDialog(GRAPH_RTT);
2790 }
2791
2792 void MainWindow::on_actionStatisticsTcpStreamWindowScaling_triggered()
2793 {
2794     openTcpStreamDialog(GRAPH_WSCALE);
2795 }
2796
2797 // -z mcast,stat
2798 void MainWindow::statCommandMulticastStatistics(const char *arg, void *)
2799 {
2800     MulticastStatisticsDialog *mcast_stats_dlg = new MulticastStatisticsDialog(*this, capture_file_, arg);
2801     connect(mcast_stats_dlg, SIGNAL(filterAction(QString&,FilterAction::Action,FilterAction::ActionType)),
2802             this, SLOT(filterAction(QString&,FilterAction::Action,FilterAction::ActionType)));
2803     mcast_stats_dlg->show();
2804 }
2805
2806 void MainWindow::on_actionStatisticsUdpMulticastStreams_triggered()
2807 {
2808     statCommandMulticastStatistics(NULL, NULL);
2809 }
2810
2811 void MainWindow::openStatisticsTreeDialog(const gchar *abbr)
2812 {
2813     StatsTreeDialog *st_dialog = new StatsTreeDialog(*this, capture_file_, abbr);
2814 //    connect(st_dialog, SIGNAL(goToPacket(int)),
2815 //            packet_list_, SLOT(goToPacket(int)));
2816     st_dialog->show();
2817 }
2818
2819 void MainWindow::on_actionStatistics29WestTopics_Advertisements_by_Topic_triggered()
2820 {
2821     openStatisticsTreeDialog("lbmr_topic_ads_topic");
2822 }
2823
2824 void MainWindow::on_actionStatistics29WestTopics_Advertisements_by_Source_triggered()
2825 {
2826     openStatisticsTreeDialog("lbmr_topic_ads_source");
2827 }
2828
2829 void MainWindow::on_actionStatistics29WestTopics_Advertisements_by_Transport_triggered()
2830 {
2831     openStatisticsTreeDialog("lbmr_topic_ads_transport");
2832 }
2833
2834 void MainWindow::on_actionStatistics29WestTopics_Queries_by_Topic_triggered()
2835 {
2836     openStatisticsTreeDialog("lbmr_topic_queries_topic");
2837 }
2838
2839 void MainWindow::on_actionStatistics29WestTopics_Queries_by_Receiver_triggered()
2840 {
2841     openStatisticsTreeDialog("lbmr_topic_queries_receiver");
2842 }
2843
2844 void MainWindow::on_actionStatistics29WestTopics_Wildcard_Queries_by_Pattern_triggered()
2845 {
2846     openStatisticsTreeDialog("lbmr_topic_queries_pattern");
2847 }
2848
2849 void MainWindow::on_actionStatistics29WestTopics_Wildcard_Queries_by_Receiver_triggered()
2850 {
2851     openStatisticsTreeDialog("lbmr_topic_queries_pattern_receiver");
2852 }
2853
2854 void MainWindow::on_actionStatistics29WestQueues_Advertisements_by_Queue_triggered()
2855 {
2856     openStatisticsTreeDialog("lbmr_queue_ads_queue");
2857 }
2858
2859 void MainWindow::on_actionStatistics29WestQueues_Advertisements_by_Source_triggered()
2860 {
2861     openStatisticsTreeDialog("lbmr_queue_ads_source");
2862 }
2863
2864 void MainWindow::on_actionStatistics29WestQueues_Queries_by_Queue_triggered()
2865 {
2866     openStatisticsTreeDialog("lbmr_queue_queries_queue");
2867 }
2868
2869 void MainWindow::on_actionStatistics29WestQueues_Queries_by_Receiver_triggered()
2870 {
2871     openStatisticsTreeDialog("lbmr_queue_queries_receiver");
2872 }
2873
2874 void MainWindow::on_actionStatistics29WestUIM_Streams_triggered()
2875 {
2876     LBMStreamDialog *stream_dialog = new LBMStreamDialog(this, capture_file_.capFile());
2877 //    connect(stream_dialog, SIGNAL(goToPacket(int)),
2878 //            packet_list_, SLOT(goToPacket(int)));
2879     connect(this, SIGNAL(setCaptureFile(capture_file*)),
2880             stream_dialog, SLOT(setCaptureFile(capture_file*)));
2881     stream_dialog->show();
2882 }
2883
2884 void MainWindow::on_actionStatistics29WestUIM_Stream_Flow_Graph_triggered()
2885 {
2886     LBMUIMFlowDialog * uimflow_dialog = new LBMUIMFlowDialog(this, capture_file_.capFile());
2887     connect(uimflow_dialog, SIGNAL(goToPacket(int)),
2888             packet_list_, SLOT(goToPacket(int)));
2889     connect(this, SIGNAL(setCaptureFile(capture_file*)),
2890             uimflow_dialog, SLOT(setCaptureFile(capture_file*)));
2891     uimflow_dialog->show();
2892 }
2893
2894 void MainWindow::on_actionStatistics29WestLBTRM_triggered()
2895 {
2896     LBMLBTRMTransportDialog * lbtrm_dialog = new LBMLBTRMTransportDialog(this, capture_file_.capFile());
2897     connect(lbtrm_dialog, SIGNAL(goToPacket(int)),
2898             packet_list_, SLOT(goToPacket(int)));
2899     connect(this, SIGNAL(setCaptureFile(capture_file*)),
2900             lbtrm_dialog, SLOT(setCaptureFile(capture_file*)));
2901     lbtrm_dialog->show();
2902 }
2903 void MainWindow::on_actionStatistics29WestLBTRU_triggered()
2904 {
2905     LBMLBTRUTransportDialog * lbtru_dialog = new LBMLBTRUTransportDialog(this, capture_file_.capFile());
2906     connect(lbtru_dialog, SIGNAL(goToPacket(int)),
2907             packet_list_, SLOT(goToPacket(int)));
2908     connect(this, SIGNAL(setCaptureFile(capture_file*)),
2909             lbtru_dialog, SLOT(setCaptureFile(capture_file*)));
2910     lbtru_dialog->show();
2911 }
2912
2913 void MainWindow::on_actionStatisticsANCP_triggered()
2914 {
2915     openStatisticsTreeDialog("ancp");
2916 }
2917
2918 void MainWindow::on_actionStatisticsBACappInstanceId_triggered()
2919 {
2920     openStatisticsTreeDialog("bacapp_instanceid");
2921 }
2922
2923 void MainWindow::on_actionStatisticsBACappIP_triggered()
2924 {
2925     openStatisticsTreeDialog("bacapp_ip");
2926 }
2927
2928 void MainWindow::on_actionStatisticsBACappObjectId_triggered()
2929 {
2930     openStatisticsTreeDialog("bacapp_objectid");
2931 }
2932
2933 void MainWindow::on_actionStatisticsBACappService_triggered()
2934 {
2935     openStatisticsTreeDialog("bacapp_service");
2936 }
2937
2938 void MainWindow::on_actionStatisticsCollectd_triggered()
2939 {
2940     openStatisticsTreeDialog("collectd");
2941 }
2942
2943 // -z conv,...
2944 void MainWindow::statCommandConversations(const char *arg, void *userdata)
2945 {
2946     ConversationDialog *conv_dialog = new ConversationDialog(*this, capture_file_, GPOINTER_TO_INT(userdata), arg);
2947     connect(conv_dialog, SIGNAL(filterAction(QString&,FilterAction::Action,FilterAction::ActionType)),
2948             this, SLOT(filterAction(QString&,FilterAction::Action,FilterAction::ActionType)));
2949     connect(conv_dialog, SIGNAL(openFollowStreamDialog(follow_type_t)),
2950             this, SLOT(openFollowStreamDialog(follow_type_t)));
2951     connect(conv_dialog, SIGNAL(openTcpStreamGraph(int)),
2952             this, SLOT(openTcpStreamDialog(int)));
2953     conv_dialog->show();
2954 }
2955
2956 void MainWindow::on_actionStatisticsConversations_triggered()
2957 {
2958     statCommandConversations(NULL, NULL);
2959 }
2960
2961 // -z endpoints,...
2962 void MainWindow::statCommandEndpoints(const char *arg, void *userdata)
2963 {
2964     EndpointDialog *endp_dialog = new EndpointDialog(*this, capture_file_, GPOINTER_TO_INT(userdata), arg);
2965     connect(endp_dialog, SIGNAL(filterAction(QString&,FilterAction::Action,FilterAction::ActionType)),
2966             this, SLOT(filterAction(QString&,FilterAction::Action,FilterAction::ActionType)));
2967     connect(endp_dialog, SIGNAL(openFollowStreamDialog(follow_type_t)),
2968             this, SLOT(openFollowStreamDialog(follow_type_t)));
2969     connect(endp_dialog, SIGNAL(openTcpStreamGraph(int)),
2970             this, SLOT(openTcpStreamDialog(int)));
2971     endp_dialog->show();
2972 }
2973
2974 void MainWindow::on_actionStatisticsEndpoints_triggered()
2975 {
2976     statCommandEndpoints(NULL, NULL);
2977 }
2978
2979 void MainWindow::on_actionStatisticsHART_IP_triggered()
2980 {
2981     openStatisticsTreeDialog("hart_ip");
2982 }
2983
2984 void MainWindow::on_actionStatisticsHTTPPacketCounter_triggered()
2985 {
2986     openStatisticsTreeDialog("http");
2987 }
2988
2989 void MainWindow::on_actionStatisticsHTTPRequests_triggered()
2990 {
2991     openStatisticsTreeDialog("http_req");
2992 }
2993
2994 void MainWindow::on_actionStatisticsHTTPLoadDistribution_triggered()
2995 {
2996     openStatisticsTreeDialog("http_srv");
2997 }
2998
2999 void MainWindow::on_actionStatisticsPacketLengths_triggered()
3000 {
3001     openStatisticsTreeDialog("plen");
3002 }
3003
3004 // -z io,stat
3005 void MainWindow::statCommandIOGraph(const char *, void *)
3006 {
3007     IOGraphDialog *iog_dialog = new IOGraphDialog(*this, capture_file_);
3008     connect(iog_dialog, SIGNAL(goToPacket(int)), packet_list_, SLOT(goToPacket(int)));
3009     connect(this, SIGNAL(reloadFields()), iog_dialog, SLOT(reloadFields()));
3010     iog_dialog->show();
3011 }
3012
3013 void MainWindow::on_actionStatisticsIOGraph_triggered()
3014 {
3015     statCommandIOGraph(NULL, NULL);
3016 }
3017
3018 void MainWindow::on_actionStatisticsSametime_triggered()
3019 {
3020     openStatisticsTreeDialog("sametime");
3021 }
3022
3023 void MainWindow::on_actionStatisticsDNS_triggered()
3024 {
3025     openStatisticsTreeDialog("dns");
3026 }
3027
3028 void MainWindow::actionStatisticsPlugin_triggered()
3029 {
3030     QAction* action = qobject_cast<QAction*>(sender());
3031     if(action) {
3032         openStatisticsTreeDialog(action->data().toString().toUtf8());
3033     }
3034 }
3035
3036 void MainWindow::on_actionStatisticsHTTP2_triggered()
3037 {
3038     openStatisticsTreeDialog("http2");
3039
3040 }
3041
3042 // Telephony Menu
3043
3044 void MainWindow::openVoipCallsDialog(bool all_flows)
3045 {
3046     VoipCallsDialog *voip_calls_dialog = new VoipCallsDialog(*this, capture_file_, all_flows);
3047     connect(voip_calls_dialog, SIGNAL(goToPacket(int)),
3048             packet_list_, SLOT(goToPacket(int)));
3049     connect(voip_calls_dialog, SIGNAL(updateFilter(QString, bool)),
3050             this, SLOT(filterPackets(QString, bool)));
3051     voip_calls_dialog->show();
3052 }
3053
3054 void MainWindow::on_actionTelephonyVoipCalls_triggered()
3055 {
3056     openVoipCallsDialog();
3057 }
3058
3059 void MainWindow::on_actionTelephonyGsmMapSummary_triggered()
3060 {
3061     GsmMapSummaryDialog *gms_dialog = new GsmMapSummaryDialog(*this, capture_file_);
3062     gms_dialog->show();
3063 }
3064
3065 void MainWindow::on_actionTelephonyIax2StreamAnalysis_triggered()
3066 {
3067     Iax2AnalysisDialog *iax2_analysis_dialog = new  Iax2AnalysisDialog(*this, capture_file_);
3068     connect(iax2_analysis_dialog, SIGNAL(goToPacket(int)),
3069             packet_list_, SLOT(goToPacket(int)));
3070     iax2_analysis_dialog->show();
3071 }
3072
3073 void MainWindow::on_actionTelephonyISUPMessages_triggered()
3074 {
3075     openStatisticsTreeDialog("isup_msg");
3076 }
3077
3078 // -z mac-lte,stat
3079 void MainWindow::statCommandLteMacStatistics(const char *arg, void *)
3080 {
3081     LteMacStatisticsDialog *lte_mac_stats_dlg = new LteMacStatisticsDialog(*this, capture_file_, arg);
3082     connect(lte_mac_stats_dlg, SIGNAL(filterAction(QString&,FilterAction::Action,FilterAction::ActionType)),
3083             this, SLOT(filterAction(QString&,FilterAction::Action,FilterAction::ActionType)));
3084     lte_mac_stats_dlg->show();
3085 }
3086
3087 void MainWindow::on_actionTelephonyLteMacStatistics_triggered()
3088 {
3089     statCommandLteMacStatistics(NULL, NULL);
3090 }
3091
3092 void MainWindow::statCommandLteRlcStatistics(const char *arg, void *)
3093 {
3094     LteRlcStatisticsDialog *lte_rlc_stats_dlg = new LteRlcStatisticsDialog(*this, capture_file_, arg);
3095     connect(lte_rlc_stats_dlg, SIGNAL(filterAction(QString&,FilterAction::Action,FilterAction::ActionType)),
3096             this, SLOT(filterAction(QString&,FilterAction::Action,FilterAction::ActionType)));
3097     // N.B. It is necessary for the RLC Statistics window to launch the RLC graph in this way, to ensure
3098     // that the goToPacket() signal/slot connection gets set up...
3099     connect(lte_rlc_stats_dlg, SIGNAL(launchRLCGraph(bool, guint16, guint8, guint16, guint16, guint8)),
3100             this, SLOT(launchRLCGraph(bool, guint16, guint8, guint16, guint16, guint8)));
3101
3102     lte_rlc_stats_dlg->show();
3103 }
3104
3105 void MainWindow::on_actionTelephonyLteRlcStatistics_triggered()
3106 {
3107     statCommandLteRlcStatistics(NULL, NULL);
3108 }
3109
3110 void MainWindow::launchRLCGraph(bool channelKnown,
3111                                 guint16 ueid, guint8 rlcMode,
3112                                 guint16 channelType, guint16 channelId, guint8 direction)
3113 {
3114     LteRlcGraphDialog *lrg_dialog = new LteRlcGraphDialog(*this, capture_file_, channelKnown);
3115     connect(lrg_dialog, SIGNAL(goToPacket(int)), packet_list_, SLOT(goToPacket(int)));
3116     // This is a bit messy, but wanted to hide these parameters from users of
3117     // on_actionTelephonyLteRlcGraph_triggered().
3118     if (channelKnown) {
3119         lrg_dialog->setChannelInfo(ueid, rlcMode, channelType, channelId, direction);
3120     }
3121     lrg_dialog->show();
3122 }
3123
3124 void MainWindow::on_actionTelephonyLteRlcGraph_triggered()
3125 {
3126     // We don't yet know the channel.
3127     launchRLCGraph(false, 0, 0, 0, 0, 0);
3128 }
3129
3130 void MainWindow::on_actionTelephonyMtp3Summary_triggered()
3131 {
3132     Mtp3SummaryDialog *mtp3s_dialog = new Mtp3SummaryDialog(*this, capture_file_);
3133     mtp3s_dialog->show();
3134 }
3135
3136 void MainWindow::on_actionTelephonyRTPStreams_triggered()
3137 {
3138     RtpStreamDialog *rtp_stream_dialog = new  RtpStreamDialog(*this, capture_file_);
3139     connect(rtp_stream_dialog, SIGNAL(packetsMarked()),
3140             packet_list_, SLOT(redrawVisiblePackets()));
3141     connect(rtp_stream_dialog, SIGNAL(goToPacket(int)),
3142             packet_list_, SLOT(goToPacket(int)));
3143     connect(rtp_stream_dialog, SIGNAL(updateFilter(QString, bool)),
3144             this, SLOT(filterPackets(QString, bool)));
3145     rtp_stream_dialog->show();
3146 }
3147
3148 void MainWindow::on_actionTelephonyRTPStreamAnalysis_triggered()
3149 {
3150     RtpAnalysisDialog *rtp_analysis_dialog = new  RtpAnalysisDialog(*this, capture_file_);
3151     connect(rtp_analysis_dialog, SIGNAL(goToPacket(int)),
3152             packet_list_, SLOT(goToPacket(int)));
3153     rtp_analysis_dialog->show();
3154 }
3155
3156 void MainWindow::on_actionTelephonyRTSPPacketCounter_triggered()
3157 {
3158     openStatisticsTreeDialog("rtsp");
3159 }
3160
3161 void MainWindow::on_actionTelephonySMPPOperations_triggered()
3162 {
3163     openStatisticsTreeDialog("smpp_commands");
3164 }
3165
3166 void MainWindow::on_actionTelephonyUCPMessages_triggered()
3167 {
3168     openStatisticsTreeDialog("ucp_messages");
3169 }
3170
3171 void MainWindow::on_actionTelephonySipFlows_triggered()
3172 {
3173     openVoipCallsDialog(true);
3174 }
3175
3176 // Bluetooth Menu
3177
3178 void MainWindow::on_actionBluetoothATT_Server_Attributes_triggered()
3179 {
3180     BluetoothAttServerAttributesDialog *bluetooth_att_sever_attributes_dialog = new BluetoothAttServerAttributesDialog(*this, capture_file_);
3181     connect(bluetooth_att_sever_attributes_dialog, SIGNAL(goToPacket(int)),
3182             packet_list_, SLOT(goToPacket(int)));
3183     connect(bluetooth_att_sever_attributes_dialog, SIGNAL(updateFilter(QString, bool)),
3184             this, SLOT(filterPackets(QString, bool)));
3185     bluetooth_att_sever_attributes_dialog->show();
3186 }
3187
3188 void MainWindow::on_actionBluetoothDevices_triggered()
3189 {
3190     BluetoothDevicesDialog *bluetooth_devices_dialog = new BluetoothDevicesDialog(*this, capture_file_);
3191     connect(bluetooth_devices_dialog, SIGNAL(goToPacket(int)),
3192             packet_list_, SLOT(goToPacket(int)));
3193     connect(bluetooth_devices_dialog, SIGNAL(updateFilter(QString, bool)),
3194             this, SLOT(filterPackets(QString, bool)));
3195     bluetooth_devices_dialog->show();
3196 }
3197
3198 void MainWindow::on_actionBluetoothHCI_Summary_triggered()
3199 {
3200     BluetoothHciSummaryDialog *bluetooth_hci_summary_dialog = new BluetoothHciSummaryDialog(*this, capture_file_);
3201     connect(bluetooth_hci_summary_dialog, SIGNAL(goToPacket(int)),
3202             packet_list_, SLOT(goToPacket(int)));
3203     connect(bluetooth_hci_summary_dialog, SIGNAL(updateFilter(QString, bool)),
3204             this, SLOT(filterPackets(QString, bool)));
3205     bluetooth_hci_summary_dialog->show();
3206 }
3207
3208 // Help Menu
3209 void MainWindow::on_actionHelpContents_triggered() {
3210
3211     wsApp->helpTopicAction(HELP_CONTENT);
3212 }
3213
3214 void MainWindow::on_actionHelpMPWireshark_triggered() {
3215
3216     wsApp->helpTopicAction(LOCALPAGE_MAN_WIRESHARK);
3217 }
3218
3219 void MainWindow::on_actionHelpMPWireshark_Filter_triggered() {
3220     wsApp->helpTopicAction(LOCALPAGE_MAN_WIRESHARK_FILTER);
3221 }
3222
3223 void MainWindow::on_actionHelpMPCapinfos_triggered() {
3224     wsApp->helpTopicAction(LOCALPAGE_MAN_CAPINFOS);
3225 }
3226
3227 void MainWindow::on_actionHelpMPDumpcap_triggered() {
3228     wsApp->helpTopicAction(LOCALPAGE_MAN_DUMPCAP);
3229 }
3230
3231 void MainWindow::on_actionHelpMPEditcap_triggered() {
3232     wsApp->helpTopicAction(LOCALPAGE_MAN_EDITCAP);
3233 }
3234
3235 void MainWindow::on_actionHelpMPMergecap_triggered() {
3236     wsApp->helpTopicAction(LOCALPAGE_MAN_MERGECAP);
3237 }
3238
3239 void MainWindow::on_actionHelpMPRawShark_triggered() {
3240     wsApp->helpTopicAction(LOCALPAGE_MAN_RAWSHARK);
3241 }
3242
3243 void MainWindow::on_actionHelpMPReordercap_triggered() {
3244     wsApp->helpTopicAction(LOCALPAGE_MAN_REORDERCAP);
3245 }
3246
3247  void MainWindow::on_actionHelpMPText2cap_triggered() {
3248     wsApp->helpTopicAction(LOCALPAGE_MAN_TEXT2PCAP);
3249 }
3250
3251 void MainWindow::on_actionHelpMPTShark_triggered() {
3252     wsApp->helpTopicAction(LOCALPAGE_MAN_TSHARK);
3253 }
3254
3255 void MainWindow::on_actionHelpWebsite_triggered() {
3256
3257     wsApp->helpTopicAction(ONLINEPAGE_HOME);
3258 }
3259
3260 void MainWindow::on_actionHelpFAQ_triggered() {
3261
3262     wsApp->helpTopicAction(ONLINEPAGE_FAQ);
3263 }
3264
3265 void MainWindow::on_actionHelpAsk_triggered() {
3266
3267     wsApp->helpTopicAction(ONLINEPAGE_ASK);
3268 }
3269
3270 void MainWindow::on_actionHelpDownloads_triggered() {
3271
3272     wsApp->helpTopicAction(ONLINEPAGE_DOWNLOAD);
3273 }
3274
3275 void MainWindow::on_actionHelpWiki_triggered() {
3276
3277     wsApp->helpTopicAction(ONLINEPAGE_WIKI);
3278 }
3279
3280 void MainWindow::on_actionHelpSampleCaptures_triggered() {
3281
3282     wsApp->helpTopicAction(ONLINEPAGE_SAMPLE_FILES);
3283 }
3284
3285 #ifdef HAVE_SOFTWARE_UPDATE
3286 void MainWindow::checkForUpdates()
3287 {
3288     software_update_check();
3289 }
3290 #endif
3291
3292 void MainWindow::on_actionHelpAbout_triggered()
3293 {
3294     AboutDialog *about_dialog = new AboutDialog(this);
3295
3296     if (about_dialog->isMinimized() == true)
3297     {
3298         about_dialog->showNormal();
3299     }
3300     else
3301     {
3302         about_dialog->show();
3303     }
3304
3305     about_dialog->raise();
3306     about_dialog->activateWindow();
3307 }
3308
3309 void MainWindow::on_actionGoGoToPacket_triggered() {
3310     if (packet_list_->model()->rowCount() < 1) {
3311         return;
3312     }
3313     previous_focus_ = wsApp->focusWidget();
3314     connect(previous_focus_, SIGNAL(destroyed()), this, SLOT(resetPreviousFocus()));
3315
3316     showAccordionFrame(main_ui_->goToFrame, true);
3317     if (main_ui_->goToFrame->isVisible()) {
3318         main_ui_->goToLineEdit->clear();
3319         main_ui_->goToLineEdit->setFocus();
3320     }
3321 }
3322
3323 void MainWindow::on_actionGoGoToLinkedPacket_triggered()
3324 {
3325     QAction *gta = qobject_cast<QAction*>(sender());
3326     if (!gta) return;
3327
3328     bool ok = false;
3329     int packet_num = gta->data().toInt(&ok);
3330     if (!ok) return;
3331
3332     packet_list_->goToPacket(packet_num);
3333 }
3334
3335 // gtk/main_menubar.c:goto_conversation_frame
3336 void MainWindow::goToConversationFrame(bool go_next) {
3337     gchar     *filter       = NULL;
3338     dfilter_t *dfcode       = NULL;
3339     gboolean   found_packet = FALSE;
3340     packet_info *pi = &(capture_file_.capFile()->edt->pi);
3341     conversation_filter_t* conv_filter;
3342
3343     /* Try to build a conversation
3344      * filter in the order TCP, UDP, IP, Ethernet and apply the
3345      * coloring */
3346     conv_filter = find_conversation_filter("tcp");
3347     if ((conv_filter != NULL) && (conv_filter->is_filter_valid(pi)))
3348         filter = conv_filter->build_filter_string(pi);
3349     conv_filter = find_conversation_filter("udp");
3350     if ((conv_filter != NULL) && (conv_filter->is_filter_valid(pi)))
3351         filter = conv_filter->build_filter_string(pi);
3352     conv_filter = find_conversation_filter("ip");
3353     if ((conv_filter != NULL) && (conv_filter->is_filter_valid(pi)))
3354         filter = conv_filter->build_filter_string(pi);
3355     conv_filter = find_conversation_filter("ipv6");
3356     if ((conv_filter != NULL) && (conv_filter->is_filter_valid(pi)))
3357         filter = conv_filter->build_filter_string(pi);
3358
3359     if( filter == NULL ) {
3360         main_ui_->statusBar->pushTemporaryStatus(tr("Unable to build conversation filter."));
3361         g_free(filter);
3362         return;
3363     }
3364
3365     if (!dfilter_compile(filter, &dfcode, NULL)) {
3366         /* The attempt failed; report an error. */
3367         main_ui_->statusBar->pushTemporaryStatus(tr("Error compiling filter for this conversation."));
3368         g_free(filter);
3369         return;
3370     }
3371
3372     found_packet = cf_find_packet_dfilter(capture_file_.capFile(), dfcode, go_next ? SD_FORWARD : SD_BACKWARD);
3373
3374     if (!found_packet) {
3375         /* We didn't find a packet */
3376         main_ui_->statusBar->pushTemporaryStatus(tr("No previous/next packet in conversation."));
3377     }
3378
3379     dfilter_free(dfcode);
3380     g_free(filter);
3381 }
3382
3383 void MainWindow::on_actionGoNextConversationPacket_triggered()
3384 {
3385     goToConversationFrame(true);
3386 }
3387
3388 void MainWindow::on_actionGoPreviousConversationPacket_triggered()
3389 {
3390     goToConversationFrame(false);
3391 }
3392
3393 void MainWindow::on_actionGoAutoScroll_toggled(bool checked)
3394 {
3395     packet_list_->setVerticalAutoScroll(checked);
3396 }
3397
3398 void MainWindow::resetPreviousFocus() {
3399     previous_focus_ = NULL;
3400 }
3401
3402 void MainWindow::on_goToCancel_clicked()
3403 {
3404     main_ui_->goToFrame->animatedHide();
3405     if (previous_focus_) {
3406         disconnect(previous_focus_, SIGNAL(destroyed()), this, SLOT(resetPreviousFocus()));
3407         previous_focus_->setFocus();
3408         resetPreviousFocus();
3409     }
3410 }
3411
3412 void MainWindow::on_goToGo_clicked()
3413 {
3414     gotoFrame(main_ui_->goToLineEdit->text().toInt());
3415
3416     on_goToCancel_clicked();
3417 }
3418
3419 void MainWindow::on_goToLineEdit_returnPressed()
3420 {
3421     on_goToGo_clicked();
3422 }
3423
3424 void MainWindow::on_actionCaptureStart_triggered()
3425 {
3426 //#ifdef HAVE_AIRPCAP
3427 //  airpcap_if_active = airpcap_if_selected;
3428 //  if (airpcap_if_active)
3429 //    airpcap_set_toolbar_start_capture(airpcap_if_active);
3430 //#endif
3431
3432 //  if (cap_open_w) {
3433 //    /*
3434 //     * There's an options dialog; get the values from it and close it.
3435 //     */
3436 //    gboolean success;
3437
3438 //    /* Determine if "capture start" while building of the "capture options" window */
3439 //    /*  is in progress. If so, ignore the "capture start.                          */
3440 //    /* XXX: Would it be better/cleaner for the "capture options" window code to    */
3441 //    /*      disable the capture start button temporarily ?                         */
3442 //    if (cap_open_complete == FALSE) {
3443 //      return;  /* Building options window: ignore "capture start" */
3444 //    }
3445 //    success = capture_dlg_prep(cap_open_w);
3446 //    window_destroy(GTK_WIDGET(cap_open_w));
3447 //    if (!success)
3448 //      return;   /* error in options dialog */
3449 //  }
3450
3451 #ifdef HAVE_LIBPCAP
3452     if (global_capture_opts.num_selected == 0) {
3453         QString err_msg = tr("No Interface Selected");
3454         main_ui_->statusBar->pushTemporaryStatus(err_msg);
3455         main_ui_->actionCaptureStart->setChecked(false);
3456         return;
3457     }
3458
3459     /* XXX - will closing this remove a temporary file? */
3460     QString before_what(tr(" before starting a new capture"));
3461     if (testCaptureFileClose(FALSE, before_what)) {
3462         startCapture();
3463     } else {
3464         // simply clicking the button sets it to 'checked' even though we've
3465         // decided to do nothing, so undo that
3466         main_ui_->actionCaptureStart->setChecked(false);
3467     }
3468 #endif // HAVE_LIBPCAP
3469 }
3470
3471 void MainWindow::on_actionCaptureStop_triggered()
3472 {
3473     stopCapture();
3474 }
3475
3476 void MainWindow::on_actionCaptureRestart_triggered()
3477 {
3478 /* TODO: GTK use only this: capture_restart(&cap_session_); */
3479     captureStop();
3480     startCapture();
3481 }
3482
3483 static FilterDialog *capture_filter_dlg_ = NULL;
3484 void MainWindow::on_actionCaptureCaptureFilters_triggered()
3485 {
3486     if (!capture_filter_dlg_) {
3487         capture_filter_dlg_ = new FilterDialog(this, FilterDialog::CaptureFilter);
3488     }
3489     capture_filter_dlg_->show();
3490     capture_filter_dlg_->raise();
3491     capture_filter_dlg_->activateWindow();
3492 }
3493
3494 void MainWindow::on_actionStatisticsCaptureFileProperties_triggered()
3495 {
3496     CaptureFilePropertiesDialog *capture_file_properties_dialog = new CaptureFilePropertiesDialog(*this, capture_file_);
3497     connect(capture_file_properties_dialog, SIGNAL(captureCommentChanged()),
3498             this, SLOT(updateForUnsavedChanges()));
3499     capture_file_properties_dialog->show();
3500 }
3501
3502 void MainWindow::on_actionStatisticsResolvedAddresses_triggered()
3503 {
3504     ResolvedAddressesDialog *resolved_addresses_dialog = new ResolvedAddressesDialog(this, &capture_file_);
3505     resolved_addresses_dialog->show();
3506 }
3507
3508 void MainWindow::on_actionStatisticsProtocolHierarchy_triggered()
3509 {
3510     ProtocolHierarchyDialog *phd = new ProtocolHierarchyDialog(*this, capture_file_);
3511     connect(phd, SIGNAL(filterAction(QString&,FilterAction::Action,FilterAction::ActionType)),
3512             this, SLOT(filterAction(QString&,FilterAction::Action,FilterAction::ActionType)));
3513     phd->show();
3514 }
3515
3516 #ifdef HAVE_LIBPCAP
3517 void MainWindow::on_actionCaptureOptions_triggered()
3518 {
3519     connect(&capture_interfaces_dialog_, SIGNAL(setFilterValid(bool)), this, SLOT(startInterfaceCapture(bool)));
3520     capture_interfaces_dialog_.SetTab(0);
3521     capture_interfaces_dialog_.updateInterfaces();
3522
3523     if (capture_interfaces_dialog_.isMinimized() == true)
3524     {
3525         capture_interfaces_dialog_.showNormal();
3526     }
3527     else
3528     {
3529         capture_interfaces_dialog_.show();
3530     }
3531
3532     capture_interfaces_dialog_.raise();
3533     capture_interfaces_dialog_.activateWindow();
3534 }
3535
3536 void MainWindow::on_actionCaptureRefreshInterfaces_triggered()
3537 {
3538     main_ui_->actionCaptureRefreshInterfaces->setEnabled(false);
3539     wsApp->refreshLocalInterfaces();
3540     main_ui_->actionCaptureRefreshInterfaces->setEnabled(true);
3541 }
3542 #endif
3543
3544 void MainWindow::externalMenuItem_triggered()
3545 {
3546     QAction * triggerAction = NULL;
3547     QVariant v;
3548     ext_menubar_t * entry = NULL;
3549
3550     if ( QObject::sender() != NULL)
3551     {
3552         triggerAction = (QAction *)QObject::sender();
3553         v = triggerAction->data();
3554
3555         if ( v.canConvert<void *>())
3556         {
3557             entry = (ext_menubar_t *)v.value<void *>();
3558
3559             if ( entry->type == EXT_MENUBAR_ITEM )
3560             {
3561                 entry->callback(EXT_MENUBAR_QT_GUI, (gpointer) ((void *)main_ui_), entry->user_data);
3562             }
3563             else
3564             {
3565                 QDesktopServices::openUrl(QUrl(QString((gchar *)entry->user_data)));
3566             }
3567         }
3568     }
3569 }
3570
3571 void MainWindow::gotoFrame(int packet_num)
3572 {
3573     if ( packet_num > 0 )
3574     {
3575         packet_list_->goToPacket(packet_num);
3576     }
3577 }
3578
3579 #ifdef HAVE_EXTCAP
3580 void MainWindow::extcap_options_finished(int result)
3581 {
3582     if ( result == QDialog::Accepted )
3583     {
3584         startCapture();
3585     }
3586     this->main_welcome_->getInterfaceTree()->interfaceListChanged();
3587 }
3588
3589 void MainWindow::showExtcapOptionsDialog(QString &device_name)
3590 {
3591     ExtcapOptionsDialog * extcap_options_dialog = ExtcapOptionsDialog::createForDevice(device_name, this);
3592     /* The dialog returns null, if the given device name is not a valid extcap device */
3593     if ( extcap_options_dialog != NULL )
3594     {
3595         connect(extcap_options_dialog, SIGNAL(finished(int)),
3596                 this, SLOT(extcap_options_finished(int)));
3597         extcap_options_dialog->show();
3598     }
3599 }
3600 #endif
3601
3602 // Q_DECLARE_METATYPE(field_info *) called in proto_tree.h
3603
3604 void MainWindow::on_actionContextCopyBytesHexTextDump_triggered()
3605 {
3606     QAction *ca = qobject_cast<QAction*>(sender());
3607     if (!ca) return;
3608
3609     field_info *fi = ca->data().value<field_info *>();
3610
3611     byte_view_tab_->copyData(ByteViewTab::copyDataHexTextDump, fi);
3612 }
3613
3614 void MainWindow::on_actionContextCopyBytesHexDump_triggered()
3615 {
3616     QAction *ca = qobject_cast<QAction*>(sender());
3617     if (!ca) return;
3618
3619     field_info *fi = ca->data().value<field_info *>();
3620
3621     byte_view_tab_->copyData(ByteViewTab::copyDataHexDump, fi);
3622 }
3623
3624 void MainWindow::on_actionContextCopyBytesPrintableText_triggered()
3625 {
3626     QAction *ca = qobject_cast<QAction*>(sender());
3627     if (!ca) return;
3628
3629     field_info *fi = ca->data().value<field_info *>();
3630
3631     byte_view_tab_->copyData(ByteViewTab::copyDataPrintableText, fi);
3632 }
3633
3634 void MainWindow::on_actionContextCopyBytesHexStream_triggered()
3635 {
3636     QAction *ca = qobject_cast<QAction*>(sender());
3637     if (!ca) return;
3638
3639     field_info *fi = ca->data().value<field_info *>();
3640
3641     byte_view_tab_->copyData(ByteViewTab::copyDataHexStream, fi);
3642 }
3643
3644 void MainWindow::on_actionContextCopyBytesBinary_triggered()
3645 {
3646     QAction *ca = qobject_cast<QAction*>(sender());
3647     if (!ca) return;
3648
3649     field_info *fi = ca->data().value<field_info *>();
3650
3651     byte_view_tab_->copyData(ByteViewTab::copyDataBinary, fi);
3652 }
3653
3654 void MainWindow::on_actionContextWikiProtocolPage_triggered()
3655 {
3656     QAction *wa = qobject_cast<QAction*>(sender());
3657     if (!wa) return;
3658
3659     bool ok = false;
3660     int field_id = wa->data().toInt(&ok);
3661     if (!ok) return;
3662
3663     const QString proto_abbrev = proto_registrar_get_abbrev(field_id);
3664
3665     int ret = QMessageBox::question(this, wsApp->windowTitleString(tr("Wiki Page for %1").arg(proto_abbrev)),
3666                                    tr("<p>The Wireshark Wiki is maintained by the community.</p>"
3667                                       "<p>The page you are about to load might be wonderful, "
3668                                       "incomplete, wrong, or nonexistent.</p>"
3669                                       "<p>Proceed to the wiki?</p>"),
3670                                    QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
3671
3672     if (ret != QMessageBox::Yes) return;
3673
3674     QUrl wiki_url = QString("https://wiki.wireshark.org/Protocols/%1").arg(proto_abbrev);
3675     QDesktopServices::openUrl(wiki_url);
3676 }
3677
3678 void MainWindow::on_actionContextFilterFieldReference_triggered()
3679 {
3680     QAction *wa = qobject_cast<QAction*>(sender());
3681     if (!wa) return;
3682
3683     bool ok = false;
3684     int field_id = wa->data().toInt(&ok);
3685     if (!ok) return;
3686
3687     const QString proto_abbrev = proto_registrar_get_abbrev(field_id);
3688
3689     QUrl dfref_url = QString("https://www.wireshark.org/docs/dfref/%1/%2")
3690             .arg(proto_abbrev[0])
3691             .arg(proto_abbrev);
3692     QDesktopServices::openUrl(dfref_url);
3693 }
3694
3695 #ifdef _MSC_VER
3696 #pragma warning(pop)
3697 #endif
3698
3699 /*
3700  * Editor modelines
3701  *
3702  * Local Variables:
3703  * c-basic-offset: 4
3704  * tab-width: 8
3705  * indent-tabs-mode: nil
3706  * End:
3707  *
3708  * ex: set shiftwidth=4 tabstop=8 expandtab:
3709  * :indentSize=4:tabSize=8:noTabs=true:
3710  */