mirror of
https://github.com/rizinorg/cutter.git
synced 2024-12-19 19:36:11 +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);
|
||||
this->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
this->setUniformRowHeights(true);
|
||||
}
|
||||
|
||||
CutterTreeView::~CutterTreeView() {}
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <QMenu>
|
||||
#include <QShortcut>
|
||||
#include <QTreeWidget>
|
||||
#include <QStandardItemModel>
|
||||
|
||||
FlagsModel::FlagsModel(QList<FlagDescription> *flags, QObject *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
|
||||
{
|
||||
const FlagDescription &flag = flags->at(index.row());
|
||||
return flag.offset;
|
||||
const FlagDescription &flag = flags->at(index.row());
|
||||
return flag.offset;
|
||||
}
|
||||
|
||||
QString FlagsModel::name(const QModelIndex &index) const
|
||||
@ -82,6 +83,14 @@ QString FlagsModel::name(const QModelIndex &index) const
|
||||
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)
|
||||
: 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
|
||||
{
|
||||
FlagDescription left_flag = left.data(FlagsModel::FlagDescriptionRole).value<FlagDescription>();
|
||||
FlagDescription right_flag = right.data(FlagsModel::FlagDescriptionRole).value<FlagDescription>();
|
||||
auto source = static_cast<FlagsModel *>(sourceModel());
|
||||
auto left_flag = source->description(left);
|
||||
auto right_flag = source->description(right);
|
||||
|
||||
switch (left.column()) {
|
||||
case FlagsModel::SIZE:
|
||||
if (left_flag.size != right_flag.size)
|
||||
return left_flag.size < right_flag.size;
|
||||
if (left_flag->size != right_flag->size)
|
||||
return left_flag->size < right_flag->size;
|
||||
// fallthrough
|
||||
case FlagsModel::OFFSET:
|
||||
if (left_flag.offset != right_flag.offset)
|
||||
return left_flag.offset < right_flag.offset;
|
||||
if (left_flag->offset != right_flag->offset)
|
||||
return left_flag->offset < right_flag->offset;
|
||||
// fallthrough
|
||||
case FlagsModel::NAME:
|
||||
return left_flag.name < right_flag.name;
|
||||
return left_flag->name < right_flag->name;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// 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)
|
||||
cur_idx = 0;
|
||||
|
||||
disableFlagRefresh = true; // prevent duplicate flag refresh caused by flagspaceCombo modifications
|
||||
ui->flagspaceCombo->clear();
|
||||
ui->flagspaceCombo->addItem(tr("(all)"));
|
||||
|
||||
@ -221,12 +232,16 @@ void FlagsWidget::refreshFlagspaces()
|
||||
|
||||
if (cur_idx > 0)
|
||||
ui->flagspaceCombo->setCurrentIndex(cur_idx);
|
||||
disableFlagRefresh = false;
|
||||
|
||||
refreshFlags();
|
||||
}
|
||||
|
||||
void FlagsWidget::refreshFlags()
|
||||
{
|
||||
if (disableFlagRefresh) {
|
||||
return;
|
||||
}
|
||||
QString flagspace;
|
||||
|
||||
QVariant flagspace_data = ui->flagspaceCombo->currentData();
|
||||
@ -238,10 +253,8 @@ void FlagsWidget::refreshFlags()
|
||||
flags = Core()->getAllFlags(flagspace);
|
||||
flags_model->endResetModel();
|
||||
|
||||
qhelpers::adjustColumns(ui->flagsTreeView, 2, 0);
|
||||
|
||||
tree->showItemsNumber(flags_proxy_model->rowCount());
|
||||
|
||||
|
||||
// TODO: this is not a very good place for the following:
|
||||
QStringList flagNames;
|
||||
for (const FlagDescription &i : flags)
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QStandardItemModel>
|
||||
|
||||
#include "core/Cutter.h"
|
||||
#include "CutterDockWidget.h"
|
||||
@ -34,10 +35,13 @@ public:
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) 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;
|
||||
QString name(const QModelIndex &index) const override;
|
||||
|
||||
const FlagDescription *description(QModelIndex index) const;
|
||||
};
|
||||
|
||||
|
||||
@ -81,6 +85,7 @@ private:
|
||||
std::unique_ptr<Ui::FlagsWidget> ui;
|
||||
MainWindow *main;
|
||||
|
||||
bool disableFlagRefresh = false;
|
||||
FlagsModel *flags_model;
|
||||
FlagsSortFilterProxyModel *flags_proxy_model;
|
||||
QList<FlagDescription> flags;
|
||||
|
@ -88,6 +88,11 @@ RVA StringsModel::address(const QModelIndex &index) const
|
||||
return str.vaddr;
|
||||
}
|
||||
|
||||
const StringDescription *StringsModel::description(const QModelIndex &index) const
|
||||
{
|
||||
return &strings->at(index.row());
|
||||
}
|
||||
|
||||
StringsProxyModel::StringsProxyModel(StringsModel *sourceModel, QObject *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
|
||||
{
|
||||
auto leftStr = left.data(StringsModel::StringDescriptionRole).value<StringDescription>();
|
||||
auto rightStr = right.data(StringsModel::StringDescriptionRole).value<StringDescription>();
|
||||
auto model = static_cast<StringsModel *>(sourceModel());
|
||||
auto leftStr = model->description(left);
|
||||
auto rightStr = model->description(right);
|
||||
|
||||
switch (left.column()) {
|
||||
case StringsModel::OffsetColumn:
|
||||
return leftStr.vaddr < rightStr.vaddr;
|
||||
return leftStr->vaddr < rightStr->vaddr;
|
||||
case StringsModel::StringColumn: // sort by string
|
||||
return leftStr.string < rightStr.string;
|
||||
return leftStr->string < rightStr->string;
|
||||
case StringsModel::TypeColumn: // sort by type
|
||||
return leftStr.type < rightStr.type;
|
||||
return leftStr->type < rightStr->type;
|
||||
case StringsModel::SizeColumn: // sort by size
|
||||
return leftStr.size < rightStr.size;
|
||||
return leftStr->size < rightStr->size;
|
||||
case StringsModel::LengthColumn: // sort by length
|
||||
return leftStr.length < rightStr.length;
|
||||
return leftStr->length < rightStr->length;
|
||||
case StringsModel::SectionColumn:
|
||||
return leftStr.section < rightStr.section;
|
||||
return leftStr->section < rightStr->section;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// fallback
|
||||
return leftStr.vaddr < rightStr.vaddr;
|
||||
return leftStr->vaddr < rightStr->vaddr;
|
||||
}
|
||||
|
||||
|
||||
StringsWidget::StringsWidget(MainWindow *main, QAction *action) :
|
||||
CutterDockWidget(main, action),
|
||||
ui(new Ui::StringsWidget),
|
||||
@ -162,7 +167,7 @@ StringsWidget::StringsWidget(MainWindow *main, QAction *action) :
|
||||
proxyModel = new StringsProxyModel(model, this);
|
||||
ui->stringsTreeView->setMainWindow(main);
|
||||
ui->stringsTreeView->setModel(proxyModel);
|
||||
ui->stringsTreeView->sortByColumn(StringsModel::OffsetColumn, Qt::AscendingOrder);
|
||||
ui->stringsTreeView->sortByColumn(-1, Qt::AscendingOrder);
|
||||
|
||||
//
|
||||
auto menu = ui->stringsTreeView->getItemContextMenu();
|
||||
@ -176,7 +181,8 @@ StringsWidget::StringsWidget(MainWindow *main, QAction *action) :
|
||||
});
|
||||
|
||||
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);
|
||||
|
||||
QShortcut *clearShortcut = new QShortcut(QKeySequence(Qt::Key_Escape), this);
|
||||
@ -197,6 +203,12 @@ StringsWidget::StringsWidget(MainWindow *main, QAction *action) :
|
||||
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() {}
|
||||
@ -235,10 +247,6 @@ void StringsWidget::stringSearchFinished(const QList<StringDescription> &strings
|
||||
this->strings = strings;
|
||||
model->endResetModel();
|
||||
|
||||
qhelpers::adjustColumns(ui->stringsTreeView, 5, 0);
|
||||
if (ui->stringsTreeView->columnWidth(1) > 300)
|
||||
ui->stringsTreeView->setColumnWidth(1, 300);
|
||||
|
||||
tree->showItemsNumber(proxyModel->rowCount());
|
||||
|
||||
task.clear();
|
||||
|
@ -39,9 +39,11 @@ public:
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) 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;
|
||||
const StringDescription *description(const QModelIndex &index) const;
|
||||
};
|
||||
|
||||
|
||||
|
@ -160,9 +160,11 @@ VTablesWidget::VTablesWidget(MainWindow *main, QAction *action) :
|
||||
connect(ui->quickFilterView, &QuickFilterView::filterTextChanged, this, [this] {
|
||||
tree->showItemsNumber(proxy->rowCount());
|
||||
});
|
||||
|
||||
|
||||
connect(Core(), &CutterCore::codeRebased, this, &VTablesWidget::refreshVTables);
|
||||
connect(Core(), &CutterCore::refreshAll, this, &VTablesWidget::refreshVTables);
|
||||
|
||||
refreshDeferrer = createRefreshDeferrer([this]() { refreshVTables(); });
|
||||
}
|
||||
|
||||
VTablesWidget::~VTablesWidget()
|
||||
@ -171,6 +173,10 @@ VTablesWidget::~VTablesWidget()
|
||||
|
||||
void VTablesWidget::refreshVTables()
|
||||
{
|
||||
if (!refreshDeferrer->attemptRefresh(nullptr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
model->beginResetModel();
|
||||
vtables = Core()->getAllVTables();
|
||||
model->endResetModel();
|
||||
|
@ -70,6 +70,7 @@ private:
|
||||
QSortFilterProxyModel *proxy;
|
||||
QList<VTableDescription> vtables;
|
||||
CutterTreeWidget *tree;
|
||||
RefreshDeferrer *refreshDeferrer;
|
||||
};
|
||||
|
||||
#endif // VTABLESWIDGET_H
|
||||
|
Loading…
Reference in New Issue
Block a user