From d58e69d411fc954676901ac36356722ae341b03c Mon Sep 17 00:00:00 2001 From: Paul I Date: Tue, 24 Apr 2018 21:40:40 +0300 Subject: [PATCH] Add QuickFilter to RelocsWidget (#452) --- src/widgets/ExportsWidget.cpp | 34 +++++++------- src/widgets/ExportsWidget.h | 8 ++-- src/widgets/ImportsWidget.cpp | 22 ++++----- src/widgets/ImportsWidget.h | 6 +-- src/widgets/RelocsWidget.cpp | 88 +++++++++++++++++++++++++++++------ src/widgets/RelocsWidget.h | 22 +++++++-- src/widgets/RelocsWidget.ui | 11 +++++ 7 files changed, 133 insertions(+), 58 deletions(-) diff --git a/src/widgets/ExportsWidget.cpp b/src/widgets/ExportsWidget.cpp index 28942bbe..4b6ef8c8 100644 --- a/src/widgets/ExportsWidget.cpp +++ b/src/widgets/ExportsWidget.cpp @@ -78,8 +78,7 @@ void ExportsModel::endReloadExports() endResetModel(); } -ExportsSortFilterProxyModel::ExportsSortFilterProxyModel(ExportsModel *source_model, - QObject *parent) +ExportsProxyModel::ExportsProxyModel(ExportsModel *source_model, QObject *parent) : QSortFilterProxyModel(parent) { setSourceModel(source_model); @@ -87,40 +86,39 @@ ExportsSortFilterProxyModel::ExportsSortFilterProxyModel(ExportsModel *source_mo setSortCaseSensitivity(Qt::CaseInsensitive); } -bool ExportsSortFilterProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) const +bool ExportsProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) const { QModelIndex index = sourceModel()->index(row, 0, parent); - ExportDescription exp = index.data(ExportsModel::ExportDescriptionRole).value(); + auto exp = index.data(ExportsModel::ExportDescriptionRole).value(); + return exp.name.contains(filterRegExp()); } -bool ExportsSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const +bool ExportsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const { - ExportDescription left_exp = left.data( - ExportsModel::ExportDescriptionRole).value(); - ExportDescription right_exp = right.data( - ExportsModel::ExportDescriptionRole).value(); + auto leftExp = left.data(ExportsModel::ExportDescriptionRole).value(); + auto rightExp = right.data(ExportsModel::ExportDescriptionRole).value(); switch (left.column()) { case ExportsModel::SizeColumn: - if (left_exp.size != right_exp.size) - return left_exp.size < right_exp.size; + if (leftExp.size != rightExp.size) + return leftExp.size < rightExp.size; // fallthrough case ExportsModel::OffsetColumn: - if (left_exp.vaddr != right_exp.vaddr) - return left_exp.vaddr < right_exp.vaddr; + if (leftExp.vaddr != rightExp.vaddr) + return leftExp.vaddr < rightExp.vaddr; // fallthrough case ExportsModel::NameColumn: - return left_exp.name < right_exp.name; + return leftExp.name < rightExp.name; case ExportsModel::TypeColumn: - if (left_exp.type != right_exp.type) - return left_exp.type < right_exp.type; + if (leftExp.type != rightExp.type) + return leftExp.type < rightExp.type; default: break; } // fallback - return left_exp.vaddr < right_exp.vaddr; + return leftExp.vaddr < rightExp.vaddr; } @@ -132,7 +130,7 @@ ExportsWidget::ExportsWidget(MainWindow *main, QAction *action) : ui->setupUi(this); exportsModel = new ExportsModel(&exports, this); - exportsProxyModel = new ExportsSortFilterProxyModel(exportsModel, this); + exportsProxyModel = new ExportsProxyModel(exportsModel, this); ui->exportsTreeView->setModel(exportsProxyModel); ui->exportsTreeView->sortByColumn(ExportsModel::OffsetColumn, Qt::AscendingOrder); diff --git a/src/widgets/ExportsWidget.h b/src/widgets/ExportsWidget.h index 27bf66a7..a853c08f 100644 --- a/src/widgets/ExportsWidget.h +++ b/src/widgets/ExportsWidget.h @@ -32,7 +32,7 @@ public: enum Column { OffsetColumn = 0, SizeColumn, TypeColumn, NameColumn, ColumnCount }; enum Role { ExportDescriptionRole = Qt::UserRole }; - ExportsModel(QList *exports, QObject *parent = 0); + ExportsModel(QList *exports, QObject *parent = Q_NULLPTR); int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; @@ -46,12 +46,12 @@ public: -class ExportsSortFilterProxyModel : public QSortFilterProxyModel +class ExportsProxyModel : public QSortFilterProxyModel { Q_OBJECT public: - ExportsSortFilterProxyModel(ExportsModel *source_model, QObject *parent = 0); + ExportsProxyModel(ExportsModel *source_model, QObject *parent = Q_NULLPTR); protected: bool filterAcceptsRow(int row, const QModelIndex &parent) const override; @@ -77,7 +77,7 @@ private: std::unique_ptr ui; ExportsModel *exportsModel; - ExportsSortFilterProxyModel *exportsProxyModel; + ExportsProxyModel *exportsProxyModel; QList exports; void setScrollMode(); diff --git a/src/widgets/ImportsWidget.cpp b/src/widgets/ImportsWidget.cpp index 41844eb9..587d9b62 100644 --- a/src/widgets/ImportsWidget.cpp +++ b/src/widgets/ImportsWidget.cpp @@ -90,7 +90,7 @@ void ImportsModel::endReload() endResetModel(); } -ImportsSortFilterProxyModel::ImportsSortFilterProxyModel(ImportsModel *sourceModel, QObject *parent) +ImportsProxyModel::ImportsProxyModel(ImportsModel *sourceModel, QObject *parent) : QSortFilterProxyModel(parent) { setSourceModel(sourceModel); @@ -98,30 +98,24 @@ ImportsSortFilterProxyModel::ImportsSortFilterProxyModel(ImportsModel *sourceMod setSortCaseSensitivity(Qt::CaseInsensitive); } -bool ImportsSortFilterProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) const +bool ImportsProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) const { - QModelIndex index; - ImportDescription import; - - index = sourceModel()->index(row, 0, parent); - import = index.data(ImportsModel::ImportDescriptionRole).value(); + QModelIndex index = sourceModel()->index(row, 0, parent); + auto import = index.data(ImportsModel::ImportDescriptionRole).value(); return import.name.contains(filterRegExp()); } -bool ImportsSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const +bool ImportsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const { - ImportDescription leftImport; - ImportDescription rightImport; - if (!left.isValid() || !right.isValid()) return false; if (left.parent().isValid() || right.parent().isValid()) return false; - leftImport = left.data(ImportsModel::ImportDescriptionRole).value(); - rightImport = right.data(ImportsModel::ImportDescriptionRole).value(); + auto leftImport = left.data(ImportsModel::ImportDescriptionRole).value(); + auto rightImport = right.data(ImportsModel::ImportDescriptionRole).value(); switch (left.column()) { case ImportsModel::AddressColumn: @@ -147,7 +141,7 @@ ImportsWidget::ImportsWidget(MainWindow *main, QAction *action) : CutterDockWidget(main, action), ui(new Ui::ImportsWidget), importsModel(new ImportsModel(&imports, this)), - importsProxyModel(new ImportsSortFilterProxyModel(importsModel, this)) + importsProxyModel(new ImportsProxyModel(importsModel, this)) { ui->setupUi(this); diff --git a/src/widgets/ImportsWidget.h b/src/widgets/ImportsWidget.h index 59146a03..1270a354 100644 --- a/src/widgets/ImportsWidget.h +++ b/src/widgets/ImportsWidget.h @@ -57,12 +57,12 @@ public: void endReload(); }; -class ImportsSortFilterProxyModel : public QSortFilterProxyModel +class ImportsProxyModel : public QSortFilterProxyModel { Q_OBJECT public: - ImportsSortFilterProxyModel(ImportsModel *sourceModel, QObject *parent = Q_NULLPTR); + ImportsProxyModel(ImportsModel *sourceModel, QObject *parent = Q_NULLPTR); protected: bool filterAcceptsRow(int row, const QModelIndex &parent) const override; @@ -85,7 +85,7 @@ private slots: private: std::unique_ptr ui; ImportsModel *importsModel; - ImportsSortFilterProxyModel *importsProxyModel; + ImportsProxyModel *importsProxyModel; QList imports; void highlightUnsafe(); diff --git a/src/widgets/RelocsWidget.cpp b/src/widgets/RelocsWidget.cpp index 93e21817..13e3e446 100644 --- a/src/widgets/RelocsWidget.cpp +++ b/src/widgets/RelocsWidget.cpp @@ -11,12 +11,12 @@ RelocsModel::RelocsModel(QList *relocs, QObject *parent) : int RelocsModel::rowCount(const QModelIndex &parent) const { - return parent.isValid()? 0 : relocs->count(); + return parent.isValid() ? 0 : relocs->count(); } int RelocsModel::columnCount(const QModelIndex&) const { - return COUNT; + return RelocsModel::ColumnCount; } QVariant RelocsModel::data(const QModelIndex &index, int role) const @@ -24,20 +24,22 @@ QVariant RelocsModel::data(const QModelIndex &index, int role) const const RelocDescription &reloc = relocs->at(index.row()); switch (role) { - case AddressRole: - return reloc.vaddr; case Qt::DisplayRole: switch (index.column()) { - case VADDR: + case RelocsModel::VAddrColumn: return RAddressString(reloc.vaddr); - case TYPE: + case RelocsModel::TypeColumn: return reloc.type; - case NAME: + case RelocsModel::NameColumn: return reloc.name; default: break; } + case RelocsModel::RelocDescriptionRole: + return QVariant::fromValue(reloc); + case RelocsModel::AddressRole: + return reloc.vaddr; default: break; } @@ -46,14 +48,14 @@ QVariant RelocsModel::data(const QModelIndex &index, int role) const QVariant RelocsModel::headerData(int section, Qt::Orientation, int role) const { - if(role == Qt::DisplayRole) + if (role == Qt::DisplayRole) switch (section) { - case VADDR: + case RelocsModel::VAddrColumn: return tr("Address"); - case TYPE: + case RelocsModel::TypeColumn: return tr("Type"); - case NAME: + case RelocsModel::NameColumn: return tr("Name"); } return QVariant(); @@ -69,15 +71,71 @@ void RelocsModel::endReload() endResetModel(); } +RelocsProxyModel::RelocsProxyModel(RelocsModel *sourceModel, QObject *parent) + : QSortFilterProxyModel(parent) +{ + setSourceModel(sourceModel); + setFilterCaseSensitivity(Qt::CaseInsensitive); + setSortCaseSensitivity(Qt::CaseInsensitive); +} + +bool RelocsProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) const +{ + QModelIndex index = sourceModel()->index(row, 0, parent); + auto reloc = index.data(RelocsModel::RelocDescriptionRole).value(); + + return reloc.name.contains(filterRegExp()); +} + +bool RelocsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const +{ + if (!left.isValid() || !right.isValid()) + return false; + + if (left.parent().isValid() || right.parent().isValid()) + return false; + + auto leftReloc = left.data(RelocsModel::RelocDescriptionRole).value(); + auto rightReloc = right.data(RelocsModel::RelocDescriptionRole).value(); + + switch (left.column()) { + case RelocsModel::VAddrColumn: + return leftReloc.vaddr < rightReloc.vaddr; + case RelocsModel::TypeColumn: + return leftReloc.type < rightReloc.type; + case RelocsModel::NameColumn: + return leftReloc.name < rightReloc.name; + default: + break; + } + + return false; +} RelocsWidget::RelocsWidget(MainWindow *main, QAction *action) : CutterDockWidget(main, action), ui(new Ui::RelocsWidget), - model(new RelocsModel(&relocs, this)) + relocsModel(new RelocsModel(&relocs, this)), + relocsProxyModel(new RelocsProxyModel(relocsModel, this)) { ui->setupUi(this); - ui->relocsTreeView->setModel(model); + ui->relocsTreeView->setModel(relocsProxyModel); + ui->relocsTreeView->sortByColumn(RelocsModel::NameColumn, Qt::AscendingOrder); + + // Ctrl-F to show/hide the filter entry + QShortcut *searchShortcut = new QShortcut(QKeySequence::Find, this); + connect(searchShortcut, &QShortcut::activated, ui->quickFilterView, &QuickFilterView::showFilter); + searchShortcut->setContext(Qt::WidgetWithChildrenShortcut); + + // Esc to clear the filter entry + QShortcut *clearShortcut = new QShortcut(QKeySequence(Qt::Key_Escape), this); + connect(clearShortcut, &QShortcut::activated, ui->quickFilterView, &QuickFilterView::clearFilter); + clearShortcut->setContext(Qt::WidgetWithChildrenShortcut); + + connect(ui->quickFilterView, SIGNAL(filterTextChanged(const QString &)), + relocsProxyModel, SLOT(setFilterWildcard(const QString &))); + connect(ui->quickFilterView, SIGNAL(filterClosed()), ui->relocsTreeView, SLOT(setFocus())); setScrollMode(); @@ -96,9 +154,9 @@ void RelocsWidget::on_relocsTreeView_doubleClicked(const QModelIndex &index) void RelocsWidget::refreshRelocs() { - model->beginReload(); + relocsModel->beginReload(); relocs = Core()->getAllRelocs(); - model->endReload(); + relocsModel->endReload(); qhelpers::adjustColumns(ui->relocsTreeView, 3, 0); } diff --git a/src/widgets/RelocsWidget.h b/src/widgets/RelocsWidget.h index 25b881c2..f9531a33 100644 --- a/src/widgets/RelocsWidget.h +++ b/src/widgets/RelocsWidget.h @@ -3,6 +3,7 @@ #include #include +#include #include "CutterDockWidget.h" #include "Cutter.h" @@ -21,10 +22,10 @@ private: QList *relocs; public: - enum COLUMNS {VADDR = 0, TYPE, NAME, COUNT}; - static const int AddressRole = Qt::UserRole; + enum Column { VAddrColumn = 0, TypeColumn, NameColumn, ColumnCount }; + enum Role { RelocDescriptionRole = Qt::UserRole, AddressRole }; - RelocsModel(QList *relocs, QObject* parent = nullptr); + RelocsModel(QList *relocs, QObject* parent = Q_NULLPTR); int rowCount(const QModelIndex &parent) const; int columnCount(const QModelIndex &parent) const; @@ -36,6 +37,18 @@ public: void endReload(); }; +class RelocsProxyModel : public QSortFilterProxyModel +{ + Q_OBJECT + +public: + RelocsProxyModel(RelocsModel *sourceModel, QObject *parent = Q_NULLPTR); + +protected: + bool filterAcceptsRow(int row, const QModelIndex &parent) const override; + bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; +}; + class RelocsWidget : public CutterDockWidget { Q_OBJECT @@ -50,7 +63,8 @@ private slots: private: std::unique_ptr ui; - RelocsModel *model; + RelocsModel *relocsModel; + RelocsProxyModel *relocsProxyModel; QList relocs; void setScrollMode(); diff --git a/src/widgets/RelocsWidget.ui b/src/widgets/RelocsWidget.ui index 1fc19fc0..e1ebfd98 100644 --- a/src/widgets/RelocsWidget.ui +++ b/src/widgets/RelocsWidget.ui @@ -47,9 +47,20 @@ + + + + + + QuickFilterView + QWidget +
widgets/QuickFilterView.h
+ 1 +
+