diff options
author | Michael Mann <mmann78@netscape.net> | 2018-01-08 19:43:36 -0500 |
---|---|---|
committer | Anders Broman <a.broman58@gmail.com> | 2018-02-14 07:45:47 +0000 |
commit | f0db412f57effe6234edc78e1f438b735efae805 (patch) | |
tree | afef4b6a0e893ed2805a2fe6de1396e0bbe896ed | |
parent | a3e14cb514976a9354676a2caa7b001e50dc6189 (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.txt | 4 | ||||
-rw-r--r-- | ui/qt/Makefile.am | 4 | ||||
-rw-r--r-- | ui/qt/coloring_rules_dialog.cpp | 420 | ||||
-rw-r--r-- | ui/qt/coloring_rules_dialog.h | 51 | ||||
-rw-r--r-- | ui/qt/coloring_rules_dialog.ui | 36 | ||||
-rw-r--r-- | ui/qt/models/coloring_rules_delegate.cpp | 134 | ||||
-rw-r--r-- | ui/qt/models/coloring_rules_delegate.h | 42 | ||||
-rw-r--r-- | ui/qt/models/coloring_rules_model.cpp | 557 | ||||
-rw-r--r-- | ui/qt/models/coloring_rules_model.h | 98 | ||||
-rw-r--r-- | ui/qt/models/tree_model_helpers.h | 17 |
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 ¤t = 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)); |