*/
#include "main_window.h"
+
+/*
+ * The generated Ui_MainWindow::setupUi() can grow larger than our configured limit,
+ * so turn off -Wframe-larger-than= for ui_main_window.h.
+ */
+DIAG_OFF(frame-larger-than=)
#include <ui_main_window.h>
+DIAG_ON(frame-larger-than=)
#include <epan/addr_resolv.h>
#include "epan/dissector_filters.h"
#include <epan/epan_dissect.h>
#include <wsutil/filesystem.h>
-#include <ws_version_info.h>
+#include <version_info.h>
#include <epan/prefs.h>
#include <epan/stats_tree_priv.h>
#include <epan/plugin_if.h>
+#include <epan/export_object.h>
+
+#include "ui/iface_toolbar.h"
#ifdef HAVE_LIBPCAP
#include "ui/capture.h"
#include "ui/capture_globals.h"
#include "ui/main_statusbar.h"
#include "ui/recent.h"
+#include "ui/recent_utils.h"
#include "ui/util.h"
#include "ui/preference_utils.h"
#include "capture_interfaces_dialog.h"
#endif
#include "conversation_colorize_action.h"
-#include "display_filter_edit.h"
+#include "export_object_action.h"
+#include <ui/qt/widgets/display_filter_edit.h>
#include "export_dissection_dialog.h"
#include "file_set_dialog.h"
#include "funnel_statistics.h"
#include "import_text_dialog.h"
+#include "interface_toolbar.h"
#include "packet_list.h"
+#include "wireless_timeline.h"
#include "proto_tree.h"
#include "simple_dialog.h"
-#include "stock_icon.h"
+#include <ui/qt/utils/stock_icon.h>
#include "tap_parameter_dialog.h"
#include "wireless_frame.h"
#include "wireshark_application.h"
-#include "qt_ui_utils.h"
+#include <ui/qt/widgets/additional_toolbar.h>
+#include <ui/qt/utils/variant_pointer.h>
+
+#include <ui/qt/utils/qt_ui_utils.h>
+
+#include <ui/qt/widgets/drag_drop_toolbar.h>
#include <QAction>
#include <QActionGroup>
g_free(ws_info->cf_filename);
ws_info->cf_filename = g_strdup(cf->filename);
- if (cf->state == FILE_READ_DONE) {
+ if (cf->state == FILE_READ_DONE && cf->current_frame) {
ws_info->cf_framenr = cf->current_frame->num;
ws_info->frame_passed_dfilter = (cf->current_frame->flags.passed_dfilter == 1);
} else {
#endif /* HAVE_LIBPCAP */
-gpointer
-simple_dialog(ESD_TYPE_E type, gint btn_mask, const gchar *msg_format, ...)
-{
- va_list ap;
-
- va_start(ap, msg_format);
- SimpleDialog sd(gbl_cur_main_window_, type, btn_mask, msg_format, ap);
- va_end(ap);
-
- sd.exec();
- return NULL;
-}
-
-/*
- * Alert box, with optional "don't show this message again" variable
- * and checkbox, and optional secondary text.
- */
-void
-simple_message_box(ESD_TYPE_E type, gboolean *notagain,
- const char *secondary_msg, const char *msg_format, ...)
+static void plugin_if_mainwindow_update_toolbars(gconstpointer user_data)
{
- if (notagain && *notagain) {
+ if (!gbl_cur_main_window_ || ! user_data)
return;
- }
-
- va_list ap;
- va_start(ap, msg_format);
- SimpleDialog sd(gbl_cur_main_window_, type, ESD_BTN_OK, msg_format, ap);
- va_end(ap);
-
- sd.setDetailedText(secondary_msg);
+ GHashTable * data_set = (GHashTable *)user_data;
+ if (g_hash_table_lookup_extended(data_set, "toolbar_name", NULL, NULL)) {
+ QString toolbarName((const char *)g_hash_table_lookup(data_set, "toolbar_name"));
+ gbl_cur_main_window_->removeAdditionalToolbar(toolbarName);
-#if (QT_VERSION > QT_VERSION_CHECK(5, 2, 0))
- QCheckBox *cb = NULL;
- if (notagain) {
- cb = new QCheckBox();
- cb->setChecked(true);
- cb->setText(QObject::tr("Don't show this message again."));
- sd.setCheckBox(cb);
}
-#endif
-
- sd.exec();
+}
-#if (QT_VERSION > QT_VERSION_CHECK(5, 2, 0))
- if (notagain && cb) {
- *notagain = cb->isChecked();
+#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
+static void mainwindow_add_toolbar(const iface_toolbar *toolbar_entry)
+{
+ if (gbl_cur_main_window_ && toolbar_entry)
+ {
+ gbl_cur_main_window_->addInterfaceToolbar(toolbar_entry);
}
-#endif
}
-/*
- * Error alert box, taking a format and a va_list argument.
- */
-void
-vsimple_error_message_box(const char *msg_format, va_list ap)
+static void mainwindow_remove_toolbar(const gchar *menu_title)
{
- SimpleDialog sd(gbl_cur_main_window_, ESD_TYPE_ERROR, ESD_BTN_OK, msg_format, ap);
- sd.exec();
+ if (gbl_cur_main_window_ && menu_title)
+ {
+ gbl_cur_main_window_->removeInterfaceToolbar(menu_title);
+ }
}
-
+#endif
QMenu* MainWindow::findOrAddMenu(QMenu *parent_menu, QString& menu_text) {
QList<QAction *> actions = parent_menu->actions();
time_precision_actions_(NULL),
funnel_statistics_(NULL),
freeze_focus_(NULL),
+ was_maximized_(false),
capture_stopping_(false),
capture_filter_valid_(false)
#ifdef HAVE_LIBPCAP
// iterates over *all* of our children, looking for matching "on_" slots.
// The fewer children we have at this point the better.
main_ui_->setupUi(this);
+#ifdef HAVE_SOFTWARE_UPDATE
+ update_action_ = new QAction(tr("Check for Updates" UTF8_HORIZONTAL_ELLIPSIS), main_ui_->menuHelp);
+#endif
setWindowIcon(wsApp->normalIcon());
setTitlebarForCaptureFile();
setMenusForCaptureFile();
main_ui_->actionAnalyzeReloadLuaPlugins->setVisible(false);
#endif
+ qRegisterMetaType<FilterAction::Action>("FilterAction::Action");
+ qRegisterMetaType<FilterAction::ActionType>("FilterAction::ActionType");
+ connect(this, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)),
+ this, SLOT(queuedFilterAction(QString,FilterAction::Action,FilterAction::ActionType)),
+ Qt::QueuedConnection);
+
//To prevent users use features before initialization complete
//Otherwise unexpected problems may occur
setFeaturesEnabled(false);
connect(wsApp, SIGNAL(appInitialized()), this, SLOT(setFeaturesEnabled()));
+ connect(wsApp, SIGNAL(appInitialized()), this, SLOT(applyGlobalCommandLineOptions()));
connect(wsApp, SIGNAL(appInitialized()), this, SLOT(zoomText()));
connect(wsApp, SIGNAL(appInitialized()), this, SLOT(initViewColorizeMenu()));
connect(wsApp, SIGNAL(appInitialized()), this, SLOT(addStatsPluginsToMenu()));
connect(wsApp, SIGNAL(appInitialized()), this, SLOT(addDynamicMenus()));
- connect(wsApp, SIGNAL(appInitialized()), this, SLOT(addExternalMenus()));
+ connect(wsApp, SIGNAL(appInitialized()), this, SLOT(addPluginIFStructures()));
connect(wsApp, SIGNAL(appInitialized()), this, SLOT(initConversationMenus()));
+ connect(wsApp, SIGNAL(appInitialized()), this, SLOT(initExportObjectsMenus()));
connect(wsApp, SIGNAL(profileChanging()), this, SLOT(saveWindowGeometry()));
connect(wsApp, SIGNAL(preferencesChanged()), this, SLOT(layoutPanes()));
connect(wsApp, SIGNAL(preferencesChanged()), this, SLOT(zoomText()));
connect(wsApp, SIGNAL(preferencesChanged()), this, SLOT(setTitlebarForCaptureFile()));
- connect(wsApp, SIGNAL(updateRecentItemStatus(const QString &, qint64, bool)), this, SLOT(updateRecentFiles()));
- updateRecentFiles();
+ connect(wsApp, SIGNAL(updateRecentCaptureStatus(const QString &, qint64, bool)), this, SLOT(updateRecentCaptures()));
+ updateRecentCaptures();
+
+#ifdef HAVE_SOFTWARE_UPDATE
+ connect(wsApp, SIGNAL(softwareUpdateRequested()), this, SLOT(softwareUpdateRequested()),
+ Qt::BlockingQueuedConnection);
+ connect(wsApp, SIGNAL(softwareUpdateClose()), this, SLOT(close()),
+ Qt::BlockingQueuedConnection);
+#endif
df_combo_box_ = new DisplayFilterCombo();
const DisplayFilterEdit *df_edit = dynamic_cast<DisplayFilterEdit *>(df_combo_box_->lineEdit());
this, SLOT(openCaptureFile(QString,QString)));
connect(this, SIGNAL(displayFilterSuccess(bool)), df_edit, SLOT(displayFilterSuccess(bool)));
+ file_set_dialog_ = new FileSetDialog(this);
+ connect(file_set_dialog_, SIGNAL(fileSetOpenCaptureFile(QString)),
+ this, SLOT(openCaptureFile(QString)));
+
initMainToolbarIcons();
main_ui_->displayFilterToolBar->insertWidget(main_ui_->actionDisplayFilterExpression, df_combo_box_);
// Make sure filter expressions overflow into a menu instead of a
// larger toolbar. We do this by adding them to a child toolbar.
// https://bugreports.qt.io/browse/QTBUG-2472
- filter_expression_toolbar_ = new QToolBar();
+ filter_expression_toolbar_ = new DragDropToolBar();
filter_expression_toolbar_->setStyleSheet("QToolBar { background: none; border: none; }");
+ filter_expression_toolbar_->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(filter_expression_toolbar_, SIGNAL(customContextMenuRequested(QPoint)),
+ this, SLOT(filterToolbarCustomMenuHandler(QPoint)));
+ connect(filter_expression_toolbar_, SIGNAL(actionMoved(QAction*, int, int)),
+ this, SLOT(filterToolbarActionMoved(QAction*, int, int)));
+
main_ui_->displayFilterToolBar->addWidget(filter_expression_toolbar_);
wireless_frame_ = new WirelessFrame(this);
main_ui_->addressEditorFrame->hide();
main_ui_->columnEditorFrame->hide();
+ connect(main_ui_->columnEditorFrame, SIGNAL(pushFilterSyntaxStatus(const QString&)),
+ main_ui_->statusBar, SLOT(pushTemporaryStatus(const QString&)));
main_ui_->preferenceEditorFrame->hide();
+ connect(main_ui_->preferenceEditorFrame, SIGNAL(pushFilterSyntaxStatus(const QString&)),
+ main_ui_->statusBar, SLOT(pushTemporaryStatus(const QString&)));
main_ui_->filterExpressionFrame->hide();
+ connect(main_ui_->filterExpressionFrame, SIGNAL(pushFilterSyntaxStatus(const QString&)),
+ main_ui_->statusBar, SLOT(pushTemporaryStatus(const QString&)));
#ifndef HAVE_LIBPCAP
main_ui_->menuCapture->setEnabled(false);
#endif
+ // Set OS specific shortcuts for fullscreen mode
+#if defined(Q_OS_MAC) && QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
+ main_ui_->actionViewFullScreen->setShortcut(QKeySequence::FullScreen);
+#else
+ main_ui_->actionViewFullScreen->setShortcut(QKeySequence(Qt::Key_F11));
+#endif
+
#if defined(Q_OS_MAC)
#if defined(QT_MACEXTRAS_LIB) && QT_VERSION < QT_VERSION_CHECK(5, 2, 1)
QMacNativeToolBar *ntb = QtMacExtras::setNativeToolBar(main_ui_->mainToolBar);
#ifdef HAVE_SOFTWARE_UPDATE
QAction *update_sep = main_ui_->menuHelp->insertSeparator(main_ui_->actionHelpAbout);
- QAction *update_action = new QAction(tr("Check for Updates" UTF8_HORIZONTAL_ELLIPSIS), main_ui_->menuHelp);
- main_ui_->menuHelp->insertAction(update_sep, update_action);
- connect(update_action, SIGNAL(triggered()), this, SLOT(checkForUpdates()));
+ main_ui_->menuHelp->insertAction(update_sep, update_action_);
+ connect(update_action_, SIGNAL(triggered()), this, SLOT(checkForUpdates()));
#endif
master_split_.setObjectName("splitterMaster");
extra_split_.setObjectName("splitterExtra");
empty_pane_.setObjectName("emptyPane");
packet_list_ = new PacketList(&master_split_);
+ main_ui_->wirelessTimelineWidget->setPacketList(packet_list_);
+ connect(packet_list_, SIGNAL(packetSelectionChanged()),
+ main_ui_->wirelessTimelineWidget, SLOT(packetSelectionChanged()));
+ connect(packet_list_->packetListModel(), SIGNAL(bgColorizationProgress(int,int)),
+ main_ui_->wirelessTimelineWidget, SLOT(bgColorizationProgress(int,int)));
+ connect(packet_list_, SIGNAL(packetSelectionChanged()),
+ main_ui_->statusBar, SLOT(packetSelectionChanged()));
proto_tree_ = new ProtoTree(&master_split_);
proto_tree_->installEventFilter(this);
updateRecentActions();
setForCaptureInProgress(false);
- setTabOrder(df_combo_box_, packet_list_);
+ setTabOrder(df_combo_box_->lineEdit(), packet_list_);
+ setTabOrder(packet_list_, proto_tree_);
connect(&capture_file_, SIGNAL(captureCapturePrepared(capture_session *)),
this, SLOT(captureCapturePrepared(capture_session *)));
this, SLOT(captureFileRetapStarted()));
connect(&capture_file_, SIGNAL(captureFileRetapFinished()),
this, SLOT(captureFileRetapFinished()));
+ connect(&capture_file_, SIGNAL(captureFileMergeStarted()),
+ this, SLOT(captureFileMergeStarted()));
+ connect(&capture_file_, SIGNAL(captureFileMergeFinished()),
+ this, SLOT(captureFileMergeFinished()));
connect(&capture_file_, SIGNAL(captureFileFlushTapsData()),
this, SLOT(captureFileFlushTapsData()));
connect(&capture_file_, SIGNAL(captureFileClosing()),
packet_list_, SLOT(columnsChanged()));
connect(wsApp, SIGNAL(preferencesChanged()),
packet_list_, SLOT(preferencesChanged()));
- connect(wsApp, SIGNAL(recentFilesRead()),
+ connect(wsApp, SIGNAL(recentPreferencesRead()),
this, SLOT(applyRecentPaneGeometry()));
- connect(wsApp, SIGNAL(recentFilesRead()),
+ connect(wsApp, SIGNAL(recentPreferencesRead()),
this, SLOT(updateRecentActions()));
connect(wsApp, SIGNAL(packetDissectionChanged()),
this, SLOT(redissectPackets()), Qt::QueuedConnection);
packet_list_, SLOT(goFirstPacket()));
connect(main_ui_->actionGoLastPacket, SIGNAL(triggered()),
packet_list_, SLOT(goLastPacket()));
+ connect(main_ui_->actionGoNextHistoryPacket, SIGNAL(triggered()),
+ packet_list_, SLOT(goNextHistoryPacket()));
+ connect(main_ui_->actionGoPreviousHistoryPacket, SIGNAL(triggered()),
+ packet_list_, SLOT(goPreviousHistoryPacket()));
connect(main_ui_->actionViewExpandSubtrees, SIGNAL(triggered()),
proto_tree_, SLOT(expandSubtrees()));
connect(byte_view_tab_, SIGNAL(byteFieldHovered(const QString&)),
main_ui_->statusBar, SLOT(pushByteStatus(const QString&)));
+ connect(byte_view_tab_, SIGNAL(currentChanged(int)),
+ this, SLOT(byteViewTabChanged(int)));
connect(main_ui_->statusBar, SIGNAL(showExpertInfo()),
this, SLOT(on_actionAnalyzeExpertInfo_triggered()));
#ifdef HAVE_LIBPCAP
plugin_if_register_gui_cb(PLUGIN_IF_GET_WS_INFO, plugin_if_mainwindow_get_ws_info);
#endif
+ plugin_if_register_gui_cb(PLUGIN_IF_REMOVE_TOOLBAR, plugin_if_mainwindow_update_toolbars);
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
+ // Register Interface Toolbar callbacks
+ //
+ // Qt version must be 5.2 or higher because the use of
+ // QThread::requestInterruption() in interface_toolbar.cpp and
+ // QThread::isInterruptionRequested() in interface_toolbar_reader.cpp
+ iface_toolbar_register_cb(mainwindow_add_toolbar, mainwindow_remove_toolbar);
+#endif
main_ui_->mainStack->setCurrentWidget(main_welcome_);
}
MainWindow::~MainWindow()
{
+ disconnect(main_ui_->mainStack, 0, 0, 0);
+
+#ifndef Q_OS_MAC
+ // file_set_dialog_ is a subclass of GeometryStateDialog.
+ // For reasons described in geometry_state_dialog.h no parent is set when
+ // instantiating the dialog and as a result the object is not automatically
+ // freed by its parent. Free it here explicitly to avoid leak and numerous
+ // Valgrind complaints.
+ delete file_set_dialog_;
+#endif
delete main_ui_;
}
menu->addAction(main_ui_->actionViewMainToolbar);
menu->addAction(main_ui_->actionViewFilterToolbar);
menu->addAction(main_ui_->actionViewWirelessToolbar);
+
+ if (!main_ui_->menuInterfaceToolbars->actions().isEmpty()) {
+ QMenu *submenu = menu->addMenu(main_ui_->menuInterfaceToolbars->title());
+ foreach (QAction *action, main_ui_->menuInterfaceToolbars->actions()) {
+ submenu->addAction(action);
+ }
+ }
+
+ if (!main_ui_->menuAdditionalToolbars->actions().isEmpty()) {
+ QMenu *subMenu = menu->addMenu(main_ui_->menuAdditionalToolbars->title());
+ foreach (QAction *action, main_ui_->menuAdditionalToolbars->actions()) {
+ subMenu->addAction(action);
+ }
+ }
+
menu->addAction(main_ui_->actionViewStatusBar);
+
menu->addSeparator();
menu->addAction(main_ui_->actionViewPacketList);
menu->addAction(main_ui_->actionViewPacketDetails);
return menu;
}
+void MainWindow::addInterfaceToolbar(const iface_toolbar *toolbar_entry)
+{
+ QMenu *menu = main_ui_->menuInterfaceToolbars;
+ bool visible = g_list_find_custom(recent.interface_toolbars, toolbar_entry->menu_title, (GCompareFunc) strcmp) ? true : false;
+
+ QString title = QString().fromUtf8(toolbar_entry->menu_title);
+ QAction *action = new QAction(title, menu);
+ action->setEnabled(true);
+ action->setCheckable(true);
+ action->setChecked(visible);
+ action->setToolTip(tr("Show or hide the toolbar"));
+
+ QAction *before = NULL;
+ foreach (QAction *action, menu->actions()) {
+ // Ensure we add the menu entries in sorted order
+ if (action->text().compare(title, Qt::CaseInsensitive) > 0) {
+ before = action;
+ break;
+ }
+ }
+ menu->insertAction(before, action);
+
+ InterfaceToolbar *interface_toolbar = new InterfaceToolbar(this, toolbar_entry);
+ connect(wsApp, SIGNAL(appInitialized()), interface_toolbar, SLOT(interfaceListChanged()));
+ connect(wsApp, SIGNAL(localInterfaceListChanged()), interface_toolbar, SLOT(interfaceListChanged()));
+
+ QToolBar *toolbar = new QToolBar(this);
+ toolbar->addWidget(interface_toolbar);
+ toolbar->setMovable(false);
+ toolbar->setVisible(visible);
+
+ action->setData(qVariantFromValue(toolbar));
+
+ addToolBar(Qt::TopToolBarArea, toolbar);
+ insertToolBarBreak(toolbar);
+
+ if (show_hide_actions_) {
+ show_hide_actions_->addAction(action);
+ }
+
+ menu->menuAction()->setVisible(true);
+}
+
+void MainWindow::removeInterfaceToolbar(const gchar *menu_title)
+{
+ QMenu *menu = main_ui_->menuInterfaceToolbars;
+ QAction *action = NULL;
+ QMap<QAction *, QWidget *>::iterator i;
+
+ QString title = QString().fromUtf8(menu_title);
+ foreach (action, menu->actions()) {
+ if (title.compare(action->text()) == 0) {
+ break;
+ }
+ }
+
+ if (action) {
+ if (show_hide_actions_) {
+ show_hide_actions_->removeAction(action);
+ }
+ menu->removeAction(action);
+
+ QToolBar *toolbar = action->data().value<QToolBar *>();
+ removeToolBar(toolbar);
+
+ delete action;
+ delete toolbar;
+ }
+
+ menu->menuAction()->setVisible(!menu->actions().isEmpty());
+}
+
void MainWindow::setPipeInputHandler(gint source, gpointer user_data, ws_process_id *child_process, pipe_input_cb_t input_cb)
{
pipe_source_ = source;
// proto tree, and main welcome widgets.
if (event->type() == QEvent::KeyPress) {
QKeyEvent *kevt = static_cast<QKeyEvent *>(event);
- if (kevt->text().length() > 0 && kevt->text()[0].isPrint()) {
+ if (kevt->text().length() > 0 && kevt->text()[0].isPrint() &&
+ !(kevt->modifiers() & Qt::ControlModifier)) {
df_combo_box_->lineEdit()->insert(kevt->text());
df_combo_box_->lineEdit()->setFocus();
return true;
exit(0);
}
wsApp->quit();
+ // When the main loop is not yet running (i.e. when openCaptureFile is
+ // executing in wireshark-qt.cpp), the above quit action has no effect.
+ // Schedule a quit action for the next execution of the main loop.
+ QMetaObject::invokeMethod(wsApp, "quit", Qt::QueuedConnection);
}
+// XXX On windows the drag description is "Copy". It should be "Open" or
+// "Merge" as appropriate. It looks like we need access to IDataObject in
+// order to set DROPDESCRIPTION.
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
- bool accept = false;
+ if (!main_ui_->actionFileOpen->isEnabled()) {
+ // We could alternatively call setAcceptDrops(!capture_in_progress)
+ // in setMenusForCaptureInProgress but that wouldn't provide feedback.
+
+ main_ui_->statusBar->pushTemporaryStatus(tr("Unable to drop files during capture."));
+ event->setDropAction(Qt::IgnoreAction);
+ event->ignore();
+ return;
+ }
+
+ bool have_files = false;
foreach (QUrl drag_url, event->mimeData()->urls()) {
if (!drag_url.toLocalFile().isEmpty()) {
- accept = true;
+ have_files = true;
break;
}
}
- if (accept) event->acceptProposedAction();
+
+ if (have_files) {
+ event->acceptProposedAction();
+ }
}
void MainWindow::dropEvent(QDropEvent *event)
{
+ QList<QByteArray> local_files;
+
foreach (QUrl drop_url, event->mimeData()->urls()) {
- QString local_file = drop_url.toLocalFile();
- if (!local_file.isEmpty()) {
- event->acceptProposedAction();
- openCaptureFile(local_file);
- break;
+ QString drop_file = drop_url.toLocalFile();
+ if (!drop_file.isEmpty()) {
+ local_files << drop_file.toUtf8();
}
}
+
+ if (local_files.size() < 1) {
+ return;
+ }
+ event->acceptProposedAction();
+
+
+ if (local_files.size() == 1) {
+ openCaptureFile(local_files.at(0));
+ return;
+ }
+
+ char **in_filenames = (char **)g_malloc(sizeof(char*) * local_files.size());
+ char *tmpname = NULL;
+
+ for (int i = 0; i < local_files.size(); i++) {
+ in_filenames[i] = (char *) local_files.at(i).constData();
+ }
+
+ /* merge the files in chronological order */
+ if (cf_merge_files_to_tempfile(this, &tmpname, local_files.size(),
+ in_filenames, WTAP_FILE_TYPE_SUBTYPE_PCAPNG,
+ FALSE) == CF_OK) {
+ /* Merge succeeded; close the currently-open file and try
+ to open the merged capture file. */
+ openCaptureFile(tmpname, QString(), WTAP_TYPE_AUTO, TRUE);
+ }
+
+ g_free(tmpname);
+ g_free(in_filenames);
+
}
// Apply recent settings to the main window geometry.
// We haven't loaded the preferences at this point so we assume that the
// position and size preference are enabled.
+// Note we might end up with unexpected screen geometries if the user
+// unplugs or plugs in a monitor:
+// https://bugreports.qt.io/browse/QTBUG-44213
void MainWindow::loadWindowGeometry()
{
int min_sensible_dimension = 200;
QRect recent_geom(recent.gui_geometry_main_x, recent.gui_geometry_main_y,
recent.gui_geometry_main_width, recent.gui_geometry_main_height);
if (!rect_on_screen(recent_geom)) {
- // We're not visible on any screens. Give up and use the default geometry.
+ // We're not visible on any screens. See if we can move onscreen
+ // without resizing.
+ recent_geom.moveTo(50, 50); // recent.c defaults to 20.
+ }
+
+ if (!rect_on_screen(recent_geom)) {
+ // Give up and use the default geometry.
return;
}
}
if (prefs.gui_geometry_save_maximized) {
- // On OS X this is false when it shouldn't be
+ // On macOS this is false when it shouldn't be
recent.gui_geometry_main_maximized = isMaximized();
}
gchar *err_msg;
if (!dfilter_compile(read_filter.toUtf8().constData(), &rfcode, &err_msg)) {
- /* Not valid. Tell the user, and go back and run the file
+ /* Not valid. Tell the user, and go back and run the file
selection box again once they dismiss the alert. */
- //bad_dfilter_alert_box(top_level, read_filter->str);
+ // Similar to commandline_info.jfilter section in main().
QMessageBox::warning(this, tr("Invalid Read Filter"),
QString(tr("The filter expression %1 isn't a valid read filter. (%2).").arg(read_filter, err_msg)),
QMessageBox::Ok);
file_type = capture_file_.capFile()->cd_t;
/* Try to merge or append the two files */
- tmpname = NULL;
if (merge_dlg.mergeType() == 0) {
/* chronological order */
in_filenames[0] = g_strdup(capture_file_.capFile()->filename);
in_filenames[1] = qstring_strdup(file_name);
- merge_status = cf_merge_files(&tmpname, 2, in_filenames, file_type, FALSE);
+ merge_status = cf_merge_files_to_tempfile(this, &tmpname, 2, in_filenames, file_type, FALSE);
} else if (merge_dlg.mergeType() <= 0) {
/* prepend file */
in_filenames[0] = qstring_strdup(file_name);
in_filenames[1] = g_strdup(capture_file_.capFile()->filename);
- merge_status = cf_merge_files(&tmpname, 2, in_filenames, file_type, TRUE);
+ merge_status = cf_merge_files_to_tempfile(this, &tmpname, 2, in_filenames, file_type, TRUE);
} else {
/* append file */
in_filenames[0] = g_strdup(capture_file_.capFile()->filename);
in_filenames[1] = qstring_strdup(file_name);
- merge_status = cf_merge_files(&tmpname, 2, in_filenames, file_type, TRUE);
+ merge_status = cf_merge_files_to_tempfile(this, &tmpname, 2, in_filenames, file_type, TRUE);
}
g_free(in_filenames[0]);
openCaptureFile(import_dlg.capfileName());
}
-void MainWindow::saveCaptureFile(capture_file *cf, bool dont_reopen) {
+bool MainWindow::saveCaptureFile(capture_file *cf, bool dont_reopen) {
QString file_name;
gboolean discard_comments;
probably pcap-ng, which supports comments and, if it's
not pcap-ng, let the user decide what they want to do
if they've added comments. */
- saveAsCaptureFile(cf, FALSE, dont_reopen);
+ return saveAsCaptureFile(cf, FALSE, dont_reopen);
} else {
if (cf->unsaved_changes) {
cf_write_status_t status;
support comments, and the user said not to delete the
comments. Do a "Save As" so the user can select
one of those formats and choose a file name. */
- saveAsCaptureFile(cf, TRUE, dont_reopen);
- return;
+ return saveAsCaptureFile(cf, TRUE, dont_reopen);
case CANCELLED:
/* The user said "forget it". Just return. */
- return;
+ return false;
default:
/* Squelch warnings that discard_comments is being used
uninitialized. */
g_assert_not_reached();
- return;
+ return false;
}
/* XXX - cf->filename might get freed out from under us, because
case CF_WRITE_ABORTED:
/* The write was aborted; just drive on. */
- break;
+ return false;
}
}
/* Otherwise just do nothing. */
}
+
+ return true;
}
-void MainWindow::saveAsCaptureFile(capture_file *cf, bool must_support_comments, bool dont_reopen) {
+bool MainWindow::saveAsCaptureFile(capture_file *cf, bool must_support_comments, bool dont_reopen) {
QString file_name = "";
int file_type;
gboolean compressed;
gboolean discard_comments = FALSE;
if (!cf) {
- return;
+ return false;
}
for (;;) {
case CANCELLED:
/* The user said "forget it". Just get rid of the dialog box
and return. */
- return;
+ return false;
}
file_type = save_as_dlg.selectedFileType();
compressed = save_as_dlg.isCompressed();
cf->unsaved_changes = false; //we just saved so we signal that we have no unsaved changes
updateForUnsavedChanges(); // we update the title bar to remove the *
- return;
+ /* Add this filename to the list of recent files in the "Recent Files" submenu */
+ add_menu_recent_capture_file(file_name.toUtf8().constData());
+ return true;
case CF_WRITE_ERROR:
/* The save failed; let the user try again. */
case CF_WRITE_ABORTED:
/* The user aborted the save; just return. */
- return;
+ return false;
}
}
- return;
+ return true;
}
void MainWindow::exportSelectedPackets() {
any packets that no longer have comments. */
if (discard_comments)
packet_list_queue_draw();
+ /* Add this filename to the list of recent files in the "Recent Files" submenu */
+ add_menu_recent_capture_file(file_name.toUtf8().constData());
return;
case CF_WRITE_ERROR:
void MainWindow::fileAddExtension(QString &file_name, int file_type, bool compressed) {
QString file_name_lower;
- QString file_suffix;
GSList *extensions_list;
gboolean add_extension;
/* OK, see if the file has one of those extensions. */
for (extension = extensions_list; extension != NULL;
extension = g_slist_next(extension)) {
- file_suffix += tr(".") + (char *)extension->data;
+ QString file_suffix = tr(".") + (char *)extension->data;
if (file_name_lower.endsWith(file_suffix)) {
/*
* The file name has one of the extensions for
#ifdef HAVE_LIBPCAP
if (capture_file_.capFile()->state == FILE_READ_IN_PROGRESS) {
- /* This is true if we're reading a capture file *or* if we're doing
- a live capture. If we're reading a capture file, the main loop
- is busy reading packets, and only accepting input from the
- progress dialog, so we can't get here, so this means we're
- doing a capture. */
- capture_in_progress = true;
+ /*
+ * This (FILE_READ_IN_PROGRESS) is true if we're reading a capture file
+ * *or* if we're doing a live capture. From the capture file itself we
+ * cannot differentiate the cases, so check the current capture session.
+ */
+ capture_in_progress = captureSession()->state != CAPTURE_STOPPED;
}
#endif
if (prefs.gui_ask_unsaved) {
- if (cf_has_unsaved_data(capture_file_.capFile()) ||
- (capture_in_progress && capture_file_.capFile()->count > 0))
- {
+ if (cf_has_unsaved_data(capture_file_.capFile())) {
QMessageBox msg_dialog;
QString question;
QString infotext;
}
discard_button = msg_dialog.addButton(discard_button_text, QMessageBox::DestructiveRole);
+ discard_button->setAutoDefault(false);
+ discard_button->setFocus();
+
msg_dialog.exec();
/* According to the Qt doc:
* when using QMessageBox with custom buttons, exec() function returns an opaque value.
captureStop();
#endif
/* Save the file and close it */
- saveCaptureFile(capture_file_.capFile(), true);
+ // XXX if no packets were captured, any unsaved comments set by
+ // the user are silently discarded because capFile() is null.
+ if (capture_file_.capFile() && saveCaptureFile(capture_file_.capFile(), true) == false)
+ return false;
do_close_file = true;
} else if(msg_dialog.clickedButton() == discard_button) {
/* Just close the file, discarding changes */
do_close_file = true;
}
+ /*
+ * Are we done with this file and should we close the file?
+ */
if (do_close_file) {
#ifdef HAVE_LIBPCAP
/* If there's a capture in progress, we have to stop the capture
and then do the close. */
if (capture_in_progress)
captureStop();
+ else if (capture_file_.capFile() && capture_file_.capFile()->state == FILE_READ_IN_PROGRESS) {
+ /*
+ * When an offline capture is being read, mark it as aborted.
+ * cf_read will be responsible for actually closing the capture.
+ *
+ * We cannot just invoke cf_close here since cf_read is up in the
+ * call chain. (update_progress_dlg can end up processing the Quit
+ * event from the user which then ends up here.)
+ */
+ capture_file_.capFile()->state = FILE_READ_ABORTED;
+ return true;
+ }
#endif
/* captureStop() will close the file if not having any packets */
if (capture_file_.capFile() && context != Restart && context != Reload)
int icon_size = style()->pixelMetric(QStyle::PM_SmallIconSize);
#if !defined(Q_OS_WIN)
// Force icons to 24x24 for now, otherwise actionFileOpen looks wonky.
- // The OS X HIG specifies 32-pixel icons but they're a little too
+ // The macOS HIG specifies 32-pixel icons but they're a little too
// large IMHO.
icon_size = icon_size * 3 / 2;
#endif
main_ui_->actionGoPreviousConversationPacket->setShortcut(QKeySequence(Qt::META | Qt::Key_Comma));
main_ui_->actionGoNextConversationPacket->setShortcut(QKeySequence(Qt::META | Qt::Key_Period));
#endif
+ main_ui_->actionGoPreviousHistoryPacket->setIcon(StockIcon("go-previous"));
+ main_ui_->actionGoNextHistoryPacket->setIcon(StockIcon("go-next"));
main_ui_->actionGoAutoScroll->setIcon(StockIcon("x-stay-last"));
main_ui_->actionViewColorizePacketList->setIcon(StockIcon("x-colorize-packets"));
-// main_ui_->actionViewAutoScroll->setIcon(StockIcon("x-stay-last"));
QList<QKeySequence> zi_seq = main_ui_->actionViewZoomIn->shortcuts();
zi_seq << QKeySequence(Qt::CTRL + Qt::Key_Equal);
showHideMainWidgets(shmwa);
}
+ // Initial hide the Interface Toolbar submenu
+ main_ui_->menuInterfaceToolbars->menuAction()->setVisible(false);
+
+ /* Initially hide the additional toolbars menus */
+ main_ui_->menuAdditionalToolbars->menuAction()->setVisible(false);
+
connect(show_hide_actions_, SIGNAL(triggered(QAction*)), this, SLOT(showHideMainWidgets(QAction*)));
}
-Q_DECLARE_METATYPE(ts_type)
-
void MainWindow::initTimeDisplayFormatMenu()
{
if (time_display_actions_) {
connect(time_display_actions_, SIGNAL(triggered(QAction*)), this, SLOT(setTimestampFormat(QAction*)));
}
-Q_DECLARE_METATYPE(ts_precision)
-
void MainWindow::initTimePrecisionFormatMenu()
{
if (time_precision_actions_) {
conv_action->setColorNumber(i++);
submenu->addAction(conv_action);
connect(this, SIGNAL(packetInfoChanged(_packet_info*)), conv_action, SLOT(setPacketInfo(_packet_info*)));
- connect(conv_action, SIGNAL(triggered()), this, SLOT(colorizeWithFilter()));
+ connect(conv_action, SIGNAL(triggered()), this, SLOT(colorizeActionTriggered()));
}
conv_action = new ConversationAction(submenu, conv_filter);
conv_action->setText(main_ui_->actionViewColorizeNewColoringRule->text());
submenu->addAction(conv_action);
connect(this, SIGNAL(packetInfoChanged(_packet_info*)), conv_action, SLOT(setPacketInfo(_packet_info*)));
- connect(conv_action, SIGNAL(triggered()), this, SLOT(colorizeWithFilter()));
+ connect(conv_action, SIGNAL(triggered()), this, SLOT(colorizeActionTriggered()));
// Proto tree conversation menu is filled in in ProtoTree::contextMenuEvent.
// We should probably do that here.
colorize_action->setColorNumber(i++);
proto_tree_->colorizeMenu()->addAction(colorize_action);
connect(this, SIGNAL(fieldFilterChanged(QByteArray)), colorize_action, SLOT(setFieldFilter(QByteArray)));
- connect(colorize_action, SIGNAL(triggered()), this, SLOT(colorizeWithFilter()));
+ connect(colorize_action, SIGNAL(triggered()), this, SLOT(colorizeActionTriggered()));
}
colorize_action = new ColorizeAction(proto_tree_->colorizeMenu());
colorize_action->setText(main_ui_->actionViewColorizeNewColoringRule->text());
proto_tree_->colorizeMenu()->addAction(colorize_action);
connect(this, SIGNAL(fieldFilterChanged(QByteArray)), colorize_action, SLOT(setFieldFilter(QByteArray)));
- connect(colorize_action, SIGNAL(triggered()), this, SLOT(colorizeWithFilter()));
+ connect(colorize_action, SIGNAL(triggered()), this, SLOT(colorizeActionTriggered()));
+}
+
+gboolean MainWindow::addExportObjectsMenuItem(const void *, void *value, void *userdata)
+{
+ register_eo_t *eo = (register_eo_t*)value;
+ MainWindow *window = (MainWindow*)userdata;
+
+ ExportObjectAction *export_action = new ExportObjectAction(window->main_ui_->menuFileExportObjects, eo);
+ window->main_ui_->menuFileExportObjects->addAction(export_action);
+
+ //initially disable until a file is loaded (then file signals will take over)
+ export_action->setEnabled(false);
+
+ connect(&window->capture_file_, SIGNAL(captureFileOpened()), export_action, SLOT(captureFileOpened()));
+ connect(&window->capture_file_, SIGNAL(captureFileClosed()), export_action, SLOT(captureFileClosed()));
+ connect(export_action, SIGNAL(triggered()), window, SLOT(applyExportObject()));
+ return FALSE;
+}
+
+void MainWindow::initExportObjectsMenus()
+{
+ eo_iterate_tables(addExportObjectsMenuItem, this);
}
// Titlebar
} else {
//
// For a user file, set the full path; that way,
- // for OS X, it'll set the "proxy icon". Qt
+ // for macOS, it'll set the "proxy icon". Qt
// handles extracting the last component.
//
// Sadly, some UN*Xes don't necessarily use UTF-8
if (prefs.gui_window_title && prefs.gui_window_title[0]) {
QString custom_title = replaceWindowTitleVariables(prefs.gui_window_title);
#ifdef __APPLE__
- // On OS X we separate the titles with a unicode em dash
+ // On macOS we separate the titles with a unicode em dash
title.append(QString(" %1 %2").arg(UTF8_EM_DASH).arg(custom_title));
#else
title.append(QString(" [%1]").arg(custom_title));
bool enable = true;
bool can_write = false;
bool can_save = false;
+ bool can_save_as = false;
if (force_disable || capture_file_.capFile() == NULL || capture_file_.capFile()->state == FILE_READ_IN_PROGRESS) {
/* We have no capture file or we're currently reading a file */
/* We have a capture file. Can we write or save? */
can_write = cf_can_write_with_wiretap(capture_file_.capFile());
can_save = cf_can_save(capture_file_.capFile());
+ can_save_as = cf_can_save_as(capture_file_.capFile());
}
main_ui_->actionViewReload_as_File_Format_or_Capture->setEnabled(enable);
main_ui_->actionFileMerge->setEnabled(can_write);
main_ui_->actionFileClose->setEnabled(enable);
main_ui_->actionFileSave->setEnabled(can_save);
- main_ui_->actionFileSaveAs->setEnabled(can_save);
+ main_ui_->actionFileSaveAs->setEnabled(can_save_as);
main_ui_->actionStatisticsCaptureFileProperties->setEnabled(enable);
/*
* "Export Specified Packets..." should be available only if
main_ui_->actionFileExportAsPDML->setEnabled(enable);
main_ui_->actionFileExportAsPlainText->setEnabled(enable);
main_ui_->actionFileExportAsPSML->setEnabled(enable);
+ main_ui_->actionFileExportAsJSON->setEnabled(enable);
main_ui_->actionFileExportPacketBytes->setEnabled(enable);
main_ui_->actionFileExportPDU->setEnabled(enable);
}
main_ui_->actionViewReload->setEnabled(enable);
+
+#ifdef HAVE_SOFTWARE_UPDATE
+ // We might want to enable or disable automatic checks here as well.
+ update_action_->setEnabled(!can_save);
+#endif
}
void MainWindow::setMenusForCaptureInProgress(bool capture_in_progress) {
main_ui_->actionFileExportAsPDML->setEnabled(capture_in_progress);
main_ui_->actionFileExportAsPlainText->setEnabled(capture_in_progress);
main_ui_->actionFileExportAsPSML->setEnabled(capture_in_progress);
+ main_ui_->actionFileExportAsJSON->setEnabled(capture_in_progress);
main_ui_->actionFileExportPacketBytes->setEnabled(capture_in_progress);
- main_ui_->actionFileExportPDU->setEnabled(capture_in_progress);
+ main_ui_->actionFileExportPDU->setEnabled(!capture_in_progress);
main_ui_->actionFileExportSSLSessionKeys->setEnabled(capture_in_progress);
foreach (QAction *eo_action, main_ui_->menuFileExportObjects->actions()) {
main_ui_->menuFileSet->setEnabled(!capture_in_progress);
main_ui_->actionFileQuit->setEnabled(true);
+#ifdef HAVE_SOFTWARE_UPDATE
+ // We might want to enable or disable automatic checks here as well.
+ update_action_->setEnabled(!capture_in_progress);
+#endif
main_ui_->actionStatisticsCaptureFileProperties->setEnabled(capture_in_progress);
void MainWindow::setMenusForCaptureStopping() {
main_ui_->actionFileQuit->setEnabled(false);
+#ifdef HAVE_SOFTWARE_UPDATE
+ update_action_->setEnabled(false);
+#endif
main_ui_->actionStatisticsCaptureFileProperties->setEnabled(false);
#ifdef HAVE_LIBPCAP
main_ui_->actionCaptureStart->setChecked(false);
case QEvent::LanguageChange:
main_ui_->retranslateUi(this);
// make sure that the "Clear Menu" item is retranslated
- updateRecentFiles();
+ wsApp->emitAppSignal(WiresharkApplication::RecentCapturesChanged);
break;
case QEvent::LocaleChange:{
QString locale = QLocale::system().name();
wsApp->loadLanguage(locale);
}
break;
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
+ case QEvent::WindowStateChange:
+ main_ui_->actionViewFullScreen->setChecked(this->isFullScreen());
+ break;
+#endif
default:
break;
}
}
/* Update main window items based on whether there's a capture in progress. */
-void MainWindow::setForCaptureInProgress(gboolean capture_in_progress)
+void MainWindow::setForCaptureInProgress(bool capture_in_progress, GArray *ifaces)
{
setMenusForCaptureInProgress(capture_in_progress);
#ifdef HAVE_LIBPCAP
packet_list_->setCaptureInProgress(capture_in_progress);
-// set_toolbar_for_capture_in_progress(capture_in_progress);
+ packet_list_->setVerticalAutoScroll(capture_in_progress && main_ui_->actionGoAutoScroll->isChecked());
// set_capture_if_dialog_for_capture_in_progress(capture_in_progress);
#endif
+
+#ifdef HAVE_EXTCAP
+ QList<InterfaceToolbar *> toolbars = findChildren<InterfaceToolbar *>();
+ foreach (InterfaceToolbar *toolbar, toolbars) {
+ if (capture_in_progress && ifaces) {
+ toolbar->startCapture(ifaces);
+ } else {
+ toolbar->stopCapture();
+ }
+ }
+#else
+ Q_UNUSED(ifaces)
+#endif
}
static QList<register_stat_group_t> menu_groups = QList<register_stat_group_t>()
}
// Empty menus don't show up: https://bugreports.qt.io/browse/QTBUG-33728
- // We've added a placeholder in order to make sure the "Tools" menu is
- // visible. Hide it as needed.
- if (wsApp->dynamicMenuGroupItems(REGISTER_TOOLS_GROUP_UNSORTED).length() > 0) {
- main_ui_->actionToolsPlaceholder->setVisible(false);
- }
+ // We've added a placeholder in order to make sure some menus are visible.
+ // Hide them as needed.
if (wsApp->dynamicMenuGroupItems(REGISTER_STAT_GROUP_TELEPHONY_ANSI).length() > 0) {
main_ui_->actionTelephonyANSIPlaceholder->setVisible(false);
}
return 0;
}
-void MainWindow::addExternalMenus()
+void MainWindow::addPluginIFStructures()
{
- QMenu * subMenu = NULL;
- GList * user_menu = NULL;
- ext_menu_t * menu = NULL;
-
- user_menu = ext_menubar_get_entries();
+ GList *user_menu = ext_menubar_get_entries();
while (user_menu && user_menu->data) {
- menu = (ext_menu_t *) user_menu->data;
+ QMenu *subMenu = NULL;
+ ext_menu_t *menu = (ext_menu_t *) user_menu->data;
/* On this level only menu items should exist. Not doing an assert here,
* as it could be an honest mistake */
/* Create main submenu and add it to the menubar */
if (menu->parent_menu) {
- QMenu * sortUnderneath = searchSubMenu(QString(menu->parent_menu));
+ QMenu *sortUnderneath = searchSubMenu(QString(menu->parent_menu));
if (sortUnderneath)
subMenu = sortUnderneath->addMenu(menu->label);
}
/* Iterate Loop */
user_menu = g_list_next (user_menu);
}
+
+ int cntToolbars = 0;
+
+ QMenu *tbMenu = main_ui_->menuAdditionalToolbars;
+ GList *if_toolbars = ext_toolbar_get_entries();
+ while (if_toolbars && if_toolbars->data) {
+ ext_toolbar_t *toolbar = (ext_toolbar_t*) if_toolbars->data;
+
+ if (toolbar->type != EXT_TOOLBAR_BAR) {
+ if_toolbars = g_list_next (if_toolbars);
+ continue;
+ }
+
+ bool visible = g_list_find_custom(recent.gui_additional_toolbars, toolbar->name, (GCompareFunc) strcmp) ? true : false;
+
+ AdditionalToolBar *ifToolBar = AdditionalToolBar::create(this, toolbar);
+
+ if (ifToolBar) {
+ ifToolBar->setVisible(visible);
+
+ QAction *iftbAction = new QAction(QString(toolbar->name), this);
+ iftbAction->setToolTip(toolbar->tooltip);
+ iftbAction->setEnabled(true);
+ iftbAction->setCheckable(true);
+ iftbAction->setChecked(visible);
+ iftbAction->setToolTip(tr("Show or hide the toolbar"));
+ iftbAction->setData(VariantPointer<ext_toolbar_t>::asQVariant(toolbar));
+
+ QAction *before = 0;
+
+ foreach (QAction *action, tbMenu->actions()) {
+ /* Ensure we add the menu entries in sorted order */
+ if (action->text().compare(toolbar->name, Qt::CaseInsensitive) > 0) {
+ before = action;
+ break;
+ }
+ }
+
+ tbMenu->insertAction(before, iftbAction);
+
+ addToolBar(Qt::TopToolBarArea, ifToolBar);
+ insertToolBarBreak(ifToolBar);
+
+ if (show_hide_actions_)
+ show_hide_actions_->addAction(iftbAction);
+
+ cntToolbars++;
+ }
+
+ if_toolbars = g_list_next (if_toolbars);
+ }
+
+ if (cntToolbars)
+ tbMenu->menuAction()->setVisible(true);
}
+void MainWindow::removeAdditionalToolbar(QString toolbarName)
+{
+ if (toolbarName.length() == 0)
+ return;
+
+ QList<QToolBar *> toolbars = findChildren<QToolBar *>();
+ foreach(QToolBar *tb, toolbars) {
+ AdditionalToolBar *ifToolBar = dynamic_cast<AdditionalToolBar *>(tb);
+
+ if (ifToolBar && ifToolBar->menuName().compare(toolbarName)) {
+ GList *entry = g_list_find_custom(recent.gui_additional_toolbars, ifToolBar->menuName().toStdString().c_str(), (GCompareFunc) strcmp);
+ if (entry) {
+ recent.gui_additional_toolbars = g_list_remove(recent.gui_additional_toolbars, entry->data);
+ }
+ QList<QAction *> actions = main_ui_->menuAdditionalToolbars->actions();
+ foreach(QAction *action, actions) {
+ ext_toolbar_t *item = VariantPointer<ext_toolbar_t>::asPtr(action->data());
+ if (item && ifToolBar->menuName().compare(item->name)) {
+ if (show_hide_actions_)
+ show_hide_actions_->removeAction(action);
+ main_ui_->menuAdditionalToolbars->removeAction(action);
+ }
+ }
+ break;
+ }
+ }
+
+}
+
+
/*
* Editor modelines
*