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