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