Kerberos: add kerberos_inject_longterm_key() helper function
[wireshark-sm.git] / ui / stratoshark / stratoshark_main_window_slots.cpp
blobc3f8a6a9bfe3c99ef29425b84218c183a39c08d8
1 /* stratoshark_main_window_slots.cpp
3 * Stratoshark - System call and event log analyzer
4 * By Gerald Combs <gerald@wireshark.org>
5 * Copyright 1998 Gerald Combs
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
10 #include <config.h>
12 // Qt 5.5.0 + Visual C++ 2013
13 #ifdef _MSC_VER
14 #pragma warning(push)
15 #pragma warning(disable:4996)
16 #endif
18 #include "stratoshark_main_window.h"
21 * The generated Ui_StratosharkMainWindow::setupUi() can grow larger than our configured limit,
22 * so turn off -Wframe-larger-than= for ui_stratoshark_window.h.
24 DIAG_OFF(frame-larger-than=)
25 #include <ui_stratoshark_main_window.h>
26 DIAG_ON(frame-larger-than=)
28 #ifdef _WIN32
29 #include <windows.h>
30 #endif
32 #include "ui/dissect_opts.h"
34 #ifdef HAVE_LIBPCAP
35 #include "ui/capture.h"
36 #endif
38 #include "ui/commandline.h"
40 #include "ui/urls.h"
42 #include "epan/color_filters.h"
44 #include "wsutil/file_util.h"
45 #include "wsutil/filesystem.h"
46 #include <wsutil/wslog.h>
47 #include <wsutil/ws_assert.h>
49 #include "epan/addr_resolv.h"
50 #include "epan/column.h"
51 #include "epan/dfilter/dfilter-macro.h"
52 #include "epan/conversation_filter.h"
53 #include "epan/epan_dissect.h"
54 #include "epan/filter_expressions.h"
55 #include "epan/prefs.h"
56 #include "epan/plugin_if.h"
57 #include "epan/uat.h"
58 #include "epan/uat-int.h"
59 #include "epan/value_string.h"
61 #ifdef HAVE_LUA
62 #include <epan/wslua/init_wslua.h>
63 #endif
65 #include "ui/alert_box.h"
66 #ifdef HAVE_LIBPCAP
67 #include "ui/capture_ui_utils.h"
68 #endif
70 #include "ui/capture_globals.h"
71 #include "ui/help_url.h"
72 #include "ui/main_statusbar.h"
73 #include "ui/preference_utils.h"
74 #include "ui/recent.h"
75 #include "ui/recent_utils.h"
76 #include "ui/ssl_key_export.h"
77 #include "ui/ws_ui_util.h"
78 #include "ui/all_files_wildcard.h"
79 #include "ui/qt/simple_dialog.h"
81 #include <ui/qt/utils/variant_pointer.h>
82 #include <ui/qt/widgets/drag_drop_toolbar.h>
83 #include "ui/qt/widgets/wireshark_file_dialog.h"
85 #ifdef HAVE_SOFTWARE_UPDATE
86 #include "ui/software_update.h"
87 #endif
89 #include "about_dialog.h"
90 #include "capture_file_dialog.h"
91 #include "capture_file_properties_dialog.h"
92 #ifdef HAVE_LIBPCAP
93 #include "capture_options_dialog.h"
94 #endif
95 #include <ui/qt/utils/color_utils.h>
96 #include "coloring_rules_dialog.h"
97 #include "conversation_dialog.h"
98 #include "conversation_colorize_action.h"
99 #include "conversation_hash_tables_dialog.h"
100 #include "enabled_protocols_dialog.h"
101 #include "decode_as_dialog.h"
102 #include <ui/qt/widgets/display_filter_edit.h>
103 #include "display_filter_expression_dialog.h"
104 #include "dissector_tables_dialog.h"
105 #include "endpoint_dialog.h"
106 #include "expert_info_dialog.h"
107 #include "extcap_options_dialog.h"
108 #include "file_set_dialog.h"
109 #include "filter_action.h"
110 #include "filter_dialog.h"
111 #include "follow_stream_action.h"
112 #include "follow_stream_dialog.h"
113 #include "funnel_statistics.h"
114 #include "interface_toolbar.h"
115 #include "io_graph_dialog.h"
116 #include <ui/qt/widgets/additional_toolbar.h>
117 #include "main_application.h"
118 #include "packet_comment_dialog.h"
119 #include "packet_dialog.h"
120 #include "packet_list.h"
121 #include "preferences_dialog.h"
122 #include "print_dialog.h"
123 #include "profile_dialog.h"
124 #include "protocol_hierarchy_dialog.h"
125 #include <ui/qt/utils/qt_ui_utils.h>
126 #include "resolved_addresses_dialog.h"
127 #include "show_packet_bytes_dialog.h"
128 #include "stats_tree_dialog.h"
129 #include <ui/qt/utils/stock_icon.h>
130 #include "supported_protocols_dialog.h"
131 #include "tap_parameter_dialog.h"
132 #include "time_shift_dialog.h"
133 #include "uat_dialog.h"
135 #include <functional>
136 #include <QClipboard>
137 #include <QFileInfo>
138 #include <QMessageBox>
139 #include <QMetaObject>
140 #include <QMimeData>
141 #include <QToolBar>
142 #include <QDesktopServices>
143 #include <QUrl>
144 #include <QMutex>
146 // XXX You must uncomment QT_WINEXTRAS_LIB lines in CMakeList.txt and
147 // cmakeconfig.h.in.
148 // #if defined(QT_WINEXTRAS_LIB)
149 // #include <QWinJumpList>
150 // #include <QWinJumpListCategory>
151 // #include <QWinJumpListItem>
152 // #endif
155 // Public slots
158 bool StratosharkMainWindow::openCaptureFile(QString cf_path, QString read_filter, unsigned int type, bool is_tempfile)
160 QString file_name = "";
161 dfilter_t *rfcode = NULL;
162 df_error_t *df_err = NULL;
163 int err;
164 bool name_param;
165 bool ret = true;
167 // was a file name given as function parameter?
168 name_param = !cf_path.isEmpty();
170 for (;;) {
172 if (cf_path.isEmpty()) {
173 CaptureFileDialog open_dlg(this, capture_file_.capFile());
175 if (open_dlg.open(file_name, type, read_filter)) {
176 cf_path = file_name;
177 } else {
178 ret = false;
179 goto finish;
181 } else {
182 this->welcome_page_->getInterfaceFrame()->showRunOnFile();
185 // TODO detect call from "cf_read" -> "update_progress_dlg"
186 // ("capture_file_.capFile()->read_lock"), possibly queue opening the
187 // file and return early to avoid the warning in testCaptureFileClose.
189 QString before_what(tr(" before opening another file"));
190 if (!testCaptureFileClose(before_what)) {
191 ret = false;
192 goto finish;
195 if (dfilter_compile(qUtf8Printable(read_filter), &rfcode, &df_err)) {
196 cf_set_rfcode(CaptureFile::globalCapFile(), rfcode);
197 } else {
198 /* Not valid. Tell the user, and go back and run the file
199 selection box again once they dismiss the alert. */
200 //bad_dfilter_alert_box(top_level, read_filter->str);
201 QMessageBox::warning(this, tr("Invalid Display Filter"),
202 QStringLiteral("The filter expression ") +
203 read_filter +
204 QStringLiteral(" isn't a valid display filter. (") +
205 df_err->msg + QStringLiteral(")."),
206 QMessageBox::Ok);
207 df_error_free(&df_err);
209 if (!name_param) {
210 // go back to the selection dialogue only if the file
211 // was selected from this dialogue
212 cf_path.clear();
213 continue;
217 /* Make the file name available via MainWindow */
218 setMwFileName(cf_path);
220 /* Try to open the capture file. This closes the current file if it succeeds. */
221 CaptureFile::globalCapFile()->window = this;
222 if (cf_open(CaptureFile::globalCapFile(), qUtf8Printable(cf_path), type, is_tempfile, &err) != CF_OK) {
223 /* We couldn't open it; don't dismiss the open dialog box,
224 just leave it around so that the user can, after they
225 dismiss the alert box popped up for the open error,
226 try again. */
227 CaptureFile::globalCapFile()->window = NULL;
228 dfilter_free(rfcode);
229 cf_path.clear();
230 continue;
233 switch (cf_read(CaptureFile::globalCapFile(), /*reloading=*/false)) {
234 case CF_READ_OK:
235 case CF_READ_ERROR:
236 /* Just because we got an error, that doesn't mean we were unable
237 to read any of the file; we handle what we could get from the
238 file. */
239 break;
241 case CF_READ_ABORTED:
242 /* The user bailed out of re-reading the capture file; the
243 capture file has been closed - just free the capture file name
244 string and return (without changing the last containing
245 directory). */
246 capture_file_.setCapFile(NULL);
247 ret = false;
248 goto finish;
250 break;
253 if (!is_tempfile) {
254 mainApp->setLastOpenDirFromFilename(cf_path);
257 main_ui_->statusBar->showExpert();
259 finish:
260 #ifdef HAVE_LIBPCAP
261 if (global_commandline_info.quit_after_cap)
262 exit(0);
263 #endif
264 return ret;
267 void StratosharkMainWindow::filterPackets(QString new_filter, bool force)
269 cf_status_t cf_status;
271 cf_status = cf_filter_packets(CaptureFile::globalCapFile(), new_filter.toUtf8().data(), force);
273 if (cf_status == CF_OK) {
274 if (new_filter.length() > 0) {
275 int index = df_combo_box_->findText(new_filter);
276 if (index == -1) {
277 df_combo_box_->insertItem(0, new_filter);
278 df_combo_box_->setCurrentIndex(0);
279 } else {
280 df_combo_box_->setCurrentIndex(index);
282 } else {
283 df_combo_box_->lineEdit()->clear();
285 // Only after the display filter has been updated,
286 // disable the arrow button
287 emit displayFilterSuccess(true);
288 } else {
289 emit displayFilterSuccess(false);
293 void StratosharkMainWindow::layoutToolbars()
295 Qt::ToolButtonStyle tbstyle = Qt::ToolButtonIconOnly;
296 switch (prefs.gui_toolbar_main_style) {
297 case TB_STYLE_TEXT:
298 tbstyle = Qt::ToolButtonTextOnly;
299 break;
300 case TB_STYLE_BOTH:
301 tbstyle = Qt::ToolButtonTextUnderIcon;
302 break;
305 main_ui_->mainToolBar->setToolButtonStyle(tbstyle);
307 main_ui_->mainToolBar->setVisible(recent.main_toolbar_show);
308 main_ui_->displayFilterToolBar->setVisible(recent.filter_toolbar_show);
309 main_ui_->statusBar->setVisible(recent.statusbar_show);
311 foreach(QAction *action, main_ui_->menuInterfaceToolbars->actions()) {
312 QToolBar *toolbar = action->data().value<QToolBar *>();
313 if (g_list_find_custom(recent.interface_toolbars, action->text().toUtf8(), (GCompareFunc)strcmp)) {
314 toolbar->setVisible(true);
315 } else {
316 toolbar->setVisible(false);
320 QList<QToolBar *> toolbars = findChildren<QToolBar *>();
321 foreach(QToolBar *bar, toolbars) {
322 AdditionalToolBar *iftoolbar = dynamic_cast<AdditionalToolBar *>(bar);
323 if (iftoolbar) {
324 bool visible = false;
325 if (g_list_find_custom(recent.gui_additional_toolbars, qUtf8Printable(iftoolbar->menuName()), (GCompareFunc)strcmp))
326 visible = true;
328 iftoolbar->setVisible(visible);
334 static const char* layout_icons[] = {
335 NULL,
336 "x-reset-layout_5",
337 "x-reset-layout_2",
338 "x-reset-layout_1",
339 "x-reset-layout_4",
340 "x-reset-layout_3",
341 "x-reset-layout_6"
344 void StratosharkMainWindow::updatePreferenceActions()
346 main_ui_->actionViewPacketList->setEnabled(prefs_has_layout_pane_content(layout_pane_content_plist));
347 main_ui_->actionViewPacketDetails->setEnabled(prefs_has_layout_pane_content(layout_pane_content_pdetails));
348 main_ui_->actionViewPacketBytes->setEnabled(prefs_has_layout_pane_content(layout_pane_content_pbytes));
350 main_ui_->actionViewNameResolutionPhysical->setChecked(gbl_resolv_flags.mac_name);
351 main_ui_->actionViewNameResolutionNetwork->setChecked(gbl_resolv_flags.network_name);
352 main_ui_->actionViewNameResolutionTransport->setChecked(gbl_resolv_flags.transport_name);
354 if (prefs.gui_layout_type > 0)
355 main_ui_->actionViewResetLayout->setIcon(StockIcon(layout_icons[prefs.gui_layout_type]));
358 void StratosharkMainWindow::updateRecentActions()
360 main_ui_->actionViewMainToolbar->setChecked(recent.main_toolbar_show);
361 main_ui_->actionViewFilterToolbar->setChecked(recent.filter_toolbar_show);
362 main_ui_->actionViewStatusBar->setChecked(recent.statusbar_show);
363 main_ui_->actionViewPacketList->setChecked(recent.packet_list_show && prefs_has_layout_pane_content(layout_pane_content_plist));
364 main_ui_->actionViewPacketDetails->setChecked(recent.tree_view_show && prefs_has_layout_pane_content(layout_pane_content_pdetails));
365 main_ui_->actionViewPacketBytes->setChecked(recent.byte_view_show && prefs_has_layout_pane_content(layout_pane_content_pbytes));
367 foreach(QAction *action, main_ui_->menuInterfaceToolbars->actions()) {
368 if (g_list_find_custom(recent.interface_toolbars, action->text().toUtf8(), (GCompareFunc)strcmp)) {
369 action->setChecked(true);
370 } else {
371 action->setChecked(false);
375 foreach(QAction * action, main_ui_->menuAdditionalToolbars->actions()) {
376 ext_toolbar_t * toolbar = VariantPointer<ext_toolbar_t>::asPtr(action->data());
377 bool checked = false;
378 if (toolbar && g_list_find_custom(recent.gui_additional_toolbars, toolbar->name, (GCompareFunc)strcmp))
379 checked = true;
381 action->setChecked(checked);
384 foreach(QAction* tda, td_actions.keys()) {
385 if (recent.gui_time_format == td_actions[tda]) {
386 tda->setChecked(true);
389 foreach(QAction* tpa, tp_actions.keys()) {
390 if (recent.gui_time_precision == tp_actions[tpa]) {
391 tpa->setChecked(true);
392 break;
395 main_ui_->actionViewTimeDisplaySecondsWithHoursAndMinutes->setChecked(recent.gui_seconds_format == TS_SECONDS_HOUR_MIN_SEC);
397 main_ui_->actionViewColorizePacketList->setChecked(recent.packet_list_colorize);
399 main_ui_->actionGoAutoScroll->setChecked(recent.capture_auto_scroll);
402 // Don't connect to this directly. Connect to or emit filterAction(...) instead.
403 void StratosharkMainWindow::queuedFilterAction(QString action_filter, FilterAction::Action action, FilterAction::ActionType type)
405 QString cur_filter, new_filter;
407 if (!df_combo_box_) return;
408 cur_filter = df_combo_box_->lineEdit()->text();
410 switch (type) {
411 case FilterAction::ActionTypePlain:
412 new_filter = action_filter;
413 break;
414 case FilterAction::ActionTypeAnd:
415 if (cur_filter.length()) {
416 new_filter = "(" + cur_filter + ") && (" + action_filter + ")";
418 else {
419 new_filter = action_filter;
421 break;
422 case FilterAction::ActionTypeOr:
423 if (cur_filter.length()) {
424 new_filter = "(" + cur_filter + ") || (" + action_filter + ")";
425 } else {
426 new_filter = action_filter;
428 break;
429 case FilterAction::ActionTypeNot:
430 new_filter = "!(" + action_filter + ")";
431 break;
432 case FilterAction::ActionTypeAndNot:
433 if (cur_filter.length()) {
434 new_filter = "(" + cur_filter + ") && !(" + action_filter + ")";
435 } else {
436 new_filter = "!(" + action_filter + ")";
438 break;
439 case FilterAction::ActionTypeOrNot:
440 if (cur_filter.length()) {
441 new_filter = "(" + cur_filter + ") || !(" + action_filter + ")";
442 } else {
443 new_filter = "!(" + action_filter + ")";
445 break;
446 default:
447 ws_assert_not_reached();
448 break;
451 switch (action) {
452 case FilterAction::ActionApply:
453 df_combo_box_->lineEdit()->setText(new_filter);
454 df_combo_box_->applyDisplayFilter();
455 break;
456 case FilterAction::ActionColorize:
457 colorizeWithFilter(new_filter.toUtf8());
458 break;
459 case FilterAction::ActionCopy:
460 mainApp->clipboard()->setText(new_filter);
461 break;
462 case FilterAction::ActionFind:
463 main_ui_->searchFrame->findFrameWithFilter(new_filter);
464 break;
465 case FilterAction::ActionPrepare:
466 df_combo_box_->lineEdit()->setText(new_filter);
467 df_combo_box_->lineEdit()->setFocus();
468 break;
469 case FilterAction::ActionWebLookup:
471 QString url = QStringLiteral("https://www.google.com/search?q=") + new_filter;
472 QDesktopServices::openUrl(QUrl(url));
473 break;
475 default:
476 ws_assert_not_reached();
477 break;
481 // Capture callbacks
483 #ifdef HAVE_LIBPCAP
484 void StratosharkMainWindow::captureCapturePrepared(capture_session *session) {
485 setTitlebarForCaptureInProgress();
486 setWindowIcon(mainApp->captureIcon());
487 pushLiveCaptureInProgress();
489 /* Disable menu items that make no sense if you're currently running
490 a capture. */
491 bool handle_toolbars = (session->session_will_restart ? false : true);
492 setForCaptureInProgress(true, handle_toolbars, session->capture_opts->ifaces);
493 // set_capture_if_dialog_for_capture_in_progress(true);
495 // /* Don't set up main window for a capture file. */
496 // main_set_for_capture_file(false);
497 showCapture();
500 void StratosharkMainWindow::captureCaptureUpdateStarted(capture_session *session) {
502 /* We've done this in "prepared" above, but it will be cleared while
503 switching to the next multiple file. */
504 setTitlebarForCaptureInProgress();
505 setWindowIcon(mainApp->captureIcon());
506 pushLiveCaptureInProgress();
508 bool handle_toolbars = (session->session_will_restart ? false : true);
509 setForCaptureInProgress(true, handle_toolbars, session->capture_opts->ifaces);
511 setForCapturedPackets(true);
514 void StratosharkMainWindow::captureCaptureUpdateFinished(capture_session *session) {
516 /* The capture isn't stopping any more - it's stopped. */
517 capture_stopping_ = false;
519 /* Update the main window as appropriate */
520 updateForUnsavedChanges();
521 setTitlebarForCaptureFile();
523 /* Enable menu items that make sense if you're not currently running
524 a capture. */
525 bool handle_toolbars = (session->session_will_restart ? false : true);
526 setForCaptureInProgress(false, handle_toolbars);
527 setMenusForCaptureFile();
529 setWindowIcon(mainApp->normalIcon());
530 popLiveCaptureInProgress();
532 if (global_commandline_info.quit_after_cap) {
533 // Command line asked us to quit after capturing.
534 // Don't pop up a dialog to ask for unsaved files etc.
535 exit(0);
539 void StratosharkMainWindow::captureCaptureFixedFinished(capture_session *) {
541 /* The capture isn't stopping any more - it's stopped. */
542 capture_stopping_ = false;
543 setTitlebarForCaptureFile();
545 /* Enable menu items that make sense if you're not currently running
546 a capture. */
547 setForCaptureInProgress(false);
548 /* There isn't a real capture_file structure yet, so just force disabling
549 menu options. They will "refresh" when the capture file is reloaded to
550 display packets */
551 setMenusForCaptureFile(true);
553 setWindowIcon(mainApp->normalIcon());
554 popLiveCaptureInProgress();
556 if (global_commandline_info.quit_after_cap) {
557 // Command line asked us to quit after capturing.
558 // Don't pop up a dialog to ask for unsaved files etc.
559 exit(0);
563 void StratosharkMainWindow::captureCaptureFailed(capture_session *) {
564 /* Capture isn't stopping any more. */
565 capture_stopping_ = false;
566 setTitlebarForCaptureFile();
567 setForCaptureInProgress(false);
568 showWelcome();
570 // Reset expert information indicator
571 main_ui_->statusBar->captureFileClosing();
572 mainApp->popStatus(WiresharkApplication::FileStatus);
574 setWindowIcon(mainApp->normalIcon());
575 popLiveCaptureInProgress();
577 if (global_commandline_info.quit_after_cap) {
578 // Command line asked us to quit after capturing.
579 // Don't pop up a dialog to ask for unsaved files etc.
580 exit(0);
583 #endif // HAVE_LIBPCAP
585 // Callbacks from cfile.c and file.c via CaptureFile::captureFileCallback
587 void StratosharkMainWindow::captureEventHandler(CaptureEvent ev)
589 switch (ev.captureContext()) {
591 case CaptureEvent::File:
592 switch (ev.eventType()) {
593 case CaptureEvent::Opened:
594 captureFileOpened();
595 break;
596 case CaptureEvent::Closing:
597 captureFileClosing();
598 break;
599 case CaptureEvent::Closed:
600 captureFileClosed();
601 break;
602 case CaptureEvent::Started:
603 captureFileReadStarted(tr("Loading"));
604 break;
605 case CaptureEvent::Finished:
606 captureFileReadFinished();
607 break;
608 default:
609 break;
611 break;
613 case CaptureEvent::Reload:
614 switch (ev.eventType()) {
615 case CaptureEvent::Started:
616 captureFileReadStarted(tr("Reloading"));
617 break;
618 case CaptureEvent::Finished:
619 captureFileReadFinished();
620 break;
621 default:
622 break;
624 break;
626 case CaptureEvent::Rescan:
627 switch (ev.eventType()) {
628 case CaptureEvent::Started:
629 setMenusForCaptureFile(true);
630 captureFileReadStarted(tr("Rescanning"));
631 break;
632 case CaptureEvent::Finished:
633 captureFileReadFinished();
634 break;
635 default:
636 break;
638 break;
640 case CaptureEvent::Retap:
641 switch (ev.eventType()) {
642 case CaptureEvent::Started:
643 freeze();
644 break;
645 case CaptureEvent::Finished:
646 thaw();
647 break;
648 case CaptureEvent::Flushed:
649 draw_tap_listeners(false);
650 break;
651 default:
652 break;
654 break;
656 case CaptureEvent::Merge:
657 switch (ev.eventType()) {
658 case CaptureEvent::Started:
659 mainApp->popStatus(WiresharkApplication::FileStatus);
660 mainApp->pushStatus(WiresharkApplication::FileStatus, tr("Merging files."), QString());
661 break;
662 case CaptureEvent::Finished:
663 mainApp->popStatus(WiresharkApplication::FileStatus);
664 break;
665 default:
666 break;
668 break;
670 case CaptureEvent::Save:
671 switch (ev.eventType()) {
672 case CaptureEvent::Started:
674 QFileInfo file_info(ev.filePath());
675 mainApp->popStatus(WiresharkApplication::FileStatus);
676 mainApp->pushStatus(WiresharkApplication::FileStatus, tr("Saving %1…").arg(file_info.fileName()));
677 break;
679 default:
680 break;
682 break;
684 #ifdef HAVE_LIBPCAP
685 case CaptureEvent::Capture:
686 switch (ev.eventType()) {
687 case CaptureEvent::Prepared:
688 captureCapturePrepared(ev.capSession());
689 break;
690 case CaptureEvent::Stopping:
691 capture_stopping_ = true;
692 setMenusForCaptureStopping();
693 break;
694 case CaptureEvent::Failed:
695 captureCaptureFailed(ev.capSession());
696 default:
697 break;
699 break;
701 case CaptureEvent::Update:
702 switch (ev.eventType()) {
703 case CaptureEvent::Started:
704 captureCaptureUpdateStarted(ev.capSession());
705 break;
706 case CaptureEvent::Finished:
707 captureCaptureUpdateFinished(ev.capSession());
708 break;
709 default:
710 break;
712 break;
714 case CaptureEvent::Fixed:
715 switch (ev.eventType()) {
716 case CaptureEvent::Finished:
717 captureCaptureFixedFinished(ev.capSession());
718 break;
719 default:
720 break;
722 break;
723 #endif
727 void StratosharkMainWindow::captureFileOpened() {
728 if (capture_file_.window() != this) return;
730 file_set_dialog_->fileOpened(capture_file_.capFile());
731 setMenusForFileSet(true);
732 emit setCaptureFile(capture_file_.capFile());
735 void StratosharkMainWindow::captureFileReadStarted(const QString &action) {
736 // tap_param_dlg_update();
738 /* Set up main window for a capture file. */
739 // main_set_for_capture_file(true);
741 mainApp->popStatus(WiresharkApplication::FileStatus);
742 QString msg = tr("%1: %2").arg(action).arg(capture_file_.fileName());
743 QString msgtip = QString();
744 mainApp->pushStatus(WiresharkApplication::FileStatus, msg, msgtip);
745 showCapture();
746 main_ui_->actionAnalyzeReloadLuaPlugins->setEnabled(false);
749 void StratosharkMainWindow::captureFileReadFinished() {
750 if (!capture_file_.capFile()->is_tempfile && capture_file_.capFile()->filename) {
751 /* Add this filename to the list of recent files in the "Recent Files" submenu */
752 add_menu_recent_capture_file(capture_file_.capFile()->filename, false);
754 /* Remember folder for next Open dialog and save it in recent */
755 mainApp->setLastOpenDirFromFilename(capture_file_.capFile()->filename);
758 /* Update the appropriate parts of the main window. */
759 updateForUnsavedChanges();
761 /* Enable menu items that make sense if you have some captured packets. */
762 setForCapturedPackets(true);
764 main_ui_->statusBar->setFileName(capture_file_);
765 main_ui_->actionAnalyzeReloadLuaPlugins->setEnabled(true);
767 packet_list_->captureFileReadFinished();
769 emit setDissectedCaptureFile(capture_file_.capFile());
772 void StratosharkMainWindow::captureFileClosing() {
773 setMenusForCaptureFile(true);
774 setTitlebarForCaptureFile();
775 setForCapturedPackets(false);
776 setForCaptureInProgress(false);
778 // Reset expert information indicator
779 main_ui_->statusBar->captureFileClosing();
780 main_ui_->searchFrame->animatedHide();
781 main_ui_->goToFrame->animatedHide();
782 // gtk_widget_show(expert_info_none);
783 emit setCaptureFile(NULL);
784 emit setDissectedCaptureFile(NULL);
787 void StratosharkMainWindow::captureFileClosed() {
788 packets_bar_update();
790 file_set_dialog_->fileClosed();
791 setMenusForFileSet(false);
792 setWindowModified(false);
794 // Reset expert information indicator
795 main_ui_->statusBar->captureFileClosing();
796 mainApp->popStatus(WiresharkApplication::FileStatus);
798 setWSWindowTitle();
799 setWindowIcon(mainApp->normalIcon());
800 setMenusForSelectedPacket();
801 setMenusForSelectedTreeRow();
803 #ifdef HAVE_LIBPCAP
804 if (!global_capture_opts.multi_files_on)
805 showWelcome();
806 #endif
810 // Private slots
813 // ui/gtk/capture_dlg.c:start_capture_confirmed
815 void StratosharkMainWindow::startCapture(QStringList) {
816 startCapture();
819 void StratosharkMainWindow::startCapture() {
820 #ifdef HAVE_LIBPCAP
821 interface_options *interface_opts;
822 unsigned i;
823 interface_t *device;
824 bool can_start_capture = true;
826 /* did the user ever select a capture interface before? */
827 if (global_capture_opts.num_selected == 0) {
828 QString msg = tr("No interface selected.");
829 mainApp->pushStatus(WiresharkApplication::TemporaryStatus, msg);
830 main_ui_->actionCaptureStart->setChecked(false);
831 return;
834 for (i = 0; i < global_capture_opts.all_ifaces->len; i++) {
835 device = &g_array_index(global_capture_opts.all_ifaces, interface_t, i);
836 if (device->selected && (device->if_info.type == IF_EXTCAP)) {
837 /* device is EXTCAP and is selected. Check if all mandatory
838 * settings are set.
840 if (extcap_requires_configuration(device->name))
842 /* Request opening of extcap options dialog */
843 QString device_name(device->name);
844 emit showExtcapOptions(device_name, false);
845 /* Cancel start of capture */
846 can_start_capture = false;
851 /* If some of extcap was not configured, do not start with the capture */
852 if (!can_start_capture) {
853 QString msg = tr("Configure all extcaps before start of capture.");
854 mainApp->pushStatus(WiresharkApplication::TemporaryStatus, msg);
855 main_ui_->actionCaptureStart->setChecked(false);
856 return;
859 // Ideally we should have disabled the start capture
860 // toolbar buttons and menu items. This may not be the
861 // case, e.g. with QtMacExtras.
862 if (!capture_filter_valid_) {
863 QString msg = tr("Invalid capture filter.");
864 mainApp->pushStatus(WiresharkApplication::TemporaryStatus, msg);
865 main_ui_->actionCaptureStart->setChecked(false);
866 return;
869 showCapture();
871 /* XXX - we might need to init other pref data as well... */
872 main_ui_->actionGoAutoScroll->setChecked(recent.capture_auto_scroll);
874 /* XXX - can this ever happen? */
875 if (cap_session_.state != CAPTURE_STOPPED)
876 return;
878 /* close the currently loaded capture file */
879 cf_close((capture_file *)cap_session_.cf);
881 /* Copy the selected interfaces to the set of interfaces to use for
882 this capture. */
883 collect_ifaces(&global_capture_opts);
885 CaptureFile::globalCapFile()->window = this;
886 info_data_.ui.ui = this;
887 if (capture_start(&global_capture_opts, NULL, &cap_session_, &info_data_,
888 main_window_update)) {
889 /* The capture succeeded, which means the capture filter syntax is
890 valid; add this capture filter to the recent capture filter list. */
891 QByteArray filter_ba;
892 for (i = 0; i < global_capture_opts.ifaces->len; i++) {
893 interface_opts = &g_array_index(global_capture_opts.ifaces, interface_options, i);
894 if (interface_opts->cfilter) {
895 recent_add_cfilter(interface_opts->name, interface_opts->cfilter);
896 if (filter_ba.isEmpty()) {
897 filter_ba = interface_opts->cfilter;
898 } else {
899 /* Not the first selected interface; is its capture filter
900 the same as the one the other interfaces we've looked
901 at have? */
902 if (strcmp(interface_opts->cfilter, filter_ba.constData()) != 0) {
903 /* No, so not all selected interfaces have the same capture
904 filter. */
905 filter_ba.clear();
910 if (!filter_ba.isEmpty()) {
911 recent_add_cfilter(NULL, filter_ba.constData());
913 } else {
914 CaptureFile::globalCapFile()->window = NULL;
916 #endif // HAVE_LIBPCAP
919 void StratosharkMainWindow::pushLiveCaptureInProgress() {
920 #ifdef HAVE_LIBPCAP
921 capture_options *capture_opts = cap_session_.capture_opts;
922 GString *interface_names;
924 /* Add "interface name<live capture in progress>" on main status bar */
925 interface_names = get_iface_list_string(capture_opts, 0);
926 if (strlen(interface_names->str) > 0) {
927 g_string_append(interface_names, ":");
929 g_string_append(interface_names, " ");
931 mainApp->popStatus(WiresharkApplication::FileStatus);
932 QString msg = QStringLiteral("%1<live capture in progress>").arg(interface_names->str);
933 QString msgtip = QStringLiteral("to file: ");
934 if (capture_opts->save_file)
935 msgtip += capture_opts->save_file;
936 mainApp->pushStatus(WiresharkApplication::FileStatus, msg, msgtip);
937 g_string_free(interface_names, TRUE);
938 #endif // HAVE_LIBPCAP
941 void StratosharkMainWindow::popLiveCaptureInProgress() {
942 /* Pop the "<live capture in progress>" message off the status bar. */
943 main_ui_->statusBar->setFileName(capture_file_);
946 void StratosharkMainWindow::stopCapture() {
947 //#ifdef HAVE_AIRPCAP
948 // if (airpcap_if_active)
949 // airpcap_set_toolbar_stop_capture(airpcap_if_active);
950 //#endif
952 #ifdef HAVE_LIBPCAP
953 capture_stop(&cap_session_);
954 #endif // HAVE_LIBPCAP
958 // Keep focus rects from showing through the welcome screen. Primarily for
959 // macOS.
960 void StratosharkMainWindow::mainStackChanged(int)
962 for (int i = 0; i < main_ui_->mainStack->count(); i++) {
963 main_ui_->mainStack->widget(i)->setEnabled(i == main_ui_->mainStack->currentIndex());
967 // XXX - Copied from ui/gtk/menus.c
970 * Add the capture filename (with an absolute path) to the "Recent Files" menu.
972 // XXX - We should probably create a RecentFile class.
973 void StratosharkMainWindow::updateRecentCaptures() {
974 QAction *ra;
975 QMenu *recentMenu = main_ui_->menuOpenRecentCaptureFile;
976 QString action_cf_name;
978 if (!recentMenu) {
979 return;
981 recentMenu->clear();
983 #if 0
984 #if defined(QT_WINEXTRAS_LIB)
985 QWinJumpList recent_jl(this);
986 QWinJumpListCategory *recent_jlc = recent_jl.recent();
987 if (recent_jlc) {
988 recent_jlc->clear();
989 recent_jlc->setVisible(true);
991 #endif
992 #endif
993 #if defined(Q_OS_MAC)
994 if (!dock_menu_) {
995 dock_menu_ = new QMenu();
996 dock_menu_->setAsDockMenu();
998 dock_menu_->clear();
999 #endif
1001 /* Iterate through the actions in menuOpenRecentCaptureFile,
1002 * removing special items, a maybe duplicate entry and every item above count_max */
1003 #if defined(Q_OS_MAC)
1004 int shortcut = Qt::Key_0;
1005 #endif
1006 foreach(recent_item_status *ri, mainApp->recentItems()) {
1007 // Add the new item
1008 ra = new QAction(recentMenu);
1009 ra->setData(ri->filename);
1010 // XXX - Needs get_recent_item_status or equivalent
1011 ra->setEnabled(ri->accessible);
1012 recentMenu->insertAction(NULL, ra);
1013 action_cf_name = ra->data().toString();
1014 #if defined(Q_OS_MAC)
1015 if (shortcut <= Qt::Key_9) {
1016 ra->setShortcut(Qt::META | (Qt::Key)shortcut);
1017 shortcut++;
1019 #endif
1020 ra->setText(action_cf_name);
1021 connect(ra, &QAction::triggered, this, &StratosharkMainWindow::recentActionTriggered);
1023 /* This is slow, at least on my VM here. The added links also open Wireshark
1024 * in a new window. It might make more sense to add a recent item when we
1025 * open a capture file. */
1026 #if 0
1027 #if defined(QT_WINEXTRAS_LIB)
1028 if (recent_jlc) {
1029 QFileInfo fi(ri->filename);
1030 QWinJumpListItem *jli = recent_jlc->addLink(
1031 fi.fileName(),
1032 QApplication::applicationFilePath(),
1033 QStringList() << "-r" << ri->filename
1035 // XXX set icon
1036 jli->setWorkingDirectory(QDir::toNativeSeparators(QApplication::applicationDirPath()));
1038 #endif
1039 #endif
1040 #if defined(Q_OS_MAC)
1041 QAction *rda = new QAction(dock_menu_);
1042 QFileInfo fi(ri->filename);
1043 rda->setText(fi.fileName());
1044 dock_menu_->insertAction(NULL, rda);
1045 connect(rda, &QAction::triggered, ra, &QAction::trigger);
1046 #endif
1047 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
1048 if (recentMenu->actions().count() == static_cast<int>(prefs.gui_recent_files_count_max)) {
1049 #else
1050 if (recentMenu->actions().count() == static_cast<qsizetype>(prefs.gui_recent_files_count_max)) {
1051 #endif
1052 break;
1056 if (recentMenu->actions().count() > 0) {
1057 // Separator + "Clear"
1058 // XXX - Do we really need this?
1059 ra = new QAction(recentMenu);
1060 ra->setSeparator(true);
1061 recentMenu->insertAction(NULL, ra);
1063 ra = new QAction(recentMenu);
1064 ra->setText(tr("Clear Menu"));
1065 recentMenu->insertAction(NULL, ra);
1066 connect(ra, &QAction::triggered, mainApp, &MainApplication::clearRecentCaptures);
1067 } else {
1068 if (main_ui_->actionDummyNoFilesFound) {
1069 recentMenu->addAction(main_ui_->actionDummyNoFilesFound);
1074 void StratosharkMainWindow::recentActionTriggered() {
1075 QAction *ra = qobject_cast<QAction*>(sender());
1077 if (ra) {
1078 QString cfPath = ra->data().toString();
1079 openCaptureFile(cfPath);
1083 QString StratosharkMainWindow::commentToMenuText(QString text, int max_len)
1085 text = text.trimmed().replace(QRegularExpression("(\\r?\\n|\\r\\n?)+"), " ");
1086 if (text.size() > 0) {
1087 if (text.size() > max_len) {
1088 text.truncate(max_len);
1089 text += "…";
1092 else {
1093 text = tr("(empty comment)", "placeholder for empty comment");
1095 return text;
1098 void StratosharkMainWindow::setEditCommentsMenu()
1100 main_ui_->menuPacketComment->clear();
1101 QAction *action = main_ui_->menuPacketComment->addAction(tr("Add New Comment…"));
1102 connect(action, &QAction::triggered, this, &StratosharkMainWindow::addPacketComment);
1103 action->setShortcut(QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_C));
1104 if (selectedRows().count() == 1) {
1105 const int thisRow = selectedRows().first();
1106 frame_data * current_frame = frameDataForRow(thisRow);
1107 wtap_block_t pkt_block = cf_get_packet_block(capture_file_.capFile(), current_frame);
1108 unsigned nComments = wtap_block_count_option(pkt_block, OPT_COMMENT);
1109 if (nComments > 0) {
1110 main_ui_->menuPacketComment->addSeparator();
1111 for (unsigned i = 0; i < nComments; i++) {
1112 QString comment = packet_list_->getPacketComment(i);
1113 comment = this->commentToMenuText(comment);
1114 action = main_ui_->menuPacketComment->addAction(tr("Edit \"%1\"", "edit event comment").arg(comment));
1115 connect(action, &QAction::triggered, this, &StratosharkMainWindow::editPacketComment);
1116 action->setData(i);
1119 main_ui_->menuPacketComment->addSeparator();
1120 for (unsigned i = 0; i < nComments; i++) {
1121 QString comment = packet_list_->getPacketComment(i);
1122 comment = this->commentToMenuText(comment);
1123 action = main_ui_->menuPacketComment->addAction(tr("Delete \"%1\"", "delete event comment").arg(comment));
1124 connect(action, &QAction::triggered, this, &StratosharkMainWindow::deletePacketComment);
1125 action->setData(i);
1127 main_ui_->menuPacketComment->addSeparator();
1128 action = main_ui_->menuPacketComment->addAction(tr("Delete event comments"));
1129 connect(action, &QAction::triggered, this, &StratosharkMainWindow::deleteCommentsFromPackets);
1131 wtap_block_unref(pkt_block);
1133 if (selectedRows().count() > 1) {
1134 main_ui_->menuPacketComment->addSeparator();
1135 action = main_ui_->menuPacketComment->addAction(tr("Delete comments from %n event(s)", nullptr, static_cast<int>(selectedRows().count())));
1136 connect(action, &QAction::triggered, this, &StratosharkMainWindow::deleteCommentsFromPackets);
1140 void StratosharkMainWindow::setMenusForSelectedPacket()
1142 /* Making the menu context-sensitive allows for easier selection of the
1143 desired item and has the added benefit, with large captures, of
1144 avoiding needless looping through huge lists for marked, ignored,
1145 or time-referenced packets. */
1147 /* We have one or more items in the packet list */
1148 bool have_frames = false;
1149 /* A frame is selected */
1150 bool frame_selected = false;
1151 bool multi_selection = false;
1152 /* A visible packet comes after this one in the selection history */
1153 bool next_selection_history = false;
1154 /* A visible packet comes before this one in the selection history */
1155 bool previous_selection_history = false;
1156 /* We have marked frames. (XXX - why check frame_selected?) */
1157 bool have_marked = false;
1158 /* We have a marked frame other than the current frame (i.e.,
1159 we have at least one marked frame, and either there's more
1160 than one marked frame or the current frame isn't marked). */
1161 bool another_is_marked = false;
1162 /* One or more frames are hidden by a display filter */
1163 bool have_filtered = false;
1164 /* One or more frames have been ignored */
1165 bool have_ignored = false;
1166 bool have_time_ref = false;
1167 /* We have a time reference frame other than the current frame (i.e.,
1168 we have at least one time reference frame, and either there's more
1169 than one time reference frame or the current frame isn't a
1170 time reference frame). (XXX - why check frame_selected?) */
1171 bool another_is_time_ref = false;
1173 QList<QAction *> cc_actions = QList<QAction *>()
1174 << main_ui_->actionViewColorizeConversation1 << main_ui_->actionViewColorizeConversation2
1175 << main_ui_->actionViewColorizeConversation3 << main_ui_->actionViewColorizeConversation4
1176 << main_ui_->actionViewColorizeConversation5 << main_ui_->actionViewColorizeConversation6
1177 << main_ui_->actionViewColorizeConversation7 << main_ui_->actionViewColorizeConversation8
1178 << main_ui_->actionViewColorizeConversation9 << main_ui_->actionViewColorizeConversation10;
1180 if (capture_file_.capFile()) {
1181 QList<int> rows = selectedRows();
1182 frame_data * current_frame = 0;
1183 if (rows.count() > 0)
1184 current_frame = frameDataForRow(rows.at(0));
1186 frame_selected = rows.count() == 1;
1187 if (packet_list_->multiSelectActive())
1189 frame_selected = false;
1190 multi_selection = true;
1192 next_selection_history = packet_list_->haveNextHistory();
1193 previous_selection_history = packet_list_->havePreviousHistory();
1194 have_frames = capture_file_.capFile()->count > 0;
1195 have_marked = capture_file_.capFile()->marked_count > 0;
1196 another_is_marked = have_marked && rows.count() <= 1 &&
1197 !(capture_file_.capFile()->marked_count == 1 && frame_selected &&
1198 current_frame && current_frame->marked);
1199 have_filtered = capture_file_.capFile()->displayed_count > 0 && capture_file_.capFile()->displayed_count != capture_file_.capFile()->count;
1200 have_ignored = capture_file_.capFile()->ignored_count > 0;
1201 have_time_ref = capture_file_.capFile()->ref_time_count > 0;
1202 another_is_time_ref = have_time_ref && rows.count() <= 1 &&
1203 !(capture_file_.capFile()->ref_time_count == 1 && frame_selected &&
1204 current_frame && current_frame->ref_time);
1206 if (capture_file_.capFile()->edt && ! multi_selection && frame_selected)
1208 foreach (FollowStreamAction *follow_action, main_ui_->menuFollow->findChildren<FollowStreamAction *>()) {
1209 bool is_frame = proto_is_frame_protocol(capture_file_.capFile()->edt->pi.layers, follow_action->filterName());
1210 follow_action->setEnabled(is_frame);
1212 } else {
1213 foreach (FollowStreamAction *follow_action, main_ui_->menuFollow->findChildren<FollowStreamAction *>()) {
1214 follow_action->setEnabled(false);
1219 main_ui_->actionCopyListAsText->setEnabled(selectedRows().count() > 0);
1220 main_ui_->actionCopyListAsCSV->setEnabled(selectedRows().count() > 0);
1221 main_ui_->actionCopyListAsYAML->setEnabled(selectedRows().count() > 0);
1223 main_ui_->actionEditMarkSelected->setEnabled(frame_selected || multi_selection);
1224 main_ui_->actionEditMarkAllDisplayed->setEnabled(have_frames);
1225 /* Unlike un-ignore, do not allow unmark of all frames when no frames are displayed */
1226 main_ui_->actionEditUnmarkAllDisplayed->setEnabled(have_marked);
1227 main_ui_->actionEditNextMark->setEnabled(another_is_marked);
1228 main_ui_->actionEditPreviousMark->setEnabled(another_is_marked);
1230 GArray * linkTypes = Q_NULLPTR;
1231 if (capture_file_.capFile() && capture_file_.capFile()->linktypes)
1232 linkTypes = capture_file_.capFile()->linktypes;
1234 bool enableEditComments = linkTypes && wtap_dump_can_write(capture_file_.capFile()->linktypes, WTAP_COMMENT_PER_PACKET);
1235 main_ui_->menuPacketComment->setEnabled(enableEditComments && selectedRows().count() > 0);
1236 main_ui_->actionDeleteAllPacketComments->setEnabled(enableEditComments);
1238 main_ui_->actionEditIgnoreSelected->setEnabled(frame_selected || multi_selection);
1239 main_ui_->actionEditIgnoreAllDisplayed->setEnabled(have_filtered);
1240 /* Allow un-ignore of all frames even with no frames currently displayed */
1241 main_ui_->actionEditUnignoreAllDisplayed->setEnabled(have_ignored);
1243 main_ui_->actionEditSetTimeReference->setEnabled(frame_selected);
1244 main_ui_->actionEditUnsetAllTimeReferences->setEnabled(have_time_ref);
1245 main_ui_->actionEditNextTimeReference->setEnabled(another_is_time_ref);
1246 main_ui_->actionEditPreviousTimeReference->setEnabled(another_is_time_ref);
1247 main_ui_->actionEditTimeShift->setEnabled(have_frames);
1249 main_ui_->actionGoGoToLinkedPacket->setEnabled(false);
1250 main_ui_->actionGoNextHistoryPacket->setEnabled(next_selection_history);
1251 main_ui_->actionGoPreviousHistoryPacket->setEnabled(previous_selection_history);
1253 foreach(QAction *cc_action, cc_actions) {
1254 cc_action->setEnabled(frame_selected);
1256 main_ui_->actionViewColorizeNewColoringRule->setEnabled(frame_selected);
1258 main_ui_->actionViewColorizeResetColorization->setEnabled(tmp_color_filters_used());
1260 main_ui_->actionViewShowPacketInNewWindow->setEnabled(frame_selected);
1261 // main_ui_->actionViewEditResolvedName->setEnabled(frame_selected && is_ip);
1263 emit packetInfoChanged(capture_file_.packetInfo());
1265 // set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/ViewMenu/NameResolution/ResolveName",
1266 // frame_selected && (gbl_resolv_flags.mac_name || gbl_resolv_flags.network_name ||
1267 // gbl_resolv_flags.transport_name));
1270 void StratosharkMainWindow::setMenusForSelectedTreeRow(FieldInformation *finfo) {
1272 bool can_match_selected = false;
1273 bool is_framenum = false;
1274 bool have_subtree = false;
1275 bool can_open_url = false;
1276 bool have_packet_bytes = false;
1277 QByteArray field_filter;
1278 int field_id = -1;
1280 field_info * fi = 0;
1281 if (finfo)
1282 fi = finfo->fieldInfo();
1284 if (capture_file_.capFile()) {
1285 capture_file_.capFile()->finfo_selected = fi;
1287 if (fi && fi->tree_type != -1) {
1288 have_subtree = true;
1291 if (fi && fi->ds_tvb && (fi->length > 0)) {
1292 have_packet_bytes = true;
1295 if (!(capture_file_.capFile()->search_in_progress && (capture_file_.capFile()->hex || (capture_file_.capFile()->string && capture_file_.capFile()->packet_data)))) {
1296 // If we're not in the middle of a packet bytes search, then set
1297 // search_pos and search_len so that we can start a new search
1298 // from this point. (If we are, then we already set it.)
1299 if (fi && capture_file_.capFile()->edt && (fi->ds_tvb == capture_file_.capFile()->edt->tvb)) {
1300 // We can only do a Packet Bytes search in the main bytes from
1301 // the frame, not from any secondary data sources. (XXX: This
1302 // might be surprising to users, though.)
1303 capture_file_.capFile()->search_pos = (uint32_t)(finfo->position().start + finfo->position().length - 1);
1304 capture_file_.capFile()->search_len = (uint32_t)finfo->position().length;
1305 } else {
1306 capture_file_.capFile()->search_pos = 0;
1307 capture_file_.capFile()->search_len = 0;
1312 if (capture_file_.capFile() != NULL && fi != NULL) {
1313 const header_field_info *hfinfo = fi->hfinfo;
1314 int linked_frame = -1;
1316 can_match_selected = proto_can_match_selected(capture_file_.capFile()->finfo_selected, capture_file_.capFile()->edt);
1317 if (hfinfo && hfinfo->type == FT_FRAMENUM) {
1318 is_framenum = true;
1319 linked_frame = fvalue_get_uinteger(fi->value);
1322 char *tmp_field = proto_construct_match_selected_string(fi, capture_file_.capFile()->edt);
1323 field_filter = tmp_field;
1324 wmem_free(NULL, tmp_field);
1325 emit fieldFilterChanged(field_filter);
1327 field_id = fi->hfinfo->id;
1328 /* if the selected field isn't a protocol, get its parent */
1329 if (!proto_registrar_is_protocol(field_id)) {
1330 field_id = proto_registrar_get_parent(fi->hfinfo->id);
1333 if (field_id >= 0) {
1334 can_open_url = true;
1335 main_ui_->actionContextWikiProtocolPage->setData(field_id);
1336 main_ui_->actionContextFilterFieldReference->setData(field_id);
1337 } else {
1338 main_ui_->actionContextWikiProtocolPage->setData(QVariant());
1339 main_ui_->actionContextFilterFieldReference->setData(QVariant());
1342 if (linked_frame > 0) {
1343 main_ui_->actionGoGoToLinkedPacket->setData(linked_frame);
1344 } else {
1345 main_ui_->actionGoGoToLinkedPacket->setData(QVariant());
1349 // Always enable / disable the following items.
1350 main_ui_->actionCopyAllVisibleItems->setEnabled(capture_file_.capFile() != NULL && ! packet_list_->multiSelectActive());
1351 main_ui_->actionCopyAllVisibleSelectedTreeItems->setEnabled(can_match_selected);
1352 main_ui_->actionEditCopyDescription->setEnabled(can_match_selected);
1353 main_ui_->actionEditCopyFieldName->setEnabled(can_match_selected);
1354 main_ui_->actionEditCopyValue->setEnabled(can_match_selected);
1355 main_ui_->actionEditCopyAsFilter->setEnabled(can_match_selected);
1357 main_ui_->actionAnalyzeShowPacketBytes->setEnabled(have_packet_bytes);
1359 main_ui_->actionViewExpandSubtrees->setEnabled(have_subtree);
1360 main_ui_->actionViewCollapseSubtrees->setEnabled(have_subtree);
1362 main_ui_->actionGoGoToLinkedPacket->setEnabled(is_framenum);
1364 main_ui_->actionAnalyzeApplyAsColumn->setEnabled(can_match_selected);
1366 main_ui_->actionContextShowLinkedPacketInNewWindow->setEnabled(is_framenum);
1368 main_ui_->actionContextWikiProtocolPage->setEnabled(can_open_url);
1369 main_ui_->actionContextFilterFieldReference->setEnabled(can_open_url);
1372 // Only enable / disable the following items if we have focus so that we
1373 // don't clobber anything we may have set in setMenusForSelectedPacket.
1374 if (!proto_tree_ || !proto_tree_->hasFocus()) return;
1376 emit packetInfoChanged(capture_file_.packetInfo());
1378 // set_menu_sensitivity(ui_manager_tree_view_menu, "/TreeViewPopup/ResolveName",
1379 // frame_selected && (gbl_resolv_flags.mac_name || gbl_resolv_flags.network_name ||
1380 // gbl_resolv_flags.transport_name));
1384 void StratosharkMainWindow::interfaceSelectionChanged()
1386 #ifdef HAVE_LIBPCAP
1387 // XXX This doesn't disable the toolbar button when using
1388 // QtMacExtras.
1389 if (global_capture_opts.num_selected > 0 && capture_filter_valid_) {
1390 main_ui_->actionCaptureStart->setEnabled(true);
1391 } else {
1392 main_ui_->actionCaptureStart->setEnabled(false);
1394 #endif // HAVE_LIBPCAP
1397 void StratosharkMainWindow::captureFilterSyntaxChanged(bool valid)
1399 capture_filter_valid_ = valid;
1400 interfaceSelectionChanged();
1403 void StratosharkMainWindow::startInterfaceCapture(bool valid, const QString capture_filter)
1405 capture_filter_valid_ = valid;
1406 welcome_page_->setCaptureFilter(capture_filter);
1407 QString before_what(tr(" before starting a new capture"));
1408 if (testCaptureFileClose(before_what)) {
1409 // The interface tree will update the selected interfaces via its timer
1410 // so no need to do anything here.
1411 startCapture();
1415 void StratosharkMainWindow::applyGlobalCommandLineOptions()
1417 if (global_dissect_options.time_format != TS_NOT_SET) {
1418 foreach(QAction* tda, td_actions.keys()) {
1419 if (global_dissect_options.time_format == td_actions[tda]) {
1420 tda->setChecked(true);
1421 // XXX - this means that if the user sets the
1422 // time stamp format with the -t flag, that
1423 // setting will persist and will be used as
1424 // the default the next time Stratoshark is run.
1425 recent.gui_time_format = global_dissect_options.time_format;
1426 timestamp_set_type(global_dissect_options.time_format);
1427 break;
1431 if (global_dissect_options.time_precision != TS_PREC_NOT_SET) {
1432 foreach(QAction* tpa, tp_actions.keys()) {
1433 if (global_dissect_options.time_precision == tp_actions[tpa]) {
1434 tpa->setChecked(true);
1435 // XXX - this means that if the user sets the
1436 // time stamp precision with the -t flag, that
1437 // setting will persist and will be used as
1438 // the default the next time Stratoshark is run.
1439 recent.gui_time_precision = global_dissect_options.time_precision;
1440 timestamp_set_precision(global_dissect_options.time_precision);
1441 break;
1445 if (global_commandline_info.full_screen) {
1446 this->showFullScreen();
1450 void StratosharkMainWindow::redissectPackets()
1452 if (capture_file_.capFile()) {
1453 cf_redissect_packets(capture_file_.capFile());
1454 main_ui_->statusBar->expertUpdate();
1457 proto_free_deregistered_fields();
1460 void StratosharkMainWindow::checkDisplayFilter()
1462 if (!df_combo_box_->checkDisplayFilter()) {
1463 g_free(CaptureFile::globalCapFile()->dfilter);
1464 CaptureFile::globalCapFile()->dfilter = NULL;
1468 void StratosharkMainWindow::fieldsChanged()
1470 char *err_msg = NULL;
1471 if (!color_filters_reload(&err_msg, color_filter_add_cb)) {
1472 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_msg);
1473 g_free(err_msg);
1475 tap_listeners_dfilter_recompile();
1477 emit checkDisplayFilter();
1479 if (have_custom_cols(&CaptureFile::globalCapFile()->cinfo)) {
1480 // Recreate packet list columns according to new/changed/deleted fields
1481 packet_list_->fieldsChanged(CaptureFile::globalCapFile());
1484 emit reloadFields();
1487 void StratosharkMainWindow::reloadLuaPlugins()
1489 #ifdef HAVE_LUA
1490 if (mainApp->isReloadingLua())
1491 return;
1493 bool uses_lua_filehandler = false;
1495 if (capture_file_.capFile()) {
1496 // Check if the current capture file is opened with a Lua FileHandler
1497 capture_file *cf = capture_file_.capFile();
1498 uses_lua_filehandler = wtap_uses_lua_filehandler(cf->provider.wth);
1500 if (uses_lua_filehandler && cf->unsaved_changes) {
1501 // Prompt to save the file before reloading, in case the FileHandler has changed
1502 QString before_what(tr(" before reloading Lua plugins"));
1503 if (!testCaptureFileClose(before_what, Reload)) {
1504 return;
1509 mainApp->setReloadingLua(true);
1511 wslua_reload_plugins(NULL, NULL);
1512 funnel_statistics_reload_menus();
1513 reloadDynamicMenus();
1514 closePacketDialogs();
1516 // Preferences may have been deleted so close all widgets using prefs
1517 main_ui_->preferenceEditorFrame->animatedHide();
1519 mainApp->readConfigurationFiles(true);
1520 commandline_options_reapply();
1522 fieldsChanged();
1523 prefs_apply_all();
1525 if (uses_lua_filehandler) {
1526 // Reload the file in case the FileHandler has changed
1527 if (cf_reload(capture_file_.capFile()) != CF_OK) {
1528 cf_close(capture_file_.capFile());
1530 proto_free_deregistered_fields();
1531 } else {
1532 redissectPackets();
1535 mainApp->setReloadingLua(false);
1536 SimpleDialog::displayQueuedMessages();
1537 #endif
1540 void StratosharkMainWindow::showAccordionFrame(AccordionFrame *show_frame, bool toggle)
1542 QList<AccordionFrame *>frame_list = QList<AccordionFrame *>()
1543 << main_ui_->goToFrame << main_ui_->searchFrame
1544 << main_ui_->addressEditorFrame << main_ui_->columnEditorFrame
1545 << main_ui_->preferenceEditorFrame << main_ui_->filterExpressionFrame;
1547 frame_list.removeAll(show_frame);
1548 foreach(AccordionFrame *af, frame_list) af->animatedHide();
1550 if (toggle) {
1551 if (show_frame->isVisible()) {
1552 show_frame->animatedHide();
1553 return;
1556 show_frame->animatedShow();
1559 void StratosharkMainWindow::showColumnEditor(int column)
1561 setPreviousFocus();
1562 main_ui_->columnEditorFrame->editColumn(column);
1563 showAccordionFrame(main_ui_->columnEditorFrame);
1566 void StratosharkMainWindow::showPreferenceEditor()
1568 showAccordionFrame(main_ui_->preferenceEditorFrame);
1571 void StratosharkMainWindow::initViewColorizeMenu()
1573 QList<QAction *> cc_actions = QList<QAction *>()
1574 << main_ui_->actionViewColorizeConversation1 << main_ui_->actionViewColorizeConversation2
1575 << main_ui_->actionViewColorizeConversation3 << main_ui_->actionViewColorizeConversation4
1576 << main_ui_->actionViewColorizeConversation5 << main_ui_->actionViewColorizeConversation6
1577 << main_ui_->actionViewColorizeConversation7 << main_ui_->actionViewColorizeConversation8
1578 << main_ui_->actionViewColorizeConversation9 << main_ui_->actionViewColorizeConversation10;
1580 uint8_t color_num = 1;
1582 foreach(QAction *cc_action, cc_actions) {
1583 cc_action->setData(color_num);
1584 connect(cc_action, &QAction::triggered, this, &StratosharkMainWindow::colorizeConversation);
1586 const color_filter_t *colorf = color_filters_tmp_color(color_num);
1587 if (colorf) {
1588 QColor bg = ColorUtils::fromColorT(colorf->bg_color);
1589 QColor fg = ColorUtils::fromColorT(colorf->fg_color);
1590 cc_action->setIcon(StockIcon::colorIcon(bg.rgb(), fg.rgb(), QString::number(color_num)));
1592 color_num++;
1595 #ifdef Q_OS_MAC
1596 // Spotlight uses Cmd+Space
1597 main_ui_->actionViewColorizeResetColorization->setShortcut(QKeySequence("Meta+Space"));
1598 #endif
1601 void StratosharkMainWindow::addStatsPluginsToMenu() {
1602 GList *cfg_list = stats_tree_get_cfg_list();
1603 QAction *stats_tree_action;
1604 QMenu *parent_menu;
1605 bool first_item = true;
1607 for (GList *iter = g_list_first(cfg_list); iter; iter = gxx_list_next(iter)) {
1608 stats_tree_cfg *cfg = gxx_list_data(stats_tree_cfg *, iter);
1609 if (!menu_groups_.contains(cfg->stat_group)) {
1610 continue;
1612 if (cfg->plugin) {
1613 if (first_item) {
1614 main_ui_->menuStatistics->addSeparator();
1615 first_item = false;
1618 parent_menu = main_ui_->menuStatistics;
1619 // gtk/main_menubar.c compresses double slashes, hence SkipEmptyParts
1620 QStringList cfg_name_parts = QString(cfg->path).split(STATS_TREE_MENU_SEPARATOR, Qt::SkipEmptyParts);
1621 if (cfg_name_parts.isEmpty()) continue;
1623 QString stat_name = cfg_name_parts.takeLast().trimmed();
1624 if (!cfg_name_parts.isEmpty()) {
1625 parent_menu = findOrAddMenu(parent_menu, cfg_name_parts);
1628 stats_tree_action = new QAction(stat_name, this);
1629 stats_tree_action->setData(QString::fromUtf8(cfg->abbr));
1630 parent_menu->addAction(stats_tree_action);
1631 connect(stats_tree_action, &QAction::triggered, this, [this]() {
1632 QAction* action = qobject_cast<QAction*>(sender());
1633 if (action) {
1634 openStatisticsTreeDialog(action->data().toString().toUtf8());
1639 g_list_free(cfg_list);
1642 void StratosharkMainWindow::setFeaturesEnabled(bool enabled)
1644 main_ui_->menuBar->setEnabled(enabled);
1645 main_ui_->mainToolBar->setEnabled(enabled);
1646 main_ui_->displayFilterToolBar->setEnabled(enabled);
1647 if (enabled)
1649 main_ui_->statusBar->clearMessage();
1650 #ifdef HAVE_LIBPCAP
1651 main_ui_->actionGoAutoScroll->setChecked(recent.capture_auto_scroll);
1652 #endif
1654 else
1656 main_ui_->statusBar->showMessage(tr("Please wait while Stratoshark is initializing…"));
1660 // Display Filter Toolbar
1662 void StratosharkMainWindow::on_actionNewDisplayFilterExpression_triggered()
1664 main_ui_->filterExpressionFrame->addExpression(df_combo_box_->lineEdit()->text());
1667 void StratosharkMainWindow::onFilterSelected(QString filterText, bool prepare)
1669 if (filterText.length() <= 0)
1670 return;
1672 df_combo_box_->setDisplayFilter(filterText);
1673 // Holding down the Shift key will only prepare filter.
1674 if (!prepare)
1675 df_combo_box_->applyDisplayFilter();
1678 void StratosharkMainWindow::onFilterPreferences()
1680 emit showPreferencesDialog(PrefsModel::typeToString(PrefsModel::FilterButtons));
1683 void StratosharkMainWindow::onFilterEdit(int uatIndex)
1685 main_ui_->filterExpressionFrame->editExpression(uatIndex);
1688 void StratosharkMainWindow::openStatCommandDialog(const QString &menu_path, const char *arg, void *userdata)
1690 QString slot = QStringLiteral("statCommand%1").arg(menu_path);
1691 QMetaObject::invokeMethod(this, slot.toLatin1().constData(), Q_ARG(const char *, arg), Q_ARG(void *, userdata));
1694 void StratosharkMainWindow::openTapParameterDialog(const QString cfg_str, const QString arg, void *userdata)
1696 TapParameterDialog *tp_dialog = TapParameterDialog::showTapParameterStatistics(*this, capture_file_, cfg_str, arg, userdata);
1697 if (!tp_dialog) return;
1699 connect(tp_dialog, &TapParameterDialog::filterAction, this, &StratosharkMainWindow::filterAction);
1700 connect(tp_dialog, &TapParameterDialog::updateFilter, df_combo_box_->lineEdit(), &QLineEdit::setText);
1701 tp_dialog->show();
1704 void StratosharkMainWindow::openTapParameterDialog()
1706 QAction *tpa = qobject_cast<QAction *>(QObject::sender());
1707 if (!tpa) return;
1709 const QString cfg_str = tpa->data().toString();
1710 openTapParameterDialog(cfg_str, NULL, NULL);
1713 #if defined(HAVE_SOFTWARE_UPDATE) && defined(Q_OS_WIN)
1714 void StratosharkMainWindow::softwareUpdateRequested() {
1715 // testCaptureFileClose doesn't use this string because we aren't
1716 // going to launch another dialog, but maybe we'll change that.
1717 QString before_what(tr(" before updating"));
1718 if (!testCaptureFileClose(before_what, Update)) {
1719 mainApp->rejectSoftwareUpdate();
1722 #endif
1724 // File Menu
1726 void StratosharkMainWindow::connectFileMenuActions()
1728 connect(main_ui_->actionFileOpen, &QAction::triggered, this,
1729 [this]() { openCaptureFile(); });
1731 connect(main_ui_->actionFileMerge, &QAction::triggered, this,
1732 [this]() { mergeCaptureFile(); });
1734 connect(main_ui_->actionFileImportFromHexDump, &QAction::triggered, this,
1735 [this]() { importCaptureFile(); });
1737 connect(main_ui_->actionFileClose, &QAction::triggered, this, [this]() {
1738 QString before_what(tr(" before closing the file"));
1739 if (testCaptureFileClose(before_what)) {
1740 showWelcome();
1744 connect(main_ui_->actionFileSave, &QAction::triggered, this,
1745 [this]() { saveCaptureFile(capture_file_.capFile(), false); });
1747 connect(main_ui_->actionFileSaveAs, &QAction::triggered, this,
1748 [this]() { saveAsCaptureFile(capture_file_.capFile()); });
1750 connect(main_ui_->actionFileSetListFiles, &QAction::triggered, this,
1751 [this]() { file_set_dialog_->show(); });
1753 connect(main_ui_->actionFileSetNextFile, &QAction::triggered, this, [this]() {
1754 fileset_entry *entry = fileset_get_next();
1756 if (entry) {
1757 QString new_cf_path = entry->fullname;
1758 openCaptureFile(new_cf_path);
1762 connect(main_ui_->actionFileSetPreviousFile, &QAction::triggered, this, [this]() {
1763 fileset_entry *entry = fileset_get_previous();
1765 if (entry) {
1766 QString new_cf_path = entry->fullname;
1767 openCaptureFile(new_cf_path);
1771 connect(main_ui_->actionFileExportPackets, &QAction::triggered, this,
1772 [this]() { exportSelectedPackets(); });
1774 connect(main_ui_->actionFileExportAsPlainText, &QAction::triggered, this,
1775 [this]() { exportDissections(export_type_text); });
1777 connect(main_ui_->actionFileExportAsCSV, &QAction::triggered, this,
1778 [this]() { exportDissections(export_type_csv); });
1780 connect(main_ui_->actionFileExportAsCArrays, &QAction::triggered, this,
1781 [this]() { exportDissections(export_type_carrays); });
1783 connect(main_ui_->actionFileExportAsPSML, &QAction::triggered, this,
1784 [this]() { exportDissections(export_type_psml); });
1786 connect(main_ui_->actionFileExportAsPDML, &QAction::triggered, this,
1787 [this]() { exportDissections(export_type_pdml); });
1789 connect(main_ui_->actionFileExportAsJSON, &QAction::triggered, this,
1790 [this]() { exportDissections(export_type_json); });
1792 connect(main_ui_->actionFilePrint, &QAction::triggered, this,
1793 [this]() { printFile(); });
1796 void StratosharkMainWindow::printFile()
1798 capture_file *cf = capture_file_.capFile();
1799 g_return_if_fail(cf);
1801 QList<int> rows = packet_list_->selectedRows(true);
1803 QStringList entries;
1804 foreach (int row, rows)
1805 entries << QString::number(row);
1806 QString selRange = entries.join(",");
1808 PrintDialog * pdlg_ = new PrintDialog(this, cf, selRange);
1809 pdlg_->setWindowModality(Qt::ApplicationModal);
1810 pdlg_->show();
1813 // Edit Menu
1815 void StratosharkMainWindow::connectEditMenuActions()
1817 connect(main_ui_->actionCopyAllVisibleItems, &QAction::triggered, this,
1818 [this]() { copySelectedItems(CopyAllVisibleItems); });
1820 connect(main_ui_->actionCopyListAsText, &QAction::triggered, this,
1821 [this]() { copySelectedItems(CopyListAsText); });
1823 connect(main_ui_->actionCopyListAsCSV, &QAction::triggered, this,
1824 [this]() { copySelectedItems(CopyListAsCSV); });
1826 connect(main_ui_->actionCopyListAsYAML, &QAction::triggered, this,
1827 [this]() { copySelectedItems(CopyListAsYAML); });
1829 connect(main_ui_->actionCopyListAsHTML, &QAction::triggered, this,
1830 [this]() { copySelectedItems(CopyListAsHTML); });
1832 connect(main_ui_->actionCopyAllVisibleSelectedTreeItems, &QAction::triggered, this,
1833 [this]() { copySelectedItems(CopyAllVisibleSelectedTreeItems); });
1835 connect(main_ui_->actionEditCopyDescription, &QAction::triggered, this,
1836 [this]() { copySelectedItems(CopySelectedDescription); });
1838 connect(main_ui_->actionEditCopyFieldName, &QAction::triggered, this,
1839 [this]() { copySelectedItems(CopySelectedFieldName); });
1841 connect(main_ui_->actionEditCopyValue, &QAction::triggered, this,
1842 [this]() { copySelectedItems(CopySelectedValue); });
1844 connect(main_ui_->actionEditCopyAsFilter, &QAction::triggered, this,
1845 [this]() { matchFieldFilter(FilterAction::ActionCopy, FilterAction::ActionTypePlain); });
1847 connect(main_ui_->actionEditFindPacket, &QAction::triggered, this,
1848 [this]() { findPacket(); });
1850 connect(main_ui_->actionEditFindNext, &QAction::triggered, this,
1851 [this]() { main_ui_->searchFrame->findNext(); });
1853 connect(main_ui_->actionEditFindPrevious, &QAction::triggered, this,
1854 [this]() { main_ui_->searchFrame->findPrevious(); });
1856 // The items below are used in the packet list and detail context menus.
1857 // Use QueuedConnections so that the context menus aren't destroyed
1858 // prematurely.
1859 connect(main_ui_->actionEditMarkSelected, &QAction::triggered, this, [this]() {
1860 freeze();
1861 packet_list_->markFrame();
1862 thaw();
1863 setMenusForSelectedPacket();
1864 }, Qt::QueuedConnection);
1866 connect(main_ui_->actionEditMarkAllDisplayed, &QAction::triggered, this, [this]() {
1867 freeze();
1868 packet_list_->markAllDisplayedFrames(true);
1869 thaw();
1870 setMenusForSelectedPacket();
1871 }, Qt::QueuedConnection);
1873 connect(main_ui_->actionEditUnmarkAllDisplayed, &QAction::triggered, this, [this]() {
1874 freeze();
1875 packet_list_->markAllDisplayedFrames(false);
1876 thaw();
1877 setMenusForSelectedPacket();
1878 }, Qt::QueuedConnection);
1880 connect(main_ui_->actionEditNextMark, &QAction::triggered, this, [this]() {
1881 if (capture_file_.capFile()) {
1882 cf_find_packet_marked(capture_file_.capFile(), SD_FORWARD);
1884 }, Qt::QueuedConnection);
1886 connect(main_ui_->actionEditPreviousMark, &QAction::triggered, this, [this]() {
1887 if (capture_file_.capFile()) {
1888 cf_find_packet_marked(capture_file_.capFile(), SD_BACKWARD);
1890 }, Qt::QueuedConnection);
1892 connect(main_ui_->actionEditIgnoreSelected, &QAction::triggered, this, [this]() {
1893 freeze();
1894 packet_list_->ignoreFrame();
1895 thaw();
1896 setMenusForSelectedPacket();
1897 }, Qt::QueuedConnection);
1899 connect(main_ui_->actionEditIgnoreAllDisplayed, &QAction::triggered, this, [this]() {
1900 freeze();
1901 packet_list_->ignoreAllDisplayedFrames(true);
1902 thaw();
1903 setMenusForSelectedPacket();
1904 }, Qt::QueuedConnection);
1906 connect(main_ui_->actionEditUnignoreAllDisplayed, &QAction::triggered, this, [this]() {
1907 freeze();
1908 packet_list_->ignoreAllDisplayedFrames(false);
1909 thaw();
1910 setMenusForSelectedPacket();
1911 }, Qt::QueuedConnection);
1913 connect(main_ui_->actionEditSetTimeReference, &QAction::triggered, this, [this]() {
1914 packet_list_->setTimeReference();
1915 setMenusForSelectedPacket();
1916 }, Qt::QueuedConnection);
1918 connect(main_ui_->actionEditUnsetAllTimeReferences, &QAction::triggered, this, [this]() {
1919 packet_list_->unsetAllTimeReferences();
1920 setMenusForSelectedPacket();
1921 }, Qt::QueuedConnection);
1923 connect(main_ui_->actionEditNextTimeReference, &QAction::triggered, this, [this]() {
1924 if (!capture_file_.capFile()) return;
1925 cf_find_packet_time_reference(capture_file_.capFile(), SD_FORWARD);
1926 }, Qt::QueuedConnection);
1928 connect(main_ui_->actionEditPreviousTimeReference, &QAction::triggered, this, [this]() {
1929 if (!capture_file_.capFile()) return;
1930 cf_find_packet_time_reference(capture_file_.capFile(), SD_BACKWARD);
1931 }, Qt::QueuedConnection);
1933 connect(main_ui_->actionEditTimeShift, &QAction::triggered, this,
1934 [this]() { editTimeShift(); }, Qt::QueuedConnection);
1936 connect(main_ui_->actionDeleteAllPacketComments, &QAction::triggered, this,
1937 [this]() { deleteAllPacketComments(); }, Qt::QueuedConnection);
1939 connect(main_ui_->actionEditConfigurationProfiles, &QAction::triggered, this,
1940 [this]() { editConfigurationProfiles(); }, Qt::QueuedConnection);
1942 connect(main_ui_->actionEditPreferences, &QAction::triggered, this,
1943 [this]() { showPreferencesDialog(PrefsModel::typeToString(PrefsModel::Appearance)); }, Qt::QueuedConnection);
1946 // XXX This should probably be somewhere else.
1947 void StratosharkMainWindow::copySelectedItems(StratosharkMainWindow::CopySelected selection_type)
1949 char label_str[ITEM_LABEL_LENGTH];
1950 QString clip;
1952 if (!capture_file_.capFile()) return;
1954 field_info *finfo_selected = capture_file_.capFile()->finfo_selected;
1956 switch (selection_type) {
1957 case CopySelectedDescription:
1958 if (proto_tree_->selectionModel()->hasSelection()) {
1959 QModelIndex idx = proto_tree_->selectionModel()->selectedIndexes().first();
1960 clip = idx.data(Qt::DisplayRole).toString();
1962 break;
1963 case CopySelectedFieldName:
1964 if (finfo_selected && finfo_selected->hfinfo->abbrev != 0) {
1965 clip.append(finfo_selected->hfinfo->abbrev);
1967 break;
1968 case CopySelectedValue:
1969 if (finfo_selected && capture_file_.capFile()->edt != 0) {
1970 char* field_str = get_node_field_value(finfo_selected, capture_file_.capFile()->edt);
1971 clip.append(field_str[0] ? field_str : "(null)");
1972 g_free(field_str);
1974 break;
1975 case CopyAllVisibleItems:
1976 clip = proto_tree_->toString();
1977 break;
1978 case CopyAllVisibleSelectedTreeItems:
1979 if (proto_tree_->selectionModel()->hasSelection()) {
1980 clip = proto_tree_->toString(proto_tree_->selectionModel()->selectedIndexes().first());
1982 break;
1983 case CopyListAsText:
1984 case CopyListAsCSV:
1985 case CopyListAsYAML:
1986 case CopyListAsHTML:
1988 if (packet_list_->selectedRows().count() > 0)
1990 QList<int> rows = packet_list_->selectedRows();
1991 QStringList content, htmlContent;
1993 PacketList::SummaryCopyType copyType = PacketList::CopyAsText;
1994 if (selection_type == CopyListAsCSV)
1995 copyType = PacketList::CopyAsCSV;
1996 else if (selection_type == CopyListAsYAML)
1997 copyType = PacketList::CopyAsYAML;
1998 else if (selection_type == CopyListAsHTML)
1999 copyType = PacketList::CopyAsHTML;
2001 QStringList hdr_parts;
2002 QList<int> align_parts, size_parts;
2004 if (copyType == PacketList::CopyAsText || copyType == PacketList::CopyAsHTML) {
2005 if (prefs.gui_packet_list_copy_text_with_aligned_columns) {
2006 hdr_parts = packet_list_->createHeaderPartsForAligned();
2007 align_parts = packet_list_->createAlignmentPartsForAligned();
2008 size_parts = packet_list_->createSizePartsForAligned(true, hdr_parts, rows);
2009 content << packet_list_->createHeaderSummaryForAligned(hdr_parts, align_parts, size_parts);
2011 else {
2012 content << packet_list_->createHeaderSummaryText(PacketList::CopyAsText);
2014 if (copyType == PacketList::CopyAsHTML) {
2015 htmlContent << packet_list_->createDefaultStyleForHtml();
2016 htmlContent << packet_list_->createOpeningTagForHtml();
2017 htmlContent << packet_list_->createHeaderSummaryForHtml();
2020 else if (copyType == PacketList::CopyAsCSV) {
2021 content << packet_list_->createHeaderSummaryText(copyType);
2024 foreach (int row, rows)
2026 QModelIndex idx = packet_list_->model()->index(row, 0);
2027 if (! idx.isValid())
2028 continue;
2030 if (copyType == PacketList::CopyAsText || copyType == PacketList::CopyAsHTML) {
2031 if (prefs.gui_packet_list_copy_text_with_aligned_columns)
2032 content << packet_list_->createSummaryForAligned(idx, align_parts, size_parts);
2033 else
2034 content << packet_list_->createSummaryText(idx, PacketList::CopyAsText);
2035 if (copyType == PacketList::CopyAsHTML)
2036 htmlContent << packet_list_->createSummaryForHtml(idx);
2038 else {
2039 content << packet_list_->createSummaryText(idx, copyType);
2043 if (selection_type == CopyListAsHTML) {
2044 // htmlContent will never be empty as they will always have style and table tags
2045 QMimeData *mimeData = new QMimeData;
2046 htmlContent << packet_list_->createClosingTagForHtml();
2047 mimeData->setHtml(htmlContent.join('\n'));
2048 mimeData->setText(content.join('\n').append("\n"));
2049 mainApp->clipboard()->setMimeData(mimeData, QClipboard::Clipboard);
2051 else {
2052 if (content.count() > 0) {
2054 // Each YAML item ends with a newline, hence it is not
2055 // joined with a newline else a blank line is created
2056 // before start of entry (or ---) from second packet
2057 // when multiple packets are copied.
2059 // Each YAML item ends with a newline, so the string
2060 // ends with a newline already if it's CopyListAsYAML.
2061 // If we add a newline, there'd be an extra blank
2062 // line.
2064 // Otherwise, we've used newlines as separators, not
2065 // terminators, so there's no final newline. Add it.
2067 if (selection_type == CopyListAsYAML) {
2068 clip = content.join("");
2070 else {
2071 clip = content.join("\n");
2072 clip += "\n";
2078 break;
2081 if (selection_type != CopyListAsHTML)
2083 if (clip.length() == 0) {
2084 /* If no representation then... Try to read the value */
2085 proto_item_fill_label(capture_file_.capFile()->finfo_selected, label_str, NULL);
2086 clip.append(label_str);
2089 if (clip.length()) {
2090 mainApp->clipboard()->setText(clip);
2091 } else {
2092 QString err = tr("Couldn't copy text. Try another item.");
2093 mainApp->pushStatus(WiresharkApplication::TemporaryStatus, err);
2098 void StratosharkMainWindow::findPacket()
2100 if (! packet_list_->model() || packet_list_->model()->rowCount() < 1) {
2101 return;
2103 setPreviousFocus();
2104 if (!main_ui_->searchFrame->isVisible()) {
2105 showAccordionFrame(main_ui_->searchFrame, true);
2106 } else {
2107 main_ui_->searchFrame->animatedHide();
2109 main_ui_->searchFrame->setFocus();
2112 void StratosharkMainWindow::editTimeShift()
2114 TimeShiftDialog *ts_dialog = new TimeShiftDialog(this, capture_file_.capFile());
2115 connect(ts_dialog, &TimeShiftDialog::finished, this, &StratosharkMainWindow::editTimeShiftFinished);
2117 connect(this, &StratosharkMainWindow::setCaptureFile, ts_dialog, &TimeShiftDialog::setCaptureFile);
2118 connect(ts_dialog, &TimeShiftDialog::timeShifted, packet_list_, &PacketList::applyTimeShift, Qt::QueuedConnection);
2120 ts_dialog->setWindowModality(Qt::ApplicationModal);
2121 ts_dialog->setAttribute(Qt::WA_DeleteOnClose);
2122 ts_dialog->show();
2125 void StratosharkMainWindow::editTimeShiftFinished(int)
2127 if (capture_file_.capFile()->unsaved_changes) {
2128 updateForUnsavedChanges();
2132 void StratosharkMainWindow::addPacketComment()
2134 QList<int> rows = selectedRows();
2135 if (rows.count() == 0)
2136 return;
2138 frame_data * fdata = frameDataForRow(rows.at(0));
2139 if (! fdata)
2140 return;
2142 PacketCommentDialog* pc_dialog;
2143 pc_dialog = new PacketCommentDialog(false, this, NULL);
2144 connect(pc_dialog, &QDialog::finished, std::bind(&StratosharkMainWindow::addPacketCommentFinished, this, pc_dialog, std::placeholders::_1));
2145 pc_dialog->setWindowModality(Qt::ApplicationModal);
2146 pc_dialog->setAttribute(Qt::WA_DeleteOnClose);
2147 pc_dialog->show();
2150 void StratosharkMainWindow::addPacketCommentFinished(PacketCommentDialog* pc_dialog _U_, int result _U_)
2152 if (result == QDialog::Accepted) {
2153 packet_list_->addPacketComment(pc_dialog->text());
2154 updateForUnsavedChanges();
2158 void StratosharkMainWindow::editPacketComment()
2160 QList<int> rows = selectedRows();
2161 if (rows.count() != 1)
2162 return;
2164 QAction *ra = qobject_cast<QAction*>(sender());
2165 unsigned nComment = ra->data().toUInt();
2166 PacketCommentDialog* pc_dialog;
2167 pc_dialog = new PacketCommentDialog(true, this, packet_list_->getPacketComment(nComment));
2168 connect(pc_dialog, &QDialog::finished, std::bind(&StratosharkMainWindow::editPacketCommentFinished, this, pc_dialog, std::placeholders::_1, nComment));
2169 pc_dialog->setWindowModality(Qt::ApplicationModal);
2170 pc_dialog->setAttribute(Qt::WA_DeleteOnClose);
2171 pc_dialog->show();
2174 void StratosharkMainWindow::editPacketCommentFinished(PacketCommentDialog* pc_dialog _U_, int result _U_, unsigned nComment)
2176 if (result == QDialog::Accepted) {
2177 packet_list_->setPacketComment(nComment, pc_dialog->text());
2178 updateForUnsavedChanges();
2182 void StratosharkMainWindow::deletePacketComment()
2184 QAction *ra = qobject_cast<QAction*>(sender());
2185 unsigned nComment = ra->data().toUInt();
2186 packet_list_->setPacketComment(nComment, QString(""));
2187 updateForUnsavedChanges();
2190 void StratosharkMainWindow::deleteCommentsFromPackets()
2192 packet_list_->deleteCommentsFromPackets();
2193 updateForUnsavedChanges();
2196 void StratosharkMainWindow::deleteAllPacketComments()
2198 QMessageBox *msg_dialog = new QMessageBox(this);
2199 connect(msg_dialog, &QMessageBox::finished, this, &StratosharkMainWindow::deleteAllPacketCommentsFinished);
2201 msg_dialog->setIcon(QMessageBox::Question);
2202 msg_dialog->setText(tr("Are you sure you want to remove all packet comments?"));
2204 msg_dialog->setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
2205 msg_dialog->setDefaultButton(QMessageBox::Ok);
2207 msg_dialog->setWindowModality(Qt::ApplicationModal);
2208 msg_dialog->setAttribute(Qt::WA_DeleteOnClose);
2209 msg_dialog->show();
2212 void StratosharkMainWindow::deleteAllPacketCommentsFinished(int result)
2214 if (result == QMessageBox::Ok) {
2215 /* XXX Do we need a wait/hourglass for large files? */
2216 packet_list_->deleteAllPacketComments();
2217 updateForUnsavedChanges();
2221 void StratosharkMainWindow::editConfigurationProfiles()
2223 ProfileDialog *cp_dialog = new ProfileDialog(this);
2224 cp_dialog->setWindowModality(Qt::ApplicationModal);
2225 cp_dialog->setAttribute(Qt::WA_DeleteOnClose);
2226 cp_dialog->show();
2229 void StratosharkMainWindow::showPreferencesDialog(QString module_name)
2231 PreferencesDialog *pref_dialog = new PreferencesDialog(this);
2232 connect(pref_dialog, &PreferencesDialog::destroyed, mainApp, &MainApplication::flushAppSignals);
2233 saveWindowGeometry(); // Save in case the layout panes are rearranged
2235 pref_dialog->setPane(module_name);
2236 pref_dialog->setWindowModality(Qt::ApplicationModal);
2237 pref_dialog->setAttribute(Qt::WA_DeleteOnClose);
2238 pref_dialog->show();
2241 // View Menu
2243 void StratosharkMainWindow::connectViewMenuActions()
2245 connect(main_ui_->actionViewFullScreen, &QAction::triggered, this, [this](bool checked) {
2246 if (checked) {
2247 // Save the state for future restore
2248 was_maximized_ = this->isMaximized();
2249 this->showFullScreen();
2250 } else {
2251 // Restore the previous state
2252 if (was_maximized_) {
2253 this->showMaximized();
2254 } else {
2255 this->showNormal();
2260 connect(main_ui_->actionViewTimeDisplaySecondsWithHoursAndMinutes, &QAction::triggered, this,
2261 [this](bool checked) { setTimeDisplaySecondsWithHoursAndMinutes(checked); });
2263 connect(main_ui_->actionViewEditResolvedName, &QAction::triggered, this,
2264 [this]() { editResolvedName(); });
2266 connect(main_ui_->actionViewNameResolutionPhysical, &QAction::triggered, this,
2267 [this]() { setNameResolution(); });
2269 connect(main_ui_->actionViewNameResolutionNetwork, &QAction::triggered, this,
2270 [this]() { setNameResolution(); });
2272 connect(main_ui_->actionViewNameResolutionTransport, &QAction::triggered, this,
2273 [this]() { setNameResolution(); });
2275 connect(main_ui_->actionViewZoomIn, &QAction::triggered, this, [this]() {
2276 recent.gui_zoom_level++;
2277 zoomText();
2280 connect(main_ui_->actionViewZoomOut, &QAction::triggered, this, [this]() {
2281 recent.gui_zoom_level--;
2282 zoomText();
2285 connect(main_ui_->actionViewNormalSize, &QAction::triggered, this, [this]() {
2286 recent.gui_zoom_level = 0;
2287 zoomText();
2290 connect(main_ui_->actionViewExpandSubtrees, &QAction::triggered,
2291 proto_tree_, &ProtoTree::expandSubtrees);
2293 connect(main_ui_->actionViewCollapseSubtrees, &QAction::triggered,
2294 proto_tree_, &ProtoTree::collapseSubtrees);
2296 connect(main_ui_->actionViewExpandAll, &QAction::triggered,
2297 proto_tree_, &ProtoTree::expandAll);
2299 connect(main_ui_->actionViewCollapseAll, &QAction::triggered,
2300 proto_tree_, &ProtoTree::collapseAll);
2302 connect(main_ui_->actionViewColorizePacketList, &QAction::triggered, this, [this](bool checked) {
2303 recent.packet_list_colorize = checked;
2304 packet_list_->recolorPackets();
2307 connect(main_ui_->actionViewColoringRules, &QAction::triggered, this,
2308 [this]() { showColoringRulesDialog(); });
2310 connect(main_ui_->actionViewColorizeResetColorization, &QAction::triggered, this, [this]() {
2311 char *err_msg = NULL;
2312 if (!color_filters_reset_tmp(&err_msg)) {
2313 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_msg);
2314 g_free(err_msg);
2316 packet_list_->recolorPackets();
2317 setMenusForSelectedPacket();
2320 connect(main_ui_->actionViewColorizeNewColoringRule, &QAction::triggered, this,
2321 [this]() { colorizeConversation(true); });
2323 connect(main_ui_->actionViewResetLayout, &QAction::triggered, this, [this]() {
2324 recent.gui_geometry_main_upper_pane = 0;
2325 recent.gui_geometry_main_lower_pane = 0;
2326 g_free(recent.gui_geometry_main_master_split);
2327 g_free(recent.gui_geometry_main_extra_split);
2328 recent.gui_geometry_main_master_split = NULL;
2329 recent.gui_geometry_main_extra_split = NULL;
2330 applyRecentPaneGeometry();
2333 connect(main_ui_->actionViewResizeColumns, &QAction::triggered, this, [this]() {
2334 if (! packet_list_->model())
2335 return;
2336 for (int col = 0; col < packet_list_->model()->columnCount(); col++) {
2337 packet_list_->resizeColumnToContents(col);
2338 recent_set_column_width(col, packet_list_->columnWidth(col));
2342 connect(main_ui_->actionViewInternalsConversationHashTables, &QAction::triggered, this, [this]() {
2343 ConversationHashTablesDialog *conversation_hash_tables_dlg = new ConversationHashTablesDialog(this);
2344 conversation_hash_tables_dlg->show();
2347 connect(main_ui_->actionViewInternalsDissectorTables, &QAction::triggered, this, [this]() {
2348 DissectorTablesDialog *dissector_tables_dlg = new DissectorTablesDialog(this);
2349 dissector_tables_dlg->show();
2352 connect(main_ui_->actionViewInternalsSupportedProtocols, &QAction::triggered, this, [this]() {
2353 SupportedProtocolsDialog *supported_protocols_dlg = new SupportedProtocolsDialog(this);
2354 supported_protocols_dlg->show();
2357 connect(main_ui_->actionViewShowPacketInNewWindow, &QAction::triggered, this,
2358 [this]() { openPacketDialog(); });
2360 // This is only used in ProtoTree. Defining it here makes more sense.
2361 connect(main_ui_->actionContextShowLinkedPacketInNewWindow, &QAction::triggered, this,
2362 [this]() { openPacketDialog(true); });
2364 connect(main_ui_->actionViewReload_as_File_Format_or_Capture, &QAction::triggered, this,
2365 [this]() { reloadCaptureFileAsFormatOrCapture(); });
2367 connect(main_ui_->actionViewReload, &QAction::triggered, this,
2368 [this]() { reloadCaptureFile(); });
2371 void StratosharkMainWindow::showHideMainWidgets(QAction *action)
2373 if (!action) {
2374 return;
2376 bool show = action->isChecked();
2377 QWidget *widget = action->data().value<QWidget*>();
2379 // We may have come from the toolbar context menu, so check/uncheck each
2380 // action as well.
2381 if (widget == main_ui_->mainToolBar) {
2382 recent.main_toolbar_show = show;
2383 main_ui_->actionViewMainToolbar->setChecked(show);
2384 } else if (widget == main_ui_->displayFilterToolBar) {
2385 recent.filter_toolbar_show = show;
2386 main_ui_->actionViewFilterToolbar->setChecked(show);
2387 } else if (widget == main_ui_->statusBar) {
2388 recent.statusbar_show = show;
2389 main_ui_->actionViewStatusBar->setChecked(show);
2390 } else if (widget == packet_list_) {
2391 recent.packet_list_show = show;
2392 main_ui_->actionViewPacketList->setChecked(show);
2393 } else if (widget == proto_tree_) {
2394 recent.tree_view_show = show;
2395 main_ui_->actionViewPacketDetails->setChecked(show);
2396 } else if (widget == byte_view_tab_) {
2397 recent.byte_view_show = show;
2398 main_ui_->actionViewPacketBytes->setChecked(show);
2399 } else {
2400 foreach(QAction *action, main_ui_->menuInterfaceToolbars->actions()) {
2401 QToolBar *toolbar = action->data().value<QToolBar *>();
2402 if (widget == toolbar) {
2403 GList *entry = g_list_find_custom(recent.interface_toolbars, action->text().toUtf8(), (GCompareFunc)strcmp);
2404 if (show && !entry) {
2405 recent.interface_toolbars = g_list_append(recent.interface_toolbars, g_strdup(action->text().toUtf8()));
2406 } else if (!show && entry) {
2407 recent.interface_toolbars = g_list_remove(recent.interface_toolbars, entry->data);
2409 action->setChecked(show);
2413 ext_toolbar_t * toolbar = VariantPointer<ext_toolbar_t>::asPtr(action->data());
2414 if (toolbar) {
2415 GList *entry = g_list_find_custom(recent.gui_additional_toolbars, toolbar->name, (GCompareFunc)strcmp);
2416 if (show && !entry) {
2417 recent.gui_additional_toolbars = g_list_append(recent.gui_additional_toolbars, g_strdup(toolbar->name));
2418 } else if (!show && entry) {
2419 recent.gui_additional_toolbars = g_list_remove(recent.gui_additional_toolbars, entry->data);
2421 action->setChecked(show);
2423 QList<QToolBar *> toolbars = findChildren<QToolBar *>();
2424 foreach(QToolBar *bar, toolbars) {
2425 AdditionalToolBar *iftoolbar = dynamic_cast<AdditionalToolBar *>(bar);
2426 if (iftoolbar && iftoolbar->menuName().compare(toolbar->name) == 0) {
2427 iftoolbar->setVisible(show);
2433 if (widget) {
2434 widget->setVisible(show);
2438 void StratosharkMainWindow::setTimestampFormat(QAction *action)
2440 if (!action) {
2441 return;
2443 ts_type tsf = action->data().value<ts_type>();
2444 if (recent.gui_time_format != tsf) {
2445 timestamp_set_type(tsf);
2446 recent.gui_time_format = tsf;
2448 if (packet_list_) {
2449 packet_list_->resetColumns();
2450 packet_list_->resizeAllColumns(true);
2455 void StratosharkMainWindow::setTimestampPrecision(QAction *action)
2457 if (!action) {
2458 return;
2460 ts_precision tsp = action->data().value<ts_precision>();
2461 if (recent.gui_time_precision != tsp) {
2462 timestamp_set_precision(tsp);
2463 recent.gui_time_precision = tsp;
2465 if (packet_list_) {
2466 packet_list_->resetColumns();
2467 packet_list_->resizeAllColumns(true);
2472 void StratosharkMainWindow::setTimeDisplaySecondsWithHoursAndMinutes(bool checked)
2474 if (checked) {
2475 recent.gui_seconds_format = TS_SECONDS_HOUR_MIN_SEC;
2476 } else {
2477 recent.gui_seconds_format = TS_SECONDS_DEFAULT;
2479 timestamp_set_seconds_type(recent.gui_seconds_format);
2481 if (packet_list_) {
2482 packet_list_->resetColumns();
2483 packet_list_->resizeAllColumns(true);
2487 void StratosharkMainWindow::editResolvedName()
2489 //int column = packet_list_->selectedColumn();
2490 int column = -1;
2492 if (packet_list_->contextMenuActive() || packet_list_->hasFocus()) {
2493 if (packet_list_->currentIndex().isValid()) {
2494 column = packet_list_->currentIndex().column();
2498 main_ui_->addressEditorFrame->editAddresses(capture_file_, column);
2499 showAccordionFrame(main_ui_->addressEditorFrame);
2502 void StratosharkMainWindow::setNameResolution()
2504 gbl_resolv_flags.mac_name = main_ui_->actionViewNameResolutionPhysical->isChecked() ? true : false;
2505 gbl_resolv_flags.network_name = main_ui_->actionViewNameResolutionNetwork->isChecked() ? true : false;
2506 gbl_resolv_flags.transport_name = main_ui_->actionViewNameResolutionTransport->isChecked() ? true : false;
2508 if (packet_list_) {
2509 packet_list_->resetColumns();
2511 mainApp->emitAppSignal(WiresharkApplication::NameResolutionChanged);
2514 void StratosharkMainWindow::zoomText()
2516 mainApp->zoomTextFont(recent.gui_zoom_level);
2519 void StratosharkMainWindow::showColoringRulesDialog()
2521 ColoringRulesDialog *coloring_rules_dialog = new ColoringRulesDialog(this);
2522 connect(coloring_rules_dialog, &ColoringRulesDialog::accepted,
2523 packet_list_, &PacketList::recolorPackets);
2524 connect(coloring_rules_dialog, &ColoringRulesDialog::filterAction,
2525 this, &StratosharkMainWindow::filterAction);
2527 coloring_rules_dialog->setWindowModality(Qt::ApplicationModal);
2528 coloring_rules_dialog->setAttribute(Qt::WA_DeleteOnClose);
2529 coloring_rules_dialog->show();
2532 // actionViewColorizeConversation1 - 10
2533 void StratosharkMainWindow::colorizeConversation(bool create_rule)
2535 QAction *colorize_action = qobject_cast<QAction *>(sender());
2536 if (!colorize_action) return;
2538 if (capture_file_.capFile() && selectedRows().count() > 0) {
2539 packet_info *pi = capture_file_.packetInfo();
2540 uint8_t cc_num = colorize_action->data().toUInt();
2541 char *filter = conversation_filter_from_log(pi);
2542 if (filter == NULL) {
2543 mainApp->pushStatus(WiresharkApplication::TemporaryStatus, tr("Unable to build conversation filter."));
2544 return;
2547 if (create_rule) {
2548 ColoringRulesDialog coloring_rules_dialog(this, filter);
2549 connect(&coloring_rules_dialog, &ColoringRulesDialog::accepted,
2550 packet_list_, &PacketList::recolorPackets);
2551 connect(&coloring_rules_dialog, &ColoringRulesDialog::filterAction,
2552 this, &StratosharkMainWindow::filterAction);
2553 coloring_rules_dialog.exec();
2554 } else {
2555 char *err_msg = NULL;
2556 if (!color_filters_set_tmp(cc_num, filter, false, &err_msg)) {
2557 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_msg);
2558 g_free(err_msg);
2560 packet_list_->recolorPackets();
2563 setMenusForSelectedPacket();
2566 void StratosharkMainWindow::colorizeActionTriggered()
2568 QByteArray filter;
2569 int color_number = -1;
2571 ConversationAction *conv_action = qobject_cast<ConversationAction *>(sender());
2572 if (conv_action) {
2573 filter = conv_action->filter();
2574 color_number = conv_action->colorNumber();
2575 } else {
2576 ColorizeAction *colorize_action = qobject_cast<ColorizeAction *>(sender());
2577 if (colorize_action) {
2578 filter = colorize_action->filter();
2579 color_number = colorize_action->colorNumber();
2583 colorizeWithFilter(filter, color_number);
2586 void StratosharkMainWindow::colorizeWithFilter(QByteArray filter, int color_number)
2588 if (filter.isEmpty()) return;
2590 if (color_number > 0) {
2591 // Assume "Color X"
2592 char *err_msg = NULL;
2593 if (!color_filters_set_tmp(color_number, filter.constData(), false, &err_msg)) {
2594 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_msg);
2595 g_free(err_msg);
2597 packet_list_->recolorPackets();
2598 } else {
2599 // New coloring rule
2600 ColoringRulesDialog coloring_rules_dialog(window(), filter);
2601 connect(&coloring_rules_dialog, &ColoringRulesDialog::accepted,
2602 packet_list_, &PacketList::recolorPackets);
2603 connect(&coloring_rules_dialog, &ColoringRulesDialog::filterAction,
2604 this, &StratosharkMainWindow::filterAction);
2605 coloring_rules_dialog.exec();
2607 main_ui_->actionViewColorizeResetColorization->setEnabled(tmp_color_filters_used());
2610 void StratosharkMainWindow::openPacketDialog(bool from_reference)
2612 frame_data * fdata = Q_NULLPTR;
2614 /* Find the frame for which we're popping up a dialog */
2615 if (from_reference) {
2616 uint32_t framenum = fvalue_get_uinteger(capture_file_.capFile()->finfo_selected->value);
2617 if (framenum == 0)
2618 return;
2620 fdata = frame_data_sequence_find(capture_file_.capFile()->provider.frames, framenum);
2621 } else if (selectedRows().count() == 1) {
2622 fdata = frameDataForRow(selectedRows().at(0));
2623 } else if (selectedRows().count() > 1)
2624 return;
2626 /* If we have a frame, pop up the dialog */
2627 if (fdata) {
2628 PacketDialog *packet_dialog = new PacketDialog(*this, capture_file_, fdata);
2630 connect(packet_dialog, &PacketDialog::showProtocolPreferences,
2631 this, &StratosharkMainWindow::showPreferencesDialog);
2632 connect(packet_dialog, SIGNAL(editProtocolPreference(preference*, pref_module*)),
2633 main_ui_->preferenceEditorFrame, SLOT(editPreference(preference*, pref_module*)));
2635 connect(this, &StratosharkMainWindow::closePacketDialogs, packet_dialog, &PacketDialog::close);
2636 zoomText(); // Emits mainApp->zoomMonospaceFont(QFont)
2638 packet_dialog->show();
2642 void StratosharkMainWindow::reloadCaptureFileAsFormatOrCapture()
2644 capture_file *cf = CaptureFile::globalCapFile();
2646 if (cf->unsaved_changes) {
2647 QString before_what(tr(" before reloading the file"));
2648 if (!testCaptureFileClose(before_what, Reload))
2649 return;
2652 if (cf->open_type == WTAP_TYPE_AUTO)
2653 cf->open_type = open_info_name_to_type("MIME Files Format");
2654 else /* TODO: This should be latest format chosen by user */
2655 cf->open_type = WTAP_TYPE_AUTO;
2657 cf_reload(cf);
2660 void StratosharkMainWindow::reloadCaptureFile()
2662 capture_file *cf = CaptureFile::globalCapFile();
2664 if (cf->unsaved_changes) {
2665 QString before_what(tr(" before reloading the file"));
2666 if (!testCaptureFileClose(before_what, Reload))
2667 return;
2670 cf_reload(cf);
2674 // Expand / collapse slots in proto_tree
2676 // Go Menu
2678 void StratosharkMainWindow::connectGoMenuActions()
2680 connect(main_ui_->actionGoGoToPacket, &QAction::triggered, this, [this]() {
2681 if (! packet_list_->model() || packet_list_->model()->rowCount() < 1) {
2682 return;
2684 setPreviousFocus();
2686 showAccordionFrame(main_ui_->goToFrame, true);
2687 if (main_ui_->goToFrame->isVisible()) {
2688 main_ui_->goToLineEdit->clear();
2689 main_ui_->goToLineEdit->setFocus();
2693 connect(main_ui_->actionGoGoToLinkedPacket, &QAction::triggered, this, [this]() {
2694 QAction *gta = qobject_cast<QAction*>(sender());
2695 if (!gta) return;
2697 bool ok = false;
2698 int packet_num = gta->data().toInt(&ok);
2699 if (!ok) return;
2701 packet_list_->goToPacket(packet_num);
2704 connect(main_ui_->actionGoNextPacket, &QAction::triggered,
2705 packet_list_, &PacketList::goNextPacket);
2707 connect(main_ui_->actionGoPreviousPacket, &QAction::triggered,
2708 packet_list_, &PacketList::goPreviousPacket);
2710 connect(main_ui_->actionGoFirstPacket, &QAction::triggered,
2711 packet_list_, &PacketList::goFirstPacket);
2713 connect(main_ui_->actionGoLastPacket, &QAction::triggered,
2714 packet_list_, &PacketList::goLastPacket);
2716 connect(main_ui_->actionGoNextConversationPacket, &QAction::triggered, this,
2717 [this]() { goToConversationFrame(true); });
2719 connect(main_ui_->actionGoPreviousConversationPacket, &QAction::triggered, this,
2720 [this]() { goToConversationFrame(false); });
2722 connect(main_ui_->actionGoNextHistoryPacket, &QAction::triggered,
2723 packet_list_, &PacketList::goNextHistoryPacket);
2725 connect(main_ui_->actionGoPreviousHistoryPacket, &QAction::triggered,
2726 packet_list_, &PacketList::goPreviousHistoryPacket);
2728 // triggered is whenever the user clicks the button; save that as
2729 // the new recent value
2730 connect(main_ui_->actionGoAutoScroll, &QAction::triggered, this,
2731 [](bool checked) { recent.capture_auto_scroll = checked; });
2733 // toggled is whenever the value changes; if it changes programmatically
2734 // (e.g., the user scrolls upwards so we stop auto scrolling) change
2735 // whether the button is checked but don't save value to recent (it's
2736 // a temporary change)
2737 connect(main_ui_->actionGoAutoScroll, &QAction::toggled, this,
2738 [this](bool checked) { packet_list_->setVerticalAutoScroll(checked); });
2741 void StratosharkMainWindow::goToConversationFrame(bool go_next) {
2742 char *filter = NULL;
2743 dfilter_t *dfcode = NULL;
2744 bool found_packet = false;
2745 packet_info *pi = capture_file_.packetInfo();
2747 if (!pi) {
2748 // No packet was selected, or multiple packets were selected.
2749 return;
2752 /* Try to build a conversation
2753 * filter in the order TCP, UDP, IP, Ethernet and apply the
2754 * coloring */
2755 filter = conversation_filter_from_log(pi);
2756 if (filter == NULL) {
2757 mainApp->pushStatus(WiresharkApplication::TemporaryStatus, tr("Unable to build conversation filter."));
2758 g_free(filter);
2759 return;
2762 if (!dfilter_compile(filter, &dfcode, NULL)) {
2763 /* The attempt failed; report an error. */
2764 mainApp->pushStatus(WiresharkApplication::TemporaryStatus, tr("Error compiling filter for this conversation."));
2765 g_free(filter);
2766 return;
2769 found_packet = cf_find_packet_dfilter(capture_file_.capFile(), dfcode, go_next ? SD_FORWARD : SD_BACKWARD);
2771 if (!found_packet) {
2772 /* We didn't find a packet */
2773 mainApp->pushStatus(WiresharkApplication::TemporaryStatus, tr("No previous/next packet in conversation."));
2776 dfilter_free(dfcode);
2777 g_free(filter);
2780 // Capture Menu
2782 void StratosharkMainWindow::connectCaptureMenuActions()
2784 #ifdef HAVE_LIBPCAP
2785 connect(main_ui_->actionCaptureOptions, &QAction::triggered, this,
2786 [this]() { showCaptureOptionsDialog(); });
2787 #endif
2789 connect(main_ui_->actionCaptureStart, &QAction::triggered, this,
2790 [this]() { startCaptureTriggered(); });
2792 connect(main_ui_->actionCaptureStop, &QAction::triggered, this,
2793 [this]() { stopCapture(); });
2795 connect(main_ui_->actionCaptureRestart, &QAction::triggered, this, [this]() {
2796 #ifdef HAVE_LIBPCAP
2797 QString before_what(tr(" before restarting the capture"));
2798 cap_session_.capture_opts->restart = true;
2799 if (!testCaptureFileClose(before_what, Restart)) {
2800 return;
2802 startCapture(QStringList());
2803 #endif // HAVE_LIBPCAP
2806 connect(main_ui_->actionCaptureCaptureFilters, &QAction::triggered, this, [this]() {
2807 FilterDialog *capture_filter_dlg = new FilterDialog(window(), FilterDialog::CaptureFilter);
2808 capture_filter_dlg->setWindowModality(Qt::ApplicationModal);
2809 capture_filter_dlg->setAttribute(Qt::WA_DeleteOnClose);
2810 capture_filter_dlg->show();
2813 #ifdef HAVE_LIBPCAP
2814 connect(main_ui_->actionCaptureRefreshInterfaces, &QAction::triggered, this, [this]() {
2815 main_ui_->actionCaptureRefreshInterfaces->setEnabled(false);
2816 mainApp->refreshLocalInterfaces();
2817 main_ui_->actionCaptureRefreshInterfaces->setEnabled(true);
2819 #endif
2822 void StratosharkMainWindow::showCaptureOptionsDialog()
2824 #ifdef HAVE_LIBPCAP
2825 if (!capture_options_dialog_) {
2826 capture_options_dialog_ = new CaptureOptionsDialog(this);
2828 connect(capture_options_dialog_, &CaptureOptionsDialog::startCapture, this, [this]() { startCapture(); });
2829 connect(capture_options_dialog_, &CaptureOptionsDialog::stopCapture, this, &StratosharkMainWindow::stopCapture);
2831 connect(capture_options_dialog_, &CaptureOptionsDialog::interfacesChanged,
2832 this->welcome_page_, &WelcomePage::interfaceSelected);
2833 connect(capture_options_dialog_, &CaptureOptionsDialog::interfacesChanged,
2834 this->welcome_page_->getInterfaceFrame(), &InterfaceFrame::updateSelectedInterfaces);
2835 connect(capture_options_dialog_, &CaptureOptionsDialog::interfaceListChanged,
2836 this->welcome_page_->getInterfaceFrame(), &InterfaceFrame::interfaceListChanged);
2837 connect(capture_options_dialog_, &CaptureOptionsDialog::captureFilterTextEdited,
2838 this->welcome_page_, &WelcomePage::setCaptureFilterText);
2839 // Propagate selection changes from main UI to dialog.
2840 connect(this->welcome_page_, &WelcomePage::interfacesChanged,
2841 capture_options_dialog_, &CaptureOptionsDialog::interfaceSelected);
2843 connect(capture_options_dialog_, &CaptureOptionsDialog::setFilterValid,
2844 this, &StratosharkMainWindow::startInterfaceCapture);
2846 connect(capture_options_dialog_, &CaptureOptionsDialog::showExtcapOptions,
2847 this, &StratosharkMainWindow::showExtcapOptionsDialog);
2849 capture_options_dialog_->updateInterfaces();
2851 if (capture_options_dialog_->isMinimized()) {
2852 capture_options_dialog_->showNormal();
2853 } else {
2854 capture_options_dialog_->show();
2857 capture_options_dialog_->raise();
2858 capture_options_dialog_->activateWindow();
2859 #endif
2862 void StratosharkMainWindow::startCaptureTriggered()
2864 //#ifdef HAVE_AIRPCAP
2865 // airpcap_if_active = airpcap_if_selected;
2866 // if (airpcap_if_active)
2867 // airpcap_set_toolbar_start_capture(airpcap_if_active);
2868 //#endif
2870 // if (cap_open_w) {
2871 // /*
2872 // * There's an options dialog; get the values from it and close it.
2873 // */
2874 // bool success;
2876 // /* Determine if "capture start" while building of the "capture options" window */
2877 // /* is in progress. If so, ignore the "capture start. */
2878 // /* XXX: Would it be better/cleaner for the "capture options" window code to */
2879 // /* disable the capture start button temporarily ? */
2880 // if (cap_open_complete == false) {
2881 // return; /* Building options window: ignore "capture start" */
2882 // }
2883 // success = capture_dlg_prep(cap_open_w);
2884 // window_destroy(GTK_WIDGET(cap_open_w));
2885 // if (!success)
2886 // return; /* error in options dialog */
2887 // }
2889 #ifdef HAVE_LIBPCAP
2890 if (global_capture_opts.num_selected == 0) {
2891 QString err_msg = tr("No Interface Selected.");
2892 mainApp->pushStatus(WiresharkApplication::TemporaryStatus, err_msg);
2893 main_ui_->actionCaptureStart->setChecked(false);
2894 return;
2897 /* XXX - will closing this remove a temporary file? */
2898 QString before_what(tr(" before starting a new capture"));
2899 if (testCaptureFileClose(before_what)) {
2900 startCapture();
2901 } else {
2902 // simply clicking the button sets it to 'checked' even though we've
2903 // decided to do nothing, so undo that
2904 main_ui_->actionCaptureStart->setChecked(false);
2906 #endif // HAVE_LIBPCAP
2909 // Analyze Menu
2911 void StratosharkMainWindow::connectAnalyzeMenuActions()
2913 connect(main_ui_->actionAnalyzeDisplayFilters, &QAction::triggered, this, [=]() {
2914 FilterDialog *display_filter_dlg = new FilterDialog(window(), FilterDialog::DisplayFilter);
2915 display_filter_dlg->setWindowModality(Qt::ApplicationModal);
2916 display_filter_dlg->setAttribute(Qt::WA_DeleteOnClose);
2917 display_filter_dlg->show();
2920 connect(main_ui_->actionAnalyzeDisplayFilterMacros, &QAction::triggered, this, [=]() {
2921 FilterDialog *display_filter_dlg = new FilterDialog(window(), FilterDialog::DisplayMacro);
2922 display_filter_dlg->setWindowModality(Qt::ApplicationModal);
2923 display_filter_dlg->setAttribute(Qt::WA_DeleteOnClose);
2924 display_filter_dlg->show();
2927 connect(main_ui_->actionDisplayFilterExpression, &QAction::triggered, this, [=]() {
2928 DisplayFilterExpressionDialog *dfe_dialog = new DisplayFilterExpressionDialog(this);
2930 connect(dfe_dialog, &DisplayFilterExpressionDialog::insertDisplayFilter,
2931 qobject_cast<SyntaxLineEdit *>(df_combo_box_->lineEdit()), &SyntaxLineEdit::insertFilter);
2933 dfe_dialog->show();
2936 connect(main_ui_->actionAnalyzeApplyAsColumn, &QAction::triggered, this, &StratosharkMainWindow::applyFieldAsColumn);
2938 connect(main_ui_->actionAnalyzeEnabledProtocols, &QAction::triggered, this, [=]() {
2939 EnabledProtocolsDialog *enable_proto_dialog = new EnabledProtocolsDialog(this);
2940 connect(enable_proto_dialog, &EnabledProtocolsDialog::destroyed, mainApp, &MainApplication::flushAppSignals);
2942 enable_proto_dialog->setWindowModality(Qt::ApplicationModal);
2943 enable_proto_dialog->setAttribute(Qt::WA_DeleteOnClose);
2944 enable_proto_dialog->show();
2947 connect(main_ui_->actionAnalyzeReloadLuaPlugins, &QAction::triggered, this, &StratosharkMainWindow::reloadLuaPlugins);
2949 connect(main_ui_->actionAnalyzeShowPacketBytes, &QAction::triggered, this, [=]() {
2950 ShowPacketBytesDialog *spbd = new ShowPacketBytesDialog(*this, capture_file_);
2951 spbd->addCodecs(text_codec_map_);
2952 spbd->show();
2955 connect(main_ui_->actionAnalyzeExpertInfo, &QAction::triggered, this, [=]() {
2956 statCommandExpertInfo(NULL, NULL);
2961 void StratosharkMainWindow::filterMenuAboutToShow()
2963 QMenu * menu = qobject_cast<QMenu *>(sender());
2964 QString field_filter;
2966 if (capture_file_.capFile() && capture_file_.capFile()->finfo_selected) {
2967 char *tmp_field = proto_construct_match_selected_string(capture_file_.capFile()->finfo_selected,
2968 capture_file_.capFile()->edt);
2969 field_filter = QString(tmp_field);
2970 wmem_free(NULL, tmp_field);
2972 bool enable = ! field_filter.isEmpty();
2973 bool prepare = menu->objectName().compare("menuPrepareAFilter") == 0;
2975 menu->clear();
2976 QActionGroup * group = FilterAction::createFilterGroup(field_filter, prepare, enable, menu);
2977 menu->addActions(group->actions());
2980 void StratosharkMainWindow::matchFieldFilter(FilterAction::Action action, FilterAction::ActionType filter_type)
2982 QString field_filter;
2984 if (packet_list_->contextMenuActive() || packet_list_->hasFocus()) {
2985 field_filter = packet_list_->getFilterFromRowAndColumn(packet_list_->currentIndex());
2986 } else if (capture_file_.capFile() && capture_file_.capFile()->finfo_selected) {
2987 char *tmp_field = proto_construct_match_selected_string(capture_file_.capFile()->finfo_selected,
2988 capture_file_.capFile()->edt);
2989 field_filter = QString(tmp_field);
2990 wmem_free(NULL, tmp_field);
2993 if (field_filter.isEmpty()) {
2994 QString err = tr("No filter available. Try another %1.").arg(packet_list_->contextMenuActive() ? tr("column") : tr("item"));
2995 mainApp->pushStatus(WiresharkApplication::TemporaryStatus, err);
2996 return;
2999 setDisplayFilter(field_filter, action, filter_type);
3002 void StratosharkMainWindow::applyFieldAsColumn()
3004 if (capture_file_.capFile() != 0 && capture_file_.capFile()->finfo_selected != 0) {
3005 const header_field_info *hfinfo = capture_file_.capFile()->finfo_selected->hfinfo;
3006 int col = column_prefs_has_custom(hfinfo->abbrev);
3007 if (col == -1) {
3008 insertColumn(hfinfo->name, hfinfo->abbrev);
3009 } else {
3010 QString status;
3011 if (QString(hfinfo->name) == get_column_title(col)) {
3012 status = tr("The \"%1\" column already exists.").arg(hfinfo->name);
3013 } else {
3014 status = tr("The \"%1\" column already exists as \"%2\".").arg(hfinfo->name).arg(get_column_title(col));
3016 mainApp->pushStatus(WiresharkApplication::TemporaryStatus, status);
3018 if (!get_column_visible(col)) {
3019 packet_list_->setColumnHidden(col, false);
3020 set_column_visible(col, true);
3021 prefs_main_write();
3027 void StratosharkMainWindow::applyConversationFilter()
3029 ConversationAction *conv_action = qobject_cast<ConversationAction*>(sender());
3030 if (!conv_action) return;
3032 packet_info *pinfo = capture_file_.packetInfo();
3033 if (!pinfo) return;
3035 QByteArray conv_filter = conv_action->filter();
3036 if (conv_filter.isEmpty()) return;
3038 if (conv_action->isFilterValid(pinfo)) {
3040 df_combo_box_->lineEdit()->setText(conv_filter);
3041 df_combo_box_->applyDisplayFilter();
3045 void StratosharkMainWindow::openFollowStreamDialog(int proto_id, unsigned stream_num, unsigned sub_stream_num, bool use_stream_index) {
3046 FollowStreamDialog *fsd = new FollowStreamDialog(*this, capture_file_, proto_id);
3047 connect(fsd, &FollowStreamDialog::updateFilter, this, &StratosharkMainWindow::filterPackets);
3048 connect(fsd, &FollowStreamDialog::goToPacket, this, [=](int packet_num) {packet_list_->goToPacket(packet_num);});
3049 fsd->addCodecs(text_codec_map_);
3050 fsd->show();
3051 if (use_stream_index) {
3052 // If a specific conversation was requested, then ignore any previous
3053 // display filters and display all related packets.
3054 fsd->follow("", true, stream_num, sub_stream_num);
3055 } else {
3056 fsd->follow(getFilter());
3060 void StratosharkMainWindow::openFollowStreamDialog(int proto_id) {
3061 openFollowStreamDialog(proto_id, 0, 0, false);
3064 // -z expert
3065 void StratosharkMainWindow::statCommandExpertInfo(const char *, void *)
3067 const DisplayFilterEdit *df_edit = dynamic_cast<DisplayFilterEdit *>(df_combo_box_->lineEdit());
3068 ExpertInfoDialog *expert_dialog = new ExpertInfoDialog(*this, capture_file_, df_edit->text());
3070 connect(expert_dialog->getExpertInfoView(), &ExpertInfoTreeView::goToPacket,
3071 this, [=](int packet_num) {packet_list_->goToPacket(packet_num);});
3072 connect(expert_dialog, &ExpertInfoDialog::filterAction, this, &StratosharkMainWindow::filterAction);
3074 expert_dialog->show();
3078 // Next / previous / first / last slots in packet_list
3080 // Statistics Menu
3082 void StratosharkMainWindow::connectStatisticsMenuActions()
3084 connect(main_ui_->actionStatisticsCaptureFileProperties, &QAction::triggered, this, [=]() {
3085 CaptureFilePropertiesDialog *capture_file_properties_dialog = new CaptureFilePropertiesDialog(*this, capture_file_);
3086 connect(capture_file_properties_dialog, &CaptureFilePropertiesDialog::captureCommentChanged,
3087 this, &StratosharkMainWindow::updateForUnsavedChanges);
3088 capture_file_properties_dialog->show();
3091 main_ui_->actionStatisticsResolvedAddresses->setVisible(false); // Hide for now.
3092 // connect(main_ui_->actionStatisticsResolvedAddresses, &QAction::triggered, this, &StratosharkMainWindow::showResolvedAddressesDialog);
3094 main_ui_->actionStatisticsProtocolHierarchy->setVisible(false); // Hide for now.
3095 // connect(main_ui_->actionStatisticsProtocolHierarchy, &QAction::triggered, this, [=]() {
3096 // ProtocolHierarchyDialog *phd = new ProtocolHierarchyDialog(*this, capture_file_);
3097 // connect(phd, &ProtocolHierarchyDialog::filterAction, this, &StratosharkMainWindow::filterAction);
3098 // phd->show();
3099 // });
3101 main_ui_->actionStatisticsConversations->setVisible(false); // Hide for now.
3102 // connect(main_ui_->actionStatisticsConversations, &QAction::triggered, this, &StratosharkMainWindow::showConversationsDialog);
3103 main_ui_->actionStatisticsEndpoints->setVisible(false); // Hide for now.
3104 // connect(main_ui_->actionStatisticsEndpoints, &QAction::triggered, this, &StratosharkMainWindow::showEndpointsDialog);
3106 main_ui_->actionStatisticsPacketLengths->setVisible(false); // Hide for now.
3107 // connect(main_ui_->actionStatisticsPacketLengths, &QAction::triggered, this, [=]() { openStatisticsTreeDialog("plen"); });
3109 connect(main_ui_->actionStatisticsIOGraph, &QAction::triggered, this, [=]() { statCommandIOGraph(NULL, NULL); });
3111 main_ui_->actionStatisticsFlowGraph->setVisible(false); // Hide for now.
3112 // connect(main_ui_->actionStatisticsFlowGraph, &QAction::triggered, this, [=]() {
3113 // QMessageBox::warning(this, "Oops", "SequenceDialog depends on RTPStreamDialog");
3114 // // SequenceDialog *sequence_dialog = new SequenceDialog(*this, capture_file_);
3115 // // sequence_dialog->show();
3116 // });
3119 void StratosharkMainWindow::openStatisticsTreeDialog(const char *abbr)
3121 StatsTreeDialog *st_dialog = new StatsTreeDialog(*this, capture_file_, abbr);
3122 // connect(st_dialog, &StatsTreeDialog::goToPacket, packet_list_, &PacketList::goToPacket);
3123 st_dialog->show();
3126 // -z io,stat
3127 void StratosharkMainWindow::statCommandIOGraph(const char *, void *)
3129 showIOGraphDialog(IOG_ITEM_UNIT_PACKETS, QString());
3132 void StratosharkMainWindow::showIOGraphDialog(io_graph_item_unit_t value_units, QString yfield)
3134 const DisplayFilterEdit *df_edit = qobject_cast<DisplayFilterEdit *>(df_combo_box_->lineEdit());
3135 IOGraphDialog *iog_dialog = nullptr;
3136 QString displayFilter;
3137 if (df_edit)
3138 displayFilter = df_edit->text();
3140 if (!yfield.isEmpty()) {
3141 QList<IOGraphDialog *> iographdialogs = findChildren<IOGraphDialog *>();
3142 // GeometryStateDialogs aren't parented on Linux and Windows
3143 // (see geometry_state_dialog.h), so we search for an
3144 // I/O Dialog in all the top level widgets.
3145 if (iographdialogs.isEmpty()) {
3146 foreach(QWidget *topLevelWidget, mainApp->topLevelWidgets()) {
3147 if (qobject_cast<IOGraphDialog*>(topLevelWidget)) {
3148 iographdialogs << qobject_cast<IOGraphDialog*>(topLevelWidget);
3152 bool iog_found = false;
3153 foreach(iog_dialog, iographdialogs) {
3154 if (!iog_dialog->fileClosed()) {
3155 iog_found = true;
3156 iog_dialog->addGraph(true, false, displayFilter, value_units, yfield);
3157 break;
3160 if (!iog_found) {
3161 iog_dialog = nullptr;
3165 if (iog_dialog == nullptr) {
3166 iog_dialog = new IOGraphDialog(*this, capture_file_, displayFilter, value_units, yfield);
3167 connect(iog_dialog, &IOGraphDialog::goToPacket, this, [=](int packet_num) {packet_list_->goToPacket(packet_num);});
3168 connect(this, &StratosharkMainWindow::reloadFields, iog_dialog, &IOGraphDialog::reloadFields);
3170 iog_dialog->show();
3173 // Tools Menu
3175 void StratosharkMainWindow::connectToolsMenuActions()
3177 // We don't have any built in tools yet, so hide it until we add actions via Lua scripts.
3178 main_ui_->menuTools->hide();
3181 // Help Menu
3182 void StratosharkMainWindow::connectHelpMenuActions()
3184 connect(main_ui_->actionHelpAbout, &QAction::triggered, this, [=]() {
3185 AboutDialog *about_dialog = new AboutDialog(this);
3187 if (about_dialog->isMinimized() == true)
3189 about_dialog->showNormal();
3191 else
3193 about_dialog->show();
3196 about_dialog->raise();
3197 about_dialog->activateWindow();
3200 connect(main_ui_->actionHelpContents, &QAction::triggered, this, [=]() { mainApp->helpTopicAction(HELP_CONTENT); });
3201 connect(main_ui_->actionHelpMPWireshark, &QAction::triggered, this, [=]() { mainApp->helpTopicAction(LOCALPAGE_MAN_WIRESHARK); });
3202 connect(main_ui_->actionHelpMPWireshark_Filter, &QAction::triggered, this, [=]() { mainApp->helpTopicAction(LOCALPAGE_MAN_WIRESHARK_FILTER); });
3203 connect(main_ui_->actionHelpMPCapinfos, &QAction::triggered, this, [=]() { mainApp->helpTopicAction(LOCALPAGE_MAN_CAPINFOS); });
3204 connect(main_ui_->actionHelpMPDumpcap, &QAction::triggered, this, [=]() { mainApp->helpTopicAction(LOCALPAGE_MAN_DUMPCAP); });
3205 connect(main_ui_->actionHelpMPEditcap, &QAction::triggered, this, [=]() { mainApp->helpTopicAction(LOCALPAGE_MAN_EDITCAP); });
3206 connect(main_ui_->actionHelpMPMergecap, &QAction::triggered, this, [=]() { mainApp->helpTopicAction(LOCALPAGE_MAN_MERGECAP); });
3207 connect(main_ui_->actionHelpMPRawshark, &QAction::triggered, this, [=]() { mainApp->helpTopicAction(LOCALPAGE_MAN_RAWSHARK); });
3208 connect(main_ui_->actionHelpMPReordercap, &QAction::triggered, this, [=]() { mainApp->helpTopicAction(LOCALPAGE_MAN_REORDERCAP); });
3209 connect(main_ui_->actionHelpMPText2pcap, &QAction::triggered, this, [=]() { mainApp->helpTopicAction(LOCALPAGE_MAN_TEXT2PCAP); });
3210 connect(main_ui_->actionHelpMPTShark, &QAction::triggered, this, [=]() { mainApp->helpTopicAction(LOCALPAGE_MAN_TSHARK); });
3211 connect(main_ui_->actionHelpWebsite, &QAction::triggered, this, [=]() { mainApp->helpTopicAction(ONLINEPAGE_HOME); });
3212 connect(main_ui_->actionHelpFAQ, &QAction::triggered, this, [=]() { mainApp->helpTopicAction(ONLINEPAGE_FAQ); });
3213 connect(main_ui_->actionHelpAsk, &QAction::triggered, this, [=]() { mainApp->helpTopicAction(ONLINEPAGE_ASK); });
3214 connect(main_ui_->actionHelpDownloads, &QAction::triggered, this, [=]() { mainApp->helpTopicAction(ONLINEPAGE_DOWNLOAD); });
3215 connect(main_ui_->actionHelpWiki, &QAction::triggered, this, [=]() { mainApp->helpTopicAction(ONLINEPAGE_WIKI); });
3216 connect(main_ui_->actionHelpSampleCaptures, &QAction::triggered, this, [=]() { mainApp->helpTopicAction(ONLINEPAGE_SAMPLE_FILES); });
3219 #ifdef HAVE_SOFTWARE_UPDATE
3220 void StratosharkMainWindow::checkForUpdates()
3222 software_update_check();
3224 #endif
3226 void StratosharkMainWindow::setPreviousFocus() {
3227 previous_focus_ = mainApp->focusWidget();
3228 if (previous_focus_ != nullptr) {
3229 connect(previous_focus_, &QWidget::destroyed, this, &StratosharkMainWindow::resetPreviousFocus);
3233 void StratosharkMainWindow::resetPreviousFocus() {
3234 previous_focus_ = nullptr;
3237 void StratosharkMainWindow::goToCancelClicked()
3239 main_ui_->goToFrame->animatedHide();
3240 if (previous_focus_) {
3241 disconnect(previous_focus_, &QWidget::destroyed, this, &StratosharkMainWindow::resetPreviousFocus);
3242 previous_focus_->setFocus();
3243 resetPreviousFocus();
3247 void StratosharkMainWindow::goToGoClicked()
3249 gotoFrame(main_ui_->goToLineEdit->text().toInt());
3251 goToCancelClicked();
3254 void StratosharkMainWindow::goToLineEditReturnPressed()
3256 goToGoClicked();
3259 void StratosharkMainWindow::showResolvedAddressesDialog()
3261 QString capFileName;
3262 wtap* wth = Q_NULLPTR;
3263 if (capture_file_.isValid())
3265 capFileName = capture_file_.capFile()->filename;
3266 wth = capture_file_.capFile()->provider.wth;
3268 ResolvedAddressesDialog *resolved_addresses_dialog =
3269 new ResolvedAddressesDialog(this, capFileName, wth);
3270 resolved_addresses_dialog->show();
3273 void StratosharkMainWindow::showConversationsDialog()
3275 ConversationDialog *conv_dialog = new ConversationDialog(*this, capture_file_);
3276 connect(conv_dialog, &ConversationDialog::filterAction, this, &StratosharkMainWindow::filterAction);
3277 connect(conv_dialog, &ConversationDialog::openFollowStreamDialog, this,
3278 [=](int proto_id, unsigned stream_num, unsigned sub_stream_num) {
3279 openFollowStreamDialog(proto_id, stream_num, sub_stream_num);
3281 conv_dialog->show();
3284 void StratosharkMainWindow::showEndpointsDialog()
3286 EndpointDialog *endp_dialog = new EndpointDialog(*this, capture_file_);
3287 connect(endp_dialog, &EndpointDialog::filterAction, this, &StratosharkMainWindow::filterAction);
3288 connect(endp_dialog, &EndpointDialog::openFollowStreamDialog, this,
3289 [=](int proto_id) {openFollowStreamDialog(proto_id);
3291 endp_dialog->show();
3294 void StratosharkMainWindow::externalMenuItemTriggered()
3296 QAction * triggerAction = NULL;
3297 QVariant v;
3298 ext_menubar_t * entry = NULL;
3300 if (QObject::sender()) {
3301 triggerAction = (QAction *)QObject::sender();
3302 v = triggerAction->data();
3304 if (v.canConvert<void *>()) {
3305 entry = (ext_menubar_t *)v.value<void *>();
3307 if (entry->type == EXT_MENUBAR_ITEM) {
3308 entry->callback(EXT_MENUBAR_QT_GUI, (void *)((void *)main_ui_), entry->user_data);
3309 } else {
3310 QDesktopServices::openUrl(QUrl(QString((char *)entry->user_data)));
3316 void StratosharkMainWindow::extcap_options_finished(int result)
3318 if (result == QDialog::Accepted) {
3319 QString before_what(tr(" before starting a new capture"));
3320 if (testCaptureFileClose(before_what)) {
3321 startCapture();
3324 this->welcome_page_->getInterfaceFrame()->interfaceListChanged();
3327 void StratosharkMainWindow::showExtcapOptionsDialog(QString &device_name, bool startCaptureOnClose)
3329 ExtcapOptionsDialog * extcap_options_dialog = ExtcapOptionsDialog::createForDevice(device_name, startCaptureOnClose, this);
3330 /* The dialog returns null, if the given device name is not a valid extcap device */
3331 if (extcap_options_dialog) {
3332 extcap_options_dialog->setModal(true);
3333 extcap_options_dialog->setAttribute(Qt::WA_DeleteOnClose);
3334 if (startCaptureOnClose) {
3335 connect(extcap_options_dialog, &ExtcapOptionsDialog::finished, this, &StratosharkMainWindow::extcap_options_finished);
3337 #ifdef HAVE_LIBPCAP
3338 if (capture_options_dialog_ && startCaptureOnClose) {
3339 /* Allow capture options dialog to close */
3340 connect(extcap_options_dialog, &ExtcapOptionsDialog::accepted, capture_options_dialog_, &CaptureOptionsDialog::accept);
3342 #endif
3343 extcap_options_dialog->show();
3347 void StratosharkMainWindow::on_actionContextWikiProtocolPage_triggered()
3349 QAction *wa = qobject_cast<QAction*>(sender());
3350 if (!wa) return;
3352 bool ok = false;
3353 int field_id = wa->data().toInt(&ok);
3354 if (!ok) return;
3356 const QString proto_abbrev = proto_registrar_get_abbrev(field_id);
3358 int ret = QMessageBox::question(this, mainApp->windowTitleString(tr("Wiki Page for %1").arg(proto_abbrev)),
3359 tr("<p>The Wireshark Wiki is maintained by the community.</p>"
3360 "<p>The page you are about to load might be wonderful, "
3361 "incomplete, wrong, or nonexistent.</p>"
3362 "<p>Proceed to the wiki?</p>"),
3363 QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
3365 if (ret != QMessageBox::Yes) return;
3367 QUrl wiki_url = QString(WS_WIKI_URL("Protocols/%1")).arg(proto_abbrev);
3368 QDesktopServices::openUrl(wiki_url);
3371 void StratosharkMainWindow::on_actionContextFilterFieldReference_triggered()
3373 QAction *wa = qobject_cast<QAction*>(sender());
3374 if (!wa) return;
3376 bool ok = false;
3377 int field_id = wa->data().toInt(&ok);
3378 if (!ok) return;
3380 const QString proto_abbrev = proto_registrar_get_abbrev(field_id);
3382 QUrl dfref_url = QString(WS_DOCS_URL "/dfref/%1/%2")
3383 .arg(proto_abbrev[0])
3384 .arg(proto_abbrev);
3385 QDesktopServices::openUrl(dfref_url);
3388 void StratosharkMainWindow::activatePluginIFToolbar(bool)
3390 QAction *sendingAction = dynamic_cast<QAction *>(sender());
3391 if (!sendingAction || !sendingAction->data().isValid())
3392 return;
3394 ext_toolbar_t *toolbar = VariantPointer<ext_toolbar_t>::asPtr(sendingAction->data());
3396 QList<QToolBar *> toolbars = findChildren<QToolBar *>();
3397 foreach(QToolBar *bar, toolbars) {
3398 AdditionalToolBar *iftoolbar = dynamic_cast<AdditionalToolBar *>(bar);
3399 if (iftoolbar && iftoolbar->menuName().compare(toolbar->name) == 0) {
3400 if (iftoolbar->isVisible()) {
3401 iftoolbar->setVisible(false);
3402 sendingAction->setChecked(true);
3403 } else {
3404 iftoolbar->setVisible(true);
3405 sendingAction->setChecked(true);
3411 #ifdef _MSC_VER
3412 #pragma warning(pop)
3413 #endif