Add section comboBox to StringsWidget (#938)

This commit is contained in:
Paul I 2018-11-17 22:17:16 +03:00 committed by xarkes
parent 1bd7e13192
commit 54022a19db
9 changed files with 212 additions and 61 deletions

View File

@ -1551,6 +1551,7 @@ QList<StringDescription> 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<SectionDescription> 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<SegmentDescription> CutterCore::getAllSegments()
{
CORE_LOCK();

View File

@ -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<CutterPlugin*> plugins);
QList<CutterPlugin*> getCutterPlugins();
QStringList getSectionList();
RCoreLocked core() const;
signals:

View File

@ -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 \

View File

@ -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;
}

View File

@ -0,0 +1,29 @@
#ifndef COMBOQUICKFILTERVIEW_H
#define COMBOQUICKFILTERVIEW_H
#include <QWidget>
#include <QComboBox>
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

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ComboQuickFilterView</class>
<widget class="QWidget" name="ComboQuickFilterView">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>378</width>
<height>20</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLineEdit" name="lineEdit">
<property name="placeholderText">
<string>Quick Filter</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox"/>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -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<StringDescription>();
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>();
StringDescription right_str = right.data(
StringsModel::StringDescriptionRole).value<StringDescription>();
auto leftStr = left.data(StringsModel::StringDescriptionRole).value<StringDescription>();
auto rightStr = right.data(StringsModel::StringDescriptionRole).value<StringDescription>();
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 &section : Core()->getSectionList()) {
combo->addItem(section, section);
}
proxyModel->selectedSection.clear();
}
void StringsWidget::stringSearchFinished(const QList<StringDescription> &strings)
@ -215,7 +235,7 @@ void StringsWidget::stringSearchFinished(const QList<StringDescription> &strings
if (ui->stringsTreeView->columnWidth(1) > 300)
ui->stringsTreeView->setColumnWidth(1, 300);
tree->showItemsNumber(proxy_model->rowCount());
tree->showItemsNumber(proxyModel->rowCount());
task = nullptr;
}

View File

@ -29,7 +29,7 @@ private:
QList<StringDescription> *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<StringDescription> *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<StringDescription> &strings);
void refreshSectionCombo();
void showStringsContextMenu(const QPoint &pt);
void on_actionX_refs_triggered();
@ -80,7 +85,7 @@ private:
QSharedPointer<StringsTask> task;
StringsModel *model;
StringsSortFilterProxyModel *proxy_model;
StringsProxyModel *proxyModel;
QList<StringDescription> strings;
CutterTreeWidget *tree;
};

View File

@ -60,7 +60,7 @@
</widget>
</item>
<item>
<widget class="QuickFilterView" name="quickFilterView" native="true">
<widget class="ComboQuickFilterView" name="quickFilterView" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
@ -100,9 +100,9 @@
<container>1</container>
</customwidget>
<customwidget>
<class>QuickFilterView</class>
<class>ComboQuickFilterView</class>
<extends>QWidget</extends>
<header>widgets/QuickFilterView.h</header>
<header>widgets/ComboQuickFilterView.h</header>
<container>1</container>
</customwidget>
</customwidgets>