mirror of
https://github.com/rizinorg/cutter.git
synced 2024-12-24 05:45:27 +00:00
Add section comboBox to StringsWidget (#938)
This commit is contained in:
parent
1bd7e13192
commit
54022a19db
@ -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();
|
||||
|
@ -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:
|
||||
|
@ -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 \
|
||||
|
28
src/widgets/ComboQuickFilterView.cpp
Normal file
28
src/widgets/ComboQuickFilterView.cpp
Normal 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;
|
||||
}
|
29
src/widgets/ComboQuickFilterView.h
Normal file
29
src/widgets/ComboQuickFilterView.h
Normal 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
|
50
src/widgets/ComboQuickFilterView.ui
Normal file
50
src/widgets/ComboQuickFilterView.ui
Normal 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>
|
@ -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 §ion : 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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user