![Roland Knall](/assets/img/avatar_default.png)
Allow the user to reset the changes done. This can be done at any time, as long as the dialog has not been closed Change-Id: I0d72a7972b4ea94b53fbed4c84ea952fd6f71b01 Reviewed-on: https://code.wireshark.org/review/34825 Petri-Dish: Roland Knall <rknall@gmail.com> Tested-by: Petri Dish Buildbot Reviewed-by: Roland Knall <rknall@gmail.com>
490 lines
13 KiB
C++
490 lines
13 KiB
C++
/* column_list_models.cpp
|
|
*
|
|
* Wireshark - Network traffic analyzer
|
|
* By Gerald Combs <gerald@wireshark.org>
|
|
* Copyright 1998 Gerald Combs
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
|
|
#include <ui/qt/models/column_list_model.h>
|
|
#include <ui/qt/utils/qt_ui_utils.h>
|
|
#include <ui/qt/widgets/field_filter_edit.h>
|
|
#include <ui/qt/widgets/syntax_line_edit.h>
|
|
|
|
#include <glib.h>
|
|
#include <epan/column-info.h>
|
|
#include <epan/column.h>
|
|
#include <epan/prefs.h>
|
|
#include <epan/proto.h>
|
|
#include <ui/preference_utils.h>
|
|
|
|
#include <QLineEdit>
|
|
#include <QStringList>
|
|
#include <QComboBox>
|
|
|
|
struct ListElement
|
|
{
|
|
QString title;
|
|
QString customFields;
|
|
int nr;
|
|
int type;
|
|
int originalType;
|
|
int occurrence;
|
|
bool displayed;
|
|
bool changed;
|
|
};
|
|
|
|
static QList<ListElement> store_;
|
|
|
|
ColumnProxyModel::ColumnProxyModel(QObject * parent) :
|
|
QSortFilterProxyModel(parent),
|
|
showDisplayedOnly_(false)
|
|
{}
|
|
|
|
bool ColumnProxyModel::filterAcceptsRow(int source_row, const QModelIndex &/*source_parent*/) const
|
|
{
|
|
bool displayed = false;
|
|
if ( sourceModel() &&
|
|
sourceModel()->index(source_row, ColumnListModel::COL_DISPLAYED).data(ColumnListModel::DisplayedState).toBool() )
|
|
displayed = true;
|
|
|
|
if ( showDisplayedOnly_ && ! displayed )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
void ColumnProxyModel::setShowDisplayedOnly(bool set)
|
|
{
|
|
showDisplayedOnly_ = set;
|
|
invalidateFilter();
|
|
}
|
|
|
|
ColumnTypeDelegate::ColumnTypeDelegate(QObject * parent) :
|
|
QStyledItemDelegate(parent)
|
|
{}
|
|
|
|
QWidget *ColumnTypeDelegate::createEditor(QWidget *parent,
|
|
const QStyleOptionViewItem &option,
|
|
const QModelIndex &index) const
|
|
{
|
|
if ( index.column() == ColumnListModel::COL_TYPE )
|
|
{
|
|
QComboBox *editor = new QComboBox(parent);
|
|
|
|
for (int i = 0; i < NUM_COL_FMTS; i++)
|
|
{
|
|
editor->addItem(col_format_desc(i), QVariant(i));
|
|
if ( i == index.data().toInt() )
|
|
editor->setCurrentIndex(i);
|
|
}
|
|
|
|
editor->setFrame(false);
|
|
|
|
return editor;
|
|
}
|
|
else if ( index.column() == ColumnListModel::COL_FIELDS )
|
|
{
|
|
FieldFilterEdit * editor = new FieldFilterEdit(parent);
|
|
editor->setText(index.data().toString());
|
|
return editor;
|
|
}
|
|
else if ( index.column() == ColumnListModel::COL_OCCURRENCE )
|
|
{
|
|
SyntaxLineEdit * editor = new SyntaxLineEdit(parent);
|
|
connect(editor, &SyntaxLineEdit::textChanged, editor, &SyntaxLineEdit::checkInteger);
|
|
editor->setText(index.data().toString());
|
|
return editor;
|
|
}
|
|
|
|
return QStyledItemDelegate::createEditor(parent, option, index);
|
|
}
|
|
|
|
void ColumnTypeDelegate::setEditorData(QWidget *editor,
|
|
const QModelIndex &index) const
|
|
{
|
|
QVariant data = index.model()->data(index);
|
|
if ( index.column() == ColumnListModel::COL_TYPE )
|
|
{
|
|
QComboBox *comboBox = static_cast<QComboBox*>(editor);
|
|
comboBox->setCurrentText(data.toString());
|
|
}
|
|
else if ( index.column() == ColumnListModel::COL_FIELDS )
|
|
{
|
|
if ( qobject_cast<FieldFilterEdit *>(editor) )
|
|
qobject_cast<FieldFilterEdit *>(editor)->setText(data.toString());
|
|
}
|
|
else if ( index.column() == ColumnListModel::COL_OCCURRENCE )
|
|
{
|
|
if ( qobject_cast<SyntaxLineEdit *>(editor) )
|
|
qobject_cast<SyntaxLineEdit *>(editor)->setText(data.toString());
|
|
}
|
|
else
|
|
{
|
|
if ( qobject_cast<QLineEdit *>(editor) )
|
|
qobject_cast<QLineEdit *>(editor)->setText(data.toString());
|
|
}
|
|
}
|
|
|
|
void ColumnTypeDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
|
|
const QModelIndex &index) const
|
|
{
|
|
if ( index.column() == ColumnListModel::COL_TYPE )
|
|
{
|
|
QComboBox *comboBox = static_cast<QComboBox*>(editor);
|
|
bool ok = false;
|
|
int value = comboBox->currentData().toInt(&ok);
|
|
|
|
if ( ok )
|
|
model->setData(index, value, Qt::EditRole);
|
|
}
|
|
else if ( index.column() == ColumnListModel::COL_FIELDS )
|
|
{
|
|
FieldFilterEdit * ffe = qobject_cast<FieldFilterEdit *>(editor);
|
|
if ( ffe && ffe->checkFilter() )
|
|
{
|
|
QModelIndex typeIndex = index.sibling(index.row(), ColumnListModel::COL_TYPE);
|
|
model->setData(typeIndex, COL_CUSTOM, Qt::EditRole);
|
|
model->setData(index, ffe->text(), Qt::EditRole);
|
|
}
|
|
else
|
|
ffe->setText(index.data().toString());
|
|
|
|
if ( index.data().toString().length() == 0 )
|
|
{
|
|
QModelIndex typeIndex = index.sibling(index.row(), ColumnListModel::COL_TYPE);
|
|
model->setData(typeIndex, index.data(ColumnListModel::OriginalType).toInt(), Qt::EditRole);
|
|
|
|
}
|
|
}
|
|
else if ( index.column() == ColumnListModel::COL_OCCURRENCE )
|
|
{
|
|
SyntaxLineEdit * sle = qobject_cast<SyntaxLineEdit *>(editor);
|
|
bool ok = false;
|
|
if ( sle )
|
|
{
|
|
sle->checkInteger(index.data().toString());
|
|
if ( sle->syntaxState() == SyntaxLineEdit::Valid )
|
|
ok = true;
|
|
}
|
|
|
|
if ( ok )
|
|
{
|
|
QModelIndex typeIndex = index.sibling(index.row(), ColumnListModel::COL_TYPE);
|
|
model->setData(typeIndex, COL_CUSTOM, Qt::EditRole);
|
|
model->setData(index, sle->text(), Qt::EditRole);
|
|
}
|
|
else
|
|
sle->setText(index.data().toString());
|
|
|
|
if ( index.data().toString().length() == 0 )
|
|
{
|
|
QModelIndex typeIndex = index.sibling(index.row(), ColumnListModel::COL_TYPE);
|
|
model->setData(typeIndex, index.data(ColumnListModel::OriginalType).toInt(), Qt::EditRole);
|
|
|
|
}
|
|
}
|
|
else
|
|
QStyledItemDelegate::setModelData(editor, model, index);
|
|
}
|
|
|
|
void ColumnTypeDelegate::updateEditorGeometry(QWidget *editor,
|
|
const QStyleOptionViewItem &option,
|
|
const QModelIndex &/* index */) const
|
|
{
|
|
editor->setGeometry(option.rect);
|
|
}
|
|
|
|
ColumnListModel::ColumnListModel(QObject * parent):
|
|
QAbstractTableModel(parent)
|
|
{
|
|
populate();
|
|
}
|
|
|
|
QVariant ColumnListModel::headerData(int section, Qt::Orientation orientation, int role) const
|
|
{
|
|
if ( section > ColumnListModel::COL_OCCURRENCE || orientation != Qt::Horizontal ||
|
|
role != Qt::DisplayRole )
|
|
return QVariant();
|
|
|
|
return headerTitle(section);
|
|
}
|
|
|
|
int ColumnListModel::rowCount(const QModelIndex &/*parent*/) const
|
|
{
|
|
return store_.count();
|
|
}
|
|
|
|
int ColumnListModel::columnCount(const QModelIndex &/*parent*/) const
|
|
{
|
|
return ColumnListModel::COL_OCCURRENCE + 1;
|
|
}
|
|
|
|
QString ColumnListModel::headerTitle(int section) const
|
|
{
|
|
switch ( section )
|
|
{
|
|
case ColumnListModel::COL_DISPLAYED:
|
|
return tr("Displayed");
|
|
case ColumnListModel::COL_TITLE:
|
|
return tr("Title");
|
|
case ColumnListModel::COL_TYPE:
|
|
return tr("Type");
|
|
case ColumnListModel::COL_FIELDS:
|
|
return tr("Fields");
|
|
case ColumnListModel::COL_OCCURRENCE:
|
|
return tr("Field Occurence");
|
|
}
|
|
|
|
return QString();
|
|
}
|
|
|
|
void ColumnListModel::populate()
|
|
{
|
|
store_.clear();
|
|
|
|
int nr = 0;
|
|
|
|
for (GList *cur = g_list_first(prefs.col_list); cur != NULL && cur->data != NULL; cur = cur->next) {
|
|
fmt_data *cfmt = (fmt_data *) cur->data;
|
|
ListElement ne;
|
|
ne.nr = nr;
|
|
ne.displayed = cfmt->visible;
|
|
ne.title = cfmt->title;
|
|
ne.type = ne.originalType = cfmt->fmt;
|
|
ne.customFields = cfmt->custom_fields;
|
|
ne.occurrence = cfmt->custom_occurrence;
|
|
|
|
nr++;
|
|
store_ << ne;
|
|
}
|
|
}
|
|
|
|
QVariant ColumnListModel::data(const QModelIndex &index, int role) const
|
|
{
|
|
if ( ! index.isValid() || index.column() >= store_.count() )
|
|
return QVariant();
|
|
|
|
ListElement ne = store_.at(index.row());
|
|
|
|
if ( role == Qt::DisplayRole )
|
|
{
|
|
switch (index.column())
|
|
{
|
|
case COL_DISPLAYED:
|
|
return QVariant();
|
|
case ColumnListModel::COL_TITLE:
|
|
return ne.title;
|
|
case ColumnListModel::COL_TYPE:
|
|
return col_format_desc(ne.type);
|
|
case ColumnListModel::COL_FIELDS:
|
|
return ne.customFields;
|
|
case ColumnListModel::COL_OCCURRENCE:
|
|
return ne.customFields.length() > 0 ? qVariantFromValue(ne.occurrence) : QVariant();
|
|
}
|
|
}
|
|
else if ( role == Qt::CheckStateRole )
|
|
{
|
|
if ( index.column() == COL_DISPLAYED )
|
|
{
|
|
return ne.displayed ? Qt::Checked : Qt::Unchecked;
|
|
}
|
|
}
|
|
else if ( role == OriginalType )
|
|
return qVariantFromValue(ne.originalType);
|
|
else if ( role == DisplayedState )
|
|
return qVariantFromValue(ne.displayed);
|
|
|
|
return QVariant();
|
|
}
|
|
|
|
Qt::ItemFlags ColumnListModel::flags(const QModelIndex &index) const
|
|
{
|
|
Qt::ItemFlags defaultFlags = QAbstractTableModel::flags(index);
|
|
if ( index.isValid() && index.row() < store_.count() )
|
|
{
|
|
ListElement ne = store_.at(index.row());
|
|
|
|
Qt::ItemFlags flags = Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
|
|
|
|
if ( index.column() == COL_DISPLAYED )
|
|
flags |= Qt::ItemIsUserCheckable;
|
|
|
|
flags |= Qt::ItemIsEditable;
|
|
|
|
return flags;
|
|
}
|
|
else
|
|
return Qt::ItemIsDropEnabled | defaultFlags;
|
|
}
|
|
|
|
QMimeData *ColumnListModel::mimeData(const QModelIndexList &indexes) const
|
|
{
|
|
QMimeData *mimeData = new QMimeData;
|
|
|
|
int row = -1;
|
|
if ( indexes.count() > 0 )
|
|
row = indexes.at(0).row();
|
|
|
|
mimeData->setText(QString::number(row));
|
|
return mimeData;
|
|
}
|
|
|
|
bool ColumnListModel::canDropMimeData(const QMimeData *data,
|
|
Qt::DropAction /* action */, int /* row */, int /* column */, const QModelIndex &parent) const
|
|
{
|
|
if (parent.isValid() || data->text().isEmpty() )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ColumnListModel::dropMimeData(const QMimeData *data,
|
|
Qt::DropAction action, int row, int column, const QModelIndex &parent)
|
|
{
|
|
int moveTo;
|
|
|
|
if (!canDropMimeData(data, action, row, column, parent))
|
|
return false;
|
|
|
|
if (action == Qt::IgnoreAction || parent.isValid() )
|
|
return true;
|
|
|
|
if (row != -1)
|
|
moveTo = row;
|
|
else
|
|
moveTo = rowCount(QModelIndex());
|
|
|
|
bool ok = false;
|
|
int moveFrom = data->text().toInt(&ok);
|
|
if ( ! ok )
|
|
return false;
|
|
|
|
if ( moveFrom < moveTo )
|
|
moveTo = moveTo - 1;
|
|
|
|
if ( moveTo >= store_.count() )
|
|
moveTo = store_.count() - 1;
|
|
|
|
emit beginResetModel();
|
|
store_.move(moveFrom, moveTo);
|
|
emit endResetModel();
|
|
|
|
return true;
|
|
}
|
|
|
|
Qt::DropActions ColumnListModel::supportedDropActions() const
|
|
{
|
|
return Qt::MoveAction;
|
|
}
|
|
|
|
bool ColumnListModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
|
{
|
|
if ( !index.isValid() || ! value.isValid() )
|
|
return false;
|
|
|
|
bool change = false;
|
|
if ( role == Qt::CheckStateRole && index.column() == ColumnListModel::COL_DISPLAYED )
|
|
{
|
|
store_[index.row()].displayed = value.toInt() == Qt::Checked ? true : false;
|
|
change = true;
|
|
}
|
|
else if ( index.column() == ColumnListModel::COL_TYPE )
|
|
{
|
|
bool ok = false;
|
|
int val = value.toInt(&ok);
|
|
if ( ok )
|
|
store_[index.row()].type = val;
|
|
}
|
|
else if ( index.column() == ColumnListModel::COL_TITLE )
|
|
{
|
|
store_[index.row()].title = value.toString();
|
|
}
|
|
else if ( index.column() == ColumnListModel::COL_FIELDS )
|
|
{
|
|
store_[index.row()].customFields = value.toString();
|
|
}
|
|
else if ( index.column() == ColumnListModel::COL_OCCURRENCE )
|
|
{
|
|
bool ok = false;
|
|
int val = value.toInt(&ok);
|
|
if ( ok )
|
|
store_[index.row()].occurrence = val;
|
|
}
|
|
|
|
if ( change )
|
|
emit dataChanged(index, index);
|
|
|
|
return change;
|
|
}
|
|
|
|
void ColumnListModel::saveColumns()
|
|
{
|
|
GList *new_col_list = Q_NULLPTR;
|
|
|
|
for ( int row = 0; row < store_.count(); row++ )
|
|
{
|
|
fmt_data * cfmt = new fmt_data();
|
|
ListElement elem = store_.at(row);
|
|
|
|
cfmt->title = qstring_strdup(elem.title);
|
|
cfmt->visible = elem.displayed;
|
|
cfmt->fmt = elem.type;
|
|
cfmt->resolved = TRUE;
|
|
if ( cfmt->fmt == COL_CUSTOM )
|
|
{
|
|
cfmt->custom_fields = qstring_strdup(elem.customFields);
|
|
cfmt->custom_occurrence = elem.occurrence;
|
|
}
|
|
|
|
new_col_list = g_list_append(new_col_list, cfmt);
|
|
}
|
|
|
|
while (prefs.col_list)
|
|
column_prefs_remove_link(prefs.col_list);
|
|
|
|
prefs.col_list = new_col_list;
|
|
}
|
|
|
|
void ColumnListModel::addEntry()
|
|
{
|
|
emit beginInsertRows(QModelIndex(), rowCount(), rowCount());
|
|
ListElement elem;
|
|
elem.nr = rowCount();
|
|
elem.title = tr("New Column");
|
|
elem.displayed = true;
|
|
elem.type = elem.originalType = COL_NUMBER;
|
|
elem.occurrence = 0;
|
|
elem.customFields = QString();
|
|
store_ << elem;
|
|
emit endInsertRows();
|
|
}
|
|
|
|
void ColumnListModel::deleteEntry(int row)
|
|
{
|
|
emit beginRemoveRows(QModelIndex(), row, row);
|
|
store_.removeAt(row);
|
|
emit endRemoveRows();
|
|
}
|
|
|
|
void ColumnListModel::reset()
|
|
{
|
|
emit beginResetModel();
|
|
populate();
|
|
emit endResetModel();
|
|
}
|
|
|
|
/*
|
|
* 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:
|
|
*/
|