From 54022a19dbac4522da6b66c0d7d405c93d6ccfef Mon Sep 17 00:00:00 2001 From: Paul I Date: Sat, 17 Nov 2018 22:17:16 +0300 Subject: [PATCH] Add section comboBox to StringsWidget (#938) --- src/Cutter.cpp | 13 +++ src/Cutter.h | 3 + src/Cutter.pro | 9 +- src/widgets/ComboQuickFilterView.cpp | 28 ++++++ src/widgets/ComboQuickFilterView.h | 29 +++++++ src/widgets/ComboQuickFilterView.ui | 50 +++++++++++ src/widgets/StringsWidget.cpp | 122 ++++++++++++++++----------- src/widgets/StringsWidget.h | 13 ++- src/widgets/StringsWidget.ui | 6 +- 9 files changed, 212 insertions(+), 61 deletions(-) create mode 100644 src/widgets/ComboQuickFilterView.cpp create mode 100644 src/widgets/ComboQuickFilterView.h create mode 100644 src/widgets/ComboQuickFilterView.ui diff --git a/src/Cutter.cpp b/src/Cutter.cpp index 0ec3977b..42650a55 100644 --- a/src/Cutter.cpp +++ b/src/Cutter.cpp @@ -1551,6 +1551,7 @@ QList CutterCore::parseStringsJson(const QJsonDocument &doc) string.type = stringObject["type"].toString(); string.size = stringObject["size"].toVariant().toUInt(); string.length = stringObject["length"].toVariant().toUInt(); + string.section = stringObject["section"].toString(); ret << string; } @@ -1658,6 +1659,18 @@ QList CutterCore::getAllSections() return ret; } +QStringList CutterCore::getSectionList() +{ + CORE_LOCK(); + QStringList ret; + + QJsonArray sectionsArray = cmdj("iSj").array(); + for (QJsonValue value : sectionsArray) { + ret << value.toObject()["name"].toString(); + } + return ret; +} + QList CutterCore::getAllSegments() { CORE_LOCK(); diff --git a/src/Cutter.h b/src/Cutter.h index 88134a5e..0223ffc1 100644 --- a/src/Cutter.h +++ b/src/Cutter.h @@ -165,6 +165,7 @@ struct StringDescription { RVA vaddr; QString string; QString type; + QString section; ut32 length; ut32 size; }; @@ -613,6 +614,8 @@ public: void setCutterPlugins(QList plugins); QList getCutterPlugins(); + QStringList getSectionList(); + RCoreLocked core() const; signals: diff --git a/src/Cutter.pro b/src/Cutter.pro index 103a3322..c0577a4a 100644 --- a/src/Cutter.pro +++ b/src/Cutter.pro @@ -218,7 +218,8 @@ SOURCES += \ widgets/ColorSchemePrefWidget.cpp \ common/ColorSchemeFileSaver.cpp \ dialogs/EditFunctionDialog.cpp \ - widgets/CutterTreeView.cpp + widgets/CutterTreeView.cpp \ + widgets/ComboQuickFilterView.cpp HEADERS += \ Cutter.h \ @@ -320,7 +321,8 @@ HEADERS += \ common/ColorSchemeFileSaver.h \ widgets/ColorSchemePrefWidget.h \ dialogs/EditFunctionDialog.h \ - widgets/CutterTreeView.h + widgets/CutterTreeView.h \ + widgets/ComboQuickFilterView.h FORMS += \ dialogs/AboutDialog.ui \ @@ -378,7 +380,8 @@ FORMS += \ dialogs/SetToDataDialog.ui \ dialogs/SetFunctionVarTypes.ui \ widgets/ColorSchemePrefWidget.ui \ - widgets/CutterTreeView.ui + widgets/CutterTreeView.ui \ + widgets/ComboQuickFilterView.ui RESOURCES += \ resources.qrc \ diff --git a/src/widgets/ComboQuickFilterView.cpp b/src/widgets/ComboQuickFilterView.cpp new file mode 100644 index 00000000..05d44242 --- /dev/null +++ b/src/widgets/ComboQuickFilterView.cpp @@ -0,0 +1,28 @@ +#include "ComboQuickFilterView.h" +#include "ui_ComboQuickFilterView.h" + +ComboQuickFilterView::ComboQuickFilterView(QWidget *parent) : + QWidget(parent), + ui(new Ui::ComboQuickFilterView) +{ + ui->setupUi(this); + + connect(ui->lineEdit, &QLineEdit::textChanged, this, [this](const QString & text) { + emit filterTextChanged(text); + }); +} + +ComboQuickFilterView::~ComboQuickFilterView() +{ + delete ui; +} + +void ComboQuickFilterView::setLabelText(const QString &text) +{ + ui->label->setText(text); +} + +QComboBox *ComboQuickFilterView::comboBox() +{ + return ui->comboBox; +} diff --git a/src/widgets/ComboQuickFilterView.h b/src/widgets/ComboQuickFilterView.h new file mode 100644 index 00000000..244de402 --- /dev/null +++ b/src/widgets/ComboQuickFilterView.h @@ -0,0 +1,29 @@ +#ifndef COMBOQUICKFILTERVIEW_H +#define COMBOQUICKFILTERVIEW_H + +#include +#include + +namespace Ui { +class ComboQuickFilterView; +} + +class ComboQuickFilterView : public QWidget +{ + Q_OBJECT + +public: + explicit ComboQuickFilterView(QWidget *parent = nullptr); + ~ComboQuickFilterView(); + + void setLabelText(const QString &text); + QComboBox *comboBox(); + +signals: + void filterTextChanged(const QString &text); + +private: + Ui::ComboQuickFilterView *ui; +}; + +#endif // COMBOQUICKFILTERVIEW_H diff --git a/src/widgets/ComboQuickFilterView.ui b/src/widgets/ComboQuickFilterView.ui new file mode 100644 index 00000000..1fe8efe2 --- /dev/null +++ b/src/widgets/ComboQuickFilterView.ui @@ -0,0 +1,50 @@ + + + ComboQuickFilterView + + + + 0 + 0 + 378 + 20 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Quick Filter + + + + + + + TextLabel + + + + + + + + + + + diff --git a/src/widgets/StringsWidget.cpp b/src/widgets/StringsWidget.cpp index 511288fa..c057a184 100644 --- a/src/widgets/StringsWidget.cpp +++ b/src/widgets/StringsWidget.cpp @@ -26,7 +26,7 @@ int StringsModel::rowCount(const QModelIndex &) const int StringsModel::columnCount(const QModelIndex &) const { - return Columns::COUNT; + return StringsModel::ColumnCount; } QVariant StringsModel::data(const QModelIndex &index, int role) const @@ -39,16 +39,18 @@ QVariant StringsModel::data(const QModelIndex &index, int role) const switch (role) { case Qt::DisplayRole: switch (index.column()) { - case OFFSET: + case StringsModel::OffsetColumn: return RAddressString(str.vaddr); - case STRING: + case StringsModel::StringColumn: return str.string; - case TYPE: + case StringsModel::TypeColumn: return str.type.toUpper(); - case LENGTH: + case StringsModel::LengthColumn: return str.length; - case SIZE: + case StringsModel::SizeColumn: return str.size; + case StringsModel::SectionColumn: + return str.section; default: return QVariant(); } @@ -64,16 +66,18 @@ QVariant StringsModel::headerData(int section, Qt::Orientation, int role) const switch (role) { case Qt::DisplayRole: switch (section) { - case OFFSET: + case StringsModel::OffsetColumn: return tr("Address"); - case STRING: + case StringsModel::StringColumn: return tr("String"); - case TYPE: + case StringsModel::TypeColumn: return tr("Type"); - case LENGTH: + case StringsModel::LengthColumn: return tr("Length"); - case SIZE: + case StringsModel::SizeColumn: return tr("Size"); + case StringsModel::SectionColumn: + return tr("Section"); default: return QVariant(); } @@ -82,46 +86,48 @@ QVariant StringsModel::headerData(int section, Qt::Orientation, int role) const } } -StringsSortFilterProxyModel::StringsSortFilterProxyModel(StringsModel *source_model, - QObject *parent) +StringsProxyModel::StringsProxyModel(StringsModel *sourceModel, QObject *parent) : QSortFilterProxyModel(parent) { - setSourceModel(source_model); + setSourceModel(sourceModel); setFilterCaseSensitivity(Qt::CaseInsensitive); setSortCaseSensitivity(Qt::CaseInsensitive); } -bool StringsSortFilterProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) const +bool StringsProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) const { QModelIndex index = sourceModel()->index(row, 0, parent); StringDescription str = index.data(StringsModel::StringDescriptionRole).value(); - return str.string.contains(filterRegExp()); + if (selectedSection.isEmpty()) + return str.string.contains(filterRegExp()); + else + return selectedSection == str.section && str.string.contains(filterRegExp()); } -bool StringsSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const +bool StringsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const { - StringDescription left_str = left.data( - StringsModel::StringDescriptionRole).value(); - StringDescription right_str = right.data( - StringsModel::StringDescriptionRole).value(); + auto leftStr = left.data(StringsModel::StringDescriptionRole).value(); + auto rightStr = right.data(StringsModel::StringDescriptionRole).value(); switch (left.column()) { - case StringsModel::OFFSET: - return left_str.vaddr < right_str.vaddr; - case StringsModel::STRING: // sort by string - return left_str.string < right_str.string; - case StringsModel::TYPE: // sort by type - return left_str.type < right_str.type; - case StringsModel::SIZE: // sort by size - return left_str.size < right_str.size; - case StringsModel::LENGTH: // sort by length - return left_str.length < right_str.length; + case StringsModel::OffsetColumn: + return leftStr.vaddr < rightStr.vaddr; + case StringsModel::StringColumn: // sort by string + return leftStr.string < rightStr.string; + case StringsModel::TypeColumn: // sort by type + return leftStr.type < rightStr.type; + case StringsModel::SizeColumn: // sort by size + return leftStr.size < rightStr.size; + case StringsModel::LengthColumn: // sort by length + return leftStr.length < rightStr.length; + case StringsModel::SectionColumn: + return leftStr.section < rightStr.section; default: break; } // fallback - return left_str.vaddr < right_str.vaddr; + return leftStr.vaddr < rightStr.vaddr; } @@ -131,6 +137,7 @@ StringsWidget::StringsWidget(MainWindow *main, QAction *action) : tree(new CutterTreeWidget(this)) { ui->setupUi(this); + ui->quickFilterView->setLabelText(tr("Section:")); // Add Status Bar footer tree->addStatusBar(ui->verticalLayout); @@ -144,17 +151,6 @@ StringsWidget::StringsWidget(MainWindow *main, QAction *action) : main->updateDockActionChecked(action); } ); - // Ctrl-F to show/hide the filter entry - QShortcut *search_shortcut = new QShortcut(QKeySequence::Find, this); - connect(search_shortcut, &QShortcut::activated, ui->quickFilterView, &QuickFilterView::showFilter); - search_shortcut->setContext(Qt::WidgetWithChildrenShortcut); - - // Esc to clear the filter entry - QShortcut *clear_shortcut = new QShortcut(QKeySequence(Qt::Key_Escape), this); - connect(clear_shortcut, &QShortcut::activated, ui->quickFilterView, &QuickFilterView::clearFilter); - clear_shortcut->setContext(Qt::WidgetWithChildrenShortcut); - - connect(ui->actionFilter, SIGNAL(triggered()), ui->quickFilterView, SLOT(showFilter())); connect(ui->actionCopy_String, SIGNAL(triggered()), this, SLOT(on_actionCopy())); connect(ui->actionCopy_Address, SIGNAL(triggered()), this, SLOT(on_actionCopy())); @@ -166,19 +162,27 @@ StringsWidget::StringsWidget(MainWindow *main, QAction *action) : ui->stringsTreeView->setContextMenuPolicy(Qt::CustomContextMenu); model = new StringsModel(&strings, this); - proxy_model = new StringsSortFilterProxyModel(model, this); - ui->stringsTreeView->setModel(proxy_model); - ui->stringsTreeView->sortByColumn(StringsModel::OFFSET, Qt::AscendingOrder); + proxyModel = new StringsProxyModel(model, this); + ui->stringsTreeView->setModel(proxyModel); + ui->stringsTreeView->sortByColumn(StringsModel::OffsetColumn, Qt::AscendingOrder); - connect(ui->quickFilterView, SIGNAL(filterTextChanged(const QString &)), proxy_model, + connect(ui->quickFilterView, SIGNAL(filterTextChanged(const QString &)), proxyModel, SLOT(setFilterWildcard(const QString &))); - connect(ui->quickFilterView, SIGNAL(filterClosed()), ui->stringsTreeView, SLOT(setFocus())); - connect(ui->quickFilterView, &QuickFilterView::filterTextChanged, this, [this] { - tree->showItemsNumber(proxy_model->rowCount()); + connect(ui->quickFilterView, &ComboQuickFilterView::filterTextChanged, this, [this] { + tree->showItemsNumber(proxyModel->rowCount()); }); connect(Core(), SIGNAL(refreshAll()), this, SLOT(refreshStrings())); + + connect( + ui->quickFilterView->comboBox(), &QComboBox::currentTextChanged, this, + [this]() { + proxyModel->selectedSection = ui->quickFilterView->comboBox()->currentData().toString(); + proxyModel->setFilterRegExp(proxyModel->filterRegExp()); + tree->showItemsNumber(proxyModel->rowCount()); + } + ); } StringsWidget::~StringsWidget() {} @@ -203,6 +207,22 @@ void StringsWidget::refreshStrings() connect(task.data(), &StringsTask::stringSearchFinished, this, &StringsWidget::stringSearchFinished); Core()->getAsyncTaskManager()->start(task); + + refreshSectionCombo(); +} + +void StringsWidget::refreshSectionCombo() +{ + QComboBox *combo = ui->quickFilterView->comboBox(); + + combo->clear(); + combo->addItem(tr("(all)")); + + for (QString §ion : Core()->getSectionList()) { + combo->addItem(section, section); + } + + proxyModel->selectedSection.clear(); } void StringsWidget::stringSearchFinished(const QList &strings) @@ -215,7 +235,7 @@ void StringsWidget::stringSearchFinished(const QList &strings if (ui->stringsTreeView->columnWidth(1) > 300) ui->stringsTreeView->setColumnWidth(1, 300); - tree->showItemsNumber(proxy_model->rowCount()); + tree->showItemsNumber(proxyModel->rowCount()); task = nullptr; } diff --git a/src/widgets/StringsWidget.h b/src/widgets/StringsWidget.h index 4eb98a42..9f048d79 100644 --- a/src/widgets/StringsWidget.h +++ b/src/widgets/StringsWidget.h @@ -29,7 +29,7 @@ private: QList *strings; public: - enum Columns { OFFSET = 0, STRING, TYPE, LENGTH, SIZE, COUNT }; + enum Column { OffsetColumn = 0, StringColumn, TypeColumn, LengthColumn, SizeColumn, SectionColumn, ColumnCount }; static const int StringDescriptionRole = Qt::UserRole; StringsModel(QList *strings, QObject *parent = nullptr); @@ -43,16 +43,20 @@ public: -class StringsSortFilterProxyModel : public QSortFilterProxyModel +class StringsProxyModel : public QSortFilterProxyModel { Q_OBJECT + friend StringsWidget; + public: - StringsSortFilterProxyModel(StringsModel *source_model, QObject *parent = nullptr); + StringsProxyModel(StringsModel *sourceModel, QObject *parent = nullptr); protected: bool filterAcceptsRow(int row, const QModelIndex &parent) const override; bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; + + QString selectedSection; }; @@ -69,6 +73,7 @@ private slots: void refreshStrings(); void stringSearchFinished(const QList &strings); + void refreshSectionCombo(); void showStringsContextMenu(const QPoint &pt); void on_actionX_refs_triggered(); @@ -80,7 +85,7 @@ private: QSharedPointer task; StringsModel *model; - StringsSortFilterProxyModel *proxy_model; + StringsProxyModel *proxyModel; QList strings; CutterTreeWidget *tree; }; diff --git a/src/widgets/StringsWidget.ui b/src/widgets/StringsWidget.ui index 98e9f6a3..2486df4d 100644 --- a/src/widgets/StringsWidget.ui +++ b/src/widgets/StringsWidget.ui @@ -60,7 +60,7 @@ - + 0 @@ -100,9 +100,9 @@ 1 - QuickFilterView + ComboQuickFilterView QWidget -
widgets/QuickFilterView.h
+
widgets/ComboQuickFilterView.h
1