summaryrefslogtreecommitdiffstats
path: root/ui/qt/models/uat_model.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--ui/qt/models/uat_model.cpp175
1 files changed, 131 insertions, 44 deletions
diff --git a/ui/qt/models/uat_model.cpp b/ui/qt/models/uat_model.cpp
index a841ca8c..24b4423c 100644
--- a/ui/qt/models/uat_model.cpp
+++ b/ui/qt/models/uat_model.cpp
@@ -12,12 +12,23 @@
#include "uat_model.h"
#include <epan/to_str.h>
+#include <ui/qt/utils/qt_ui_utils.h>
+#include <QFont>
#include <QBrush>
#include <QDebug>
+// XXX - The model accesses the uat_t raw data, but if the raw data
+// is changed outside the model, e.g. by another model on the same UAT
+// or by changing configuration profiles, record_errors and dirty_records
+// don't have the proper length, which leads to accessing an illegal list
+// index. The preference dialog and configuration profile dialogs are modal,
+// which reduces the chance of this, but the I/O Graphs using a UAT invites
+// issues.
+
UatModel::UatModel(QObject *parent, epan_uat *uat) :
QAbstractTableModel(parent),
- uat_(0)
+ uat_(0),
+ applying_(false)
{
loadUat(uat);
}
@@ -46,7 +57,14 @@ void UatModel::loadUat(epan_uat * uat)
void UatModel::reloadUat()
{
+ // Avoid unnecessarily resetting the model if we're just making
+ // what's on disk match what we have.
+ if (applying_)
+ return;
+
beginResetModel();
+ record_errors.clear();
+ dirty_records.clear();
loadUat(uat_);
endResetModel();
}
@@ -54,16 +72,22 @@ void UatModel::reloadUat()
bool UatModel::applyChanges(QString &error)
{
if (uat_->changed) {
- gchar *err = NULL;
+ char *err = NULL;
if (!uat_save(uat_, &err)) {
error = QString("Error while saving %1: %2").arg(uat_->name).arg(err);
g_free(err);
}
+ applying_ = true;
+ // XXX - Why does this need to call post_update_cb? post_update_cb
+ // is for when the uat_t is updated, e.g. after loading a file.
+ // Saving makes the information on disk match the table records in
+ // memory, but it shouldn't change the uat_t.
if (uat_->post_update_cb) {
uat_->post_update_cb();
}
+ applying_ = false;
return true;
}
@@ -76,7 +100,7 @@ bool UatModel::revertChanges(QString &error)
// to avoid calling post_update_cb. Calling uat_clear + uat_load is a lazy
// option and might fail (e.g. when the UAT file is removed).
if (uat_->changed) {
- gchar *err = NULL;
+ char *err = NULL;
uat_clear(uat_);
if (!uat_load(uat_, NULL, &err)) {
error = QString("Error while loading %1: %2").arg(uat_->name).arg(err);
@@ -90,17 +114,19 @@ bool UatModel::revertChanges(QString &error)
Qt::ItemFlags UatModel::flags(const QModelIndex &index) const
{
+ Qt::ItemFlags flags = QAbstractTableModel::flags(index);
+ flags |= Qt::ItemIsDropEnabled;
+
if (!index.isValid())
- return Qt::ItemFlags();
+ return flags;
uat_field_t *field = &uat_->fields[index.column()];
- Qt::ItemFlags flags = QAbstractTableModel::flags(index);
if (field->mode == PT_TXTMOD_BOOL)
{
flags |= Qt::ItemIsUserCheckable;
}
- flags |= Qt::ItemIsEditable;
+ flags |= Qt::ItemIsEditable | Qt::ItemIsDragEnabled;
return flags;
}
@@ -114,13 +140,13 @@ QVariant UatModel::data(const QModelIndex &index, int role) const
uat_field_t *field = &uat_->fields[index.column()];
if (role == Qt::DisplayRole || role == Qt::EditRole) {
char *str = NULL;
- guint length = 0;
+ unsigned length = 0;
field->cb.tostr(rec, &str, &length, field->cbdata.tostr, field->fld_data);
switch (field->mode) {
case PT_TXTMOD_HEXBYTES:
{
- char* temp_str = bytes_to_str(NULL, (const guint8 *) str, length);
+ char* temp_str = bytes_to_str(NULL, (const uint8_t *) str, length);
g_free(str);
QString qstr(temp_str);
wmem_free(NULL, temp_str);
@@ -128,24 +154,24 @@ QVariant UatModel::data(const QModelIndex &index, int role) const
}
case PT_TXTMOD_BOOL:
case PT_TXTMOD_COLOR:
+ g_free(str);
return QVariant();
default:
- {
- QString qstr(str);
- g_free(str);
- return qstr;
- }
+ return gchar_free_to_qstring(str);
}
}
if ((role == Qt::CheckStateRole) && (field->mode == PT_TXTMOD_BOOL))
{
char *str = NULL;
- guint length = 0;
+ unsigned length = 0;
enum Qt::CheckState state = Qt::Unchecked;
field->cb.tostr(rec, &str, &length, field->cbdata.tostr, field->fld_data);
- if ((g_strcmp0(str, "TRUE") == 0) ||
- (g_strcmp0(str, "Enabled") == 0))
+ // "Enabled" is for backwards compatibility with pre-UAT IO Graphs:
+ // (Commit 5b3e3ee58748ac1fd9201d2d3facbed1b9b1e800)
+ if (str &&
+ ((g_ascii_strcasecmp(str, "true") == 0) ||
+ (g_strcmp0(str, "Enabled") == 0)))
state = Qt::Checked;
g_free(str);
@@ -166,12 +192,21 @@ QVariant UatModel::data(const QModelIndex &index, int role) const
return QVariant();
}
+ if (role == Qt::FontRole) {
+ if (!g_array_index(uat_->valid_data, bool, index.row())) {
+ QFont font;
+ font.setItalic(!font.italic());
+ return font;
+ }
+ return QVariant();
+ }
+
if ((role == Qt::DecorationRole) && (field->mode == PT_TXTMOD_COLOR)) {
char *str = NULL;
- guint length = 0;
+ unsigned length = 0;
field->cb.tostr(rec, &str, &length, field->cbdata.tostr, field->fld_data);
- return QColor(QString(str));
+ return QColor(gchar_free_to_qstring(str));
}
// expose error message if any.
@@ -259,9 +294,9 @@ QModelIndex UatModel::appendEntry(QVariantList rowData)
data = rowData[col].toString();
} else {
if (rowData[col].toInt() == Qt::Checked) {
- data = QString("TRUE");
+ data = QString("true");
} else {
- data = QString("FALSE");
+ data = QString("false");
}
}
}
@@ -281,7 +316,7 @@ QModelIndex UatModel::appendEntry(QVariantList rowData)
// postponed until the row (in the view) is not selected anymore
checkRow(row);
dirty_records.insert(row, true);
- uat_->changed = TRUE;
+ uat_->changed = true;
emit endInsertRows();
@@ -316,9 +351,9 @@ bool UatModel::setData(const QModelIndex &index, const QVariant &value, int role
field->cb.set(rec, bytes.constData(), (unsigned) bytes.size(), field->cbdata.set, field->fld_data);
} else {
if (value.toInt() == Qt::Checked) {
- field->cb.set(rec, "TRUE", 4, field->cbdata.set, field->fld_data);
+ field->cb.set(rec, "true", 4, field->cbdata.set, field->fld_data);
} else {
- field->cb.set(rec, "FALSE", 5, field->cbdata.set, field->fld_data);
+ field->cb.set(rec, "false", 5, field->cbdata.set, field->fld_data);
}
}
@@ -348,7 +383,7 @@ bool UatModel::setData(const QModelIndex &index, const QVariant &value, int role
}
uat_update_record(uat_, rec, record_errors[row].isEmpty());
dirty_records[row] = true;
- uat_->changed = TRUE;
+ uat_->changed = true;
if (updated_cols.size() > updated_cols.count(index.column())) {
// The validation status for other columns were also affected by
@@ -388,21 +423,24 @@ bool UatModel::insertRows(int row, int count, const QModelIndex &/*parent*/)
// postponed until the row (in the view) is not selected anymore
checkRow(row);
dirty_records.insert(row, true);
- uat_->changed = TRUE;
+ uat_->changed = true;
endInsertRows();
return true;
}
bool UatModel::removeRows(int row, int count, const QModelIndex &/*parent*/)
{
- if (count != 1 || row < 0 || row >= rowCount())
+ if (row < 0 || count < 0 || row + count > rowCount())
return false;
- beginRemoveRows(QModelIndex(), row, row);
- uat_remove_record_idx(uat_, row);
- record_errors.removeAt(row);
- dirty_records.removeAt(row);
- uat_->changed = TRUE;
+ if (count == 0)
+ return true;
+
+ beginRemoveRows(QModelIndex(), row, row + count - 1);
+ uat_remove_record_range(uat_, row, count);
+ record_errors.remove(row, count);
+ dirty_records.remove(row, count);
+ uat_->changed = true;
endRemoveRows();
return true;
}
@@ -416,7 +454,7 @@ void UatModel::clearAll()
uat_clear(uat_);
record_errors.clear();
dirty_records.clear();
- uat_->changed = TRUE;
+ uat_->changed = true;
endResetModel();
}
@@ -448,7 +486,7 @@ QModelIndex UatModel::copyRow(QModelIndex original)
checkRow(newRow);
dirty_records.insert(newRow, true);
- // the UAT record has been created, now it is filled with the infromation
+ // the UAT record has been created, now it is filled with the information
const void *src_record = UAT_INDEX_PTR(uat_, original.row());
void *dst_record = UAT_INDEX_PTR(uat_, newRow);
// insertRows always initializes the record with empty value. Before copying
@@ -462,35 +500,67 @@ QModelIndex UatModel::copyRow(QModelIndex original)
/* According to documentation of uat_copy_cb_t memcpy should be used if uat_->copy_cb is NULL */
memcpy(dst_record, src_record, uat_->record_size);
}
- gboolean src_valid = g_array_index(uat_->valid_data, gboolean, original.row());
+ bool src_valid = g_array_index(uat_->valid_data, bool, original.row());
uat_update_record(uat_, dst_record, src_valid);
record_errors[newRow] = record_errors[original.row()];
dirty_records[newRow] = true;
- uat_->changed = TRUE;
+ uat_->changed = true;
endInsertRows();
return index(newRow, 0, QModelIndex());
}
-bool UatModel::moveRow(int src_row, int dst_row)
+bool UatModel::moveRowPrivate(int src_row, int dst_row)
{
- if (src_row < 0 || src_row >= rowCount() || dst_row < 0 || dst_row >= rowCount())
- return false;
-
- int dst = src_row < dst_row ? dst_row + 1 : dst_row;
+ if (src_row == dst_row)
+ return true;
- beginMoveRows(QModelIndex(), src_row, src_row, QModelIndex(), dst);
uat_move_index(uat_, src_row, dst_row);
record_errors.move(src_row, dst_row);
dirty_records.move(src_row, dst_row);
- uat_->changed = TRUE;
- endMoveRows();
+ uat_->changed = true;
return true;
}
+bool UatModel::moveRow(int src_row, int dst_row)
+{
+ return moveRows(QModelIndex(), src_row, 1, QModelIndex(), dst_row);
+}
+
+bool UatModel::moveRows(const QModelIndex &, int sourceRow, int count, const QModelIndex &, int destinationChild)
+{
+ if (sourceRow < 0 || sourceRow >= rowCount() || destinationChild < 0 || destinationChild >= rowCount() || count < 0)
+ return false;
+
+ if (count == 0)
+ return true;
+
+ // beginMoveRows checks this
+ if (sourceRow <= destinationChild && destinationChild <= sourceRow + count - 1)
+ return false;
+
+ if (destinationChild < sourceRow) {
+ if (!beginMoveRows(QModelIndex(), sourceRow, sourceRow + count - 1, QModelIndex(), destinationChild)) {
+ return false;
+ }
+ for (int i = 0; i < count; i++) {
+ moveRowPrivate(sourceRow + i, destinationChild + i);
+ }
+ } else {
+ if (!beginMoveRows(QModelIndex(), sourceRow, sourceRow + count - 1, QModelIndex(), destinationChild + 1)) {
+ return false;
+ }
+ for (int i = 0; i < count; i++) {
+ moveRowPrivate(sourceRow, destinationChild);
+ }
+ }
+ endMoveRows();
+ return true;
+}
+
bool UatModel::hasErrors() const
{
for (int i = 0; i < rowCount(); i++) {
@@ -513,7 +583,7 @@ bool UatModel::checkField(int row, int col, char **error) const
}
char *str = NULL;
- guint length;
+ unsigned length;
field->cb.tostr(rec, &str, &length, field->cbdata.tostr, field->fld_data);
bool ok = field->cb.chk(rec, str, length, field->cbdata.chk, field->fld_data, error);
@@ -543,3 +613,20 @@ QList<int> UatModel::checkRow(int row)
}
return changed;
}
+
+Qt::DropActions UatModel::supportedDropActions() const
+{
+ return Qt::MoveAction;
+}
+
+bool UatModel::dropMimeData(const QMimeData *, Qt::DropAction, int, int, const QModelIndex &)
+{
+ // We could implement MimeData using uat_fld_tostr (or a new function
+ // that just gives the entire string) although it would be nice for
+ // uat_load_str to be able to load at a specified index, or else have
+ // a function to produce a UAT record from a string. Or we could use
+ // something else. However, for now we really just want internal moves.
+ // Supporting drop actions and rejecting drops still allows our row
+ // moving view's InternalMove to work.
+ return false;
+}