aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Mann <mmann78@netscape.net>2018-01-08 19:43:36 -0500
committerAnders Broman <a.broman58@gmail.com>2018-02-14 07:45:47 +0000
commitf0db412f57effe6234edc78e1f438b735efae805 (patch)
treeafef4b6a0e893ed2805a2fe6de1396e0bbe896ed
parenta3e14cb514976a9354676a2caa7b001e50dc6189 (diff)
Convert coloring rules dialog to use model.
Change-Id: I12a465b5451bdbaea871828329d48fda3627fca3 Reviewed-on: https://code.wireshark.org/review/25372 Petri-Dish: Michael Mann <mmann78@netscape.net> Tested-by: Petri Dish Buildbot Reviewed-by: Anders Broman <a.broman58@gmail.com>
-rw-r--r--ui/qt/CMakeLists.txt4
-rw-r--r--ui/qt/Makefile.am4
-rw-r--r--ui/qt/coloring_rules_dialog.cpp420
-rw-r--r--ui/qt/coloring_rules_dialog.h51
-rw-r--r--ui/qt/coloring_rules_dialog.ui36
-rw-r--r--ui/qt/models/coloring_rules_delegate.cpp134
-rw-r--r--ui/qt/models/coloring_rules_delegate.h42
-rw-r--r--ui/qt/models/coloring_rules_model.cpp557
-rw-r--r--ui/qt/models/coloring_rules_model.h98
-rw-r--r--ui/qt/models/tree_model_helpers.h17
10 files changed, 1048 insertions, 315 deletions
diff --git a/ui/qt/CMakeLists.txt b/ui/qt/CMakeLists.txt
index 799ae3e547..e4c827427f 100644
--- a/ui/qt/CMakeLists.txt
+++ b/ui/qt/CMakeLists.txt
@@ -74,6 +74,8 @@ set(WIRESHARK_UTILS_HEADERS
set(WIRESHARK_MODEL_HEADERS
models/astringlist_list_model.h
models/cache_proxy_model.h
+ models/coloring_rules_delegate.h
+ models/coloring_rules_model.h
models/decode_as_delegate.h
models/decode_as_model.h
models/dissector_tables_model.h
@@ -297,6 +299,8 @@ set(WIRESHARK_UTILS_SRCS
set(WIRESHARK_MODEL_SRCS
models/astringlist_list_model.cpp
models/cache_proxy_model.cpp
+ models/coloring_rules_delegate.cpp
+ models/coloring_rules_model.cpp
models/decode_as_delegate.cpp
models/decode_as_model.cpp
models/dissector_tables_model.cpp
diff --git a/ui/qt/Makefile.am b/ui/qt/Makefile.am
index e1eaba1f6b..7426dd68d4 100644
--- a/ui/qt/Makefile.am
+++ b/ui/qt/Makefile.am
@@ -211,6 +211,8 @@ MOC_UTILS_HDRS = \
MOC_MODELS_HDRS = \
models/astringlist_list_model.h \
models/cache_proxy_model.h \
+ models/coloring_rules_delegate.h \
+ models/coloring_rules_model.h \
models/decode_as_delegate.h \
models/decode_as_model.h \
models/dissector_tables_model.h \
@@ -559,6 +561,8 @@ WIRESHARK_QT_UTILS_SRC = \
WIRESHARK_QT_MODELS_SRCS = \
models/astringlist_list_model.cpp \
models/cache_proxy_model.cpp \
+ models/coloring_rules_delegate.cpp \
+ models/coloring_rules_model.cpp \
models/decode_as_delegate.cpp \
models/decode_as_model.cpp \
models/dissector_tables_model.cpp \
diff --git a/ui/qt/coloring_rules_dialog.cpp b/ui/qt/coloring_rules_dialog.cpp
index ab19bb5613..6f9639bfc0 100644
--- a/ui/qt/coloring_rules_dialog.cpp
+++ b/ui/qt/coloring_rules_dialog.cpp
@@ -4,41 +4,27 @@
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
- * SPDX-License-Identifier: GPL-2.0-or-later*/
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
#include "config.h"
-#include <errno.h>
-
-#include <glib.h>
-
#include "coloring_rules_dialog.h"
#include <ui_coloring_rules_dialog.h>
-#include "epan/color_filters.h"
-
-#include "ui/simple_dialog.h"
#include "ui/simple_dialog.h"
-#include "epan/dfilter/dfilter.h"
#include "epan/prefs.h"
#include <wsutil/utf8_entities.h>
#include "wsutil/filesystem.h"
-#include <ui/qt/utils/color_utils.h>
-#include "ui/ws_ui_util.h"
-#include <ui/qt/widgets/display_filter_combo.h>
-#include <ui/qt/widgets/syntax_line_edit.h>
-#include <ui/qt/widgets/display_filter_edit.h>
#include "wireshark_application.h"
#include <QColorDialog>
-#include <QDir>
#include <QFileDialog>
#include <QMessageBox>
#include <QPushButton>
-#include <QTreeWidgetItemIterator>
/*
* @file Coloring Rules dialog
@@ -50,73 +36,58 @@
// - Make the filter column narrower? It's easy to run into Qt's annoying
// habit of horizontally scrolling QTreeWidgets here.
-
-enum {
- name_col_ = 0,
- filter_col_
-};
-
-static const QString new_rule_name_ = QObject::tr("New coloring rule");
-
ColoringRulesDialog::ColoringRulesDialog(QWidget *parent, QString add_filter) :
GeometryStateDialog(parent),
ui(new Ui::ColoringRulesDialog),
- conversation_colors_(NULL)
+ colorRuleModel_(palette().color(QPalette::Text), palette().color(QPalette::Base), this),
+ colorRuleDelegate_(this)
{
ui->setupUi(this);
if (parent) loadGeometry(parent->width() * 2 / 3, parent->height() * 4 / 5);
- setWindowTitle(wsApp->windowTitleString(QStringList() << tr("Coloring Rules") << get_profile_name()));
-
- ui->coloringRulesTreeWidget->setDragEnabled(true);
- ui->coloringRulesTreeWidget->viewport()->setAcceptDrops(true);
- ui->coloringRulesTreeWidget->setDropIndicatorShown(true);
- ui->coloringRulesTreeWidget->setDragDropMode(QAbstractItemView::InternalMove);
+ setWindowTitle(wsApp->windowTitleString(tr("Coloring Rules %1").arg(get_profile_name())));
- color_filters_clone(this, color_filter_add_cb);
+ ui->coloringRulesTreeView->setModel(&colorRuleModel_);
+ ui->coloringRulesTreeView->setItemDelegate(&colorRuleDelegate_);
- for (int i = 0; i < ui->coloringRulesTreeWidget->columnCount(); i++) {
- ui->coloringRulesTreeWidget->setItemDelegateForColumn(i, &coloring_rules_tree_delegate_);
- ui->coloringRulesTreeWidget->resizeColumnToContents(i);
- }
- coloring_rules_tree_delegate_.setTree(ui->coloringRulesTreeWidget);
+ ui->coloringRulesTreeView->viewport()->setAcceptDrops(true);
- if (!add_filter.isEmpty()) {
- addColoringRule(false, new_rule_name_, add_filter,
- palette().color(QPalette::Text),
- palette().color(QPalette::Base),
- true);
+ for (int i = 0; i < colorRuleModel_.columnCount(); i++) {
+ ui->coloringRulesTreeView->resizeColumnToContents(i);
}
- connect(ui->coloringRulesTreeWidget, SIGNAL(itemChanged(QTreeWidgetItem*,int)),
- this, SLOT(updateWidgets()));
+ connect(ui->coloringRulesTreeView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
+ this, SLOT(colorRuleSelectionChanged(const QItemSelection &, const QItemSelection &)));
+ connect(&colorRuleModel_, SIGNAL(dragDropComplete()),
+ this, SLOT(dragDropComplete()));
+ connect(&colorRuleDelegate_, SIGNAL(invalidField(const QModelIndex&, const QString&)),
+ this, SLOT(invalidField(const QModelIndex&, const QString&)));
+ connect(&colorRuleDelegate_, SIGNAL(validField(const QModelIndex&)),
+ this, SLOT(validField(const QModelIndex&)));
import_button_ = ui->buttonBox->addButton(tr("Import" UTF8_HORIZONTAL_ELLIPSIS), QDialogButtonBox::ApplyRole);
import_button_->setToolTip(tr("Select a file and add its filters to the end of the list."));
export_button_ = ui->buttonBox->addButton(tr("Export" UTF8_HORIZONTAL_ELLIPSIS), QDialogButtonBox::ApplyRole);
export_button_->setToolTip(tr("Save filters in a file."));
- updateWidgets();
+ if (!add_filter.isEmpty()) {
+ colorRuleModel_.addColor(false, add_filter, palette().color(QPalette::Text), palette().color(QPalette::Base));
+
+ //setup the buttons appropriately
+ ui->coloringRulesTreeView->setCurrentIndex(colorRuleModel_.index(0, 0));
+
+ //set edit on display filter
+ ui->coloringRulesTreeView->edit(colorRuleModel_.index(0, 1));
+ }else {
+ ui->coloringRulesTreeView->setCurrentIndex(QModelIndex());
+ }
+
+ updateHint();
}
ColoringRulesDialog::~ColoringRulesDialog()
{
delete ui;
- color_filter_list_delete(&conversation_colors_);
-}
-
-void ColoringRulesDialog::addColor(_color_filter *colorf)
-{
- if (!colorf) return;
-
- if(strstr(colorf->filter_name, CONVERSATION_COLOR_PREFIX) != NULL) {
- conversation_colors_ = g_slist_append(conversation_colors_, colorf);
- } else {
- addColoringRule(colorf->disabled, colorf->filter_name, colorf->filter_text,
- ColorUtils::fromColorT(colorf->fg_color),
- ColorUtils::fromColorT(colorf->bg_color),
- false, false);
- }
}
void ColoringRulesDialog::showEvent(QShowEvent *)
@@ -126,124 +97,113 @@ void ColoringRulesDialog::showEvent(QShowEvent *)
ui->displayFilterPushButton->setFixedHeight(ui->copyToolButton->geometry().height());
}
-void ColoringRulesDialog::updateWidgets()
+void ColoringRulesDialog::invalidField(const QModelIndex &index, const QString& errMessage)
{
- QString hint = "<small><i>";
- int num_selected = ui->coloringRulesTreeWidget->selectedItems().count();
+ errors_.insert(index, errMessage);
+ updateHint();
+}
- if (num_selected == 1) {
- QTreeWidgetItem *ti = ui->coloringRulesTreeWidget->currentItem();
- QString color_button_ss =
- "QPushButton {"
- " border: 1px solid palette(Dark);"
- " padding-left: %1px;"
- " padding-right: %1px;"
- " color: %2;"
- " background-color: %3;"
- "}";
- int one_em = fontMetrics().height();
- QString fg_color = ti->foreground(0).color().name();
- QString bg_color = ti->background(0).color().name();
- ui->fGPushButton->setStyleSheet(color_button_ss.arg(one_em).arg(bg_color).arg(fg_color));
- ui->bGPushButton->setStyleSheet(color_button_ss.arg(one_em).arg(fg_color).arg(bg_color));
+void ColoringRulesDialog::validField(const QModelIndex &index)
+{
+ if (errors_.remove(index) > 0) {
+ updateHint();
}
+}
- ui->copyToolButton->setEnabled(num_selected == 1);
- ui->deleteToolButton->setEnabled(num_selected > 0);
- ui->fGPushButton->setVisible(num_selected == 1);
- ui->bGPushButton->setVisible(num_selected == 1);
- ui->displayFilterPushButton->setVisible(num_selected == 1);
-
+void ColoringRulesDialog::updateHint()
+{
+ QString hint = "<small><i>";
QString error_text;
- QTreeWidgetItemIterator iter(ui->coloringRulesTreeWidget);
bool enable_save = true;
- while (*iter) {
- QTreeWidgetItem *item = (*iter);
- if (item->text(name_col_).contains("@")) {
- error_text = tr("the \"@\" symbol will be ignored.");
- }
-
- // Check the rule's display filter syntax only if it's checked.
- QString display_filter = item->text(filter_col_);
- if (!display_filter.isEmpty() && item->checkState(name_col_) == Qt::Checked) {
- dfilter_t *dfilter;
- bool status;
- gchar *err_msg;
- status = dfilter_compile(display_filter.toUtf8().constData(), &dfilter, &err_msg);
- dfilter_free(dfilter);
- if (!status) {
- if (!error_text.isEmpty()) error_text += " ";
- error_text += err_msg;
- g_free(err_msg);
- enable_save = false;
- }
- }
-
- if (!error_text.isEmpty()) {
- error_text.prepend(QString("%1: ").arg(item->text(name_col_)));
- break;
- }
- ++iter;
+ if (errors_.count() > 0) {
+ //take the list of QModelIndexes and sort them so first color rule error is displayed
+ //This isn't the most efficent algorithm, but the list shouldn't be large to matter
+ QList<QModelIndex> keys = errors_.keys();
+
+ //list is not guaranteed to be sorted, so force it
+ qSort(keys.begin(), keys.end());
+ const QModelIndex& error_key = keys[0];
+ error_text = QString("%1: %2")
+ .arg(colorRuleModel_.data(colorRuleModel_.index(error_key.row(), ColoringRulesModel::colName), Qt::DisplayRole).toString())
+ .arg(errors_[error_key]);
}
if (error_text.isEmpty()) {
hint += tr("Double click to edit. Drag to move. Rules are processed in order until a match is found.");
} else {
hint += error_text;
+ enable_save = false;
}
+
hint += "</i></small>";
ui->hintLabel->setText(hint);
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(enable_save);
}
-GSList *ColoringRulesDialog::createColorFilterList()
+void ColoringRulesDialog::setColorButtons(QModelIndex &index)
{
- GSList *cfl = NULL;
- QTreeWidgetItemIterator iter(ui->coloringRulesTreeWidget);
-
- while (*iter) {
- QTreeWidgetItem *item = (*iter);
- color_t fg = ColorUtils::toColorT(item->foreground(0).color());
- color_t bg = ColorUtils::toColorT(item->background(0).color());
- color_filter_t *colorf = color_filter_new(item->text(name_col_).toUtf8().constData(),
- item->text(filter_col_).toUtf8().constData(),
- &bg, &fg, item->checkState(0) == Qt::Unchecked);
- cfl = g_slist_append(cfl, colorf);
- ++iter;
+ QString color_button_ss =
+ "QPushButton {"
+ " border: 1px solid palette(Dark);"
+ " padding-left: %1px;"
+ " padding-right: %1px;"
+ " color: %2;"
+ " background-color: %3;"
+ "}";
+
+ int one_em = fontMetrics().height();
+ QVariant fg = colorRuleModel_.data(index, Qt::ForegroundRole);
+ QVariant bg = colorRuleModel_.data(index, Qt::BackgroundRole);
+ if (fg.isNull() || bg.isNull()) {
+ //should never happen
+ ui->fGPushButton->setVisible(false);
+ ui->bGPushButton->setVisible(false);
+ } else {
+ QString fg_color = fg.toString();
+ QString bg_color = bg.toString();
+
+ ui->fGPushButton->setStyleSheet(color_button_ss.arg(one_em).arg(bg_color).arg(fg_color));
+ ui->bGPushButton->setStyleSheet(color_button_ss.arg(one_em).arg(fg_color).arg(bg_color));
}
- return cfl;
}
-void ColoringRulesDialog::on_coloringRulesTreeWidget_itemSelectionChanged()
+void ColoringRulesDialog::colorRuleSelectionChanged(const QItemSelection&, const QItemSelection&)
{
- updateWidgets();
+ QModelIndexList selectedList = ui->coloringRulesTreeView->selectionModel()->selectedIndexes();
+
+ //determine the number of unique rows
+ QHash<int, QModelIndex> selectedRows;
+ foreach (const QModelIndex &index, selectedList) {
+ selectedRows.insert(index.row(), index);
+ }
+
+ int num_selected = selectedRows.count();
+ if (num_selected == 1) {
+ setColorButtons(selectedList[0]);
+ }
+
+ ui->copyToolButton->setEnabled(num_selected == 1);
+ ui->deleteToolButton->setEnabled(num_selected > 0);
+ ui->fGPushButton->setVisible(num_selected == 1);
+ ui->bGPushButton->setVisible(num_selected == 1);
+ ui->displayFilterPushButton->setVisible(num_selected == 1);
}
void ColoringRulesDialog::changeColor(bool foreground)
{
- if (!ui->coloringRulesTreeWidget->currentItem()) return;
+ QModelIndex current = ui->coloringRulesTreeView->currentIndex();
+ if (!current.isValid())
+ return;
- QTreeWidgetItem *ti = ui->coloringRulesTreeWidget->currentItem();
QColorDialog color_dlg;
- color_dlg.setCurrentColor(foreground ?
- ti->foreground(0).color() : ti->background(0).color());
+ color_dlg.setCurrentColor(colorRuleModel_.data(current, foreground ? Qt::ForegroundRole : Qt::BackgroundRole).toString());
if (color_dlg.exec() == QDialog::Accepted) {
- QColor cc = color_dlg.currentColor();
- if (foreground) {
- for (int i = 0; i < ui->coloringRulesTreeWidget->columnCount(); i++) {
- ti->setForeground(i, cc);
- }
- } else {
- for (int i = 0; i < ui->coloringRulesTreeWidget->columnCount(); i++) {
- ti->setBackground(i, cc);
- }
- }
- updateWidgets();
+ colorRuleModel_.setData(current, color_dlg.currentColor(), foreground ? Qt::ForegroundRole : Qt::BackgroundRole);
+ setColorButtons(current);
}
-
}
void ColoringRulesDialog::on_fGPushButton_clicked()
@@ -258,107 +218,99 @@ void ColoringRulesDialog::on_bGPushButton_clicked()
void ColoringRulesDialog::on_displayFilterPushButton_clicked()
{
- if (!ui->coloringRulesTreeWidget->currentItem()) return;
-
- QTreeWidgetItem *ti = ui->coloringRulesTreeWidget->currentItem();
- QString filter = ti->text(filter_col_);
+ QModelIndex current = ui->coloringRulesTreeView->currentIndex();
+ if (!current.isValid())
+ return;
+ QString filter = colorRuleModel_.data(colorRuleModel_.index(current.row(), ColoringRulesModel::colFilter), Qt::DisplayRole).toString();
emit filterAction(filter, FilterAction::ActionApply, FilterAction::ActionTypePlain);
}
-void ColoringRulesDialog::addColoringRule(bool disabled, QString name, QString filter, QColor foreground, QColor background, bool start_editing, bool at_top)
+void ColoringRulesDialog::addRule(bool copy_from_current)
{
- QTreeWidgetItem *ti = new QTreeWidgetItem();
-
- ti->setFlags(ti->flags() | Qt::ItemIsUserCheckable | Qt::ItemIsEditable);
- ti->setFlags(ti->flags() & ~(Qt::ItemIsDropEnabled));
- ti->setCheckState(name_col_, disabled ? Qt::Unchecked : Qt::Checked);
- ti->setText(name_col_, name);
- ti->setText(filter_col_, filter);
+ const QModelIndex &current = ui->coloringRulesTreeView->currentIndex();
+ if (copy_from_current && !current.isValid())
+ return;
- for (int i = 0; i < ui->coloringRulesTreeWidget->columnCount(); i++) {
- ti->setForeground(i, foreground);
- ti->setBackground(i, background);
- }
-
- if (at_top) {
- ui->coloringRulesTreeWidget->insertTopLevelItem(0, ti);
+ //always add rules at the top of the list
+ if (copy_from_current) {
+ colorRuleModel_.copyRow(colorRuleModel_.index(0, 0).row(), current.row());
} else {
- ui->coloringRulesTreeWidget->addTopLevelItem(ti);
+ if (!colorRuleModel_.insertRows(0, 1)) {
+ return;
+ }
}
- if (start_editing) {
- ui->coloringRulesTreeWidget->setCurrentItem(ti);
- updateWidgets();
- ui->coloringRulesTreeWidget->editItem(ti, filter_col_);
- }
+ //set edit on display filter
+ ui->coloringRulesTreeView->edit(colorRuleModel_.index(0, 1));
}
void ColoringRulesDialog::on_newToolButton_clicked()
{
- addColoringRule(false, new_rule_name_, QString(), palette().color(QPalette::Text),
- palette().color(QPalette::Base), true);
+ addRule();
}
void ColoringRulesDialog::on_deleteToolButton_clicked()
{
- QList<QTreeWidgetItem*> selected = ui->coloringRulesTreeWidget->selectedItems();
- foreach (QTreeWidgetItem *ti, selected) {
- delete ti;
+ QModelIndexList selectedList = ui->coloringRulesTreeView->selectionModel()->selectedIndexes();
+ int num_selected = selectedList.count()/colorRuleModel_.columnCount();
+ if (num_selected > 0) {
+ //list is not guaranteed to be sorted, so force it
+ qSort(selectedList.begin(), selectedList.end());
+
+ //walk the list from the back because deleting a value in
+ //the middle will leave the selectedList out of sync and
+ //delete the wrong elements
+ for (int i = selectedList.count()-1; i >= 0; i--) {
+ QModelIndex deleteIndex = selectedList[i];
+ //selectedList includes all cells, use first column as key to remove row
+ if (deleteIndex.isValid() && (deleteIndex.column() == 0)) {
+ colorRuleModel_.removeRows(deleteIndex.row(), 1);
+ }
+ }
}
- updateWidgets();
}
void ColoringRulesDialog::on_copyToolButton_clicked()
{
- if (!ui->coloringRulesTreeWidget->currentItem()) return;
- QTreeWidgetItem *ti = ui->coloringRulesTreeWidget->currentItem();
-
- addColoringRule(ti->checkState(0) == Qt::Unchecked, ti->text(name_col_),
- ti->text(filter_col_), ti->foreground(0).color(),
- ti->background(0).color(), true);
+ addRule(true);
}
void ColoringRulesDialog::on_buttonBox_clicked(QAbstractButton *button)
{
+ QString err;
+
if (button == import_button_) {
QString file_name = QFileDialog::getOpenFileName(this, wsApp->windowTitleString(tr("Import Coloring Rules")),
wsApp->lastOpenDir().path());
if (!file_name.isEmpty()) {
- gchar* err_msg = NULL;
- if (!color_filters_import(file_name.toUtf8().constData(), this, &err_msg, color_filter_add_cb)) {
- simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_msg);
- g_free(err_msg);
+ if (!colorRuleModel_.importColors(file_name, err)) {
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err.toUtf8().constData());
}
}
} else if (button == export_button_) {
- int num_items = ui->coloringRulesTreeWidget->selectedItems().count();
+ int num_items = ui->coloringRulesTreeView->selectionModel()->selectedIndexes().count()/colorRuleModel_.columnCount();
if (num_items < 1) {
- num_items = ui->coloringRulesTreeWidget->topLevelItemCount();
+ num_items = colorRuleModel_.rowCount();
}
- if (num_items < 1) return;
+ if (num_items < 1)
+ return;
QString caption = wsApp->windowTitleString(tr("Export %1 Coloring Rules").arg(num_items));
QString file_name = QFileDialog::getSaveFileName(this, caption,
wsApp->lastOpenDir().path());
if (!file_name.isEmpty()) {
- GSList *cfl = createColorFilterList();
- gchar* err_msg = NULL;
- if (!color_filters_export(file_name.toUtf8().constData(), cfl, FALSE, &err_msg)) {
- simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_msg);
- g_free(err_msg);
+ if (!colorRuleModel_.exportColors(file_name, err)) {
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err.toUtf8().constData());
}
- color_filter_list_delete(&cfl);
}
}
}
void ColoringRulesDialog::on_buttonBox_accepted()
{
- GSList *cfl = createColorFilterList();
- gchar* err_msg = NULL;
if (prefs.unknown_colorfilters) {
QMessageBox mb;
mb.setText(tr("Your coloring rules file contains unknown rules"));
@@ -369,15 +321,11 @@ void ColoringRulesDialog::on_buttonBox_accepted()
int result = mb.exec();
if (result != QMessageBox::Save) return;
}
- if (!color_filters_apply(conversation_colors_, cfl, &err_msg)) {
- simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_msg);
- g_free(err_msg);
- }
- if (!color_filters_write(cfl, &err_msg)) {
- QMessageBox::warning(this, tr("Unable to save coloring rules: %s"), g_strerror(errno));
- g_free(err_msg);
+
+ QString err;
+ if (!colorRuleModel_.writeColors(err)) {
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err.toUtf8().constData());
}
- color_filter_list_delete(&cfl);
}
void ColoringRulesDialog::on_buttonBox_helpRequested()
@@ -385,70 +333,6 @@ void ColoringRulesDialog::on_buttonBox_helpRequested()
wsApp->helpTopicAction(HELP_COLORING_RULES_DIALOG);
}
-//
-// ColoringRulesTreeDelegate
-// Delegate for editing coloring rule names and filters.
-//
-
-QWidget *ColoringRulesTreeDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &index) const
-{
- QWidget *w = NULL;
-
- QTreeWidgetItem *ti = tree_->topLevelItem(index.row());
- if (!ti) return NULL;
-
- switch (index.column()) {
- case name_col_:
- {
- SyntaxLineEdit *sle = new SyntaxLineEdit(parent);
- connect(sle, SIGNAL(textChanged(QString)), this, SLOT(ruleNameChanged(QString)));
- sle->setText(ti->text(name_col_));
- w = (QWidget*) sle;
- }
- break;
-
- case filter_col_:
- {
- DisplayFilterEdit *dfe = new DisplayFilterEdit(parent);
- // It's possible to have an invalid filter and an enabled OK button at this point.
- // We might want to add a local slot for checking the filter status.
- connect(dfe, SIGNAL(textChanged(QString)), dfe, SLOT(checkDisplayFilter(QString)));
- dfe->setText(ti->text(filter_col_));
- w = (QWidget*) dfe;
- }
- break;
- default:
- break;
- }
-
- return w;
-}
-
-void ColoringRulesTreeDelegate::ruleNameChanged(const QString name)
-{
- SyntaxLineEdit *name_edit = qobject_cast<SyntaxLineEdit*>(QObject::sender());
- if (!name_edit) return;
-
- if (name.isEmpty()) {
- name_edit->setSyntaxState(SyntaxLineEdit::Empty);
- } else if (name.contains("@")) {
- name_edit->setSyntaxState(SyntaxLineEdit::Invalid);
- } else {
- name_edit->setSyntaxState(SyntaxLineEdit::Valid);
- }
-
-}
-
-// Callback for color_filters_clone.
-void
-color_filter_add_cb(color_filter_t *colorf, gpointer user_data)
-{
- ColoringRulesDialog *coloring_rules_dialog = static_cast<ColoringRulesDialog*>(user_data);
-
- if (!coloring_rules_dialog) return;
- coloring_rules_dialog->addColor(colorf);
-}
-
/*
* Editor modelines
*
diff --git a/ui/qt/coloring_rules_dialog.h b/ui/qt/coloring_rules_dialog.h
index c1c5e6d5fc..e9860bb8f8 100644
--- a/ui/qt/coloring_rules_dialog.h
+++ b/ui/qt/coloring_rules_dialog.h
@@ -4,7 +4,8 @@
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
- * SPDX-License-Identifier: GPL-2.0-or-later*/
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
#ifndef COLORING_RULES_DIALOG_H
#define COLORING_RULES_DIALOG_H
@@ -12,36 +13,17 @@
#include "geometry_state_dialog.h"
#include "filter_action.h"
-class QAbstractButton;
-class QTreeWidget;
+#include <ui/qt/models/coloring_rules_model.h>
+#include <ui/qt/models/coloring_rules_delegate.h>
-struct _color_filter;
-struct _GSList; // This is a completely and totally safe forward declaration, right?
+#include <QMap>
+
+class QAbstractButton;
namespace Ui {
class ColoringRulesDialog;
}
-#include <QStyledItemDelegate>
-
-class ColoringRulesTreeDelegate : public QStyledItemDelegate
-{
- Q_OBJECT
-
-public:
- ColoringRulesTreeDelegate(QObject *parent = 0) : QStyledItemDelegate(parent), tree_(NULL) {}
- ~ColoringRulesTreeDelegate() {}
-
- QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
- void setTree(QTreeWidget* tree) { tree_ = tree; }
-
-private:
- QTreeWidget* tree_;
-
-private slots:
- void ruleNameChanged(const QString name);
-};
-
class ColoringRulesDialog : public GeometryStateDialog
{
Q_OBJECT
@@ -50,8 +32,6 @@ public:
explicit ColoringRulesDialog(QWidget *parent = 0, QString add_filter = QString());
~ColoringRulesDialog();
- void addColor(struct _color_filter *colorf);
-
signals:
void filterAction(QString filter, FilterAction::Action action, FilterAction::ActionType type);
@@ -59,9 +39,7 @@ protected:
void showEvent(QShowEvent *);
private slots:
- void updateWidgets();
- struct _GSList *createColorFilterList();
- void on_coloringRulesTreeWidget_itemSelectionChanged();
+ void colorRuleSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
void on_fGPushButton_clicked();
void on_bGPushButton_clicked();
void on_displayFilterPushButton_clicked();
@@ -71,15 +49,22 @@ private slots:
void on_buttonBox_clicked(QAbstractButton *button);
void on_buttonBox_accepted();
void on_buttonBox_helpRequested();
+ void invalidField(const QModelIndex &index, const QString& errMessage);
+ void validField(const QModelIndex &index);
private:
Ui::ColoringRulesDialog *ui;
QPushButton *import_button_;
QPushButton *export_button_;
- ColoringRulesTreeDelegate coloring_rules_tree_delegate_;
- struct _GSList *conversation_colors_;
+ ColoringRulesModel colorRuleModel_;
+ ColoringRulesDelegate colorRuleDelegate_;
+
+ QMap<QModelIndex, QString> errors_;
+
+ void setColorButtons(QModelIndex &index);
+ void updateHint();
- void addColoringRule(bool disabled, QString name, QString filter, QColor foreground, QColor background, bool start_editing = false, bool at_top = true);
+ void addRule(bool copy_from_current = false);
void changeColor(bool foreground = true);
};
diff --git a/ui/qt/coloring_rules_dialog.ui b/ui/qt/coloring_rules_dialog.ui
index 667f74a7ee..28c56104d5 100644
--- a/ui/qt/coloring_rules_dialog.ui
+++ b/ui/qt/coloring_rules_dialog.ui
@@ -15,7 +15,7 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
- <widget class="TabnavTreeWidget" name="coloringRulesTreeWidget">
+ <widget class="TabnavTreeView" name="coloringRulesTreeView">
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
@@ -34,16 +34,15 @@
<property name="expandsOnDoubleClick">
<bool>false</bool>
</property>
- <column>
- <property name="text">
- <string>Name</string>
- </property>
- </column>
- <column>
- <property name="text">
- <string>Filter</string>
- </property>
- </column>
+ <property name="dragEnabled">
+ <bool>true</bool>
+ </property>
+ <property name="DropIndicatorShown">
+ <bool>true</bool>
+ </property>
+ <property name="dragDropMode">
+ <enum>QAbstractItemView::InternalMove</enum>
+ </property>
</widget>
</item>
<item>
@@ -114,6 +113,9 @@
<property name="flat">
<bool>true</bool>
</property>
+ <property name="visible">
+ <bool>false</bool>
+ </property>
</widget>
</item>
<item>
@@ -133,6 +135,9 @@
<property name="flat">
<bool>true</bool>
</property>
+ <property name="visible">
+ <bool>false</bool>
+ </property>
</widget>
</item>
<item>
@@ -146,6 +151,9 @@
<property name="autoDefault">
<bool>false</bool>
</property>
+ <property name="visible">
+ <bool>false</bool>
+ </property>
</widget>
</item>
<item>
@@ -177,9 +185,9 @@
</widget>
<customwidgets>
<customwidget>
- <class>TabnavTreeWidget</class>
- <extends>QTreeWidget</extends>
- <header>tabnav_tree_widget.h</header>
+ <class>TabnavTreeView</class>
+ <extends>QTreeView</extends>
+ <header>widgets/tabnav_tree_view.h</header>
</customwidget>
</customwidgets>
<resources>
diff --git a/ui/qt/models/coloring_rules_delegate.cpp b/ui/qt/models/coloring_rules_delegate.cpp
new file mode 100644
index 0000000000..a15c2e44a3
--- /dev/null
+++ b/ui/qt/models/coloring_rules_delegate.cpp
@@ -0,0 +1,134 @@
+/* coloring_rules_delegate.cpp
+ * Delegates for editing various coloring rule fields.
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <ui/qt/models/coloring_rules_delegate.h>
+#include <ui/qt/models/coloring_rules_model.h>
+#include <ui/qt/widgets/display_filter_edit.h>
+
+ColoringRulesDelegate::ColoringRulesDelegate(QObject *parent) : QStyledItemDelegate(parent)
+{
+}
+
+QWidget* ColoringRulesDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem&,
+ const QModelIndex &index) const
+{
+ switch (index.column())
+ {
+ case ColoringRulesModel::colName:
+ {
+ SyntaxLineEdit *editor = new SyntaxLineEdit(parent);
+ connect(editor, SIGNAL(textChanged(QString)), this, SLOT(ruleNameChanged(QString)));
+ return editor;
+ }
+
+ case ColoringRulesModel::colFilter:
+ return new DisplayFilterEdit(parent);
+
+ default:
+ Q_ASSERT(FALSE);
+ return 0;
+ }
+
+ return 0;
+}
+
+void ColoringRulesDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
+{
+ switch (index.column())
+ {
+ case ColoringRulesModel::colName:
+ {
+ SyntaxLineEdit *syntaxEdit = static_cast<SyntaxLineEdit*>(editor);
+ syntaxEdit->setText(index.model()->data(index, Qt::EditRole).toString());
+ break;
+ }
+ case ColoringRulesModel::colFilter:
+ {
+ DisplayFilterEdit *displayEdit = static_cast<DisplayFilterEdit*>(editor);
+ displayEdit->setText(index.model()->data(index, Qt::EditRole).toString());
+ break;
+ }
+ default:
+ QStyledItemDelegate::setEditorData(editor, index);
+ break;
+ }
+}
+
+void ColoringRulesDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
+ const QModelIndex &index) const
+{
+ switch (index.column())
+ {
+ case ColoringRulesModel::colName:
+ {
+ SyntaxLineEdit *syntaxEdit = static_cast<SyntaxLineEdit*>(editor);
+ model->setData(index, syntaxEdit->text(), Qt::EditRole);
+ if (syntaxEdit->syntaxState() == SyntaxLineEdit::Invalid) {
+ QString error_text = tr("the \"@\" symbol will be ignored.");
+ emit invalidField(index, error_text);
+ }
+ else
+ {
+ emit validField(index);
+ }
+ break;
+ }
+ case ColoringRulesModel::colFilter:
+ {
+ DisplayFilterEdit *displayEdit = static_cast<DisplayFilterEdit*>(editor);
+ model->setData(index, displayEdit->text(), Qt::EditRole);
+ if ((displayEdit->syntaxState() == SyntaxLineEdit::Invalid) &&
+ (model->data(model->index(index.row(), ColoringRulesModel::colName), Qt::CheckStateRole) == Qt::Checked))
+ {
+ emit invalidField(index, displayEdit->syntaxErrorMessage());
+ }
+ else
+ {
+ emit validField(index);
+ }
+ break;
+ }
+ default:
+ QStyledItemDelegate::setModelData(editor, model, index);
+ break;
+ }
+}
+
+void ColoringRulesDelegate::updateEditorGeometry(QWidget *editor,
+ const QStyleOptionViewItem &option, const QModelIndex&) const
+{
+ editor->setGeometry(option.rect);
+}
+
+void ColoringRulesDelegate::ruleNameChanged(const QString name)
+{
+ SyntaxLineEdit *name_edit = qobject_cast<SyntaxLineEdit*>(QObject::sender());
+ if (!name_edit) return;
+
+ if (name.isEmpty()) {
+ name_edit->setSyntaxState(SyntaxLineEdit::Empty);
+ } else if (name.contains("@")) {
+ name_edit->setSyntaxState(SyntaxLineEdit::Invalid);
+ } else {
+ name_edit->setSyntaxState(SyntaxLineEdit::Valid);
+ }
+}
+
+/* * 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/coloring_rules_delegate.h b/ui/qt/models/coloring_rules_delegate.h
new file mode 100644
index 0000000000..3daf8cb60b
--- /dev/null
+++ b/ui/qt/models/coloring_rules_delegate.h
@@ -0,0 +1,42 @@
+/* coloring_rules_delegate.h
+ * Delegates for editing various coloring rule fields.
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef COLORING_RULE_DELEGATE_H
+#define COLORING_RULE_DELEGATE_H
+
+#include <config.h>
+
+#include <QStyledItemDelegate>
+#include <QModelIndex>
+
+class ColoringRulesDelegate : public QStyledItemDelegate
+{
+ Q_OBJECT
+
+public:
+ ColoringRulesDelegate(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;
+
+ void updateEditorGeometry(QWidget *editor,
+ const QStyleOptionViewItem &option, const QModelIndex &index) const;
+
+signals:
+ void invalidField(const QModelIndex &index, const QString& errMessage) const;
+ void validField(const QModelIndex &index) const;
+
+private slots:
+ void ruleNameChanged(const QString name);
+};
+#endif // COLORING_RULE_DELEGATE_H
diff --git a/ui/qt/models/coloring_rules_model.cpp b/ui/qt/models/coloring_rules_model.cpp
new file mode 100644
index 0000000000..cc210c2aa0
--- /dev/null
+++ b/ui/qt/models/coloring_rules_model.cpp
@@ -0,0 +1,557 @@
+/* coloring_rules_model.cpp
+ * Data model for coloring rules.
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include "config.h"
+
+#include "coloring_rules_model.h"
+
+#include <errno.h>
+
+#include "ui/ws_ui_util.h" //for color_filter_add_cb
+
+#include <ui/qt/utils/color_utils.h>
+#include <ui/qt/utils/qt_ui_utils.h>
+#include <ui/qt/utils/variant_pointer.h>
+
+#include <QMimeData>
+
+
+static const QString new_rule_name_ = QObject::tr("New coloring rule");
+static const QString color_rule_mime_type_ = "application/x-wireshark-coloring-rules";
+
+ColoringRuleItem::ColoringRuleItem(bool disabled, QString name, QString filter, QColor foreground, QColor background, ColoringRuleItem* parent)
+ : ModelHelperTreeItem<ColoringRuleItem>(parent),
+ disabled_(disabled),
+ name_(name),
+ filter_(filter),
+ foreground_(foreground),
+ background_(background)
+{
+}
+
+ColoringRuleItem::~ColoringRuleItem()
+{
+
+}
+
+ColoringRuleItem::ColoringRuleItem(color_filter_t *colorf, ColoringRuleItem* parent)
+ : ModelHelperTreeItem<ColoringRuleItem>(parent),
+ disabled_(colorf->disabled),
+ name_(colorf->filter_name),
+ filter_(colorf->filter_text),
+ foreground_(ColorUtils::fromColorT(colorf->fg_color)),
+ background_(ColorUtils::fromColorT(colorf->bg_color))
+{
+}
+
+ColoringRuleItem::ColoringRuleItem(const ColoringRuleItem& item)
+ : ModelHelperTreeItem<ColoringRuleItem>(item.parent_),
+ disabled_(item.disabled_),
+ name_(item.name_),
+ filter_(item.filter_),
+ foreground_(item.foreground_),
+ background_(item.background_)
+{
+}
+
+// Callback for color_filters_clone.
+void
+color_filter_add_cb(color_filter_t *colorf, gpointer user_data)
+{
+ ColoringRulesModel *model = (ColoringRulesModel*)user_data;
+
+ if (model == NULL)
+ return;
+
+ model->addColor(colorf);
+}
+
+ColoringRulesModel::ColoringRulesModel(QColor defaultForeground, QColor defaultBackground, QObject *parent) :
+ QAbstractItemModel(parent),
+ root_(new ColoringRuleItem(false, "", "", QColor(), QColor(), NULL)),
+ conversation_colors_(NULL),
+ defaultForeground_(defaultForeground),
+ defaultBackground_(defaultBackground)
+
+{
+ color_filters_clone(this, color_filter_add_cb);
+}
+
+ColoringRulesModel::~ColoringRulesModel()
+{
+ delete root_;
+ color_filter_list_delete(&conversation_colors_);
+}
+
+GSList *ColoringRulesModel::createColorFilterList()
+{
+ GSList *cfl = NULL;
+ for (int row = 0; row < root_->childCount(); row++)
+ {
+ ColoringRuleItem* rule = root_->child(row);
+ if (rule == NULL)
+ continue;
+
+ color_t fg = ColorUtils::toColorT(rule->foreground_);
+ color_t bg = ColorUtils::toColorT(rule->background_);
+ color_filter_t *colorf = color_filter_new(rule->name_.toUtf8().constData(),
+ rule->filter_.toUtf8().constData(),
+ &bg, &fg, rule->disabled_);
+ cfl = g_slist_append(cfl, colorf);
+ }
+
+ return cfl;
+}
+
+void ColoringRulesModel::addColor(color_filter_t* colorf)
+{
+ if (!colorf) return;
+
+ if(strstr(colorf->filter_name, CONVERSATION_COLOR_PREFIX) != NULL) {
+ conversation_colors_ = g_slist_append(conversation_colors_, colorf);
+ } else {
+ int count = root_->childCount();
+
+ beginInsertRows(QModelIndex(), count, count);
+ ColoringRuleItem* item = new ColoringRuleItem(colorf, root_);
+ root_->appendChild(item);
+ endInsertRows();
+ }
+}
+
+void ColoringRulesModel::addColor(bool disabled, QString filter, QColor foreground, QColor background)
+{
+ //add rule to top of the list
+ beginInsertRows(QModelIndex(), 0, 0);
+ ColoringRuleItem* item = new ColoringRuleItem(disabled, new_rule_name_, filter, foreground, background, root_);
+ root_->prependChild(item);
+ endInsertRows();
+}
+
+
+bool ColoringRulesModel::importColors(QString filename, QString& err)
+{
+ bool success = true;
+ gchar* err_msg = NULL;
+ if (!color_filters_import(filename.toUtf8().constData(), this, &err_msg, color_filter_add_cb)) {
+ err = gchar_free_to_qstring(err_msg);
+ success = false;
+ }
+
+ return success;
+}
+
+bool ColoringRulesModel::exportColors(QString filename, QString& err)
+{
+ GSList *cfl = createColorFilterList();
+ bool success = true;
+ gchar* err_msg = NULL;
+ if (!color_filters_export(filename.toUtf8().constData(), cfl, FALSE, &err_msg)) {
+ err = gchar_free_to_qstring(err_msg);
+ success = false;
+ }
+ color_filter_list_delete(&cfl);
+
+ return success;
+}
+
+bool ColoringRulesModel::writeColors(QString& err)
+{
+ GSList *cfl = createColorFilterList();
+ bool success = true;
+ gchar* err_msg = NULL;
+ if (!color_filters_apply(conversation_colors_, cfl, &err_msg)) {
+ err = gchar_free_to_qstring(err_msg);
+ success = false;
+ }
+ if (!color_filters_write(cfl, &err_msg)) {
+ err = QString(tr("Unable to save coloring rules: %1").arg(g_strerror(errno)));
+ success = false;
+ g_free(err_msg);
+ }
+ color_filter_list_delete(&cfl);
+
+ return success;
+}
+
+bool ColoringRulesModel::insertRows(int row, int count, const QModelIndex& parent)
+{
+ // sanity check insertion
+ if (row < 0 )
+ return false;
+
+ beginInsertRows(parent, row, row+(count-1));
+
+ for (int i = row; i < row + count; i++)
+ {
+ ColoringRuleItem* item = new ColoringRuleItem(true, new_rule_name_, "", defaultForeground_, defaultBackground_, root_);
+ root_->insertChild(i, item);
+ }
+
+ endInsertRows();
+ return true;
+}
+
+bool ColoringRulesModel::removeRows(int row, int count, const QModelIndex& parent)
+{
+ if (row < 0 )
+ return false;
+
+ beginRemoveRows(parent, row, row+(count-1));
+ for (int i = row; i < row + count; i++)
+ {
+ root_->removeChild(row);
+ }
+ endRemoveRows();
+
+ return true;
+}
+
+bool ColoringRulesModel::copyRow(int dst_row, int src_row)
+{
+ if (src_row < 0 || src_row >= rowCount() || dst_row < 0 || dst_row >= rowCount()) {
+ return false;
+ }
+
+ ColoringRuleItem* src_item = root_->child(src_row);
+ if (src_item == NULL)
+ return false;
+
+ ColoringRuleItem* dst_item = new ColoringRuleItem(*src_item);
+ if (dst_item == NULL)
+ return false;
+
+ beginInsertRows(QModelIndex(), dst_row, dst_row);
+ root_->insertChild(dst_row, dst_item);
+ endInsertRows();
+
+ return true;
+}
+
+Qt::ItemFlags ColoringRulesModel::flags(const QModelIndex &index) const
+{
+ Qt::ItemFlags flags = QAbstractItemModel::flags(index);
+ switch (index.column())
+ {
+ case colName:
+ flags |= (Qt::ItemIsUserCheckable|Qt::ItemIsEditable);
+ break;
+ case colFilter:
+ flags |= Qt::ItemIsEditable;
+ break;
+ }
+
+ if (index.isValid())
+ flags |= (Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled);
+ else
+ flags |= Qt::ItemIsDropEnabled;
+
+ return flags;
+}
+
+
+QVariant ColoringRulesModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+
+ ColoringRuleItem* rule = root_->child(index.row());
+ if (rule == NULL)
+ return QVariant();
+
+ switch (role)
+ {
+ case Qt::DisplayRole:
+ case Qt::EditRole:
+ switch(index.column())
+ {
+ case colName:
+ return rule->name_;
+ case colFilter:
+ return rule->filter_;
+ }
+ break;
+ case Qt::CheckStateRole:
+ switch(index.column())
+ {
+ case colName:
+ return rule->disabled_ ? Qt::Unchecked : Qt::Checked;
+ }
+ break;
+ case Qt::BackgroundRole:
+ return rule->background_;
+ case Qt::ForegroundRole:
+ return rule->foreground_;
+ }
+ return QVariant();
+}
+
+bool ColoringRulesModel::setData(const QModelIndex &dataIndex, const QVariant &value, int role)
+{
+ if (!dataIndex.isValid())
+ return false;
+
+ if (data(dataIndex, role) == value) {
+ // Data appears unchanged, do not do additional checks.
+ return true;
+ }
+
+ ColoringRuleItem* rule = root_->child(dataIndex.row());
+ if (rule == NULL)
+ return false;
+
+ QModelIndex topLeft = dataIndex,
+ bottomRight = dataIndex;
+
+ switch (role)
+ {
+ case Qt::EditRole:
+ switch (dataIndex.column())
+ {
+ case colName:
+ rule->name_ = value.toString();
+ break;
+ case colFilter:
+ rule->filter_ = value.toString();
+ break;
+ default:
+ return false;
+ }
+ break;
+ case Qt::CheckStateRole:
+ switch (dataIndex.column())
+ {
+ case colName:
+ rule->disabled_ = (value == Qt::Checked) ? false : true;
+ break;
+ default:
+ return false;
+ }
+ break;
+ case Qt::BackgroundRole:
+ if (!value.canConvert(QVariant::Color))
+ return false;
+
+ rule->background_ = QColor(value.toString());
+ break;
+ case Qt::ForegroundRole:
+ if (!value.canConvert(QVariant::Color))
+ return false;
+
+ rule->foreground_ = QColor(value.toString());
+ break;
+ case Qt::UserRole:
+ {
+ ColoringRuleItem* new_rule = VariantPointer<ColoringRuleItem>::asPtr(value);
+ *rule = *new_rule;
+ topLeft = index(dataIndex.row(), colName);
+ bottomRight = index(dataIndex.row(), colFilter);
+ break;
+ }
+ default:
+ return false;
+ }
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
+ QVector<int> roles;
+ roles << role;
+#endif
+
+ emit dataChanged(topLeft, bottomRight
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
+ , roles
+#endif
+ );
+
+ return true;
+
+}
+
+QVariant ColoringRulesModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (role != Qt::DisplayRole || orientation != Qt::Horizontal)
+ return QVariant();
+
+ switch ((ColoringRulesColumn)section) {
+ case colName:
+ return tr("Name");
+ case colFilter:
+ return tr("Filter");
+ default:
+ break;
+ }
+
+ return QVariant();
+}
+
+Qt::DropActions ColoringRulesModel::supportedDropActions() const
+{
+ return Qt::MoveAction;
+}
+
+QStringList ColoringRulesModel::mimeTypes() const
+{
+ //Just use plain text to transport data
+ QStringList types;
+ types << color_rule_mime_type_;
+ return types;
+}
+
+QMimeData* ColoringRulesModel::mimeData(const QModelIndexList &indexes) const
+{
+ //if the list is empty, don't return an empty list
+ if (indexes.count() == 0)
+ return NULL;
+
+ QMimeData *mimeData = new QMimeData();
+ QByteArray encodedData;
+
+ QDataStream stream(&encodedData, QIODevice::WriteOnly);
+
+ foreach (const QModelIndex &index, indexes) {
+ //use first column as "filter"
+ if (index.column() == 0) {
+ //Retrieve "native" data to save lots of conversions in the process
+ ColoringRuleItem* item = root_->child(index.row());
+
+ stream << item->disabled_ << item->name_ << item->filter_ << item->foreground_ << item->background_;
+ }
+ }
+
+ mimeData->setData(color_rule_mime_type_, encodedData);
+ return mimeData;
+}
+
+bool ColoringRulesModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
+{
+ //clear any previous dragDrop information
+ dragDropRows_.clear();
+
+ if (action == Qt::IgnoreAction)
+ return true;
+
+ if (!data->hasFormat(color_rule_mime_type_))
+ return false;
+
+ if (column > 0)
+ return false;
+
+ int beginRow;
+
+ if (row != -1)
+ beginRow = row;
+ else if (parent.isValid())
+ beginRow = parent.row();
+ else
+ beginRow = rowCount();
+
+ bool disabled;
+ QString name;
+ QString filter;
+ QColor foreground;
+ QColor background;
+ ColoringRuleItem* item;
+ QList<QVariant> rules;
+
+ QByteArray encodedData = data->data(color_rule_mime_type_);
+ QDataStream stream(&encodedData, QIODevice::ReadOnly);
+ int rows = 0;
+
+ while (!stream.atEnd()) {
+ stream >> disabled >> name >> filter >> foreground >> background;
+
+ item = new ColoringRuleItem(disabled, name, filter, foreground, background, root_);
+ rules.append(VariantPointer<ColoringRuleItem>::asQVariant(item));
+ ++rows;
+ }
+
+ insertRows(beginRow, rows, QModelIndex());
+ for (int i = 0; i < rules.count(); i++) {
+ QModelIndex idx = index(beginRow, 0, QModelIndex());
+ setData(idx, rules[i], Qt::UserRole);
+ beginRow++;
+ }
+
+ return true;
+}
+
+QModelIndex ColoringRulesModel::index(int row, int column, const QModelIndex &parent) const
+{
+ if (!hasIndex(row, column, parent))
+ return QModelIndex();
+
+ ColoringRuleItem *parent_item, *child_item;
+
+ if (!parent.isValid())
+ parent_item = root_;
+ else
+ parent_item = static_cast<ColoringRuleItem*>(parent.internalPointer());
+
+ Q_ASSERT(parent_item);
+
+ child_item = parent_item->child(row);
+ if (child_item) {
+ return createIndex(row, column, child_item);
+ }
+
+ return QModelIndex();
+}
+
+QModelIndex ColoringRulesModel::parent(const QModelIndex& indexItem) const
+{
+ if (!indexItem.isValid())
+ return QModelIndex();
+
+ ColoringRuleItem* item = static_cast<ColoringRuleItem*>(indexItem.internalPointer());
+ if (item != NULL) {
+ ColoringRuleItem* parent_item = item->parentItem();
+ if (parent_item != NULL) {
+ if (parent_item == root_)
+ return QModelIndex();
+
+ return createIndex(parent_item->row(), 0, parent_item);
+ }
+ }
+
+ return QModelIndex();
+}
+
+int ColoringRulesModel::rowCount(const QModelIndex& parent) const
+{
+ ColoringRuleItem *parent_item;
+ if (parent.column() > 0)
+ return 0;
+
+ if (!parent.isValid())
+ parent_item = root_;
+ else
+ parent_item = static_cast<ColoringRuleItem*>(parent.internalPointer());
+
+ if (parent_item == NULL)
+ return 0;
+
+ return parent_item->childCount();
+}
+
+int ColoringRulesModel::columnCount(const QModelIndex&) const
+{
+ return colColoringRulesMax;
+}
+
+/* * 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/coloring_rules_model.h b/ui/qt/models/coloring_rules_model.h
new file mode 100644
index 0000000000..a3d727a33a
--- /dev/null
+++ b/ui/qt/models/coloring_rules_model.h
@@ -0,0 +1,98 @@
+/* coloring_rules_model.h
+ * Data model for coloring rules.
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef COLORING_RULES_MODEL_H
+#define COLORING_RULES_MODEL_H
+
+#include <config.h>
+
+#include <glib.h>
+#include <epan/color_filters.h>
+
+#include <ui/qt/models/tree_model_helpers.h>
+
+#include <QList>
+#include <QColor>
+#include <QAbstractTableModel>
+#include <QSortFilterProxyModel>
+
+class ColoringRuleItem : public ModelHelperTreeItem<ColoringRuleItem>
+{
+public:
+ ColoringRuleItem(bool disabled, QString name, QString filter, QColor foreground, QColor background, ColoringRuleItem* parent);
+ virtual ~ColoringRuleItem();
+
+ ColoringRuleItem(color_filter_t *colorf, ColoringRuleItem* parent);
+ ColoringRuleItem(const ColoringRuleItem& item);
+
+ bool disabled_;
+ QString name_;
+ QString filter_;
+ QColor foreground_;
+ QColor background_;
+};
+
+class ColoringRulesModel : public QAbstractItemModel
+{
+ Q_OBJECT
+
+public:
+ ColoringRulesModel(QColor defaultForeground, QColor defaultBackground, QObject *parent);
+ virtual ~ColoringRulesModel();
+
+ enum ColoringRulesColumn {
+ colName = 0,
+ colFilter,
+ colColoringRulesMax
+ };
+
+ void addColor(color_filter_t* colorf);
+ void addColor(bool disabled, QString filter, QColor foreground, QColor background);
+ bool importColors(QString filename, QString& err);
+ bool exportColors(QString filename, QString& err);
+ bool writeColors(QString& err);
+
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+ QVariant data(const QModelIndex &index, int role) const;
+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
+ QVariant headerData(int section, Qt::Orientation orientation,
+ int role = Qt::DisplayRole) const;
+ QModelIndex index(int row, int column,
+ const QModelIndex & = QModelIndex()) const;
+ QModelIndex parent(const QModelIndex &) const;
+
+ //Drag & drop functionality
+ Qt::DropActions supportedDropActions() const;
+ QStringList mimeTypes() const;
+ QMimeData* mimeData(const QModelIndexList &indexes) const;
+ bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent);
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+
+ bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex());
+ bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
+ bool copyRow(int dst_row, int src_row);
+
+private:
+ void populate();
+ struct _GSList *createColorFilterList();
+
+ ColoringRuleItem* root_;
+ //Save off the conversation colors, do not include in dialog
+ struct _GSList *conversation_colors_;
+
+ QColor defaultForeground_;
+ QColor defaultBackground_;
+
+ QList<int> dragDropRows_;
+};
+
+#endif // COLORING_RULES_MODEL_H
diff --git a/ui/qt/models/tree_model_helpers.h b/ui/qt/models/tree_model_helpers.h
index bf547c561c..643af38418 100644
--- a/ui/qt/models/tree_model_helpers.h
+++ b/ui/qt/models/tree_model_helpers.h
@@ -37,11 +37,28 @@ public:
childItems_.clear();
}
+ void appendChild(Item* child)
+ {
+ childItems_.append(VariantPointer<Item>::asQVariant(child));
+ }
+
void prependChild(Item* child)
{
childItems_.prepend(VariantPointer<Item>::asQVariant(child));
}
+
+ void insertChild(int row, Item* child)
+ {
+ childItems_.insert(row, VariantPointer<Item>::asQVariant(child));
+ }
+
+ void removeChild(int row)
+ {
+ delete VariantPointer<Item>::asPtr(childItems_.value(row));
+ childItems_.removeAt(row);
+ }
+
Item* child(int row)
{
return VariantPointer<Item>::asPtr(childItems_.value(row));