Added support for search in XRef dialogue (#3579)

* Updated using given instructions new class XrefFilterProxyModel
* Updated using given instructions new class XrefFilterProxyModel clang formatted
* Added shortcuts for clear and show and added sorting functionality to XrefProxyModel
* fixed clear shortcut not working
* clang formatted
This commit is contained in:
Ron Stephen Mathew 2026-03-30 19:20:06 +05:30 committed by GitHub
parent 41b91515d3
commit 9ac6c75c1a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 127 additions and 14 deletions

View file

@ -7,9 +7,18 @@
#include "core/MainWindow.h"
#include <QJsonArray>
#include <QShortcut>
#include "shortcuts/ShortcutManager.h"
#include <QApplication>
XrefsDialog::XrefsDialog(MainWindow *parent, bool hideXrefFrom)
: QDialog(parent), addr(0), toModel(this), fromModel(this), ui(new Ui::XrefsDialog)
: QDialog(parent),
addr(0),
toModel(this),
toProxyModel(&toModel),
fromModel(this),
fromProxyModel(&fromModel),
ui(new Ui::XrefsDialog)
{
ui->setupUi(this);
setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint));
@ -17,8 +26,8 @@ XrefsDialog::XrefsDialog(MainWindow *parent, bool hideXrefFrom)
ui->toTreeWidget->setMainWindow(parent);
ui->fromTreeWidget->setMainWindow(parent);
ui->toTreeWidget->setModel(&toModel);
ui->fromTreeWidget->setModel(&fromModel);
ui->toTreeWidget->setModel(&toProxyModel);
ui->fromTreeWidget->setModel(&fromProxyModel);
ui->toTreeWidget->getItemContextMenu()->toggleBreakpointAction(true);
ui->fromTreeWidget->getItemContextMenu()->toggleBreakpointAction(true);
@ -44,6 +53,34 @@ XrefsDialog::XrefsDialog(MainWindow *parent, bool hideXrefFrom)
&XrefsDialog::onToTreeWidgetItemSelectionChanged);
connect(ui->fromTreeWidget->selectionModel(), &QItemSelectionModel::selectionChanged, this,
&XrefsDialog::onFromTreeWidgetItemSelectionChanged);
connect(ui->fromQuickFilter, &QuickFilterView::filterTextChanged, &fromProxyModel,
&QSortFilterProxyModel::setFilterWildcard);
connect(ui->toQuickFilter, &QuickFilterView::filterTextChanged, &toProxyModel,
&QSortFilterProxyModel::setFilterWildcard);
// SearchWidget shortcuts
QShortcut *searchShortcut = Shortcuts()->makeQShortcut("General.showFilter", ui->toTreeWidget);
QShortcut *clearShortcut =
Shortcuts()->makeQShortcut("General.clearFilter", ui->fromQuickFilter);
connect(searchShortcut, &QShortcut::activated, this, [this]() {
QWidget *fw = QApplication::focusWidget();
if (ui->toTreeWidget->isAncestorOf(fw)) {
ui->toQuickFilter->showFilter();
} else if (ui->fromTreeWidget->isAncestorOf(fw)) {
ui->fromQuickFilter->showFilter();
}
});
connect(clearShortcut, &QShortcut::activated, [this]() {
QWidget *fw = QApplication::focusWidget();
if (ui->toQuickFilter->isAncestorOf(fw)) {
ui->toQuickFilter->clearFilter();
} else if (ui->fromQuickFilter->isAncestorOf(fw)) {
ui->fromQuickFilter->clearFilter();
}
});
// Don't create recursive xref dialogs
auto toContextMenu = ui->toTreeWidget->getItemContextMenu();
@ -317,3 +354,46 @@ RVA XrefModel::address(const QModelIndex &index) const
const auto &xref = xrefs.at(index.row());
return to ? xref.from : xref.to;
}
bool XrefModel::getTo() const
{
return to;
}
const XrefDescription *XrefModel::description(const QModelIndex &index) const
{
if (index.row() < xrefs.size()) {
return &xrefs.at(index.row());
}
return nullptr;
}
XrefFilterProxyModel::XrefFilterProxyModel(XrefModel *source_model, QObject *parent)
: AddressableFilterProxyModel(source_model, parent), to(source_model->getTo())
{
}
bool XrefFilterProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) const
{
QModelIndex index = sourceModel()->index(row, 0, parent);
XrefDescription xref = index.data(XrefModel::FlagDescriptionRole).value<XrefDescription>();
return qhelpers::filterStringContains(to ? xref.to_str : xref.from_str, this);
}
bool XrefFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
{
auto source = static_cast<XrefModel *>(sourceModel());
auto left_item = source->description(left);
auto right_item = source->description(right);
switch (left.column()) {
case XrefModel::OFFSET:
return to ? left_item->to < right_item->to : left_item->from < right_item->from;
case XrefModel::TYPE:
return left_item->type < right_item->type;
default:
return sourceModel()->data(left, Qt::DisplayRole).toString()
< sourceModel()->data(right, Qt::DisplayRole).toString();
}
}

View file

@ -7,6 +7,7 @@
#include "common/Highlighter.h"
#include "core/Cutter.h"
#include "common/AddressableItemModel.h"
#include "QuickFilterView.h"
class XrefModel : public AddressableItemModel<QAbstractListModel>
{
@ -32,6 +33,23 @@ public:
RVA address(const QModelIndex &index) const override;
static QString xrefTypeString(const QString &type);
bool getTo() const;
const XrefDescription *description(const QModelIndex &index) const;
};
class XrefFilterProxyModel : public AddressableFilterProxyModel
{
Q_OBJECT
public:
XrefFilterProxyModel(XrefModel *source_model, QObject *parent = nullptr);
private:
bool to;
protected:
bool filterAcceptsRow(int row, const QModelIndex &parent) const override;
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
};
class MainWindow;
@ -73,7 +91,9 @@ private:
RVA addr;
QString func_name;
XrefModel toModel;
XrefFilterProxyModel toProxyModel;
XrefModel fromModel;
XrefFilterProxyModel fromProxyModel;
std::unique_ptr<Ui::XrefsDialog> ui;

View file

@ -32,7 +32,7 @@
<item>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="handleWidth">
<number>5</number>
@ -49,13 +49,16 @@
</property>
</widget>
</item>
<item>
<widget class="QuickFilterView" name="toQuickFilter" native="true"/>
</item>
<item>
<widget class="AddressableItemList&lt;&gt;" name="toTreeWidget">
<property name="frameShape">
<enum>QFrame::Box</enum>
<enum>QFrame::Shape::Box</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
<enum>QFrame::Shadow::Plain</enum>
</property>
<property name="indentation">
<number>5</number>
@ -72,13 +75,16 @@
</property>
</widget>
</item>
<item>
<widget class="QuickFilterView" name="fromQuickFilter" native="true"/>
</item>
<item>
<widget class="AddressableItemList&lt;&gt;" name="fromTreeWidget">
<property name="frameShape">
<enum>QFrame::Box</enum>
<enum>QFrame::Shape::Box</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
<enum>QFrame::Shadow::Plain</enum>
</property>
<property name="indentation">
<number>5</number>
@ -102,16 +108,16 @@
<item>
<widget class="QPlainTextEdit" name="previewTextEdit">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
<enum>QFrame::Shape::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
<enum>QFrame::Shadow::Plain</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<property name="lineWrapMode">
<enum>QPlainTextEdit::NoWrap</enum>
<enum>QPlainTextEdit::LineWrapMode::NoWrap</enum>
</property>
<property name="readOnly">
<bool>true</bool>
@ -120,7 +126,7 @@
<string notr="true"/>
</property>
<property name="textInteractionFlags">
<set>Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
<set>Qt::TextInteractionFlag::TextSelectableByKeyboard|Qt::TextInteractionFlag::TextSelectableByMouse</set>
</property>
</widget>
</item>
@ -131,10 +137,10 @@
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
<set>QDialogButtonBox::StandardButton::Close</set>
</property>
</widget>
</item>
@ -145,6 +151,13 @@
<class>AddressableItemList&lt;&gt;</class>
<extends>QTreeView</extends>
<header>widgets/AddressableItemList.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>QuickFilterView</class>
<extends>QWidget</extends>
<header>widgets/QuickFilterView.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>