summaryrefslogtreecommitdiffstats
path: root/ui/qt/preferences_dialog.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ui/qt/preferences_dialog.cpp')
-rw-r--r--ui/qt/preferences_dialog.cpp337
1 files changed, 337 insertions, 0 deletions
diff --git a/ui/qt/preferences_dialog.cpp b/ui/qt/preferences_dialog.cpp
new file mode 100644
index 00000000..7f78350c
--- /dev/null
+++ b/ui/qt/preferences_dialog.cpp
@@ -0,0 +1,337 @@
+/* preferences_dialog.cpp
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "preferences_dialog.h"
+#include <ui_preferences_dialog.h>
+
+#include "module_preferences_scroll_area.h"
+
+#include <epan/prefs.h>
+#include <epan/prefs-int.h>
+#include <epan/decode_as.h>
+#include <ui/language.h>
+#include <ui/preference_utils.h>
+#include <cfile.h>
+#include <ui/commandline.h>
+#include <ui/simple_dialog.h>
+#include <ui/recent.h>
+#include <main_window.h>
+
+#include <ui/qt/utils/qt_ui_utils.h>
+
+#include "main_application.h"
+
+extern "C" {
+// Callbacks prefs routines
+
+static guint
+module_prefs_unstash(module_t *module, gpointer data)
+{
+ gboolean *must_redissect_p = static_cast<gboolean *>(data);
+ pref_unstash_data_t unstashed_data;
+
+ unstashed_data.handle_decode_as = TRUE;
+
+ module->prefs_changed_flags = 0; /* assume none of them changed */
+ for (GList *pref_l = module->prefs; pref_l && pref_l->data; pref_l = gxx_list_next(pref_l)) {
+ pref_t *pref = gxx_list_data(pref_t *, pref_l);
+
+ if (prefs_get_type(pref) == PREF_OBSOLETE || prefs_get_type(pref) == PREF_STATIC_TEXT) continue;
+
+ unstashed_data.module = module;
+ pref_unstash(pref, &unstashed_data);
+ commandline_options_drop(module->name, prefs_get_name(pref));
+ }
+
+ /* If any of them changed, indicate that we must redissect and refilter
+ the current capture (if we have one), as the preference change
+ could cause packets to be dissected differently. */
+ *must_redissect_p |= module->prefs_changed_flags;
+
+ if (prefs_module_has_submodules(module))
+ return prefs_modules_foreach_submodules(module, module_prefs_unstash, data);
+
+ return 0; /* Keep unstashing. */
+}
+
+static guint
+module_prefs_clean_stash(module_t *module, gpointer)
+{
+ for (GList *pref_l = module->prefs; pref_l && pref_l->data; pref_l = gxx_list_next(pref_l)) {
+ pref_t *pref = gxx_list_data(pref_t *, pref_l);
+
+ if (prefs_get_type(pref) == PREF_OBSOLETE || prefs_get_type(pref) == PREF_STATIC_TEXT) continue;
+
+ pref_clean_stash(pref, Q_NULLPTR);
+ }
+
+ if (prefs_module_has_submodules(module))
+ return prefs_modules_foreach_submodules(module, module_prefs_clean_stash, Q_NULLPTR);
+
+ return 0; /* Keep cleaning modules */
+}
+
+} // extern "C"
+
+// Preference tree items
+const int APPEARANCE_ITEM = 0;
+
+//placeholder key to keep dynamically loaded preferences
+static const char* MODULES_NAME = "Modules";
+
+PreferencesDialog::PreferencesDialog(QWidget *parent) :
+ GeometryStateDialog(parent),
+ pd_ui_(new Ui::PreferencesDialog),
+ model_(this),
+ advancedPrefsModel_(this),
+ advancedPrefsDelegate_(this),
+ modulePrefsModel_(this)
+{
+ advancedPrefsModel_.setSourceModel(&model_);
+ modulePrefsModel_.setSourceModel(&model_);
+ saved_capture_no_extcap_ = prefs.capture_no_extcap;
+
+ // Some classes depend on pref_ptr_to_pref_ so this MUST be called after
+ // model_.populate().
+ pd_ui_->setupUi(this);
+ loadGeometry();
+
+ setWindowTitle(mainApp->windowTitleString(tr("Preferences")));
+
+ pd_ui_->advancedView->setModel(&advancedPrefsModel_);
+ pd_ui_->advancedView->setItemDelegate(&advancedPrefsDelegate_);
+ advancedPrefsModel_.setFirstColumnSpanned(pd_ui_->advancedView);
+
+ pd_ui_->prefsView->setModel(&modulePrefsModel_);
+
+ pd_ui_->splitter->setStretchFactor(0, 1);
+ pd_ui_->splitter->setStretchFactor(1, 5);
+ pd_ui_->prefsView->sortByColumn(ModulePrefsModel::colName, Qt::AscendingOrder);
+
+ //Set the Appearance leaf to expanded
+ pd_ui_->prefsView->setExpanded(modulePrefsModel_.index(APPEARANCE_ITEM, 0), true);
+
+
+ // PreferencesPane, prefsView, and stackedWidget must all correspond to each other.
+ prefs_pane_to_item_[PrefsModel::typeToString(PrefsModel::Appearance)] = pd_ui_->appearanceFrame;
+ prefs_pane_to_item_[PrefsModel::typeToString(PrefsModel::Layout)] = pd_ui_->layoutFrame;
+ prefs_pane_to_item_[PrefsModel::typeToString(PrefsModel::Columns)] = pd_ui_->columnFrame;
+ prefs_pane_to_item_[PrefsModel::typeToString(PrefsModel::FontAndColors)] = pd_ui_->fontandcolorFrame;
+ prefs_pane_to_item_[PrefsModel::typeToString(PrefsModel::Capture)] = pd_ui_->captureFrame;
+ prefs_pane_to_item_[PrefsModel::typeToString(PrefsModel::Expert)] = pd_ui_->expertFrame;
+ prefs_pane_to_item_[PrefsModel::typeToString(PrefsModel::FilterButtons)] = pd_ui_->filterExpressonsFrame;
+ prefs_pane_to_item_[PrefsModel::typeToString(PrefsModel::RSAKeys)] = pd_ui_->rsaKeysFrame;
+ prefs_pane_to_item_[PrefsModel::typeToString(PrefsModel::Advanced)] = pd_ui_->advancedFrame;
+ prefs_pane_to_item_[MODULES_NAME] = NULL;
+
+ pd_ui_->filterExpressonsFrame->setUat(uat_get_table_by_name("Display expressions"));
+ pd_ui_->expertFrame->setUat(uat_get_table_by_name("Expert Info Severity Level Configuration"));
+
+ connect(pd_ui_->prefsView, &PrefModuleTreeView::goToPane, this, &PreferencesDialog::selectPane);
+
+ /* Create a single-shot timer for debouncing calls to
+ * updateSearchLineEdit() */
+ searchLineEditTimer = new QTimer(this);
+ searchLineEditTimer->setSingleShot(true);
+ connect(searchLineEditTimer, &QTimer::timeout, this, &PreferencesDialog::updateSearchLineEdit);
+}
+
+PreferencesDialog::~PreferencesDialog()
+{
+ delete pd_ui_;
+ delete searchLineEditTimer;
+ prefs_modules_foreach_submodules(NULL, module_prefs_clean_stash, NULL);
+}
+
+void PreferencesDialog::setPane(const QString module_name)
+{
+ pd_ui_->prefsView->setPane(module_name);
+}
+
+void PreferencesDialog::showEvent(QShowEvent *)
+{
+ QStyleOption style_opt;
+ int new_prefs_tree_width = pd_ui_->prefsView->style()->subElementRect(QStyle::SE_TreeViewDisclosureItem, &style_opt).left();
+ QList<int> sizes = pd_ui_->splitter->sizes();
+
+#ifdef Q_OS_WIN
+ new_prefs_tree_width *= 2;
+#endif
+ pd_ui_->prefsView->resizeColumnToContents(ModulePrefsModel::colName);
+ new_prefs_tree_width += pd_ui_->prefsView->columnWidth(ModulePrefsModel::colName);
+ pd_ui_->prefsView->setMinimumWidth(new_prefs_tree_width);
+
+ sizes[1] += sizes[0] - new_prefs_tree_width;
+ sizes[0] = new_prefs_tree_width;
+ pd_ui_->splitter->setSizes(sizes);
+ pd_ui_->splitter->setStretchFactor(0, 1);
+
+ pd_ui_->advancedView->expandAll();
+ pd_ui_->advancedView->setSortingEnabled(true);
+ pd_ui_->advancedView->sortByColumn(AdvancedPrefsModel::colName, Qt::AscendingOrder);
+
+ int one_em = fontMetrics().height();
+ pd_ui_->advancedView->setColumnWidth(AdvancedPrefsModel::colName, one_em * 12); // Don't let long items widen things too much
+ pd_ui_->advancedView->resizeColumnToContents(AdvancedPrefsModel::colStatus);
+ pd_ui_->advancedView->resizeColumnToContents(AdvancedPrefsModel::colType);
+ pd_ui_->advancedView->setColumnWidth(AdvancedPrefsModel::colValue, one_em * 30);
+}
+
+void PreferencesDialog::selectPane(QString pane)
+{
+ if (prefs_pane_to_item_.contains(pane)) {
+ pd_ui_->stackedWidget->setCurrentWidget(prefs_pane_to_item_[pane]);
+ } else {
+ //If not found in prefs_pane_to_item_, it must be an individual module
+ module_t* module = prefs_find_module(pane.toStdString().c_str());
+ if (module != NULL) {
+ QWidget* moduleWindow = prefs_pane_to_item_[MODULES_NAME];
+ if (moduleWindow != NULL) {
+ pd_ui_->stackedWidget->removeWidget(moduleWindow);
+ delete moduleWindow;
+ }
+
+ moduleWindow = new ModulePreferencesScrollArea(module);
+ prefs_pane_to_item_[MODULES_NAME] = moduleWindow;
+ pd_ui_->stackedWidget->addWidget(moduleWindow);
+ pd_ui_->stackedWidget->setCurrentWidget(moduleWindow);
+ }
+ }
+}
+
+void PreferencesDialog::updateSearchLineEdit()
+{
+ advancedPrefsModel_.setFilter(searchLineEditText);
+ /* If items are filtered out, then filtered back in, the tree remains collapsed
+ Force an expansion */
+ pd_ui_->advancedView->expandAll();
+}
+
+void PreferencesDialog::on_advancedSearchLineEdit_textEdited(const QString &text)
+{
+ /* As running pd_ui_->advancedView->expandAll() takes a noticeable amount
+ * of time and so would introduce significant lag while typing a string
+ * into the Search box, we instead debounce the call to
+ * updateSearchLineEdit(), so that it doesn't run until a set amount of
+ * time has elapsed with no updates to the Search field.
+ *
+ * If the user types something before the timer elapses, the timer restarts
+ * the countdown.
+ */
+ searchLineEditText = text;
+ guint gui_debounce_timer = prefs_get_uint_value("gui", "debounce.timer");
+ searchLineEditTimer->start(gui_debounce_timer);
+}
+
+void PreferencesDialog::on_showChangedValuesCheckBox_toggled(bool checked)
+{
+ advancedPrefsModel_.setShowChangedValues(checked);
+ /* If items are filtered out, then filtered back in, the tree remains collapsed
+ Force an expansion */
+ pd_ui_->advancedView->expandAll();
+}
+
+void PreferencesDialog::on_buttonBox_accepted()
+{
+ gchar* err = NULL;
+ unsigned int redissect_flags = 0;
+
+ // XXX - We should validate preferences as the user changes them, not here.
+ // XXX - We're also too enthusiastic about setting must_redissect.
+ prefs_modules_foreach_submodules(NULL, module_prefs_unstash, (gpointer)&redissect_flags);
+
+ if (redissect_flags & PREF_EFFECT_GUI_LAYOUT) {
+ // Layout type changed, reset sizes
+ recent.gui_geometry_main_upper_pane = 0;
+ recent.gui_geometry_main_lower_pane = 0;
+ }
+
+ pd_ui_->columnFrame->unstash();
+ pd_ui_->filterExpressonsFrame->acceptChanges();
+ pd_ui_->expertFrame->acceptChanges();
+#ifdef HAVE_LIBGNUTLS
+ pd_ui_->rsaKeysFrame->acceptChanges();
+#endif
+
+ //Filter expressions don't affect dissection, so there is no need to
+ //send any events to that effect. However, the app needs to know
+ //about any button changes.
+ mainApp->emitAppSignal(MainApplication::FilterExpressionsChanged);
+
+ prefs_main_write();
+ if (save_decode_as_entries(&err) < 0)
+ {
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err);
+ g_free(err);
+ }
+
+ write_language_prefs();
+ mainApp->loadLanguage(QString(language));
+
+#ifdef HAVE_AIRPCAP
+ /*
+ * Load the Wireshark decryption keys (just set) and save
+ * the changes to the adapters' registry
+ */
+ //airpcap_load_decryption_keys(airpcap_if_list);
+#endif
+
+ // gtk/prefs_dlg.c:prefs_main_apply_all
+ /*
+ * Apply the protocol preferences first - "gui_prefs_apply()" could
+ * cause redissection, and we have to make sure the protocol
+ * preference changes have been fully applied.
+ */
+ prefs_apply_all();
+
+ /* Fill in capture options with values from the preferences */
+ prefs_to_capture_opts();
+
+#ifdef HAVE_AIRPCAP
+// prefs_airpcap_update();
+#endif
+
+ mainApp->setMonospaceFont(prefs.gui_font_name);
+
+ if (redissect_flags & PREF_EFFECT_FIELDS) {
+ mainApp->queueAppSignal(MainApplication::FieldsChanged);
+ }
+
+ if (redissect_flags & PREF_EFFECT_DISSECTION) {
+ // Freeze the packet list early to avoid updating column data before doing a
+ // full redissection. The packet list will be thawed when redissection is done.
+ mainApp->queueAppSignal(MainApplication::FreezePacketList);
+
+ /* Redissect all the packets, and re-evaluate the display filter. */
+ mainApp->queueAppSignal(MainApplication::PacketDissectionChanged);
+ }
+ mainApp->queueAppSignal(MainApplication::PreferencesChanged);
+
+ if (redissect_flags & PREF_EFFECT_GUI_LAYOUT) {
+ mainApp->queueAppSignal(MainApplication::RecentPreferencesRead);
+ }
+
+ if (prefs.capture_no_extcap != saved_capture_no_extcap_)
+ mainApp->refreshLocalInterfaces();
+}
+
+void PreferencesDialog::on_buttonBox_rejected()
+{
+ //handle frames that don't have their own OK/Cancel "buttons"
+ pd_ui_->filterExpressonsFrame->rejectChanges();
+ pd_ui_->expertFrame->rejectChanges();
+#ifdef HAVE_LIBGNUTLS
+ pd_ui_->rsaKeysFrame->rejectChanges();
+#endif
+}
+
+void PreferencesDialog::on_buttonBox_helpRequested()
+{
+ mainApp->helpTopicAction(HELP_PREFERENCES_DIALOG);
+}