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