aboutsummaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
Diffstat (limited to 'ui')
-rw-r--r--ui/qt/CMakeLists.txt4
-rw-r--r--ui/qt/Makefile.am4
-rw-r--r--ui/qt/decode_as_dialog.cpp614
-rw-r--r--ui/qt/decode_as_dialog.h37
-rw-r--r--ui/qt/decode_as_dialog.ui47
-rw-r--r--ui/qt/models/decode_as_delegate.cpp408
-rw-r--r--ui/qt/models/decode_as_delegate.h71
-rw-r--r--ui/qt/models/decode_as_model.cpp650
-rw-r--r--ui/qt/models/decode_as_model.h106
9 files changed, 1306 insertions, 635 deletions
diff --git a/ui/qt/CMakeLists.txt b/ui/qt/CMakeLists.txt
index 596ef02818..01b4fb64cb 100644
--- a/ui/qt/CMakeLists.txt
+++ b/ui/qt/CMakeLists.txt
@@ -55,6 +55,8 @@ set(WIRESHARK_UTILS_HEADERS
set(WIRESHARK_MODEL_HEADERS
models/cache_proxy_model.h
+ models/decode_as_delegate.h
+ models/decode_as_model.h
models/interface_sort_filter_model.h
models/interface_tree_cache_model.h
models/interface_tree_model.h
@@ -252,6 +254,8 @@ set(WIRESHARK_UTILS_SRCS
set(WIRESHARK_MODEL_SRCS
models/cache_proxy_model.cpp
+ models/decode_as_delegate.cpp
+ models/decode_as_model.cpp
models/interface_sort_filter_model.cpp
models/interface_tree_cache_model.cpp
models/interface_tree_model.cpp
diff --git a/ui/qt/Makefile.am b/ui/qt/Makefile.am
index 37723c9360..c7647628c3 100644
--- a/ui/qt/Makefile.am
+++ b/ui/qt/Makefile.am
@@ -184,6 +184,8 @@ MOC_UTILS_HDRS = \
# Files for delegates and models
MOC_MODELS_HDRS = \
models/cache_proxy_model.h \
+ models/decode_as_delegate.h \
+ models/decode_as_model.h \
models/interface_sort_filter_model.h \
models/interface_tree_cache_model.h \
models/interface_tree_model.h \
@@ -495,6 +497,8 @@ WIRESHARK_QT_UTILS_SRC = \
WIRESHARK_QT_MODELS_SRCS = \
models/cache_proxy_model.cpp \
+ models/decode_as_delegate.cpp \
+ models/decode_as_model.cpp \
models/interface_sort_filter_model.cpp \
models/interface_tree_cache_model.cpp \
models/interface_tree_model.cpp \
diff --git a/ui/qt/decode_as_dialog.cpp b/ui/qt/decode_as_dialog.cpp
index e79530cf8d..ced22e5780 100644
--- a/ui/qt/decode_as_dialog.cpp
+++ b/ui/qt/decode_as_dialog.cpp
@@ -23,10 +23,7 @@
#include <ui_decode_as_dialog.h>
#include "epan/decode_as.h"
-#include "epan/dissectors/packet-dcerpc.h"
#include "epan/epan_dissect.h"
-#include "epan/prefs.h"
-#include "epan/prefs-int.h"
#include "ui/decode_as_utils.h"
#include "ui/simple_dialog.h"
@@ -41,266 +38,66 @@
#include <QFont>
#include <QFontMetrics>
#include <QLineEdit>
+#include <QDebug>
// To do:
// - Ranges
// - Add DCERPC support (or make DCERPC use a regular dissector table?)
-// - Fix string (BER) selectors
-// - Use a StyledItemDelegate to edit entries instead of managing widgets
-// by hand. See the coloring rules dialog for an example.
-
-const int table_col_ = 0;
-const int selector_col_ = 1;
-const int type_col_ = 2;
-const int default_col_ = 3; // aka "initial"
-const int proto_col_ = 4; // aka "current"
-
-const char *default_table_ = "TCP port";
-const char *default_proto_ = DECODE_AS_NONE;
-const char *default_int_selector_ = "0"; // Arbitrary
-const char *default_str_selector_ = "foo"; // Arbitrary
-
-typedef struct _dissector_info_t {
- QString proto_name;
- dissector_handle_t dissector_handle;
-} dissector_info_t;
-
-Q_DECLARE_METATYPE(dissector_info_t *)
-
-typedef struct _table_item_t {
- const gchar* proto_name;
- guint8 curr_layer_num;
-} table_item_t;
-
-Q_DECLARE_METATYPE(table_item_t)
DecodeAsDialog::DecodeAsDialog(QWidget *parent, capture_file *cf, bool create_new) :
GeometryStateDialog(parent),
ui(new Ui::DecodeAsDialog),
- cap_file_(cf),
- table_names_combo_box_(NULL),
- selector_combo_box_(NULL),
- cur_proto_combo_box_(NULL)
+ model_(new DecodeAsModel(this, cf)),
+ delegate_(NULL)
{
ui->setupUi(this);
loadGeometry();
- setWindowTitle(wsApp->windowTitleString(tr("Decode As" UTF8_HORIZONTAL_ELLIPSIS)));
- ui->deleteToolButton->setEnabled(false);
+ delegate_ = new DecodeAsDelegate(ui->decodeAsTreeView, cf);
- GList *cur;
- for (cur = decode_as_list; cur; cur = cur->next) {
- decode_as_t *entry = (decode_as_t *) cur->data;
- QString table_ui_name = get_dissector_table_ui_name(entry->table_name);
- if (!table_ui_name.isEmpty()) {
- ui_name_to_name_[table_ui_name] = entry->table_name;
- }
- }
+ ui->decodeAsTreeView->setModel(model_);
+ ui->decodeAsTreeView->setItemDelegate(delegate_);
+
+ setWindowTitle(wsApp->windowTitleString(tr("Decode As" UTF8_HORIZONTAL_ELLIPSIS)));
- connect(wsApp, SIGNAL(preferencesChanged()), this, SLOT(fillTable()));
fillTable();
- if (create_new) on_newToolButton_clicked();
+ if (create_new)
+ on_newToolButton_clicked();
}
DecodeAsDialog::~DecodeAsDialog()
{
delete ui;
-}
-
-void DecodeAsDialog::setCaptureFile(capture_file *cf)
-{
- cap_file_ = cf;
- fillTable();
-}
-
-QString DecodeAsDialog::entryString(const gchar *table_name, gpointer value)
-{
- QString entry_str;
- ftenum_t selector_type = get_dissector_table_selector_type(table_name);
-
- switch (selector_type) {
-
- case FT_UINT8:
- case FT_UINT16:
- case FT_UINT24:
- case FT_UINT32:
- {
- uint num_val = GPOINTER_TO_UINT(value);
- switch (get_dissector_table_param(table_name)) {
-
- case BASE_DEC:
- entry_str = QString::number(num_val);
- break;
-
- case BASE_HEX:
- int width;
- switch (selector_type) {
- case FT_UINT8:
- width = 2;
- break;
- case FT_UINT16:
- width = 4;
- break;
- case FT_UINT24:
- width = 6;
- break;
- case FT_UINT32:
- width = 8;
- break;
-
- default:
- g_assert_not_reached();
- break;
- }
- entry_str = QString("%1").arg(int_to_qstring(num_val, width, 16));
- break;
-
- case BASE_OCT:
- entry_str = "0" + QString::number(num_val, 8);
- break;
- }
- break;
- }
-
- case FT_STRING:
- case FT_STRINGZ:
- case FT_UINT_STRING:
- case FT_STRINGZPAD:
- entry_str = (char *)value;
- break;
-
- case FT_GUID:
- //TODO: DCE/RPC dissector table
- break;
-
- default:
- g_assert_not_reached();
- break;
- }
- return entry_str;
+ delete model_;
+ delete delegate_;
}
void DecodeAsDialog::fillTable()
{
- ui->decodeAsTreeWidget->clear();
- dissector_all_tables_foreach_changed(buildChangedList, this);
- decode_dcerpc_add_show_list(buildDceRpcChangedList, this);
-
- if (ui->decodeAsTreeWidget->topLevelItemCount() > 0) {
- for (int i = 0; i < ui->decodeAsTreeWidget->columnCount(); i++) {
- ui->decodeAsTreeWidget->resizeColumnToContents(i);
- }
- }
-}
-
-void DecodeAsDialog::activateLastItem()
-{
- int last_idx = ui->decodeAsTreeWidget->topLevelItemCount() - 1;
- if (last_idx < 0) return;
+ model_->fillTable();
- QTreeWidgetItem *last_item = ui->decodeAsTreeWidget->invisibleRootItem()->child(last_idx);
- if (!last_item) return;
+ resizeColumns();
- ui->decodeAsTreeWidget->setCurrentItem(last_item);
- on_decodeAsTreeWidget_itemActivated(last_item);
-}
-
-void DecodeAsDialog::on_decodeAsTreeWidget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous)
-{
- if (current == previous) return;
-
- for (int col = 0; col < ui->decodeAsTreeWidget->columnCount(); col++) {
- if (previous && ui->decodeAsTreeWidget->itemWidget(previous, col)) {
- ui->decodeAsTreeWidget->removeItemWidget(previous, col);
- }
+ //set selection as first row
+ if (model_->rowCount() > 0) {
+ const QModelIndex &new_index = model_->index(0, 0);
+ ui->decodeAsTreeView->setCurrentIndex(new_index);
}
}
-void DecodeAsDialog::on_decodeAsTreeWidget_itemActivated(QTreeWidgetItem *item, int)
+void DecodeAsDialog::resizeColumns()
{
- GList *cur;
-
- table_names_combo_box_ = new QComboBox();
- QString current_text = item->text(table_col_);
- QSet<QString> da_set;
-
- // If a packet is selected group its tables at the top in order
- // from last-dissected to first.
-
- for (cur = decode_as_list; cur; cur = cur->next) {
- decode_as_t *entry = (decode_as_t *) cur->data;
- const char *table_name = get_dissector_table_ui_name(entry->table_name);
- if (table_name) {
- da_set.insert(get_dissector_table_ui_name(entry->table_name));
- }
- }
-
- if (cap_file_ && cap_file_->edt) {
- bool copying = !current_text.isEmpty();
- wmem_list_frame_t * protos = wmem_list_head(cap_file_->edt->pi.layers);
- guint8 curr_layer_num = 1;
- while (protos != NULL) {
- int proto_id = GPOINTER_TO_INT(wmem_list_frame_data(protos));
- const gchar * proto_name = proto_get_protocol_filter_name(proto_id);
- for (cur = decode_as_list; cur; cur = cur->next) {
- decode_as_t *entry = (decode_as_t *) cur->data;
- if (g_strcmp0(proto_name, entry->name) == 0) {
- QString table_ui_name = get_dissector_table_ui_name(entry->table_name);
- table_item_t table_item;
- table_item.proto_name = proto_name;
- table_item.curr_layer_num = curr_layer_num;
- table_names_combo_box_->insertItem(0, table_ui_name, QVariant::fromValue<table_item_t>(table_item));
- da_set.remove(table_ui_name);
- if (!copying) {
- current_text = table_ui_name;
- }
- }
- }
- protos = wmem_list_frame_next(protos);
- curr_layer_num++;
+ if (model_->rowCount() > 0) {
+ for (int i = 0; i < model_->columnCount(); i++) {
+ ui->decodeAsTreeView->resizeColumnToContents(i);
}
}
-
- if (table_names_combo_box_->count() > 0) {
- table_names_combo_box_->insertSeparator(table_names_combo_box_->count());
- }
-
- QList<QString> da_list = da_set.toList();
- qSort(da_list.begin(), da_list.end());
-
- foreach (QString table_ui_name, da_list) {
- table_names_combo_box_->addItem(table_ui_name, ui_name_to_name_[table_ui_name]);
- }
-
- if (current_text.isEmpty()) current_text = default_table_;
- ui->decodeAsTreeWidget->setItemWidget(item, table_col_, table_names_combo_box_);
-
- selector_combo_box_ = new QComboBox();
- selector_combo_box_->setEditable(true);
- selector_combo_box_->lineEdit()->setText(item->text(selector_col_));
-
- connect(selector_combo_box_, SIGNAL(editTextChanged(QString)), this, SLOT(selectorEditTextChanged(QString)));
-
- ui->decodeAsTreeWidget->setItemWidget(item, selector_col_, selector_combo_box_);
-
- cur_proto_combo_box_ = new QComboBox();
-
- ui->decodeAsTreeWidget->setItemWidget(item, proto_col_, cur_proto_combo_box_);
- connect(cur_proto_combo_box_, SIGNAL(currentIndexChanged(const QString &)),
- this, SLOT(curProtoCurrentIndexChanged(const QString &)));
-
- table_names_combo_box_->setCurrentIndex(table_names_combo_box_->findText(current_text));
- tableNamesCurrentIndexChanged(current_text);
-
- connect(table_names_combo_box_, SIGNAL(currentIndexChanged(const QString &)),
- this, SLOT(tableNamesCurrentIndexChanged(const QString &)));
- table_names_combo_box_->setFocus();
}
-void DecodeAsDialog::on_decodeAsTreeWidget_itemSelectionChanged()
+void DecodeAsDialog::on_decodeAsTreeView_currentItemChanged(const QModelIndex &current, const QModelIndex&)
{
- if (ui->decodeAsTreeWidget->selectedItems().length() > 0) {
+ if (current.isValid()) {
ui->deleteToolButton->setEnabled(true);
ui->copyToolButton->setEnabled(true);
} else {
@@ -309,99 +106,28 @@ void DecodeAsDialog::on_decodeAsTreeWidget_itemSelectionChanged()
}
}
-void DecodeAsDialog::buildChangedList(const gchar *table_name, ftenum_t, gpointer key, gpointer value, gpointer user_data)
-{
- DecodeAsDialog *da_dlg = (DecodeAsDialog *)user_data;
- if (!da_dlg) return;
-
- dissector_handle_t default_dh, current_dh;
- QString default_proto_name = DECODE_AS_NONE, current_proto_name = DECODE_AS_NONE;
- QTreeWidgetItem *item = new QTreeWidgetItem();
-
- item->setText(table_col_, get_dissector_table_ui_name(table_name));
- item->setText(selector_col_, da_dlg->entryString(table_name, key));
- da_dlg->fillTypeColumn(item);
-
- default_dh = dtbl_entry_get_initial_handle((dtbl_entry_t *)value);
- if (default_dh) {
- default_proto_name = dissector_handle_get_short_name(default_dh);
- }
- item->setText(default_col_, default_proto_name);
-
- current_dh = dtbl_entry_get_handle((dtbl_entry_t *)value);
- if (current_dh) {
- current_proto_name = dissector_handle_get_short_name(current_dh);
- }
- item->setText(proto_col_, current_proto_name);
-
- dissector_info_t *dissector_info = new dissector_info_t();
- dissector_info->proto_name = current_proto_name;
- dissector_info->dissector_handle = current_dh;
- item->setData(proto_col_, Qt::UserRole, VariantPointer<dissector_info_t>::asQVariant(dissector_info));
-
- da_dlg->ui->decodeAsTreeWidget->addTopLevelItem(item);
-}
-
-void DecodeAsDialog::buildDceRpcChangedList(gpointer, gpointer)
-{
- // decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t *)data;
-}
-
void DecodeAsDialog::addRecord(bool copy_from_current)
{
- QTreeWidgetItem *cur_ti = NULL;
-
- if (copy_from_current) {
- cur_ti = ui->decodeAsTreeWidget->currentItem();
- if (!cur_ti) return;
- }
+ const QModelIndex &current = ui->decodeAsTreeView->currentIndex();
+ if (copy_from_current && !current.isValid()) return;
- QTreeWidgetItem *ti = new QTreeWidgetItem();
- ui->decodeAsTreeWidget->addTopLevelItem(ti);
+// XXX - This doesn't appear to work as intended to give "edit triggers on demand"
+ ui->decodeAsTreeView->setEditTriggers(ui->decodeAsTreeView->editTriggers() | QAbstractItemView::CurrentChanged | QAbstractItemView::AnyKeyPressed);
- if (cur_ti) {
- ti->setText(table_col_, cur_ti->text(table_col_));
- ti->setText(selector_col_, cur_ti->text(selector_col_));
- ti->setText(default_col_, cur_ti->text(default_col_));
- ti->setText(proto_col_, cur_ti->text(proto_col_));
- ti->setData(proto_col_, Qt::UserRole, cur_ti->data(proto_col_, Qt::UserRole));
+ // should not fail, but you never know.
+ if (!model_->insertRows(model_->rowCount(), 1)) {
+ qDebug() << "Failed to add a new record";
+ return;
}
-
- activateLastItem();
-
- if (ui->decodeAsTreeWidget->topLevelItemCount() > 0) {
- for (int i = 0; i < ui->decodeAsTreeWidget->columnCount(); i++) {
- ui->decodeAsTreeWidget->resizeColumnToContents(i);
- }
+ const QModelIndex &new_index = model_->index(model_->rowCount() - 1, 0);
+ if (copy_from_current) {
+ model_->copyRow(new_index.row(), current.row());
}
-}
-void DecodeAsDialog::fillTypeColumn(QTreeWidgetItem *item)
-{
- if (!item) return;
- const char *table_name = ui_name_to_name_[item->text(table_col_)];
+ resizeColumns();
- ftenum_t selector_type = get_dissector_table_selector_type(table_name);
-
- if (IS_FT_STRING(selector_type)) {
- item->setText(type_col_, tr("String"));
- } else {
- QString type_desc = tr("Integer, base ");
- switch (get_dissector_table_param(table_name)) {
- case BASE_OCT:
- type_desc.append("8");
- break;
- case BASE_DEC:
- type_desc.append("10");
- break;
- case BASE_HEX:
- type_desc.append("16");
- break;
- default:
- type_desc.append(tr("unknown"));
- }
- item->setText(type_col_, type_desc);
- }
+ // due to an EditTrigger, this will also start editing.
+ ui->decodeAsTreeView->setCurrentIndex(new_index);
}
void DecodeAsDialog::on_newToolButton_clicked()
@@ -411,272 +137,22 @@ void DecodeAsDialog::on_newToolButton_clicked()
void DecodeAsDialog::on_deleteToolButton_clicked()
{
- QTreeWidgetItem *item = ui->decodeAsTreeWidget->currentItem();
- if (!item) return;
- delete item;
-}
-
-void DecodeAsDialog::on_copyToolButton_clicked()
-{
- addRecord(true);
-}
-
-void DecodeAsDialog::decodeAddProtocol(const gchar *, const gchar *proto_name, gpointer value, gpointer user_data)
-{
- QSet<dissector_info_t *> *dissector_info_set = (QSet<dissector_info_t *> *)user_data;
- if (!dissector_info_set) return;
-
- dissector_info_t *dissector_info = new dissector_info_t();
- dissector_info->proto_name = proto_name;
- dissector_info->dissector_handle = (dissector_handle_t) value;
-
- dissector_info_set->insert(dissector_info);
-}
-
-void DecodeAsDialog::tableNamesCurrentIndexChanged(const QString &text)
-{
- QTreeWidgetItem *item = ui->decodeAsTreeWidget->currentItem();
- if (!item || text.isEmpty() || !selector_combo_box_ || !cur_proto_combo_box_) return;
-
- QString current_text = item->text(proto_col_);
- if (current_text.isEmpty()) current_text = default_proto_;
-
- item->setText(table_col_, text);
- fillTypeColumn(item);
-
- selector_combo_box_->clear();
-
- bool edt_present = cap_file_ && cap_file_->edt;
- QVariant variant = table_names_combo_box_->itemData(table_names_combo_box_->currentIndex());
- gint8 curr_layer_num_saved = edt_present ? cap_file_->edt->pi.curr_layer_num : 0;
- const gchar *proto_name = NULL;
- if (variant.canConvert<table_item_t>()) {
- table_item_t table_item = variant.value<table_item_t>();
- if (edt_present) {
- cap_file_->edt->pi.curr_layer_num = table_item.curr_layer_num;
- }
- proto_name = table_item.proto_name;
- }
-
- QSet<dissector_info_t *> dissector_info_set;
- GList *cur;
- for (cur = decode_as_list; cur; cur = cur->next) {
- decode_as_t *entry = (decode_as_t *) cur->data;
- if (((proto_name == NULL) || (g_strcmp0(proto_name, entry->name) == 0)) &&
- (g_strcmp0(ui_name_to_name_[text], entry->table_name) == 0)) {
- if (edt_present) {
- for (uint ni = 0; ni < entry->num_items; ni++) {
- if (entry->values[ni].num_values == 1) { // Skip over multi-value ("both") entries
- selector_combo_box_->addItem(entryString(entry->table_name,
- entry->values[ni].build_values[0](&cap_file_->edt->pi)));
- }
- }
- selector_combo_box_->setCurrentIndex(entry->default_index_value);
- }
- entry->populate_list(entry->table_name, decodeAddProtocol, &dissector_info_set);
- }
- }
- if (edt_present) {
- cap_file_->edt->pi.curr_layer_num = curr_layer_num_saved;
- }
- if (selector_combo_box_->count() > 0) {
- selector_combo_box_->setCurrentIndex(0);
- } else {
- ftenum_t selector_type = get_dissector_table_selector_type(ui_name_to_name_[text]);
- if (IS_FT_STRING(selector_type)) {
- selector_combo_box_->setEditText(default_str_selector_);
- } else {
- selector_combo_box_->setEditText(default_int_selector_);
+ const QModelIndex &current = ui->decodeAsTreeView->currentIndex();
+ if (model_ && current.isValid()) {
+ if (!model_->removeRows(current.row(), 1)) {
+ qDebug() << "Failed to remove row";
}
}
-
- cur_proto_combo_box_->clear();
- cur_proto_combo_box_->addItem(DECODE_AS_NONE);
- cur_proto_combo_box_->insertSeparator(cur_proto_combo_box_->count());
-
- QSetIterator<dissector_info_t *> i(dissector_info_set);
- while (i.hasNext()) {
- dissector_info_t *dissector_info = i.next();
-
- cur_proto_combo_box_->addItem(dissector_info->proto_name, VariantPointer<dissector_info_t>::asQVariant(dissector_info));
- }
-
- cur_proto_combo_box_->model()->sort(0);
- cur_proto_combo_box_->setCurrentIndex(cur_proto_combo_box_->findText(current_text));
}
-void DecodeAsDialog::selectorEditTextChanged(const QString &text)
-{
- QTreeWidgetItem *item = ui->decodeAsTreeWidget->currentItem();
- if (!item || !table_names_combo_box_ || !selector_combo_box_) return;
-
- const char *table_name = ui_name_to_name_[table_names_combo_box_->currentText()];
- if (!table_name) return;
-
- item->setText(selector_col_, text);
- ftenum_t selector_type = get_dissector_table_selector_type(table_name);
- dissector_handle_t dissector;
-
- if (IS_FT_STRING(selector_type)) {
- dissector = dissector_get_default_string_handle(table_name, text.toUtf8().constData());
- } else {
- dissector = dissector_get_default_uint_handle(table_name, text.toInt(NULL, 0));
- }
-
- if (dissector) {
- item->setText(default_col_, dissector_handle_get_short_name(dissector));
- } else {
- item->setText(default_col_, DECODE_AS_NONE);
- }
-}
-
-void DecodeAsDialog::curProtoCurrentIndexChanged(const QString &text)
-{
- QTreeWidgetItem *item = ui->decodeAsTreeWidget->currentItem();
- if (!item) return;
- item->setText(proto_col_, text);
- item->setData(proto_col_, Qt::UserRole, cur_proto_combo_box_->itemData(cur_proto_combo_box_->findText(text)));
-}
-
-typedef QPair<const char *, guint32> UintPair;
-typedef QPair<const char *, const char *> CharPtrPair;
-
-void DecodeAsDialog::gatherChangedEntries(const gchar *table_name,
- ftenum_t selector_type, gpointer key, gpointer, gpointer user_data)
+void DecodeAsDialog::on_copyToolButton_clicked()
{
- DecodeAsDialog *da_dlg = qobject_cast<DecodeAsDialog*>((DecodeAsDialog *)user_data);
- if (!da_dlg) return;
-
- switch (selector_type) {
- case FT_UINT8:
- case FT_UINT16:
- case FT_UINT24:
- case FT_UINT32:
- da_dlg->changed_uint_entries_ << UintPair(table_name, GPOINTER_TO_UINT(key));
- break;
- case FT_STRING:
- case FT_STRINGZ:
- case FT_UINT_STRING:
- case FT_STRINGZPAD:
- da_dlg->changed_string_entries_ << CharPtrPair(table_name, (const char *) key);
- break;
- default:
- break;
- }
+ addRecord(true);
}
void DecodeAsDialog::applyChanges()
{
- dissector_table_t sub_dissectors;
- module_t *module;
- pref_t* pref_value;
- dissector_handle_t handle;
- // Reset all dissector tables, then apply all rules from GUI.
-
- // We can't call g_hash_table_removed from g_hash_table_foreach, which
- // means we can't call dissector_reset_{string,uint} from
- // dissector_all_tables_foreach_changed. Collect changed entries in
- // lists and remove them separately.
- //
- // If dissector_all_tables_remove_changed existed we could call it
- // instead.
- dissector_all_tables_foreach_changed(gatherChangedEntries, this);
- foreach (UintPair uint_entry, changed_uint_entries_) {
- /* Set "Decode As preferences" to default values */
- sub_dissectors = find_dissector_table(uint_entry.first);
- handle = dissector_get_uint_handle(sub_dissectors, uint_entry.second);
- if (handle != NULL) {
- module = prefs_find_module(proto_get_protocol_filter_name(dissector_handle_get_protocol_index(handle)));
- pref_value = prefs_find_preference(module, uint_entry.first);
- if (pref_value != NULL) {
- module->prefs_changed = TRUE;
- reset_pref(pref_value);
- }
- }
-
- dissector_reset_uint(uint_entry.first, uint_entry.second);
- }
- changed_uint_entries_.clear();
- foreach (CharPtrPair char_ptr_entry, changed_string_entries_) {
- dissector_reset_string(char_ptr_entry.first, char_ptr_entry.second);
- }
- changed_string_entries_.clear();
-
- for (int i = 0; i < ui->decodeAsTreeWidget->topLevelItemCount(); i++) {
- QTreeWidgetItem *item = ui->decodeAsTreeWidget->topLevelItem(i);
- ftenum_t selector_type = get_dissector_table_selector_type(ui_name_to_name_[item->text(table_col_)]);
- dissector_info_t *dissector_info;
- QVariant variant = item->data(proto_col_, Qt::UserRole);
- decode_as_t *decode_as_entry;
-
- if (variant == QVariant::Invalid) {
- continue;
- }
-
- dissector_info = VariantPointer<dissector_info_t>::asPtr(variant);
-
- for (GList *cur = decode_as_list; cur; cur = cur->next) {
- decode_as_entry = (decode_as_t *) cur->data;
-
- if (!g_strcmp0(decode_as_entry->table_name, ui_name_to_name_[item->text(table_col_)])) {
- gpointer selector_value;
- QByteArray byteArray;
-
- switch (selector_type) {
- case FT_UINT8:
- case FT_UINT16:
- case FT_UINT24:
- case FT_UINT32:
- selector_value = GUINT_TO_POINTER(item->text(selector_col_).toUInt(0, 0));
- break;
- case FT_STRING:
- case FT_STRINGZ:
- case FT_UINT_STRING:
- case FT_STRINGZPAD:
- byteArray = item->text(selector_col_).toUtf8();
- selector_value = (gpointer) byteArray.constData();
- break;
- default:
- continue;
- }
-
- if (item->text(proto_col_) == DECODE_AS_NONE || !dissector_info->dissector_handle) {
- decode_as_entry->reset_value(decode_as_entry->table_name, selector_value);
- sub_dissectors = find_dissector_table(decode_as_entry->table_name);
-
- /* For now, only numeric dissector tables can use preferences */
- if (IS_FT_UINT(dissector_table_get_type(sub_dissectors))) {
- if (dissector_info->dissector_handle != NULL) {
- module = prefs_find_module(proto_get_protocol_filter_name(dissector_handle_get_protocol_index(dissector_info->dissector_handle)));
- pref_value = prefs_find_preference(module, decode_as_entry->table_name);
- if (pref_value != NULL) {
- module->prefs_changed = TRUE;
- prefs_remove_decode_as_value(pref_value, GPOINTER_TO_UINT(selector_value), TRUE);
- }
- }
- }
- break;
- } else {
- decode_as_entry->change_value(decode_as_entry->table_name, selector_value, &dissector_info->dissector_handle, (char *) item->text(proto_col_).toUtf8().constData());
- sub_dissectors = find_dissector_table(decode_as_entry->table_name);
-
- /* For now, only numeric dissector tables can use preferences */
- if (IS_FT_UINT(dissector_table_get_type(sub_dissectors))) {
- module = prefs_find_module(proto_get_protocol_filter_name(dissector_handle_get_protocol_index(dissector_info->dissector_handle)));
- pref_value = prefs_find_preference(module, decode_as_entry->table_name);
- if (pref_value != NULL) {
- module->prefs_changed = TRUE;
- prefs_add_decode_as_value(pref_value, GPOINTER_TO_UINT(selector_value), FALSE);
- }
- }
- break;
- }
- }
- }
-
- delete(dissector_info);
- }
-
+ model_->applyChanges();
wsApp->queueAppSignal(WiresharkApplication::PacketDissectionChanged);
}
diff --git a/ui/qt/decode_as_dialog.h b/ui/qt/decode_as_dialog.h
index 9682f7d8c7..4acf6fe51c 100644
--- a/ui/qt/decode_as_dialog.h
+++ b/ui/qt/decode_as_dialog.h
@@ -27,6 +27,8 @@
#include <glib.h>
#include "cfile.h"
+#include <ui/qt/models/decode_as_model.h>
+#include <ui/qt/models/decode_as_delegate.h>
#include "geometry_state_dialog.h"
#include <QMap>
@@ -47,45 +49,24 @@ public:
explicit DecodeAsDialog(QWidget *parent = 0, capture_file *cf = NULL, bool create_new = false);
~DecodeAsDialog();
-public slots:
- void setCaptureFile(capture_file *cf);
-
private:
Ui::DecodeAsDialog *ui;
- capture_file *cap_file_;
- QComboBox *table_names_combo_box_;
- QComboBox *selector_combo_box_;
- QComboBox *cur_proto_combo_box_;
- QMap<QString, const char *> ui_name_to_name_;
- QList<QPair<const char *, guint32> > changed_uint_entries_;
- QList<QPair<const char *, const char *> > changed_string_entries_;
-
- QString entryString(const gchar *table_name, gpointer value);
- static void gatherChangedEntries(const gchar *table_name, ftenum_t selector_type,
- gpointer key, gpointer value, gpointer user_data);
- static void buildChangedList(const gchar *table_name, ftenum_t selector_type,
- gpointer key, gpointer value, gpointer user_data);
- static void buildDceRpcChangedList(gpointer data, gpointer user_data);
- static void decodeAddProtocol(const gchar *table_name, const gchar *proto_name, gpointer value, gpointer user_data);
+ DecodeAsModel* model_;
+ DecodeAsDelegate* delegate_;
+
void addRecord(bool copy_from_current = false);
- void fillTypeColumn(QTreeWidgetItem *item);
+ void applyChanges();
+ void fillTable();
+ void resizeColumns();
private slots:
- void fillTable();
- void activateLastItem();
+ void on_decodeAsTreeView_currentItemChanged(const QModelIndex &current, const QModelIndex &previous);
- void on_decodeAsTreeWidget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous);
- void on_decodeAsTreeWidget_itemActivated(QTreeWidgetItem *item, int column = 0);
- void on_decodeAsTreeWidget_itemSelectionChanged();
void on_newToolButton_clicked();
void on_deleteToolButton_clicked();
void on_copyToolButton_clicked();
- void tableNamesCurrentIndexChanged(const QString & text);
- void selectorEditTextChanged(const QString & text);
- void curProtoCurrentIndexChanged(const QString & text);
- void applyChanges();
void on_buttonBox_clicked(QAbstractButton *button);
};
diff --git a/ui/qt/decode_as_dialog.ui b/ui/qt/decode_as_dialog.ui
index b65242104f..f8a78b1e0c 100644
--- a/ui/qt/decode_as_dialog.ui
+++ b/ui/qt/decode_as_dialog.ui
@@ -12,47 +12,10 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
- <widget class="QTreeWidget" name="decodeAsTreeWidget">
+ <widget class="TabnavTreeView" name="decodeAsTreeView">
<property name="indentation">
<number>0</number>
</property>
- <column>
- <property name="text">
- <string>Field</string>
- </property>
- <property name="toolTip">
- <string>Match using this field</string>
- </property>
- </column>
- <column>
- <property name="text">
- <string>Value</string>
- </property>
- <property name="toolTip">
- <string>Current &quot;Decode As&quot; behavior</string>
- </property>
- </column>
- <column>
- <property name="text">
- <string>Type</string>
- </property>
- </column>
- <column>
- <property name="text">
- <string>Default</string>
- </property>
- <property name="toolTip">
- <string>Default &quot;Decode As&quot; behavior</string>
- </property>
- </column>
- <column>
- <property name="text">
- <string>Current</string>
- </property>
- <property name="toolTip">
- <string>Change behavior when the protocol field matches this value</string>
- </property>
- </column>
</widget>
</item>
<item>
@@ -76,6 +39,9 @@
<property name="toolTip">
<string>Remove this dissection behavior.</string>
</property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
<property name="icon">
<iconset resource="../../image/toolbar.qrc">
<normaloff>:/stock/minus-8.png</normaloff>:/stock/minus-8.png</iconset>
@@ -148,6 +114,11 @@
<extends>QLabel</extends>
<header>widgets/elided_label.h</header>
</customwidget>
+ <customwidget>
+ <class>TabnavTreeView</class>
+ <extends>QTreeView</extends>
+ <header>widgets/tabnav_tree_view.h</header>
+ </customwidget>
</customwidgets>
<resources>
<include location="../../image/toolbar.qrc"/>
diff --git a/ui/qt/models/decode_as_delegate.cpp b/ui/qt/models/decode_as_delegate.cpp
new file mode 100644
index 0000000000..bc632f5449
--- /dev/null
+++ b/ui/qt/models/decode_as_delegate.cpp
@@ -0,0 +1,408 @@
+/* decode_as_delegate.cpp
+ * Delegates for editing various field types in a Decode As record.
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "decode_as_delegate.h"
+
+#include "epan/decode_as.h"
+#include "epan/epan_dissect.h"
+
+#include <ui/qt/utils/variant_pointer.h>
+
+#include <QComboBox>
+#include <QEvent>
+#include <QLineEdit>
+#include <QTreeView>
+
+typedef struct _dissector_info_t {
+ QString proto_name;
+ dissector_handle_t dissector_handle;
+} dissector_info_t;
+
+Q_DECLARE_METATYPE(dissector_info_t *)
+
+DecodeAsDelegate::DecodeAsDelegate(QObject *parent, capture_file *cf)
+ : QStyledItemDelegate(parent),
+ cap_file_(cf)
+{
+ cachePacketProtocols();
+}
+
+DecodeAsItem* DecodeAsDelegate::indexToField(const QModelIndex &index) const
+{
+ const QVariant v = index.model()->data(index, Qt::UserRole);
+ return static_cast<DecodeAsItem*>(v.value<void *>());
+}
+
+void DecodeAsDelegate::cachePacketProtocols()
+{
+ //cache the list of potential decode as protocols in the current packet
+ if (cap_file_ && cap_file_->edt) {
+
+ wmem_list_frame_t * protos = wmem_list_head(cap_file_->edt->pi.layers);
+ guint8 curr_layer_num = 1;
+
+ while (protos != NULL) {
+ int proto_id = GPOINTER_TO_INT(wmem_list_frame_data(protos));
+ const gchar * proto_name = proto_get_protocol_filter_name(proto_id);
+ for (GList *cur = decode_as_list; cur; cur = cur->next) {
+ decode_as_t *entry = (decode_as_t *) cur->data;
+ if (g_strcmp0(proto_name, entry->name) == 0) {
+ packet_proto_data_t proto_data;
+
+ proto_data.table_ui_name = get_dissector_table_ui_name(entry->table_name);
+ proto_data.proto_name = proto_name;
+ proto_data.curr_layer_num = curr_layer_num;
+
+ packet_proto_list_.append(proto_data);
+ }
+ }
+ protos = wmem_list_frame_next(protos);
+ curr_layer_num++;
+ }
+ }
+}
+
+void DecodeAsDelegate::collectDAProtocols(QSet<QString>& all_protocols, QList<QString>& current_list) const
+{
+ // If a packet is selected group its tables at the top in order
+ // from last-dissected to first.
+
+ //gather the initial list
+ for (GList *cur = decode_as_list; cur; cur = cur->next) {
+ decode_as_t *entry = (decode_as_t *) cur->data;
+ const char *table_name = get_dissector_table_ui_name(entry->table_name);
+ if (table_name) {
+ all_protocols.insert(get_dissector_table_ui_name(entry->table_name));
+ }
+ }
+
+ //filter out those in selected packet
+ foreach(packet_proto_data_t proto, packet_proto_list_)
+ {
+ current_list.append(proto.table_ui_name);
+ all_protocols.remove(proto.table_ui_name);
+ }
+}
+
+//Determine if there are multiple values in the selector field that would
+//correspond to using a combo box
+bool DecodeAsDelegate::isSelectorCombo(DecodeAsItem* item) const
+{
+ const gchar *proto_name = NULL;
+
+ foreach(packet_proto_data_t proto, packet_proto_list_)
+ {
+ if (g_strcmp0(proto.table_ui_name, item->tableUIName_) == 0) {
+ proto_name = proto.proto_name;
+ break;
+ }
+ }
+
+ for (GList *cur = decode_as_list; cur; cur = cur->next) {
+ decode_as_t *entry = (decode_as_t *) cur->data;
+ if ((g_strcmp0(proto_name, entry->name) == 0) &&
+ (g_strcmp0(item->tableName_, entry->table_name) == 0) &&
+ (cap_file_ && cap_file_->edt) &&
+ (entry->num_items > 1)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void DecodeAsDelegate::decodeAddProtocol(const gchar *, const gchar *proto_name, gpointer value, gpointer user_data)
+{
+ QMap<QString, dissector_info_t*>* proto_list = (QMap<QString, dissector_info_t*>*)user_data;
+
+ if (!proto_list)
+ return;
+
+ dissector_info_t *dissector_info = new dissector_info_t();
+ dissector_info->proto_name = proto_name;
+ dissector_info->dissector_handle = (dissector_handle_t) value;
+
+ proto_list->insert(proto_name, dissector_info);
+}
+
+QWidget* DecodeAsDelegate::createEditor(QWidget *parentWidget, const QStyleOptionViewItem &option,
+ const QModelIndex &index) const
+{
+ DecodeAsItem* item = indexToField(index);
+
+ switch(index.column())
+ {
+ case DecodeAsModel::colTable:
+ {
+ QComboBox *editor = new QComboBox(parentWidget);
+ QSet<QString> da_set;
+ QList<QString> packet_list;
+ QString table_ui_name;
+
+ collectDAProtocols(da_set, packet_list);
+
+ editor->setSizeAdjustPolicy(QComboBox::AdjustToContents);
+
+ //put the protocols from the packet first in the combo box
+ foreach (table_ui_name, packet_list) {
+ editor->addItem(table_ui_name, table_ui_name);
+ }
+ if (packet_list.count() > 0) {
+ editor->insertSeparator(packet_list.count());
+ }
+
+ //put the rest of the protocols in the combo box
+ QList<QString> da_list = da_set.toList();
+ qSort(da_list.begin(), da_list.end());
+
+ foreach (table_ui_name, da_list) {
+ editor->addItem(table_ui_name, table_ui_name);
+ }
+
+ //Make sure the combo box is at least as wide as the column
+ QTreeView* parentTree = (QTreeView*)parent();
+ int protoColWidth = parentTree->columnWidth(index.column());
+ if (protoColWidth > editor->size().width())
+ editor->setFixedWidth(protoColWidth);
+
+ return editor;
+ }
+ case DecodeAsModel::colSelector:
+ {
+ QComboBox *editor = NULL;
+ const gchar *proto_name = NULL;
+ bool edt_present = cap_file_ && cap_file_->edt;
+ gint8 curr_layer_num_saved = edt_present ? cap_file_->edt->pi.curr_layer_num : 0;
+
+ foreach(packet_proto_data_t proto, packet_proto_list_)
+ {
+ if (g_strcmp0(proto.table_ui_name, item->tableUIName_) == 0) {
+ if (edt_present) {
+ cap_file_->edt->pi.curr_layer_num = proto.curr_layer_num;
+ }
+ proto_name = proto.proto_name;
+ //XXX - break? Or do we always want the last layer of tunnelled protocols?
+ }
+ }
+
+ for (GList *cur = decode_as_list; cur; cur = cur->next) {
+ decode_as_t *entry = (decode_as_t *) cur->data;
+ if ((g_strcmp0(proto_name, entry->name) == 0) &&
+ (g_strcmp0(item->tableName_, entry->table_name) == 0)) {
+ if (edt_present) {
+ if (entry->num_items > 1)
+ {
+ //only create a combobox if there is a choice of values, otherwise it looks funny
+ editor = new QComboBox(parentWidget);
+
+ //Don't limit user to just what's in combo box
+ editor->setEditable(true);
+
+ editor->setSizeAdjustPolicy(QComboBox::AdjustToContents);
+
+ //add the current value of the column
+ const QString& current_value = index.model()->data(index, Qt::EditRole).toString();
+ if (!current_value.isEmpty())
+ editor->addItem(current_value);
+
+ //get the value(s) from the packet
+ for (uint ni = 0; ni < entry->num_items; ni++) {
+ if (entry->values[ni].num_values == 1) { // Skip over multi-value ("both") entries
+ QString entryStr = DecodeAsModel::entryString(entry->table_name,
+ entry->values[ni].build_values[0](&cap_file_->edt->pi));
+ //don't duplicate entries
+ if (editor->findText(entryStr) < 0)
+ editor->addItem(entryStr);
+ }
+ }
+ editor->setCurrentIndex(entry->default_index_value);
+
+ //Make sure the combo box is at least as wide as the column
+ QTreeView* parentTree = (QTreeView*)parent();
+ int protoColWidth = parentTree->columnWidth(index.column());
+ if (protoColWidth > editor->size().width())
+ editor->setFixedWidth(protoColWidth);
+
+ }
+ }
+ break;
+ }
+ }
+
+ if (edt_present) {
+ cap_file_->edt->pi.curr_layer_num = curr_layer_num_saved;
+ }
+
+ //if there isn't a need for a combobox, just let user have a text box for direct edit
+ if (editor == NULL)
+ return QStyledItemDelegate::createEditor(parentWidget, option, index);
+
+ return editor;
+ }
+
+ case DecodeAsModel::colProtocol:
+ {
+ QComboBox *editor = new QComboBox(parentWidget);
+ QMap<QString, dissector_info_t*> protocols;
+
+ editor->setSizeAdjustPolicy(QComboBox::AdjustToContents);
+
+ for (GList *cur = decode_as_list; cur; cur = cur->next) {
+ decode_as_t *entry = (decode_as_t *) cur->data;
+ if (g_strcmp0(item->tableName_, entry->table_name) == 0) {
+ entry->populate_list(entry->table_name, decodeAddProtocol, &protocols);
+ break;
+ }
+ }
+
+ editor->addItem(DECODE_AS_NONE);
+ editor->insertSeparator(editor->count());
+
+ //QMap already sorts the keys (protocols) alphabetically
+ QMap<QString, dissector_info_t*>::iterator protocol;
+ for(protocol = protocols.begin(); protocol != protocols.end(); protocol++)
+ {
+ editor->addItem(protocol.key(), VariantPointer<dissector_info_t>::asQVariant(protocol.value()));
+ }
+
+ //Make sure the combo box is at least as wide as the column
+ QTreeView* parentTree = (QTreeView*)parent();
+ int protoColWidth = parentTree->columnWidth(index.column());
+ if (protoColWidth > editor->size().width())
+ editor->setFixedWidth(protoColWidth);
+
+ return editor;
+ }
+ }
+
+ return NULL;
+}
+
+void DecodeAsDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
+{
+ DecodeAsItem* item = indexToField(index);
+
+ switch(index.column())
+ {
+ case DecodeAsModel::colTable:
+ case DecodeAsModel::colProtocol:
+ {
+ QComboBox *combobox = static_cast<QComboBox *>(editor);
+ const QString &data = index.model()->data(index, Qt::EditRole).toString();
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
+ combobox->setCurrentText(data);
+#else
+ int new_index = combobox->findText(data);
+ if (new_index >= 0) {
+ combobox->setCurrentIndex(new_index);
+ }
+#endif
+ }
+ break;
+ case DecodeAsModel::colSelector:
+ if (isSelectorCombo(item)) {
+ QComboBox *combobox = static_cast<QComboBox *>(editor);
+ const QString &data = index.model()->data(index, Qt::EditRole).toString();
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
+ combobox->setCurrentText(data);
+#else
+ int new_index = combobox->findText(data);
+ if (new_index >= 0) {
+ combobox->setCurrentIndex(new_index);
+ }
+#endif
+ }
+ else {
+ QStyledItemDelegate::setEditorData(editor, index);
+ }
+ break;
+ default:
+ QStyledItemDelegate::setEditorData(editor, index);
+ break;
+ }
+}
+
+void DecodeAsDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
+ const QModelIndex &index) const
+{
+ DecodeAsItem* item = indexToField(index);
+
+ switch(index.column())
+ {
+ case DecodeAsModel::colTable:
+ {
+ QComboBox *combobox = static_cast<QComboBox *>(editor);
+ const QString &data = combobox->currentText();
+ model->setData(index, data, Qt::EditRole);
+ break;
+ }
+ case DecodeAsModel::colSelector:
+ if (isSelectorCombo(item)) {
+ QComboBox *combobox = static_cast<QComboBox *>(editor);
+ const QString &data = combobox->currentText();
+ model->setData(index, data, Qt::EditRole);
+ } else {
+ QStyledItemDelegate::setModelData(editor, model, index);
+ }
+ break;
+ case DecodeAsModel::colProtocol:
+ {
+ QComboBox *combobox = static_cast<QComboBox *>(editor);
+ const QString &data = combobox->currentText();
+ model->setData(index, data, Qt::EditRole);
+
+ //set the dissector handle
+ QVariant var = combobox->itemData(combobox->currentIndex());
+ dissector_info_t* dissector_info = VariantPointer<dissector_info_t>::asPtr(var);
+ if (dissector_info != NULL) {
+ ((DecodeAsModel*)model)->setDissectorHandle(index, dissector_info->dissector_handle);
+ } else {
+ ((DecodeAsModel*)model)->setDissectorHandle(index, NULL);
+ }
+ break;
+ }
+ default:
+ QStyledItemDelegate::setModelData(editor, model, index);
+ break;
+ }
+}
+
+#if 0
+// Qt docs suggest overriding updateEditorGeometry, but the defaults seem sane.
+void UatDelegate::updateEditorGeometry(QWidget *editor,
+ const QStyleOptionViewItem &option, const QModelIndex &index) const
+{
+ QStyledItemDelegate::updateEditorGeometry(editor, option, index);
+}
+#endif
+
+/* * 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/decode_as_delegate.h b/ui/qt/models/decode_as_delegate.h
new file mode 100644
index 0000000000..50461f00d9
--- /dev/null
+++ b/ui/qt/models/decode_as_delegate.h
@@ -0,0 +1,71 @@
+/* decode_as_delegate.h
+ * Delegates for editing various field types in a Decode As record.
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef DECODE_AS_DELEGATE_H
+#define DECODE_AS_DELEGATE_H
+
+#include <config.h>
+#include <glib.h>
+
+#include "cfile.h"
+
+#include <QStyledItemDelegate>
+#include <QSet>
+#include <QList>
+#include <ui/qt/models/decode_as_model.h>
+
+typedef struct _packet_proto_data_t {
+ const gchar* proto_name;
+ const gchar* table_ui_name;
+ guint8 curr_layer_num;
+} packet_proto_data_t;
+
+class DecodeAsDelegate : public QStyledItemDelegate
+{
+ Q_OBJECT
+
+public:
+ DecodeAsDelegate(QObject *parent = 0, capture_file *cf = NULL);
+
+ 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;
+
+#if 0
+ void updateEditorGeometry(QWidget *editor,
+ const QStyleOptionViewItem &option, const QModelIndex &index) const;
+#endif
+
+private:
+ DecodeAsItem *indexToField(const QModelIndex &index) const;
+ void collectDAProtocols(QSet<QString>& all_protocols, QList<QString>& current_list) const;
+ void cachePacketProtocols();
+ bool isSelectorCombo(DecodeAsItem* item) const;
+
+ static void decodeAddProtocol(const gchar *table_name, const gchar *proto_name, gpointer value, gpointer user_data);
+
+ capture_file *cap_file_;
+ QList<packet_proto_data_t> packet_proto_list_;
+};
+#endif // DECODE_AS_DELEGATE_H
diff --git a/ui/qt/models/decode_as_model.cpp b/ui/qt/models/decode_as_model.cpp
new file mode 100644
index 0000000000..2c15e419fc
--- /dev/null
+++ b/ui/qt/models/decode_as_model.cpp
@@ -0,0 +1,650 @@
+/* decode_as_model.cpp
+ * Data model for Decode As records.
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "decode_as_model.h"
+#include <epan/to_str.h>
+#include <epan/decode_as.h>
+#include <epan/epan_dissect.h>
+#include <epan/packet.h>
+#include <epan/prefs.h>
+#include <epan/prefs-int.h>
+#include <epan/dissectors/packet-dcerpc.h>
+
+#include <ui/qt/utils/qt_ui_utils.h>
+
+static const char *DEFAULT_TABLE = "tcp.port"; // Arbitrary
+static const char *DEFAULT_UI_TABLE = "TCP port"; // Arbitrary
+
+DecodeAsItem::DecodeAsItem()
+ : tableName_(DEFAULT_TABLE),
+ tableUIName_(DEFAULT_UI_TABLE),
+ selectorUint_(0),
+ selectorString_(""),
+ default_proto_(DECODE_AS_NONE),
+ current_proto_(DECODE_AS_NONE),
+ dissector_handle_(NULL)
+{
+}
+
+DecodeAsItem::~DecodeAsItem()
+{
+}
+
+
+DecodeAsModel::DecodeAsModel(QObject *parent, capture_file *cf) :
+ QAbstractTableModel(parent),
+ cap_file_(cf)
+{
+}
+
+Qt::ItemFlags DecodeAsModel::flags(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return 0;
+
+ Qt::ItemFlags flags = QAbstractTableModel::flags(index);
+ switch(index.column())
+ {
+ case DecodeAsModel::colTable:
+ case DecodeAsModel::colSelector:
+ case DecodeAsModel::colProtocol:
+ flags |= Qt::ItemIsEditable;
+ break;
+ }
+
+ return flags;
+}
+
+QVariant DecodeAsModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid()) {
+ return QVariant();
+ }
+
+ DecodeAsItem* item;
+
+ switch (role)
+ {
+ case Qt::ToolTipRole:
+ switch (index.column())
+ {
+ case colTable:
+ return tr("Match using this field");
+ case colSelector:
+ return tr("Current\"Decode As\" behavior");
+ case colType:
+ return QVariant();
+ case colDefault:
+ return tr("Default \"Decode As\" behavior");
+ case colProtocol:
+ return tr("Change behavior when the protocol field matches this value");
+ }
+ return QVariant();
+ case Qt::DisplayRole:
+ case Qt::EditRole:
+ item = decode_as_items_[index.row()];
+ if (item == NULL)
+ return QVariant();
+
+ switch (index.column())
+ {
+ case colTable:
+ return item->tableUIName_;
+ case colSelector:
+ {
+ ftenum_t selector_type = get_dissector_table_selector_type(item->tableName_);
+ if (IS_FT_UINT(selector_type)) {
+ return entryString(item->tableName_, GUINT_TO_POINTER(item->selectorUint_));
+ } else if (IS_FT_STRING(selector_type)) {
+ return entryString(item->tableName_, (gpointer)item->selectorString_.toUtf8().constData());
+ }
+
+ return DECODE_AS_NONE;
+ }
+ case colType:
+ {
+ ftenum_t selector_type = get_dissector_table_selector_type(item->tableName_);
+
+ if (IS_FT_STRING(selector_type)) {
+ return tr("String");
+ } else {
+ QString type_desc = tr("Integer, base ");
+ switch (get_dissector_table_param(item->tableName_)) {
+ case BASE_OCT:
+ type_desc.append("8");
+ break;
+ case BASE_DEC:
+ type_desc.append("10");
+ break;
+ case BASE_HEX:
+ type_desc.append("16");
+ break;
+ default:
+ type_desc.append(tr("unknown"));
+ }
+ return type_desc;
+ }
+ }
+ case colDefault:
+ return item->default_proto_;
+ case colProtocol:
+ return item->current_proto_;
+ }
+ return QVariant();
+
+ case Qt::UserRole:
+ item = decode_as_items_[index.row()];
+ return QVariant::fromValue(static_cast<void *>(item));
+ }
+
+ return QVariant();
+}
+
+QVariant DecodeAsModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (role != Qt::DisplayRole || orientation != Qt::Horizontal)
+ return QVariant();
+
+ switch (section) {
+ case colTable:
+ return tr("Field");
+ case colSelector:
+ return tr("Value");
+ case colType:
+ return tr("Type");
+ case colDefault:
+ return tr("Default");
+ case colProtocol:
+ return tr("Current");
+ default:
+ g_assert_not_reached();
+ }
+
+ return QVariant();
+}
+
+int DecodeAsModel::rowCount(const QModelIndex &parent) const
+{
+ // there are no children
+ if (parent.isValid()) {
+ return 0;
+ }
+
+ return decode_as_items_.count();
+}
+
+int DecodeAsModel::columnCount(const QModelIndex &parent) const
+{
+ // there are no children
+ if (parent.isValid()) {
+ return 0;
+ }
+
+ return colDecodeAsMax;
+}
+
+bool DecodeAsModel::setData(const QModelIndex &cur_index, const QVariant &value, int role)
+{
+ if (!cur_index.isValid())
+ return false;
+
+ if (role != Qt::EditRole)
+ return false;
+
+ if (data(cur_index, role) == value) {
+ // Data appears unchanged, do not do additional checks.
+ return true;
+ }
+
+ DecodeAsItem* item = decode_as_items_[cur_index.row()];
+
+ switch(cur_index.column())
+ {
+ case DecodeAsModel::colTable:
+ {
+ QString valueStr = value.toString();
+ //grab the table values from the Decode As list because they are persistent
+ for (GList *cur = decode_as_list; cur; cur = cur->next) {
+ decode_as_t *entry = (decode_as_t *) cur->data;
+ if (valueStr.compare(entry->name) == 0) {
+ item->tableName_ = entry->table_name;
+ item->tableUIName_ = get_dissector_table_ui_name(entry->table_name);
+
+ //all other columns affected
+ emit dataChanged(index(cur_index.row(), colSelector),
+ index(cur_index.row(), colProtocol));
+
+ }
+ }
+ }
+ break;
+ case DecodeAsModel::colProtocol:
+ item->current_proto_ = value.toString();
+ break;
+ case DecodeAsModel::colSelector:
+ {
+ ftenum_t selector_type = get_dissector_table_selector_type(item->tableName_);
+
+ if (IS_FT_STRING(selector_type)) {
+ item->selectorString_ = value.toString();
+ } else if (IS_FT_UINT(selector_type)) {
+ item->selectorUint_ = value.toUInt();
+ }
+ }
+ break;
+ }
+
+ return true;
+}
+
+bool DecodeAsModel::insertRows(int row, int count, const QModelIndex &/*parent*/)
+{
+ // support insertion of just one item for now.
+ if (count != 1 || row < 0 || row > rowCount())
+ return false;
+
+ beginInsertRows(QModelIndex(), row, row);
+
+ DecodeAsItem* item = new DecodeAsItem();
+
+ if (cap_file_ && cap_file_->edt) {
+ //populate the new Decode As item with the last protocol layer
+ //that can support Decode As
+ wmem_list_frame_t * protos = wmem_list_head(cap_file_->edt->pi.layers);
+ gint8 curr_layer_num_saved = cap_file_->edt->pi.curr_layer_num;
+ guint8 curr_layer_num = 1;
+
+ while (protos != NULL) {
+ int proto_id = GPOINTER_TO_INT(wmem_list_frame_data(protos));
+ const gchar * proto_name = proto_get_protocol_filter_name(proto_id);
+ for (GList *cur = decode_as_list; cur; cur = cur->next) {
+ decode_as_t *entry = (decode_as_t *) cur->data;
+ if (g_strcmp0(proto_name, entry->name) == 0) {
+ dissector_handle_t dissector = NULL;
+ ftenum_t selector_type = get_dissector_table_selector_type(entry->table_name);
+
+ //reset the default and current protocols in case previous layer
+ //populated it and this layer doesn't have a handle for it
+ item->default_proto_ = item->current_proto_ = DECODE_AS_NONE;
+
+ item->tableName_ = entry->table_name;
+ item->tableUIName_ = get_dissector_table_ui_name(entry->table_name);
+
+ //see if there is a default dissector that matches value
+ if (IS_FT_STRING(selector_type)) {
+
+ //pick the first value in the packet as the default
+ if (entry->num_items > 1) {
+ cap_file_->edt->pi.curr_layer_num = curr_layer_num;
+ gpointer selector = entry->values[0].build_values[0](&cap_file_->edt->pi);
+ if (selector != NULL) {
+ item->selectorString_ = entryString(item->tableName_, selector);
+ dissector = dissector_get_default_string_handle(entry->table_name, (const gchar*)selector);
+ } else {
+ item->selectorString_ = "";
+ }
+ }
+
+ } else if (IS_FT_UINT(selector_type)) {
+
+ //pick the first value in the packet as the default
+ if (entry->num_items > 1) {
+ cap_file_->edt->pi.curr_layer_num = curr_layer_num;
+ item->selectorUint_ = GPOINTER_TO_UINT(entry->values[0].build_values[0](&cap_file_->edt->pi));
+ }
+
+ dissector = dissector_get_default_uint_handle(entry->table_name, item->selectorUint_);
+ }
+
+ if (dissector != NULL) {
+ item->default_proto_ = dissector_handle_get_short_name(dissector);
+ //When adding a new record, "default" should equal "current", so the user can
+ //explicitly change it
+ item->current_proto_ = item->default_proto_;
+ }
+ }
+ }
+ protos = wmem_list_frame_next(protos);
+ curr_layer_num++;
+ }
+
+ cap_file_->edt->pi.curr_layer_num = curr_layer_num_saved;
+ }
+
+ decode_as_items_ << item;
+
+ endInsertRows();
+
+ return true;
+}
+
+bool DecodeAsModel::removeRows(int row, int count, const QModelIndex &/*parent*/)
+{
+ if (count != 1 || row < 0 || row >= rowCount())
+ return false;
+
+ beginRemoveRows(QModelIndex(), row, row);
+ decode_as_items_.removeAt(row);
+ endRemoveRows();
+
+ return true;
+}
+
+bool DecodeAsModel::copyRow(int dst_row, int src_row)
+{
+ if (src_row < 0 || src_row >= rowCount() || dst_row < 0 || dst_row >= rowCount()) {
+ return false;
+ }
+
+ DecodeAsItem* src = decode_as_items_[src_row];
+ DecodeAsItem* dst = decode_as_items_[dst_row];
+
+ dst->tableName_ = src->tableName_;
+ dst->tableUIName_ = src->tableUIName_;
+ dst->selectorUint_ = src->selectorUint_;
+ dst->selectorString_ = src->selectorString_;
+ dst->default_proto_ = src->default_proto_;
+ dst->current_proto_ = src->current_proto_;
+ dst->dissector_handle_ = src->dissector_handle_;
+
+ QVector<int> roles;
+ roles << Qt::EditRole << Qt::BackgroundRole;
+ emit dataChanged(index(dst_row, 0), index(dst_row, columnCount())
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
+ , roles
+#endif
+ );
+
+ return true;
+}
+
+QString DecodeAsModel::entryString(const gchar *table_name, gpointer value)
+{
+ QString entry_str;
+ ftenum_t selector_type = get_dissector_table_selector_type(table_name);
+
+ switch (selector_type) {
+
+ case FT_UINT8:
+ case FT_UINT16:
+ case FT_UINT24:
+ case FT_UINT32:
+ {
+ uint num_val = GPOINTER_TO_UINT(value);
+ switch (get_dissector_table_param(table_name)) {
+
+ case BASE_DEC:
+ entry_str = QString::number(num_val);
+ break;
+
+ case BASE_HEX:
+ int width;
+ switch (selector_type) {
+ case FT_UINT8:
+ width = 2;
+ break;
+ case FT_UINT16:
+ width = 4;
+ break;
+ case FT_UINT24:
+ width = 6;
+ break;
+ case FT_UINT32:
+ width = 8;
+ break;
+
+ default:
+ g_assert_not_reached();
+ break;
+ }
+ entry_str = QString("%1").arg(int_to_qstring(num_val, width, 16));
+ break;
+
+ case BASE_OCT:
+ entry_str = "0" + QString::number(num_val, 8);
+ break;
+ }
+ break;
+ }
+
+ case FT_STRING:
+ case FT_STRINGZ:
+ case FT_UINT_STRING:
+ case FT_STRINGZPAD:
+ entry_str = (char *)value;
+ break;
+
+ case FT_GUID:
+ //TODO: DCE/RPC dissector table
+ break;
+
+ default:
+ g_assert_not_reached();
+ break;
+ }
+ return entry_str;
+}
+
+void DecodeAsModel::fillTable()
+{
+ decode_as_items_.clear();
+ emit beginResetModel();
+
+ dissector_all_tables_foreach_changed(buildChangedList, this);
+ decode_dcerpc_add_show_list(buildDceRpcChangedList, this);
+
+ emit endResetModel();
+}
+
+void DecodeAsModel::setDissectorHandle(const QModelIndex &index, dissector_handle_t dissector_handle)
+{
+ DecodeAsItem* item = decode_as_items_[index.row()];
+ if (item != NULL)
+ item->dissector_handle_ = dissector_handle;
+}
+
+void DecodeAsModel::buildChangedList(const gchar *table_name, ftenum_t, gpointer key, gpointer value, gpointer user_data)
+{
+ DecodeAsModel *model = (DecodeAsModel*)user_data;
+ if (model == NULL)
+ return;
+
+ dissector_handle_t default_dh, current_dh;
+ QString default_proto_name(DECODE_AS_NONE), current_proto_name(DECODE_AS_NONE);
+ DecodeAsItem* item = new DecodeAsItem();
+ ftenum_t selector_type = get_dissector_table_selector_type(table_name);
+
+ item->tableName_ = table_name;
+ item->tableUIName_ = get_dissector_table_ui_name(table_name);
+ if (IS_FT_UINT(selector_type)) {
+ item->selectorUint_ = GPOINTER_TO_UINT(key);
+ } else if (IS_FT_STRING(selector_type)) {
+ item->selectorString_ = entryString(table_name, key);
+ }
+
+ default_dh = dtbl_entry_get_initial_handle((dtbl_entry_t *)value);
+ if (default_dh) {
+ default_proto_name = dissector_handle_get_short_name(default_dh);
+ }
+ item->default_proto_ = default_proto_name;
+
+ current_dh = dtbl_entry_get_handle((dtbl_entry_t *)value);
+ if (current_dh) {
+ current_proto_name = QString(dissector_handle_get_short_name(current_dh));
+ }
+ item->current_proto_ = current_proto_name;
+ item->dissector_handle_ = current_dh;
+
+ model->decode_as_items_ << item;
+}
+
+void DecodeAsModel::buildDceRpcChangedList(gpointer, gpointer)
+{
+ // decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t *)data;
+}
+
+typedef QPair<const char *, guint32> UintPair;
+typedef QPair<const char *, const char *> CharPtrPair;
+
+void DecodeAsModel::gatherChangedEntries(const gchar *table_name,
+ ftenum_t selector_type, gpointer key, gpointer, gpointer user_data)
+{
+ DecodeAsModel *model = qobject_cast<DecodeAsModel*>((DecodeAsModel*)user_data);
+ if (model == NULL)
+ return;
+
+ switch (selector_type) {
+ case FT_UINT8:
+ case FT_UINT16:
+ case FT_UINT24:
+ case FT_UINT32:
+ model->changed_uint_entries_ << UintPair(table_name, GPOINTER_TO_UINT(key));
+ break;
+ case FT_STRING:
+ case FT_STRINGZ:
+ case FT_UINT_STRING:
+ case FT_STRINGZPAD:
+ model->changed_string_entries_ << CharPtrPair(table_name, (const char *) key);
+ break;
+ default:
+ break;
+ }
+}
+
+void DecodeAsModel::applyChanges()
+{
+ dissector_table_t sub_dissectors;
+ module_t *module;
+ pref_t* pref_value;
+ dissector_handle_t handle;
+ // Reset all dissector tables, then apply all rules from model.
+
+ // We can't call g_hash_table_removed from g_hash_table_foreach, which
+ // means we can't call dissector_reset_{string,uint} from
+ // dissector_all_tables_foreach_changed. Collect changed entries in
+ // lists and remove them separately.
+ //
+ // If dissector_all_tables_remove_changed existed we could call it
+ // instead.
+ dissector_all_tables_foreach_changed(gatherChangedEntries, this);
+ foreach (UintPair uint_entry, changed_uint_entries_) {
+ /* Set "Decode As preferences" to default values */
+ sub_dissectors = find_dissector_table(uint_entry.first);
+ handle = dissector_get_uint_handle(sub_dissectors, uint_entry.second);
+ if (handle != NULL) {
+ module = prefs_find_module(proto_get_protocol_filter_name(dissector_handle_get_protocol_index(handle)));
+ pref_value = prefs_find_preference(module, uint_entry.first);
+ if (pref_value != NULL) {
+ module->prefs_changed = TRUE;
+ reset_pref(pref_value);
+ }
+ }
+
+ dissector_reset_uint(uint_entry.first, uint_entry.second);
+ }
+ changed_uint_entries_.clear();
+ foreach (CharPtrPair char_ptr_entry, changed_string_entries_) {
+ dissector_reset_string(char_ptr_entry.first, char_ptr_entry.second);
+ }
+ changed_string_entries_.clear();
+
+ foreach(DecodeAsItem *item, decode_as_items_) {
+ decode_as_t *decode_as_entry;
+
+ if (item->current_proto_.isEmpty()) {
+ continue;
+ }
+
+ for (GList *cur = decode_as_list; cur; cur = cur->next) {
+ decode_as_entry = (decode_as_t *) cur->data;
+
+ if (!g_strcmp0(decode_as_entry->table_name, item->tableName_)) {
+
+ ftenum_t selector_type = get_dissector_table_selector_type(item->tableName_);
+ gpointer selector_value;
+ QByteArray byteArray;
+
+ switch (selector_type) {
+ case FT_UINT8:
+ case FT_UINT16:
+ case FT_UINT24:
+ case FT_UINT32:
+ selector_value = GUINT_TO_POINTER(item->selectorUint_);
+ break;
+ case FT_STRING:
+ case FT_STRINGZ:
+ case FT_UINT_STRING:
+ case FT_STRINGZPAD:
+ byteArray = item->selectorString_.toUtf8();
+ selector_value = (gpointer) byteArray.constData();
+ break;
+ default:
+ continue;
+ }
+
+ if ((item->current_proto_ == DECODE_AS_NONE) || !item->dissector_handle_) {
+ decode_as_entry->reset_value(decode_as_entry->table_name, selector_value);
+ sub_dissectors = find_dissector_table(decode_as_entry->table_name);
+
+ /* For now, only numeric dissector tables can use preferences */
+ if (IS_FT_UINT(dissector_table_get_type(sub_dissectors))) {
+ if (item->dissector_handle_ != NULL) {
+ module = prefs_find_module(proto_get_protocol_filter_name(dissector_handle_get_protocol_index(item->dissector_handle_)));
+ pref_value = prefs_find_preference(module, decode_as_entry->table_name);
+ if (pref_value != NULL) {
+ module->prefs_changed = TRUE;
+ prefs_remove_decode_as_value(pref_value, item->selectorUint_, TRUE);
+ }
+ }
+ }
+ break;
+ } else {
+ decode_as_entry->change_value(decode_as_entry->table_name, selector_value, &item->dissector_handle_, (char *) item->current_proto_.toUtf8().constData());
+ sub_dissectors = find_dissector_table(decode_as_entry->table_name);
+
+ /* For now, only numeric dissector tables can use preferences */
+ if (IS_FT_UINT(dissector_table_get_type(sub_dissectors))) {
+ module = prefs_find_module(proto_get_protocol_filter_name(dissector_handle_get_protocol_index(item->dissector_handle_)));
+ pref_value = prefs_find_preference(module, decode_as_entry->table_name);
+ if (pref_value != NULL) {
+ module->prefs_changed = TRUE;
+ prefs_add_decode_as_value(pref_value, item->selectorUint_, FALSE);
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+}
+
+/* * Editor modelines
+ *
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * ex: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */
diff --git a/ui/qt/models/decode_as_model.h b/ui/qt/models/decode_as_model.h
new file mode 100644
index 0000000000..d2990a8867
--- /dev/null
+++ b/ui/qt/models/decode_as_model.h
@@ -0,0 +1,106 @@
+/* decode_as_model.h
+ * Data model for Decode As records.
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef DECODE_AS_MODEL_H
+#define DECODE_AS_MODEL_H
+
+#include <config.h>
+#include <glib.h>
+
+#include <QAbstractItemModel>
+#include <QList>
+
+#include "cfile.h"
+
+#include <epan/packet.h>
+
+class DecodeAsItem
+{
+public:
+ DecodeAsItem();
+ virtual ~DecodeAsItem();
+
+ const gchar* tableName_;
+ const gchar* tableUIName_;
+
+ //save our sanity and not have to worry about memory management
+ //between (lack of) persistent data in GUI and underlying data
+ uint selectorUint_;
+ QString selectorString_;
+
+ QString default_proto_;
+ QString current_proto_;
+ dissector_handle_t dissector_handle_;
+};
+
+class DecodeAsModel : public QAbstractTableModel
+{
+ Q_OBJECT
+
+public:
+ DecodeAsModel(QObject *parent, capture_file *cf = NULL);
+
+ enum DecodeAsColumn {
+ colTable = 0,
+ colSelector,
+ colType,
+ colDefault, // aka "initial"
+ colProtocol, // aka "current"
+ colDecodeAsMax //not used
+ };
+
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+ QVariant data(const QModelIndex &index, int role) const;
+ QVariant headerData(int section, Qt::Orientation orientation,
+ int role = Qt::DisplayRole) const;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+
+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
+ void fillTable();
+
+ void setDissectorHandle(const QModelIndex &index, dissector_handle_t dissector_handle);
+
+ 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);
+
+ static QString entryString(const gchar *table_name, gpointer value);
+
+ void applyChanges();
+
+protected:
+ static void buildChangedList(const gchar *table_name, ftenum_t selector_type,
+ gpointer key, gpointer value, gpointer user_data);
+ static void buildDceRpcChangedList(gpointer data, gpointer user_data);
+ static void gatherChangedEntries(const gchar *table_name, ftenum_t selector_type,
+ gpointer key, gpointer value, gpointer user_data);
+
+
+private:
+ capture_file *cap_file_;
+ QList<DecodeAsItem *> decode_as_items_;
+ QList<QPair<const char *, guint32> > changed_uint_entries_;
+ QList<QPair<const char *, const char *> > changed_string_entries_;
+};
+
+#endif // DECODE_AS_MODEL_H