mirror of
https://github.com/rizinorg/cutter.git
synced 2024-12-24 13:55:26 +00:00
Improve flag and string widget performance (#2021)
* Deffer vtable refresh. * Use uniformRowHeight mode * Adjust StringsWidget column resizing mode.
This commit is contained in:
parent
8234713a42
commit
e0c80182dd
@ -7,6 +7,7 @@ CutterTreeView::CutterTreeView(QWidget *parent) :
|
|||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
this->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
this->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||||
|
this->setUniformRowHeights(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
CutterTreeView::~CutterTreeView() {}
|
CutterTreeView::~CutterTreeView() {}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QShortcut>
|
#include <QShortcut>
|
||||||
#include <QTreeWidget>
|
#include <QTreeWidget>
|
||||||
|
#include <QStandardItemModel>
|
||||||
|
|
||||||
FlagsModel::FlagsModel(QList<FlagDescription> *flags, QObject *parent)
|
FlagsModel::FlagsModel(QList<FlagDescription> *flags, QObject *parent)
|
||||||
: AddressableItemModel<QAbstractListModel>(parent),
|
: AddressableItemModel<QAbstractListModel>(parent),
|
||||||
@ -72,8 +73,8 @@ QVariant FlagsModel::headerData(int section, Qt::Orientation, int role) const
|
|||||||
|
|
||||||
RVA FlagsModel::address(const QModelIndex &index) const
|
RVA FlagsModel::address(const QModelIndex &index) const
|
||||||
{
|
{
|
||||||
const FlagDescription &flag = flags->at(index.row());
|
const FlagDescription &flag = flags->at(index.row());
|
||||||
return flag.offset;
|
return flag.offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString FlagsModel::name(const QModelIndex &index) const
|
QString FlagsModel::name(const QModelIndex &index) const
|
||||||
@ -82,6 +83,14 @@ QString FlagsModel::name(const QModelIndex &index) const
|
|||||||
return flag.name;
|
return flag.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const FlagDescription *FlagsModel::description(QModelIndex index) const
|
||||||
|
{
|
||||||
|
if (index.row() < flags->size()) {
|
||||||
|
return &flags->at(index.row());
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
FlagsSortFilterProxyModel::FlagsSortFilterProxyModel(FlagsModel *source_model, QObject *parent)
|
FlagsSortFilterProxyModel::FlagsSortFilterProxyModel(FlagsModel *source_model, QObject *parent)
|
||||||
: AddressableFilterProxyModel(source_model, parent)
|
: AddressableFilterProxyModel(source_model, parent)
|
||||||
{
|
{
|
||||||
@ -96,26 +105,27 @@ bool FlagsSortFilterProxyModel::filterAcceptsRow(int row, const QModelIndex &par
|
|||||||
|
|
||||||
bool FlagsSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
|
bool FlagsSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
|
||||||
{
|
{
|
||||||
FlagDescription left_flag = left.data(FlagsModel::FlagDescriptionRole).value<FlagDescription>();
|
auto source = static_cast<FlagsModel *>(sourceModel());
|
||||||
FlagDescription right_flag = right.data(FlagsModel::FlagDescriptionRole).value<FlagDescription>();
|
auto left_flag = source->description(left);
|
||||||
|
auto right_flag = source->description(right);
|
||||||
|
|
||||||
switch (left.column()) {
|
switch (left.column()) {
|
||||||
case FlagsModel::SIZE:
|
case FlagsModel::SIZE:
|
||||||
if (left_flag.size != right_flag.size)
|
if (left_flag->size != right_flag->size)
|
||||||
return left_flag.size < right_flag.size;
|
return left_flag->size < right_flag->size;
|
||||||
// fallthrough
|
// fallthrough
|
||||||
case FlagsModel::OFFSET:
|
case FlagsModel::OFFSET:
|
||||||
if (left_flag.offset != right_flag.offset)
|
if (left_flag->offset != right_flag->offset)
|
||||||
return left_flag.offset < right_flag.offset;
|
return left_flag->offset < right_flag->offset;
|
||||||
// fallthrough
|
// fallthrough
|
||||||
case FlagsModel::NAME:
|
case FlagsModel::NAME:
|
||||||
return left_flag.name < right_flag.name;
|
return left_flag->name < right_flag->name;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// fallback
|
// fallback
|
||||||
return left_flag.offset < right_flag.offset;
|
return left_flag->offset < right_flag->offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -212,6 +222,7 @@ void FlagsWidget::refreshFlagspaces()
|
|||||||
if (cur_idx < 0)
|
if (cur_idx < 0)
|
||||||
cur_idx = 0;
|
cur_idx = 0;
|
||||||
|
|
||||||
|
disableFlagRefresh = true; // prevent duplicate flag refresh caused by flagspaceCombo modifications
|
||||||
ui->flagspaceCombo->clear();
|
ui->flagspaceCombo->clear();
|
||||||
ui->flagspaceCombo->addItem(tr("(all)"));
|
ui->flagspaceCombo->addItem(tr("(all)"));
|
||||||
|
|
||||||
@ -221,12 +232,16 @@ void FlagsWidget::refreshFlagspaces()
|
|||||||
|
|
||||||
if (cur_idx > 0)
|
if (cur_idx > 0)
|
||||||
ui->flagspaceCombo->setCurrentIndex(cur_idx);
|
ui->flagspaceCombo->setCurrentIndex(cur_idx);
|
||||||
|
disableFlagRefresh = false;
|
||||||
|
|
||||||
refreshFlags();
|
refreshFlags();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlagsWidget::refreshFlags()
|
void FlagsWidget::refreshFlags()
|
||||||
{
|
{
|
||||||
|
if (disableFlagRefresh) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
QString flagspace;
|
QString flagspace;
|
||||||
|
|
||||||
QVariant flagspace_data = ui->flagspaceCombo->currentData();
|
QVariant flagspace_data = ui->flagspaceCombo->currentData();
|
||||||
@ -238,8 +253,6 @@ void FlagsWidget::refreshFlags()
|
|||||||
flags = Core()->getAllFlags(flagspace);
|
flags = Core()->getAllFlags(flagspace);
|
||||||
flags_model->endResetModel();
|
flags_model->endResetModel();
|
||||||
|
|
||||||
qhelpers::adjustColumns(ui->flagsTreeView, 2, 0);
|
|
||||||
|
|
||||||
tree->showItemsNumber(flags_proxy_model->rowCount());
|
tree->showItemsNumber(flags_proxy_model->rowCount());
|
||||||
|
|
||||||
// TODO: this is not a very good place for the following:
|
// TODO: this is not a very good place for the following:
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include <QAbstractItemModel>
|
#include <QAbstractItemModel>
|
||||||
#include <QSortFilterProxyModel>
|
#include <QSortFilterProxyModel>
|
||||||
|
#include <QStandardItemModel>
|
||||||
|
|
||||||
#include "core/Cutter.h"
|
#include "core/Cutter.h"
|
||||||
#include "CutterDockWidget.h"
|
#include "CutterDockWidget.h"
|
||||||
@ -34,10 +35,13 @@ public:
|
|||||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
|
||||||
QVariant data(const QModelIndex &index, int role) const override;
|
QVariant data(const QModelIndex &index, int role) const override;
|
||||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
QVariant headerData(int section, Qt::Orientation orientation,
|
||||||
|
int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
RVA address(const QModelIndex &index) const override;
|
RVA address(const QModelIndex &index) const override;
|
||||||
QString name(const QModelIndex &index) const override;
|
QString name(const QModelIndex &index) const override;
|
||||||
|
|
||||||
|
const FlagDescription *description(QModelIndex index) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -81,6 +85,7 @@ private:
|
|||||||
std::unique_ptr<Ui::FlagsWidget> ui;
|
std::unique_ptr<Ui::FlagsWidget> ui;
|
||||||
MainWindow *main;
|
MainWindow *main;
|
||||||
|
|
||||||
|
bool disableFlagRefresh = false;
|
||||||
FlagsModel *flags_model;
|
FlagsModel *flags_model;
|
||||||
FlagsSortFilterProxyModel *flags_proxy_model;
|
FlagsSortFilterProxyModel *flags_proxy_model;
|
||||||
QList<FlagDescription> flags;
|
QList<FlagDescription> flags;
|
||||||
|
@ -88,6 +88,11 @@ RVA StringsModel::address(const QModelIndex &index) const
|
|||||||
return str.vaddr;
|
return str.vaddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const StringDescription *StringsModel::description(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
return &strings->at(index.row());
|
||||||
|
}
|
||||||
|
|
||||||
StringsProxyModel::StringsProxyModel(StringsModel *sourceModel, QObject *parent)
|
StringsProxyModel::StringsProxyModel(StringsModel *sourceModel, QObject *parent)
|
||||||
: AddressableFilterProxyModel(sourceModel, parent)
|
: AddressableFilterProxyModel(sourceModel, parent)
|
||||||
{
|
{
|
||||||
@ -107,31 +112,31 @@ bool StringsProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) con
|
|||||||
|
|
||||||
bool StringsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
|
bool StringsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
|
||||||
{
|
{
|
||||||
auto leftStr = left.data(StringsModel::StringDescriptionRole).value<StringDescription>();
|
auto model = static_cast<StringsModel *>(sourceModel());
|
||||||
auto rightStr = right.data(StringsModel::StringDescriptionRole).value<StringDescription>();
|
auto leftStr = model->description(left);
|
||||||
|
auto rightStr = model->description(right);
|
||||||
|
|
||||||
switch (left.column()) {
|
switch (left.column()) {
|
||||||
case StringsModel::OffsetColumn:
|
case StringsModel::OffsetColumn:
|
||||||
return leftStr.vaddr < rightStr.vaddr;
|
return leftStr->vaddr < rightStr->vaddr;
|
||||||
case StringsModel::StringColumn: // sort by string
|
case StringsModel::StringColumn: // sort by string
|
||||||
return leftStr.string < rightStr.string;
|
return leftStr->string < rightStr->string;
|
||||||
case StringsModel::TypeColumn: // sort by type
|
case StringsModel::TypeColumn: // sort by type
|
||||||
return leftStr.type < rightStr.type;
|
return leftStr->type < rightStr->type;
|
||||||
case StringsModel::SizeColumn: // sort by size
|
case StringsModel::SizeColumn: // sort by size
|
||||||
return leftStr.size < rightStr.size;
|
return leftStr->size < rightStr->size;
|
||||||
case StringsModel::LengthColumn: // sort by length
|
case StringsModel::LengthColumn: // sort by length
|
||||||
return leftStr.length < rightStr.length;
|
return leftStr->length < rightStr->length;
|
||||||
case StringsModel::SectionColumn:
|
case StringsModel::SectionColumn:
|
||||||
return leftStr.section < rightStr.section;
|
return leftStr->section < rightStr->section;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// fallback
|
// fallback
|
||||||
return leftStr.vaddr < rightStr.vaddr;
|
return leftStr->vaddr < rightStr->vaddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
StringsWidget::StringsWidget(MainWindow *main, QAction *action) :
|
StringsWidget::StringsWidget(MainWindow *main, QAction *action) :
|
||||||
CutterDockWidget(main, action),
|
CutterDockWidget(main, action),
|
||||||
ui(new Ui::StringsWidget),
|
ui(new Ui::StringsWidget),
|
||||||
@ -162,7 +167,7 @@ StringsWidget::StringsWidget(MainWindow *main, QAction *action) :
|
|||||||
proxyModel = new StringsProxyModel(model, this);
|
proxyModel = new StringsProxyModel(model, this);
|
||||||
ui->stringsTreeView->setMainWindow(main);
|
ui->stringsTreeView->setMainWindow(main);
|
||||||
ui->stringsTreeView->setModel(proxyModel);
|
ui->stringsTreeView->setModel(proxyModel);
|
||||||
ui->stringsTreeView->sortByColumn(StringsModel::OffsetColumn, Qt::AscendingOrder);
|
ui->stringsTreeView->sortByColumn(-1, Qt::AscendingOrder);
|
||||||
|
|
||||||
//
|
//
|
||||||
auto menu = ui->stringsTreeView->getItemContextMenu();
|
auto menu = ui->stringsTreeView->getItemContextMenu();
|
||||||
@ -176,7 +181,8 @@ StringsWidget::StringsWidget(MainWindow *main, QAction *action) :
|
|||||||
});
|
});
|
||||||
|
|
||||||
QShortcut *searchShortcut = new QShortcut(QKeySequence::Find, this);
|
QShortcut *searchShortcut = new QShortcut(QKeySequence::Find, this);
|
||||||
connect(searchShortcut, &QShortcut::activated, ui->quickFilterView, &ComboQuickFilterView::showFilter);
|
connect(searchShortcut, &QShortcut::activated, ui->quickFilterView,
|
||||||
|
&ComboQuickFilterView::showFilter);
|
||||||
searchShortcut->setContext(Qt::WidgetWithChildrenShortcut);
|
searchShortcut->setContext(Qt::WidgetWithChildrenShortcut);
|
||||||
|
|
||||||
QShortcut *clearShortcut = new QShortcut(QKeySequence(Qt::Key_Escape), this);
|
QShortcut *clearShortcut = new QShortcut(QKeySequence(Qt::Key_Escape), this);
|
||||||
@ -197,6 +203,12 @@ StringsWidget::StringsWidget(MainWindow *main, QAction *action) :
|
|||||||
tree->showItemsNumber(proxyModel->rowCount());
|
tree->showItemsNumber(proxyModel->rowCount());
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
auto header = ui->stringsTreeView->header();
|
||||||
|
header->setSectionResizeMode(QHeaderView::ResizeMode::ResizeToContents);
|
||||||
|
header->setSectionResizeMode(StringsModel::StringColumn, QHeaderView::ResizeMode::Stretch);
|
||||||
|
header->setStretchLastSection(false);
|
||||||
|
header->setResizeContentsPrecision(256);
|
||||||
}
|
}
|
||||||
|
|
||||||
StringsWidget::~StringsWidget() {}
|
StringsWidget::~StringsWidget() {}
|
||||||
@ -235,10 +247,6 @@ void StringsWidget::stringSearchFinished(const QList<StringDescription> &strings
|
|||||||
this->strings = strings;
|
this->strings = strings;
|
||||||
model->endResetModel();
|
model->endResetModel();
|
||||||
|
|
||||||
qhelpers::adjustColumns(ui->stringsTreeView, 5, 0);
|
|
||||||
if (ui->stringsTreeView->columnWidth(1) > 300)
|
|
||||||
ui->stringsTreeView->setColumnWidth(1, 300);
|
|
||||||
|
|
||||||
tree->showItemsNumber(proxyModel->rowCount());
|
tree->showItemsNumber(proxyModel->rowCount());
|
||||||
|
|
||||||
task.clear();
|
task.clear();
|
||||||
|
@ -39,9 +39,11 @@ public:
|
|||||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
|
||||||
QVariant data(const QModelIndex &index, int role) const override;
|
QVariant data(const QModelIndex &index, int role) const override;
|
||||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
QVariant headerData(int section, Qt::Orientation orientation,
|
||||||
|
int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
RVA address(const QModelIndex &index) const override;
|
RVA address(const QModelIndex &index) const override;
|
||||||
|
const StringDescription *description(const QModelIndex &index) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -163,6 +163,8 @@ VTablesWidget::VTablesWidget(MainWindow *main, QAction *action) :
|
|||||||
|
|
||||||
connect(Core(), &CutterCore::codeRebased, this, &VTablesWidget::refreshVTables);
|
connect(Core(), &CutterCore::codeRebased, this, &VTablesWidget::refreshVTables);
|
||||||
connect(Core(), &CutterCore::refreshAll, this, &VTablesWidget::refreshVTables);
|
connect(Core(), &CutterCore::refreshAll, this, &VTablesWidget::refreshVTables);
|
||||||
|
|
||||||
|
refreshDeferrer = createRefreshDeferrer([this]() { refreshVTables(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
VTablesWidget::~VTablesWidget()
|
VTablesWidget::~VTablesWidget()
|
||||||
@ -171,6 +173,10 @@ VTablesWidget::~VTablesWidget()
|
|||||||
|
|
||||||
void VTablesWidget::refreshVTables()
|
void VTablesWidget::refreshVTables()
|
||||||
{
|
{
|
||||||
|
if (!refreshDeferrer->attemptRefresh(nullptr)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
model->beginResetModel();
|
model->beginResetModel();
|
||||||
vtables = Core()->getAllVTables();
|
vtables = Core()->getAllVTables();
|
||||||
model->endResetModel();
|
model->endResetModel();
|
||||||
|
@ -70,6 +70,7 @@ private:
|
|||||||
QSortFilterProxyModel *proxy;
|
QSortFilterProxyModel *proxy;
|
||||||
QList<VTableDescription> vtables;
|
QList<VTableDescription> vtables;
|
||||||
CutterTreeWidget *tree;
|
CutterTreeWidget *tree;
|
||||||
|
RefreshDeferrer *refreshDeferrer;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // VTABLESWIDGET_H
|
#endif // VTABLESWIDGET_H
|
||||||
|
Loading…
Reference in New Issue
Block a user