aboutsummaryrefslogtreecommitdiffstats
path: root/ui/qt/models
diff options
context:
space:
mode:
authorMichael Mann <mmann78@netscape.net>2017-12-29 11:23:07 -0500
committerRoland Knall <rknall@gmail.com>2018-01-04 21:20:59 +0000
commitd239da264c5d0ca2ecfd609ae3eccced939a4c46 (patch)
treeaa5b490fa2d9c1b4b6899a411bbcca03ccc0659d /ui/qt/models
parenta79b7986cddf40a8ade57638916951323fff581e (diff)
Convert preference dialog to use more models.
Convert Advanced view and Modules view to use a single base model, loading the preferences once and then filter and display what they need with QSortFilterProxyModel derived classes. Convert the PreferencePane "types" to just strings. This allows a more straightforward relationship between the "special" modules that need custom widgets for preference manipulation and it also removes dependency on preferences_dialog.h for many files. Change-Id: I091deb3061564aa4d1564e9ca1c792715961b083 Reviewed-on: https://code.wireshark.org/review/25134 Reviewed-by: Michael Mann <mmann78@netscape.net> Petri-Dish: Michael Mann <mmann78@netscape.net> Tested-by: Petri Dish Buildbot Reviewed-by: Roland Knall <rknall@gmail.com>
Diffstat (limited to 'ui/qt/models')
-rw-r--r--ui/qt/models/pref_delegate.cpp270
-rw-r--r--ui/qt/models/pref_delegate.h54
-rw-r--r--ui/qt/models/pref_models.cpp768
-rw-r--r--ui/qt/models/pref_models.h173
4 files changed, 1265 insertions, 0 deletions
diff --git a/ui/qt/models/pref_delegate.cpp b/ui/qt/models/pref_delegate.cpp
new file mode 100644
index 0000000000..8a4b83a68f
--- /dev/null
+++ b/ui/qt/models/pref_delegate.cpp
@@ -0,0 +1,270 @@
+/* pref_delegate.cpp
+ * Delegates for editing prefereneces.
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <ui/qt/models/pref_delegate.h>
+#include <epan/prefs-int.h>
+
+#include <QComboBox>
+#include <QFileDialog>
+#include <QLineEdit>
+#include <QColorDialog>
+
+#include "uat_dialog.h"
+#include "wireshark_application.h"
+
+#include <ui/qt/widgets/editor_file_dialog.h>
+
+RangeSyntaxLineEdit::RangeSyntaxLineEdit(QWidget *parent)
+ : SyntaxLineEdit(parent),
+ maxRange_(0xFFFFFFFF)
+{
+ connect(this, SIGNAL(textChanged(QString)), this, SLOT(checkRange(QString)));
+}
+
+void RangeSyntaxLineEdit::checkRange(QString range)
+{
+ if (range.isEmpty()) {
+ setSyntaxState(SyntaxLineEdit::Empty);
+ return;
+ }
+
+ range_t *newrange;
+ convert_ret_t ret = range_convert_str(NULL, &newrange, range.toUtf8().constData(), maxRange_);
+
+ if (ret == CVT_NO_ERROR) {
+ setSyntaxState(SyntaxLineEdit::Valid);
+ wmem_free(NULL, newrange);
+ } else {
+ setSyntaxState(SyntaxLineEdit::Invalid);
+ }
+}
+
+
+
+
+AdvancedPrefDelegate::AdvancedPrefDelegate(QObject *parent) : QStyledItemDelegate(parent)
+{
+}
+
+PrefsItem* AdvancedPrefDelegate::indexToPref(const QModelIndex &index) const
+{
+ const QVariant v = index.model()->data(index, Qt::UserRole);
+ return VariantPointer<PrefsItem>::asPtr(v);
+}
+
+QWidget *AdvancedPrefDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option,
+ const QModelIndex &index) const
+{
+ PrefsItem* pref;
+ QString filename;
+
+ switch(index.column())
+ {
+ case AdvancedPrefsModel::colName:
+ case AdvancedPrefsModel::colStatus:
+ case AdvancedPrefsModel::colType:
+ //If user clicks on any of these columns, reset preference back to default
+ //There is no need to launch an editor
+ ((QAbstractItemModel*)index.model())->setData(index, QVariant(), Qt::EditRole);
+ break;
+ case AdvancedPrefsModel::colValue:
+ pref = indexToPref(index);
+ switch(pref->getPrefType())
+ {
+ case PREF_DECODE_AS_UINT:
+ case PREF_UINT:
+ {
+ QLineEdit* editor = new QLineEdit(parent);
+#if 0
+ //XXX - Do we want some help handling formatting the number?
+ editor->setInputMask("0000000009;");
+#endif
+ return editor;
+ }
+ case PREF_BOOL:
+ //Setting any non-NULL value will invert boolean value
+ ((QAbstractItemModel*)index.model())->setData(index, QString("BOOL"), Qt::EditRole);
+ break;
+ case PREF_ENUM:
+ {
+ QComboBox* editor = new QComboBox(parent);
+ return editor;
+ }
+ case PREF_STRING:
+ {
+ //Separated from UINT in case formatting needs to be applied to UINT
+ QLineEdit* editor = new QLineEdit(parent);
+ return editor;
+ }
+ case PREF_DECODE_AS_RANGE:
+ case PREF_RANGE:
+ {
+ RangeSyntaxLineEdit *editor = new RangeSyntaxLineEdit(parent);
+ return editor;
+ }
+ case PREF_UAT:
+ {
+ if (pref->getPrefGUIType() == GUI_ALL || pref->getPrefGUIType() == GUI_QT) {
+ UatDialog uat_dlg(parent, prefs_get_uat_value(pref->getPref()));
+ uat_dlg.exec();
+ }
+ }
+ break;
+ case PREF_SAVE_FILENAME:
+ filename = QFileDialog::getSaveFileName(parent, wsApp->windowTitleString(prefs_get_title(pref->getPref())),
+ index.model()->data(index, Qt::DisplayRole).toString());
+ if (!filename.isEmpty()) {
+ ((QAbstractItemModel*)index.model())->setData(index, QDir::toNativeSeparators(filename), Qt::EditRole);
+ }
+ break;
+ case PREF_OPEN_FILENAME:
+ filename = QFileDialog::getOpenFileName(parent, wsApp->windowTitleString(prefs_get_title(pref->getPref())),
+ index.model()->data(index, Qt::DisplayRole).toString());
+ if (!filename.isEmpty()) {
+ ((QAbstractItemModel*)index.model())->setData(index, QDir::toNativeSeparators(filename), Qt::EditRole);
+ }
+ break;
+ case PREF_DIRNAME:
+ filename = QFileDialog::getExistingDirectory(parent, wsApp->windowTitleString(prefs_get_title(pref->getPref())),
+ index.model()->data(index, Qt::DisplayRole).toString());
+ if (!filename.isEmpty()) {
+ ((QAbstractItemModel*)index.model())->setData(index, QDir::toNativeSeparators(filename), Qt::EditRole);
+ }
+ break;
+ case PREF_COLOR:
+ {
+ QColorDialog color_dlg;
+ color_t color = *prefs_get_color_value(pref->getPref(), pref_stashed);
+
+ color_dlg.setCurrentColor(QColor(
+ color.red >> 8,
+ color.green >> 8,
+ color.blue >> 8
+ ));
+ if (color_dlg.exec() == QDialog::Accepted) {
+ ((QAbstractItemModel*)index.model())->setData(index, color_dlg.currentColor().name(), Qt::EditRole);
+ }
+ break;
+ }
+
+ }
+ break;
+ }
+
+ return 0;
+}
+
+void AdvancedPrefDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
+{
+ PrefsItem* pref = indexToPref(index);
+
+ switch(pref->getPrefType())
+ {
+ case PREF_DECODE_AS_UINT:
+ case PREF_UINT:
+ {
+ QLineEdit* line = static_cast<QLineEdit*>(editor);
+ line->setText(index.model()->data(index, Qt::DisplayRole).toString());
+ }
+ break;
+ case PREF_ENUM:
+ {
+ QComboBox* combo = static_cast<QComboBox*>(editor);
+ const enum_val_t *ev;
+ PrefsItem* pref = VariantPointer<PrefsItem>::asPtr(index.model()->data(index, Qt::UserRole));
+ for (ev = prefs_get_enumvals(pref->getPref()); ev && ev->description; ev++) {
+ combo->addItem(ev->description, QVariant(ev->value));
+ if (prefs_get_enum_value(pref->getPref(), pref_stashed) == ev->value)
+ combo->setCurrentIndex(combo->count() - 1);
+ }
+ }
+ break;
+ case PREF_STRING:
+ {
+ QLineEdit* line = static_cast<QLineEdit*>(editor);
+ line->setText(index.model()->data(index, Qt::DisplayRole).toString());
+ }
+ break;
+ case PREF_DECODE_AS_RANGE:
+ case PREF_RANGE:
+ {
+ RangeSyntaxLineEdit* syntax = static_cast<RangeSyntaxLineEdit*>(editor);
+ syntax->setText(index.model()->data(index, Qt::DisplayRole).toString());
+ }
+ break;
+ case PREF_UAT:
+ case PREF_SAVE_FILENAME:
+ case PREF_OPEN_FILENAME:
+ case PREF_DIRNAME:
+ case PREF_COLOR:
+ //Handled by the dialogs created
+ break;
+ default:
+ //Ensure any new preference types are handled
+ Q_ASSERT(FALSE);
+ break;
+ }
+}
+
+void AdvancedPrefDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
+ const QModelIndex &index) const
+{
+ PrefsItem* pref = indexToPref(index);
+ switch(pref->getPrefType())
+ {
+ case PREF_DECODE_AS_UINT:
+ case PREF_UINT:
+ case PREF_STRING:
+ {
+ QLineEdit* line = static_cast<QLineEdit*>(editor);
+ model->setData(index, line->text(), Qt::EditRole);
+ break;
+ }
+ case PREF_ENUM:
+ {
+ QComboBox* combo = static_cast<QComboBox*>(editor);
+ model->setData(index, combo->itemData(combo->currentIndex()), Qt::EditRole);
+ }
+ break;
+ case PREF_DECODE_AS_RANGE:
+ case PREF_RANGE:
+ {
+ RangeSyntaxLineEdit* syntax = static_cast<RangeSyntaxLineEdit*>(editor);
+ model->setData(index, syntax->text(), Qt::EditRole);
+ break;
+ }
+ case PREF_UAT:
+ //do nothing because UAT values aren't shown in table
+ break;
+ case PREF_SAVE_FILENAME:
+ case PREF_OPEN_FILENAME:
+ case PREF_DIRNAME:
+ case PREF_COLOR:
+ //do nothing, dialog signals will update table
+ pref = NULL;
+ break;
+ default:
+ //Ensure any new preference types are handled
+ Q_ASSERT(FALSE);
+ break;
+ }
+}
+
+/* * Editor modelines
+ *
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * ex: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */
diff --git a/ui/qt/models/pref_delegate.h b/ui/qt/models/pref_delegate.h
new file mode 100644
index 0000000000..1f693e6ade
--- /dev/null
+++ b/ui/qt/models/pref_delegate.h
@@ -0,0 +1,54 @@
+/* pref_delegate.h
+ * Delegates for editing prefereneces.
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef PREF_DELEGATE_H
+#define PREF_DELEGATE_H
+
+#include <config.h>
+
+#include <ui/qt/models/pref_models.h>
+#include <ui/qt/widgets/syntax_line_edit.h>
+
+#include <QStyledItemDelegate>
+#include <QModelIndex>
+
+class AdvancedPrefDelegate : public QStyledItemDelegate
+{
+ Q_OBJECT
+
+public:
+ AdvancedPrefDelegate(QObject *parent = 0);
+
+ QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
+ const QModelIndex &index) const;
+ void setEditorData(QWidget *editor, const QModelIndex &index) const;
+ void setModelData(QWidget *editor, QAbstractItemModel *model,
+ const QModelIndex &index) const;
+
+private:
+ PrefsItem* indexToPref(const QModelIndex &index) const;
+};
+
+//Utility class for range preferences
+class RangeSyntaxLineEdit : public SyntaxLineEdit
+{
+ Q_OBJECT
+public:
+ explicit RangeSyntaxLineEdit(QWidget *parent = 0);
+ void setMaxRange(unsigned int max) {maxRange_ = max;}
+
+public slots:
+ void checkRange(QString range);
+
+private:
+ unsigned int maxRange_;
+};
+
+#endif // PREF_DELEGATE_H
diff --git a/ui/qt/models/pref_models.cpp b/ui/qt/models/pref_models.cpp
new file mode 100644
index 0000000000..5c37035ab4
--- /dev/null
+++ b/ui/qt/models/pref_models.cpp
@@ -0,0 +1,768 @@
+/* pref_models.cpp
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <ui/qt/models/pref_models.h>
+#include <ui/qt/utils/qt_ui_utils.h>
+#include <epan/prefs-int.h>
+
+#ifdef HAVE_LIBPCAP
+#ifdef _WIN32
+#include "caputils/capture-wpcap.h"
+#endif /* _WIN32 */
+#endif /* HAVE_LIBPCAP */
+
+#include <QFont>
+#include <QColor>
+
+// XXX Should we move this to ui/preference_utils?
+static GHashTable * pref_ptr_to_pref_ = NULL;
+pref_t *prefFromPrefPtr(void *pref_ptr)
+{
+ return (pref_t *)g_hash_table_lookup(pref_ptr_to_pref_, (gpointer) pref_ptr);
+}
+
+static void prefInsertPrefPtr(void * pref_ptr, pref_t * pref)
+{
+ if ( ! pref_ptr_to_pref_ )
+ pref_ptr_to_pref_ = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, NULL);
+
+ gpointer key = (gpointer) pref_ptr;
+ gpointer val = (gpointer) pref;
+
+ /* Already existing entries will be ignored */
+ if ( (pref = (pref_t *)g_hash_table_lookup(pref_ptr_to_pref_, key) ) == NULL )
+ g_hash_table_insert(pref_ptr_to_pref_, key, val);
+}
+
+PrefsItem::PrefsItem(module_t *module, pref_t *pref, PrefsItem* parent)
+ : ModelHelperTreeItem<PrefsItem>(parent),
+ pref_(pref),
+ module_(module),
+ changed_(false)
+{
+ name_ = QString(module->name ? module->name : module->parent->name);
+ if (pref_ != NULL) {
+ name_ += QString(".%1").arg(prefs_get_name(pref_));
+ }
+}
+
+PrefsItem::PrefsItem(QString name, PrefsItem* parent)
+ : ModelHelperTreeItem<PrefsItem>(parent),
+ pref_(NULL),
+ module_(NULL),
+ name_(name),
+ changed_(false)
+{
+
+}
+
+PrefsItem::~PrefsItem()
+{
+}
+
+int PrefsItem::getPrefType() const
+{
+ if (pref_ == NULL)
+ return 0;
+
+ return prefs_get_type(pref_);
+}
+
+int PrefsItem::getPrefGUIType() const
+{
+ if (pref_ == NULL)
+ return GUI_ALL;
+
+ return prefs_get_gui_type(pref_);
+}
+
+bool PrefsItem::isPrefDefault() const
+{
+ if (pref_ == NULL)
+ return true;
+
+ if (changed_ == false)
+ return prefs_pref_is_default(pref_) ? true : false;
+
+ return false;
+}
+
+QString PrefsItem::getPrefTypeName() const
+{
+ if (pref_ == NULL)
+ return "";
+
+ return QString(prefs_pref_type_name(pref_));
+}
+
+QString PrefsItem::getModuleName() const
+{
+ if (module_ == NULL)
+ return name_;
+
+ return QString(module_->name);
+}
+
+
+void PrefsItem::setChanged(bool changed)
+{
+ changed_ = changed;
+}
+
+
+const char* PrefsModel::ADVANCED_PREFERENCE_TREE_NAME = "Advanced";
+const char* PrefsModel::APPEARANCE_PREFERENCE_TREE_NAME = "Appearance";
+const char* PrefsModel::LAYOUT_PREFERENCE_TREE_NAME = "Layout";
+const char* PrefsModel::COLUMNS_PREFERENCE_TREE_NAME = "Columns";
+const char* PrefsModel::FONT_AND_COLORS_PREFERENCE_TREE_NAME = "Font and Colors";
+const char* PrefsModel::CAPTURE_PREFERENCE_TREE_NAME = "Capture";
+const char* PrefsModel::EXPERT_PREFERENCE_TREE_NAME = "Expert";
+const char* PrefsModel::FILTER_BUTTONS_PREFERENCE_TREE_NAME = "Filter Buttons";
+
+
+PrefsModel::PrefsModel(QObject *parent) :
+ QAbstractItemModel(parent),
+ root_(new PrefsItem(QString("ROOT"), NULL))
+{
+ populate();
+}
+
+PrefsModel::~PrefsModel()
+{
+ delete root_;
+}
+
+int PrefsModel::rowCount(const QModelIndex &parent) const
+{
+ PrefsItem *parent_item;
+ if (parent.column() > 0)
+ return 0;
+
+ if (!parent.isValid())
+ parent_item = root_;
+ else
+ parent_item = static_cast<PrefsItem*>(parent.internalPointer());
+
+ if (parent_item == NULL)
+ return 0;
+
+ return parent_item->childCount();
+}
+
+int PrefsModel::columnCount(const QModelIndex&) const
+{
+ return colLast;
+}
+
+
+QModelIndex PrefsModel::parent(const QModelIndex& index) const
+{
+ if (!index.isValid())
+ return QModelIndex();
+
+ PrefsItem* item = static_cast<PrefsItem*>(index.internalPointer());
+ if (item != NULL) {
+ PrefsItem* parent_item = item->parentItem();
+ if (parent_item != NULL) {
+ if (parent_item == root_)
+ return QModelIndex();
+
+ return createIndex(parent_item->row(), 0, parent_item);
+ }
+ }
+
+ return QModelIndex();
+}
+
+QModelIndex PrefsModel::index(int row, int column, const QModelIndex& parent) const
+{
+ if (!hasIndex(row, column, parent))
+ return QModelIndex();
+
+ PrefsItem *parent_item, *child_item;
+
+ if (!parent.isValid())
+ parent_item = root_;
+ else
+ parent_item = static_cast<PrefsItem*>(parent.internalPointer());
+
+ Q_ASSERT(parent_item);
+
+ child_item = parent_item->child(row);
+ if (child_item) {
+ return createIndex(row, column, child_item);
+ }
+
+ return QModelIndex();
+}
+
+QVariant PrefsModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid() || (role != Qt::DisplayRole && role != Qt::UserRole))
+ return QVariant();
+
+ PrefsItem* item = static_cast<PrefsItem*>(index.internalPointer());
+ if (item == NULL)
+ return QVariant();
+
+ if (role == Qt::UserRole)
+ return VariantPointer<PrefsItem>::asQVariant(item);
+
+ switch ((enum PrefsModelColumn)index.column()) {
+ case colName:
+ return item->getName();
+
+ case colStatus:
+ if ((item->getPrefType() == PREF_UAT && (item->getPrefGUIType() == GUI_ALL || item->getPrefGUIType() == GUI_QT)) || item->getPrefType() == PREF_CUSTOM)
+ return QObject::tr("Unknown");
+
+ if (item->isPrefDefault())
+ return QObject::tr("Default");
+
+ return QObject::tr("Changed");
+ case colType:
+ return item->getPrefTypeName();
+ case colValue:
+ if (item->getPref() == NULL)
+ return QVariant();
+
+ return QString(gchar_free_to_qstring(prefs_pref_to_str(item->getPref(), pref_stashed)).remove(QRegExp("\n\t")));
+ default:
+ break;
+ }
+
+ return QVariant();
+}
+
+static guint
+fill_prefs(module_t *module, gpointer root_ptr)
+{
+ PrefsItem* root_item = static_cast<PrefsItem*>(root_ptr);
+
+ if ((module == NULL) || (root_item == NULL))
+ return 1;
+
+ if (module->numprefs < 1 && !prefs_module_has_submodules(module))
+ return 0;
+
+ PrefsItem* module_item = new PrefsItem(module, NULL, root_item);
+ root_item->appendChild(module_item);
+
+ for (GList *pref_l = module->prefs; pref_l && pref_l->data; pref_l = g_list_next(pref_l)) {
+ pref_t *pref = (pref_t *) pref_l->data;
+
+ if (prefs_get_type(pref) == PREF_OBSOLETE || prefs_get_type(pref) == PREF_STATIC_TEXT)
+ continue;
+
+ const char *type_name = prefs_pref_type_name(pref);
+ if (!type_name)
+ continue;
+
+ pref_stash(pref, NULL);
+
+ PrefsItem* item = new PrefsItem(module, pref, module_item);
+ module_item->appendChild(item);
+
+ // .uat is a void * so it wins the "useful key value" prize.
+ if (prefs_get_uat_value(pref)) {
+ prefInsertPrefPtr( prefs_get_uat_value(pref), pref);
+ }
+ }
+
+ if(prefs_module_has_submodules(module))
+ return prefs_modules_foreach_submodules(module, fill_prefs, module_item);
+
+ return 0;
+}
+
+void PrefsModel::populate()
+{
+ // Printing prefs don't apply here.
+ module_t *print_module = prefs_find_module("print");
+ if (print_module)
+ print_module->use_gui = FALSE;
+
+ //Since "expert" is really a pseudo protocol, it shouldn't be
+ //categorized with other "real" protocols when it comes to
+ //preferences. Since it's just a UAT, don't bury it in
+ //with the other protocols
+ module_t *expert_module = prefs_find_module("_ws.expert");
+ if (expert_module)
+ expert_module->use_gui = FALSE;
+
+ prefs_modules_foreach_submodules(NULL, fill_prefs, (gpointer)root_);
+
+ //Add the "specially handled" preferences
+ PrefsItem *appearance_item, *appearance_subitem, *special_item;
+
+ appearance_item = new PrefsItem(APPEARANCE_PREFERENCE_TREE_NAME, root_);
+ root_->appendChild(appearance_item);
+
+ appearance_subitem = new PrefsItem(LAYOUT_PREFERENCE_TREE_NAME, appearance_item);
+ appearance_item->appendChild(appearance_subitem);
+ appearance_subitem = new PrefsItem(COLUMNS_PREFERENCE_TREE_NAME, appearance_item);
+ appearance_item->appendChild(appearance_subitem);
+ appearance_subitem = new PrefsItem(FONT_AND_COLORS_PREFERENCE_TREE_NAME, appearance_item);
+ appearance_item->appendChild(appearance_subitem);
+
+ special_item = new PrefsItem(CAPTURE_PREFERENCE_TREE_NAME, root_);
+ root_->appendChild(special_item);
+ special_item = new PrefsItem(EXPERT_PREFERENCE_TREE_NAME, root_);
+ root_->appendChild(special_item);
+ special_item = new PrefsItem(FILTER_BUTTONS_PREFERENCE_TREE_NAME, root_);
+ root_->appendChild(special_item);
+ special_item = new PrefsItem(ADVANCED_PREFERENCE_TREE_NAME, root_);
+ root_->appendChild(special_item);
+}
+
+
+
+
+
+AdvancedPrefsModel::AdvancedPrefsModel(QObject * parent)
+: QSortFilterProxyModel(parent),
+filter_()
+{
+}
+
+QVariant AdvancedPrefsModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
+
+ switch (section) {
+ case colName:
+ return tr("Name");
+ case colStatus:
+ return tr("Status");
+ case colType:
+ return tr("Type");
+ case colValue:
+ return tr("Value");
+ default:
+ break;
+ }
+ }
+ return QVariant();
+}
+
+QVariant AdvancedPrefsModel::data(const QModelIndex &dataindex, int role) const
+{
+ if (!dataindex.isValid())
+ return QVariant();
+
+ QModelIndex modelIndex = mapToSource(dataindex);
+
+ PrefsItem* item = static_cast<PrefsItem*>(modelIndex.internalPointer());
+ if (item == NULL)
+ return QVariant();
+
+ switch (role)
+ {
+ case Qt::DisplayRole:
+ switch ((AdvancedPrefsModelColumn)dataindex.column())
+ {
+ case colName:
+ if (item->getPref() == NULL)
+ return item->getModule()->title;
+
+ return sourceModel()->data(sourceModel()->index(modelIndex.row(), PrefsModel::colName, modelIndex.parent()), role);
+ case colStatus:
+ if (item->getPref() == NULL)
+ return QVariant();
+
+ return sourceModel()->data(sourceModel()->index(modelIndex.row(), PrefsModel::colStatus, modelIndex.parent()), role);
+ case colType:
+ if (item->getPref() == NULL)
+ return QVariant();
+
+ return sourceModel()->data(sourceModel()->index(modelIndex.row(), PrefsModel::colType, modelIndex.parent()), role);
+ case colValue:
+ if (item->getPref() == NULL)
+ return QVariant();
+
+ return sourceModel()->data(sourceModel()->index(modelIndex.row(), PrefsModel::colValue, modelIndex.parent()), role);
+ default:
+ break;
+ }
+ break;
+ case Qt::ToolTipRole:
+ switch ((AdvancedPrefsModelColumn)dataindex.column())
+ {
+ case colName:
+ if (item->getPref() == NULL)
+ return QString("<span>%1</span>").arg(item->getModule()->description);
+
+ return QString("<span>%1</span>").arg(prefs_get_description(item->getPref()));
+ case colStatus:
+ if (item->getPref() == NULL)
+ return QVariant();
+
+ return QObject::tr("Has this preference been changed?");
+ case colType:
+ if (item->getPref() == NULL) {
+ return QVariant();
+ } else {
+ QString type_desc = gchar_free_to_qstring(prefs_pref_type_description(item->getPref()));
+ return QString("<span>%1</span>").arg(type_desc);
+ }
+ break;
+ case colValue:
+ if (item->getPref() == NULL) {
+ return QVariant();
+ } else {
+ QString default_value = gchar_free_to_qstring(prefs_pref_to_str(item->getPref(), pref_stashed));
+ return QString("<span>%1</span>").arg(
+ default_value.isEmpty() ? default_value : QObject::tr("Default value is empty"));
+ }
+ default:
+ break;
+ }
+ break;
+ case Qt::FontRole:
+ if (item->getPref() == NULL)
+ return QVariant();
+
+ if (!item->isPrefDefault() &&
+ /* UATs and custom preferences are "unknown", that shouldn't mean that they are always bolded */
+ item->getPrefType() != PREF_UAT && item->getPrefType() != PREF_CUSTOM) {
+ QFont font;
+ font.setBold(true);
+ return font;
+ }
+ break;
+ case Qt::UserRole:
+ return sourceModel()->data(modelIndex, role);
+ default:
+ break;
+ }
+
+ return QVariant();
+}
+
+bool AdvancedPrefsModel::setData(const QModelIndex &dataindex, const QVariant &value, int role)
+{
+ if ((!dataindex.isValid()) || (role != Qt::EditRole))
+ return false;
+
+ QModelIndex modelIndex = mapToSource(dataindex);
+
+ PrefsItem* item = static_cast<PrefsItem*>(modelIndex.internalPointer());
+ if (item == NULL)
+ return false;
+
+ if (value.isNull()) {
+ //reset preference to default
+ reset_stashed_pref(item->getPref());
+ item->setChanged(false);
+ } else {
+ item->setChanged(true);
+ switch (item->getPrefType())
+ {
+ case PREF_DECODE_AS_UINT:
+ case PREF_UINT:
+ {
+ bool ok;
+ guint new_val = value.toString().toUInt(&ok, prefs_get_uint_base(item->getPref()));
+
+ if (ok)
+ prefs_set_uint_value(item->getPref(), new_val, pref_stashed);
+ }
+ break;
+ case PREF_BOOL:
+ prefs_invert_bool_value(item->getPref(), pref_stashed);
+ break;
+ case PREF_ENUM:
+ prefs_set_enum_value(item->getPref(), value.toInt(), pref_stashed);
+ break;
+ case PREF_STRING:
+ prefs_set_string_value(item->getPref(), value.toString().toStdString().c_str(), pref_stashed);
+ break;
+ case PREF_DECODE_AS_RANGE:
+ case PREF_RANGE:
+ prefs_set_stashed_range_value(item->getPref(), value.toString().toUtf8().constData());
+ break;
+ case PREF_SAVE_FILENAME:
+ case PREF_OPEN_FILENAME:
+ case PREF_DIRNAME:
+ prefs_set_string_value(item->getPref(), value.toString().toStdString().c_str(), pref_stashed);
+ break;
+ case PREF_COLOR:
+ {
+ QColor qc(value.toString());
+ color_t color;
+
+ color.red = qc.red() << 8 | qc.red();
+ color.green = qc.green() << 8 | qc.green();
+ color.blue = qc.blue() << 8 | qc.blue();
+
+ prefs_set_color_value(item->getPref(), color, pref_stashed);
+ break;
+ }
+ }
+ }
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
+ QVector<int> roles;
+ roles << role;
+#endif
+
+ // The status field may change as well as the value, so mark them for update
+ emit dataChanged(index(dataindex.row(), AdvancedPrefsModel::colStatus),
+ index(dataindex.row(), AdvancedPrefsModel::colValue)
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
+ , roles
+#endif
+ );
+
+ return true;
+}
+
+Qt::ItemFlags AdvancedPrefsModel::flags(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return 0;
+
+ QModelIndex modelIndex = mapToSource(index);
+
+ PrefsItem* item = static_cast<PrefsItem*>(modelIndex.internalPointer());
+ if (item == NULL)
+ return 0;
+
+ Qt::ItemFlags flags = QAbstractItemModel::flags(index);
+ if (item->getPref() == NULL) {
+ /* Base modules aren't changable */
+ flags &= ~(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
+ } else {
+ flags |= Qt::ItemIsEditable;
+ }
+
+ return flags;
+}
+
+
+int AdvancedPrefsModel::columnCount(const QModelIndex&) const
+{
+ return colLast;
+}
+
+void AdvancedPrefsModel::setFirstColumnSpanned(QTreeView* tree, const QModelIndex& mIndex)
+{
+ int childCount, row;
+ PrefsItem* item;
+ if (mIndex.isValid()) {
+ item = VariantPointer<PrefsItem>::asPtr(data(mIndex, Qt::UserRole));
+ if (item != NULL) {
+ childCount = item->childCount();
+ if (childCount > 0) {
+ tree->setFirstColumnSpanned(mIndex.row(), mIndex.parent(), true);
+ for (row = 0; row < childCount; row++) {
+ setFirstColumnSpanned(tree, mIndex.child(row, 0));
+ }
+ }
+ }
+ } else {
+ for (row = 0; row < rowCount(); row++) {
+ setFirstColumnSpanned(tree, index(row, 0));
+ }
+ }
+}
+
+bool AdvancedPrefsModel::filterAcceptItem(PrefsItem& item) const
+{
+ if (filter_.isEmpty())
+ return true;
+
+ QString name, tooltip;
+ if (item.getPref() == NULL) {
+ name = item.getModule()->title;
+ tooltip = item.getModule()->description;
+ } else {
+ name = QString(item.getModule()->name ? item.getModule()->name : item.getModule()->parent->name);
+ name += QString(".%1").arg(prefs_get_name(item.getPref()));
+ tooltip = prefs_get_description(item.getPref());
+ }
+
+ if (name.contains(filter_, Qt::CaseInsensitive) || tooltip.contains(filter_, Qt::CaseInsensitive))
+ return true;
+
+ PrefsItem *child_item;
+ for (int child_row = 0; child_row < item.childCount(); child_row++)
+ {
+ child_item = item.child(child_row);
+ if ((child_item != NULL) && (filterAcceptItem(*child_item)))
+ return true;
+ }
+
+ return false;
+}
+
+bool AdvancedPrefsModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
+{
+ QModelIndex nameIdx = sourceModel()->index(sourceRow, PrefsModel::colName, sourceParent);
+ PrefsItem* item = static_cast<PrefsItem*>(nameIdx.internalPointer());
+ if (item == NULL)
+ return true;
+
+ //filter out the "special" preferences
+ if ((item->getModule() == NULL) && (item->getPref() == NULL))
+ return false;
+
+ if (filterAcceptItem(*item))
+ return true;
+
+ return false;
+}
+
+void AdvancedPrefsModel::setFilter(const QString& filter)
+{
+ filter_ = filter;
+ invalidateFilter();
+}
+
+
+
+
+
+ModulePrefsModel::ModulePrefsModel(QObject* parent)
+ : QSortFilterProxyModel(parent)
+ , advancedPrefName_(PrefsModel::ADVANCED_PREFERENCE_TREE_NAME)
+{
+}
+
+QVariant ModulePrefsModel::data(const QModelIndex &dataindex, int role) const
+{
+ if (!dataindex.isValid())
+ return QVariant();
+
+ QModelIndex modelIndex = mapToSource(dataindex);
+
+ PrefsItem* item = static_cast<PrefsItem*>(modelIndex.internalPointer());
+ if (item == NULL)
+ return QVariant();
+
+ switch (role)
+ {
+ case Qt::DisplayRole:
+ switch ((ModulePrefsModelColumn)dataindex.column())
+ {
+ case colName:
+ if (item->getPref() == NULL) {
+ if (item->getModule() == NULL) {
+ return item->getName();
+ }
+
+ return item->getModule()->title;
+ }
+
+ return sourceModel()->data(sourceModel()->index(modelIndex.row(), PrefsModel::colName, modelIndex.parent()), role);
+ default:
+ break;
+ }
+ break;
+ case Qt::UserRole:
+ return sourceModel()->data(modelIndex, role);
+ case ModuleName:
+ return item->getModuleName();
+ default:
+ break;
+ }
+
+ return QVariant();
+}
+Qt::ItemFlags ModulePrefsModel::flags(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return 0;
+
+ bool disable_capture = true;
+#ifdef HAVE_LIBPCAP
+#ifdef _WIN32
+ /* Is WPcap loaded? */
+ if (has_wpcap) {
+#endif /* _WIN32 */
+ disable_capture = false;
+#ifdef _WIN32
+ }
+#endif /* _WIN32 */
+#endif /* HAVE_LIBPCAP */
+
+ Qt::ItemFlags flags = QAbstractItemModel::flags(index);
+ if (disable_capture) {
+ QModelIndex modelIndex = mapToSource(index);
+
+ PrefsItem* item = static_cast<PrefsItem*>(modelIndex.internalPointer());
+ if (item == NULL)
+ return flags;
+
+ if (item->getName().compare(PrefsModel::CAPTURE_PREFERENCE_TREE_NAME) == 0) {
+ flags &= (~Qt::ItemIsEnabled);
+ }
+ }
+
+ return flags;
+}
+
+int ModulePrefsModel::columnCount(const QModelIndex&) const
+{
+ return colLast;
+}
+
+bool ModulePrefsModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
+{
+ //Force "Advanced" preferences to be at bottom of model
+ if (source_left.isValid() && !source_left.parent().isValid() &&
+ source_right.isValid() && !source_right.parent().isValid()) {
+ PrefsItem* left_item = static_cast<PrefsItem*>(source_left.internalPointer());
+ PrefsItem* right_item = static_cast<PrefsItem*>(source_right.internalPointer());
+ if ((left_item != NULL) && (left_item->getName().compare(advancedPrefName_) == 0)) {
+ return false;
+ }
+ if ((right_item != NULL) && (right_item->getName().compare(advancedPrefName_) == 0)) {
+ return true;
+ }
+ }
+
+
+ return QSortFilterProxyModel::lessThan(source_left, source_right);
+}
+
+bool ModulePrefsModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
+{
+ QModelIndex nameIdx = sourceModel()->index(sourceRow, PrefsModel::colName, sourceParent);
+ PrefsItem* item = static_cast<PrefsItem*>(nameIdx.internalPointer());
+ if (item == NULL)
+ return true;
+
+ if (item->getPref() != NULL)
+ return false;
+
+ if (item->getModule() != NULL) {
+ if (!item->getModule()->use_gui) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+
+
+/*
+ * Editor modelines
+ *
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * ex: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */
diff --git a/ui/qt/models/pref_models.h b/ui/qt/models/pref_models.h
new file mode 100644
index 0000000000..4914e61133
--- /dev/null
+++ b/ui/qt/models/pref_models.h
@@ -0,0 +1,173 @@
+/* pref_models.h
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef PREF_MODELS_H
+#define PREF_MODELS_H
+
+#include <config.h>
+
+#include <ui/qt/models/tree_model_helpers.h>
+
+#include <epan/prefs.h>
+
+#include <QSortFilterProxyModel>
+#include <QTreeView>
+
+class PrefsItem : public ModelHelperTreeItem<PrefsItem>
+{
+public:
+ PrefsItem(module_t *module, pref_t *pref, PrefsItem* parent);
+ PrefsItem(QString name, PrefsItem* parent);
+ virtual ~PrefsItem();
+
+ QString getName() const {return name_;}
+ pref_t* getPref() const {return pref_;}
+ int getPrefType() const;
+ int getPrefGUIType() const;
+ bool isPrefDefault() const;
+ QString getPrefTypeName() const;
+ module_t* getModule() const {return module_;}
+ QString getModuleName() const;
+ void setChanged(bool changed = true);
+
+private:
+ pref_t *pref_;
+ module_t *module_;
+ QString name_;
+ //set to true if changed during module manipulation
+ //Used to determine proper "default" for comparison
+ bool changed_;
+};
+
+
+class PrefsModel : public QAbstractItemModel
+{
+ Q_OBJECT
+
+public:
+ explicit PrefsModel(QObject * parent = Q_NULLPTR);
+ virtual ~PrefsModel();
+
+ //Names of special preferences handled by the GUI
+ //Names used as keys to determine correct pan displayed
+ static const char* ADVANCED_PREFERENCE_TREE_NAME;
+ static const char* APPEARANCE_PREFERENCE_TREE_NAME;
+ static const char* LAYOUT_PREFERENCE_TREE_NAME;
+ static const char* COLUMNS_PREFERENCE_TREE_NAME;
+ static const char* FONT_AND_COLORS_PREFERENCE_TREE_NAME;
+ static const char* CAPTURE_PREFERENCE_TREE_NAME;
+ static const char* EXPERT_PREFERENCE_TREE_NAME;
+ static const char* FILTER_BUTTONS_PREFERENCE_TREE_NAME;
+
+ enum PrefsModelColumn {
+ colName = 0,
+ colStatus,
+ colType,
+ colValue,
+ colLast
+ };
+
+ QModelIndex index(int row, int column,
+ const QModelIndex & = QModelIndex()) const;
+ QModelIndex parent(const QModelIndex &) const;
+ QVariant data(const QModelIndex &index, int role) const;
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+
+private:
+ void populate();
+
+ PrefsItem* root_;
+};
+
+class AdvancedPrefsModel : public QSortFilterProxyModel
+{
+ Q_OBJECT
+public:
+
+ explicit AdvancedPrefsModel(QObject * parent = Q_NULLPTR);
+
+ enum AdvancedPrefsModelColumn {
+ colName = 0,
+ colStatus,
+ colType,
+ colValue,
+ colLast
+ };
+
+ virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
+
+ void setFilter(const QString& filter);
+
+ QVariant headerData(int section, Qt::Orientation orientation,
+ int role = Qt::DisplayRole) const;
+ QVariant data(const QModelIndex &index, int role) const;
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
+
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+
+ //Keep the internals of model hidden from tree
+ void setFirstColumnSpanned(QTreeView* tree, const QModelIndex &index = QModelIndex());
+
+protected:
+ bool filterAcceptItem(PrefsItem& item) const;
+
+private:
+
+ QString filter_;
+};
+
+class ModulePrefsModel : public QSortFilterProxyModel
+{
+ Q_OBJECT
+public:
+
+ explicit ModulePrefsModel(QObject * parent = Q_NULLPTR);
+
+ enum ModulePrefsModelColumn {
+ colName = 0,
+ colLast
+ };
+
+ enum ModulePrefsRoles {
+ ModuleName = Qt::UserRole + 1
+ };
+
+ QVariant data(const QModelIndex &index, int role) const;
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+
+ virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
+
+protected:
+ bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const;
+
+private:
+ //cache of the translated "Advanced" preference name
+ QString advancedPrefName_;
+};
+
+extern pref_t *prefFromPrefPtr(void *pref_ptr);
+
+#endif // PREF_MODELS_H
+
+/*
+ * Editor modelines
+ *
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * ex: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */