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