![Roland Knall](/assets/img/avatar_default.png)
This stops the main source from being buildable by Qt 4.x Change-Id: I61edbae04ac2b3bf0ae8ee8e09d335083945c176 Reviewed-on: https://code.wireshark.org/review/26756 Petri-Dish: Roland Knall <rknall@gmail.com> Tested-by: Petri Dish Buildbot Reviewed-by: Gerald Combs <gerald@wireshark.org> Reviewed-by: Alexis La Goutte <alexis.lagoutte@gmail.com>
552 lines
14 KiB
C++
552 lines
14 KiB
C++
/* 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-or-later
|
|
*/
|
|
#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;
|
|
}
|
|
|
|
QVector<int> roles;
|
|
roles << role;
|
|
|
|
emit dataChanged(topLeft, bottomRight, roles);
|
|
|
|
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:
|
|
*/
|