diff options
Diffstat (limited to 'ui/qt/models/uat_model.cpp')
-rw-r--r-- | ui/qt/models/uat_model.cpp | 175 |
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; +} |