mirror of
https://github.com/rizinorg/cutter.git
synced 2025-01-18 18:38:51 +00:00
Common behaviour for lists with items that have address part 2 (#1718)
* Seperate addressable item list widget from ListDockWidget. * Convert ResourceWidget, strings widget, flags widget, search widget, MemoryMapWidget, xrefs dialog * Don't silently overwrite comment in add comment action.
This commit is contained in:
parent
fa759dd660
commit
567f852c3a
@ -496,7 +496,8 @@ HEADERS += \
|
||||
common/Decompiler.h \
|
||||
menus/AddressableItemContextMenu.h \
|
||||
common/AddressableItemModel.h \
|
||||
widgets/ListDockWidget.h
|
||||
widgets/ListDockWidget.h \
|
||||
widgets/AddressableItemList.h
|
||||
|
||||
GRAPHVIZ_HEADERS = widgets/GraphGridLayout.h
|
||||
|
||||
@ -536,7 +537,6 @@ FORMS += \
|
||||
widgets/RegistersWidget.ui \
|
||||
widgets/BacktraceWidget.ui \
|
||||
dialogs/OpenFileDialog.ui \
|
||||
widgets/MemoryMapWidget.ui \
|
||||
dialogs/preferences/DebugOptionsWidget.ui \
|
||||
widgets/BreakpointWidget.ui \
|
||||
dialogs/BreakpointsDialog.ui \
|
||||
|
@ -78,7 +78,7 @@ QTreeWidgetItem *appendRow(QTreeWidget *tw, const QString &str, const QString &s
|
||||
* @param tw - QTreeWidget instance
|
||||
* @return true - setCurrentItem was set, false - tree is empty
|
||||
*/
|
||||
bool selectFirstItem(QTreeWidget* tw)
|
||||
bool selectFirstItem(QTreeWidget *tw)
|
||||
{
|
||||
if (tw->topLevelItem(0)) {
|
||||
tw->setCurrentItem(tw->topLevelItem(0));
|
||||
@ -87,6 +87,19 @@ bool selectFirstItem(QTreeWidget* tw)
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool selectFirstItem(QAbstractItemView *itemView)
|
||||
{
|
||||
auto selectionModel = itemView->selectionModel();
|
||||
auto model = itemView->model();
|
||||
if (model->hasChildren()) {
|
||||
selectionModel->setCurrentIndex(model->index(0, 0), QItemSelectionModel::SelectCurrent);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void setVerticalScrollMode(QAbstractItemView *tw)
|
||||
{
|
||||
tw->setVerticalScrollMode(scrollMode());
|
||||
@ -205,7 +218,8 @@ QByteArray applyColorToSvg(const QString &filename, QColor color)
|
||||
* @param setter functor which has to be called
|
||||
* for example we need to set an action icon, the functor can be just [](void* o, const QIcon &icon) { static_cast<QAction*>(o)->setIcon(icon); }
|
||||
*/
|
||||
void setThemeIcons(QList<QPair<void*, QString>> supportedIconsNames, std::function<void(void *, const QIcon &)> setter)
|
||||
void setThemeIcons(QList<QPair<void *, QString>> supportedIconsNames,
|
||||
std::function<void(void *, const QIcon &)> setter)
|
||||
{
|
||||
if (supportedIconsNames.isEmpty() || !setter) {
|
||||
return;
|
||||
|
@ -21,7 +21,8 @@ namespace qhelpers {
|
||||
QString formatBytecount(const long bytecount);
|
||||
void adjustColumns(QTreeView *tv, int columnCount, int padding);
|
||||
void adjustColumns(QTreeWidget *tw, int padding);
|
||||
bool selectFirstItem(QTreeWidget* tw);
|
||||
bool selectFirstItem(QTreeWidget *tw);
|
||||
bool selectFirstItem(QAbstractItemView *itemView);
|
||||
QTreeWidgetItem *appendRow(QTreeWidget *tw, const QString &str, const QString &str2 = QString(),
|
||||
const QString &str3 = QString(), const QString &str4 = QString(), const QString &str5 = QString());
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include "CommentsDialog.h"
|
||||
#include "ui_CommentsDialog.h"
|
||||
|
||||
#include "core/Cutter.h"
|
||||
|
||||
CommentsDialog::CommentsDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::CommentsDialog)
|
||||
@ -34,6 +36,30 @@ void CommentsDialog::setComment(const QString &comment)
|
||||
ui->textEdit->document()->setPlainText(comment);
|
||||
}
|
||||
|
||||
void CommentsDialog::addOrEditComment(RVA offset, QWidget *parent)
|
||||
{
|
||||
QString oldComment = Core()->cmd("CC." + RAddressString(offset));
|
||||
// Remove newline at the end added by cmd
|
||||
oldComment.remove(oldComment.length() - 1, 1);
|
||||
CommentsDialog c(parent);
|
||||
|
||||
if (oldComment.isNull() || oldComment.isEmpty()) {
|
||||
c.setWindowTitle(tr("Add Comment at %1").arg(RAddressString(offset)));
|
||||
} else {
|
||||
c.setWindowTitle(tr("Edit Comment at %1").arg(RAddressString(offset)));
|
||||
}
|
||||
|
||||
c.setComment(oldComment);
|
||||
if (c.exec()) {
|
||||
QString comment = c.getComment();
|
||||
if (comment.isEmpty()) {
|
||||
Core()->delComment(offset);
|
||||
} else {
|
||||
Core()->setComment(offset, comment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CommentsDialog::eventFilter(QObject */*obj*/, QEvent *event)
|
||||
{
|
||||
if (event -> type() == QEvent::KeyPress) {
|
||||
|
@ -4,6 +4,8 @@
|
||||
#include <QDialog>
|
||||
#include <memory>
|
||||
|
||||
#include "core/CutterCommon.h"
|
||||
|
||||
namespace Ui {
|
||||
class CommentsDialog;
|
||||
}
|
||||
@ -19,6 +21,7 @@ public:
|
||||
QString getComment();
|
||||
void setComment(const QString &comment);
|
||||
|
||||
static void addOrEditComment(RVA offset, QWidget *parent);
|
||||
private slots:
|
||||
void on_buttonBox_accepted();
|
||||
|
||||
|
@ -8,14 +8,22 @@
|
||||
|
||||
#include <QJsonArray>
|
||||
|
||||
XrefsDialog::XrefsDialog(QWidget *parent) :
|
||||
XrefsDialog::XrefsDialog(MainWindow *main, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
addr(0),
|
||||
toModel(this),
|
||||
fromModel(this),
|
||||
ui(new Ui::XrefsDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint));
|
||||
|
||||
ui->toTreeWidget->setMainWindow(main);
|
||||
ui->fromTreeWidget->setMainWindow(main);
|
||||
|
||||
ui->toTreeWidget->setModel(&toModel);
|
||||
ui->fromTreeWidget->setModel(&fromModel);
|
||||
|
||||
// Modify the splitter's location to show more Disassembly instead of empty space. Not possible via Designer
|
||||
ui->splitter->setSizes(QList<int>() << 100 << 200);
|
||||
|
||||
@ -30,66 +38,24 @@ XrefsDialog::XrefsDialog(QWidget *parent) :
|
||||
connect(ui->previewTextEdit, SIGNAL(cursorPositionChanged()), this, SLOT(highlightCurrentLine()));
|
||||
connect(Config(), SIGNAL(fontsUpdated()), this, SLOT(setupPreviewFont()));
|
||||
connect(Config(), SIGNAL(colorsUpdated()), this, SLOT(setupPreviewColors()));
|
||||
|
||||
connect(ui->toTreeWidget->selectionModel(), &QItemSelectionModel::selectionChanged,
|
||||
this, &XrefsDialog::onToTreeWidgetItemSelectionChanged);
|
||||
connect(ui->fromTreeWidget->selectionModel(), &QItemSelectionModel::selectionChanged,
|
||||
this, &XrefsDialog::onFromTreeWidgetItemSelectionChanged);
|
||||
|
||||
// Don't create recursive xref dialogs
|
||||
auto toContextMenu = ui->toTreeWidget->getItemContextMenu();
|
||||
connect(toContextMenu, &AddressableItemContextMenu::xrefsTriggered, this, &QWidget::close);
|
||||
auto fromContextMenu = ui->fromTreeWidget->getItemContextMenu();
|
||||
connect(fromContextMenu, &AddressableItemContextMenu::xrefsTriggered, this, &QWidget::close);
|
||||
|
||||
connect(ui->toTreeWidget, &QAbstractItemView::doubleClicked, this, &QWidget::close);
|
||||
connect(ui->fromTreeWidget, &QAbstractItemView::doubleClicked, this, &QWidget::close);
|
||||
}
|
||||
|
||||
XrefsDialog::~XrefsDialog() { }
|
||||
|
||||
void XrefsDialog::fillRefs(QList<XrefDescription> refs, QList<XrefDescription> xrefs)
|
||||
{
|
||||
// Fill refs
|
||||
ui->fromTreeWidget->clear();
|
||||
for (const auto &xref : refs) {
|
||||
auto *tempItem = new QTreeWidgetItem();
|
||||
tempItem->setText(0, xref.to_str);
|
||||
if (xref.type != "DATA") {
|
||||
tempItem->setText(1, Core()->disassembleSingleInstruction(xref.to));
|
||||
}
|
||||
tempItem->setText(2, xrefTypeString(xref.type));
|
||||
tempItem->setData(0, Qt::UserRole, QVariant::fromValue(xref));
|
||||
ui->fromTreeWidget->insertTopLevelItem(0, tempItem);
|
||||
}
|
||||
|
||||
// Adjust columns to content
|
||||
qhelpers::adjustColumns(ui->fromTreeWidget, 0);
|
||||
|
||||
// Fill Xrefs
|
||||
ui->toTreeWidget->clear();
|
||||
for (const auto &xref : xrefs) {
|
||||
auto *tempItem = new QTreeWidgetItem();
|
||||
tempItem->setText(0, xref.from_str);
|
||||
tempItem->setText(1, Core()->disassembleSingleInstruction(xref.from));
|
||||
tempItem->setText(2, xrefTypeString(xref.type));
|
||||
tempItem->setData(0, Qt::UserRole, QVariant::fromValue(xref));
|
||||
ui->toTreeWidget->insertTopLevelItem(0, tempItem);
|
||||
}
|
||||
|
||||
// Adjust columns to content
|
||||
qhelpers::adjustColumns(ui->toTreeWidget, 0);
|
||||
|
||||
// try to select first item from refs or xrefs
|
||||
if (!qhelpers::selectFirstItem(ui->toTreeWidget)) {
|
||||
qhelpers::selectFirstItem(ui->fromTreeWidget);
|
||||
}
|
||||
}
|
||||
|
||||
void XrefsDialog::on_fromTreeWidget_itemDoubleClicked(QTreeWidgetItem *item, int column)
|
||||
{
|
||||
Q_UNUSED(column);
|
||||
|
||||
XrefDescription xref = item->data(0, Qt::UserRole).value<XrefDescription>();
|
||||
Core()->seekAndShow(xref.to);
|
||||
this->close();
|
||||
}
|
||||
|
||||
void XrefsDialog::on_toTreeWidget_itemDoubleClicked(QTreeWidgetItem *item, int column)
|
||||
{
|
||||
Q_UNUSED(column);
|
||||
|
||||
XrefDescription xref = item->data(0, Qt::UserRole).value<XrefDescription>();
|
||||
Core()->seekAndShow(xref.from);
|
||||
this->close();
|
||||
}
|
||||
|
||||
QString XrefsDialog::normalizeAddr(const QString &addr) const
|
||||
{
|
||||
QString ret = addr;
|
||||
@ -129,26 +95,24 @@ void XrefsDialog::highlightCurrentLine()
|
||||
}
|
||||
}
|
||||
|
||||
void XrefsDialog::on_fromTreeWidget_itemSelectionChanged()
|
||||
void XrefsDialog::onFromTreeWidgetItemSelectionChanged()
|
||||
{
|
||||
if (ui->fromTreeWidget->selectedItems().isEmpty()) {
|
||||
auto index = ui->fromTreeWidget->currentIndex();
|
||||
if (!ui->fromTreeWidget->selectionModel()->hasSelection() || !index.isValid()) {
|
||||
return;
|
||||
}
|
||||
ui->toTreeWidget->clearSelection();
|
||||
QTreeWidgetItem *item = ui->fromTreeWidget->currentItem();
|
||||
XrefDescription xref = item->data(0, Qt::UserRole).value<XrefDescription>();
|
||||
updatePreview(xref.to);
|
||||
updatePreview(fromModel.address(index));
|
||||
}
|
||||
|
||||
void XrefsDialog::on_toTreeWidget_itemSelectionChanged()
|
||||
void XrefsDialog::onToTreeWidgetItemSelectionChanged()
|
||||
{
|
||||
if (ui->toTreeWidget->selectedItems().isEmpty()) {
|
||||
auto index = ui->toTreeWidget->currentIndex();
|
||||
if (!ui->toTreeWidget->selectionModel()->hasSelection() || !index.isValid()) {
|
||||
return;
|
||||
}
|
||||
ui->fromTreeWidget->clearSelection();
|
||||
QTreeWidgetItem *item = ui->toTreeWidget->currentItem();
|
||||
XrefDescription xref = item->data(0, Qt::UserRole).value<XrefDescription>();
|
||||
updatePreview(xref.from);
|
||||
updatePreview(toModel.address(index));
|
||||
}
|
||||
|
||||
void XrefsDialog::updatePreview(RVA addr)
|
||||
@ -180,24 +144,113 @@ void XrefsDialog::fillRefsForAddress(RVA addr, QString name, bool whole_function
|
||||
setWindowTitle(tr("X-Refs for %1").arg(name));
|
||||
updateLabels(name);
|
||||
|
||||
// Get Refs and Xrefs
|
||||
QList<XrefDescription> refs = Core()->getXRefs(addr, false, whole_function);
|
||||
QList<XrefDescription> xrefs = Core()->getXRefs(addr, true, whole_function);
|
||||
toModel.readForOffset(addr, true, whole_function);
|
||||
fromModel.readForOffset(addr, false, whole_function);
|
||||
|
||||
fillRefs(refs, xrefs);
|
||||
// Adjust columns to content
|
||||
qhelpers::adjustColumns(ui->fromTreeWidget, fromModel.columnCount(), 0);
|
||||
qhelpers::adjustColumns(ui->toTreeWidget, toModel.columnCount(), 0);
|
||||
|
||||
// try to select first item from refs or xrefs
|
||||
if (!qhelpers::selectFirstItem(ui->toTreeWidget)) {
|
||||
qhelpers::selectFirstItem(ui->fromTreeWidget);
|
||||
}
|
||||
}
|
||||
|
||||
QString XrefsDialog::xrefTypeString(const QString &type)
|
||||
QString XrefModel::xrefTypeString(const QString &type)
|
||||
{
|
||||
if (type == "CODE") {
|
||||
return QString("Code");
|
||||
return QStringLiteral("Code");
|
||||
} else if (type == "CALL") {
|
||||
return QString("Call");
|
||||
return QStringLiteral("Call");
|
||||
} else if (type == "DATA") {
|
||||
return QString("Data");
|
||||
return QStringLiteral("Data");
|
||||
} else if (type == "STRING") {
|
||||
return QString("String");
|
||||
return QStringLiteral("String");
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
XrefModel::XrefModel(QObject *parent)
|
||||
: AddressableItemModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void XrefModel::readForOffset(RVA offset, bool to, bool whole_function)
|
||||
{
|
||||
beginResetModel();
|
||||
this->to = to;
|
||||
xrefs = Core()->getXRefs(offset, to, whole_function);
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
int XrefModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
return xrefs.size();
|
||||
}
|
||||
|
||||
int XrefModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
return Columns::COUNT;
|
||||
}
|
||||
|
||||
QVariant XrefModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid() || index.row() >= xrefs.count()) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
const XrefDescription &xref = xrefs.at(index.row());
|
||||
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
switch (index.column()) {
|
||||
case OFFSET:
|
||||
return to ? xref.from_str : xref.to_str;
|
||||
case CODE:
|
||||
if (to || xref.type != "DATA") {
|
||||
return Core()->disassembleSingleInstruction(xref.from);
|
||||
} else {
|
||||
return QString();
|
||||
}
|
||||
case TYPE:
|
||||
return xrefTypeString(xref.type);
|
||||
}
|
||||
return QVariant();
|
||||
case FlagDescriptionRole:
|
||||
return QVariant::fromValue(xref);
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant XrefModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
Q_UNUSED(orientation)
|
||||
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
switch (section) {
|
||||
case OFFSET:
|
||||
return tr("Address");
|
||||
case CODE:
|
||||
return tr("Code");
|
||||
case TYPE:
|
||||
return tr("Type");
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
RVA XrefModel::address(const QModelIndex &index) const
|
||||
{
|
||||
const auto &xref = xrefs.at(index.row());
|
||||
return to ? xref.from : xref.to;
|
||||
}
|
||||
|
@ -6,6 +6,32 @@
|
||||
#include <memory>
|
||||
#include "common/Highlighter.h"
|
||||
#include "core/Cutter.h"
|
||||
#include "common/AddressableItemModel.h"
|
||||
|
||||
class XrefModel: public AddressableItemModel<QAbstractListModel>
|
||||
{
|
||||
private:
|
||||
QList<XrefDescription> xrefs;
|
||||
bool to;
|
||||
public:
|
||||
enum Columns { OFFSET = 0, CODE, TYPE, COUNT };
|
||||
static const int FlagDescriptionRole = Qt::UserRole;
|
||||
|
||||
XrefModel(QObject *parent = nullptr);
|
||||
void readForOffset(RVA offset, bool to, bool whole_function);
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
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;
|
||||
|
||||
RVA address(const QModelIndex &index) const override;
|
||||
|
||||
static QString xrefTypeString(const QString &type);
|
||||
};
|
||||
|
||||
|
||||
class MainWindow;
|
||||
|
||||
@ -18,37 +44,32 @@ class XrefsDialog : public QDialog
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit XrefsDialog(QWidget *parent = nullptr);
|
||||
explicit XrefsDialog(MainWindow *main, QWidget *parent);
|
||||
~XrefsDialog();
|
||||
|
||||
void fillRefsForAddress(RVA addr, QString name, bool whole_function);
|
||||
|
||||
private slots:
|
||||
void on_fromTreeWidget_itemDoubleClicked(QTreeWidgetItem *item, int column);
|
||||
void on_toTreeWidget_itemDoubleClicked(QTreeWidgetItem *item, int column);
|
||||
|
||||
QString normalizeAddr(const QString &addr) const;
|
||||
|
||||
void setupPreviewFont();
|
||||
void setupPreviewColors();
|
||||
|
||||
void highlightCurrentLine();
|
||||
void on_fromTreeWidget_itemSelectionChanged();
|
||||
|
||||
void on_toTreeWidget_itemSelectionChanged();
|
||||
void onFromTreeWidgetItemSelectionChanged();
|
||||
void onToTreeWidgetItemSelectionChanged();
|
||||
|
||||
private:
|
||||
RVA addr;
|
||||
QString func_name;
|
||||
XrefModel toModel;
|
||||
XrefModel fromModel;
|
||||
|
||||
std::unique_ptr<Ui::XrefsDialog> ui;
|
||||
|
||||
void fillRefs(QList<XrefDescription> refs, QList<XrefDescription> xrefs);
|
||||
void updateLabels(QString name);
|
||||
void updatePreview(RVA addr);
|
||||
|
||||
QString xrefTypeString(const QString &type);
|
||||
|
||||
};
|
||||
|
||||
#endif // XREFSDIALOG_H
|
||||
|
@ -50,7 +50,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTreeWidget" name="toTreeWidget">
|
||||
<widget class="AddressableItemList<>" name="toTreeWidget">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Box</enum>
|
||||
</property>
|
||||
@ -60,24 +60,6 @@
|
||||
<property name="indentation">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="columnCount">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Address</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Code</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Type</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
@ -88,7 +70,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTreeWidget" name="fromTreeWidget">
|
||||
<widget class="AddressableItemList<>" name="fromTreeWidget">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Box</enum>
|
||||
</property>
|
||||
@ -98,24 +80,6 @@
|
||||
<property name="indentation">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="columnCount">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Address</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Code</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Type</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
@ -170,6 +134,13 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>AddressableItemList<></class>
|
||||
<extends>QTreeView</extends>
|
||||
<header>widgets/AddressableItemList.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
|
@ -30,7 +30,8 @@ AddressableItemContextMenu::AddressableItemContextMenu(QWidget *parent, MainWind
|
||||
|
||||
connect(&actionAddcomment, &QAction::triggered, this,
|
||||
&AddressableItemContextMenu::onActionAddComment);
|
||||
|
||||
actionAddcomment.setShortcut({Qt::Key_Semicolon});
|
||||
actionAddcomment.setShortcutContext(Qt::ShortcutContext::WidgetWithChildrenShortcut);
|
||||
|
||||
addAction(&actionShowInMenu);
|
||||
addAction(&actionCopyAddress);
|
||||
@ -38,6 +39,7 @@ AddressableItemContextMenu::AddressableItemContextMenu(QWidget *parent, MainWind
|
||||
addSeparator();
|
||||
addAction(&actionAddcomment);
|
||||
|
||||
setHasTarget(hasTarget);
|
||||
connect(this, &QMenu::aboutToShow, this, &AddressableItemContextMenu::aboutToShowSlot);
|
||||
}
|
||||
|
||||
@ -59,6 +61,12 @@ void AddressableItemContextMenu::setTarget(RVA offset, QString name)
|
||||
{
|
||||
this->offset = offset;
|
||||
this->name = name;
|
||||
setHasTarget(true);
|
||||
}
|
||||
|
||||
void AddressableItemContextMenu::clearTarget()
|
||||
{
|
||||
setHasTarget(false);
|
||||
}
|
||||
|
||||
void AddressableItemContextMenu::onActionCopyAddress()
|
||||
@ -69,7 +77,8 @@ void AddressableItemContextMenu::onActionCopyAddress()
|
||||
|
||||
void AddressableItemContextMenu::onActionShowXrefs()
|
||||
{
|
||||
XrefsDialog dialog(nullptr);
|
||||
emit xrefsTriggered();
|
||||
XrefsDialog dialog(mainWindow, nullptr);
|
||||
QString tmpName = name;
|
||||
if (name.isEmpty()) {
|
||||
name = RAddressString(offset);
|
||||
@ -80,17 +89,7 @@ void AddressableItemContextMenu::onActionShowXrefs()
|
||||
|
||||
void AddressableItemContextMenu::onActionAddComment()
|
||||
{
|
||||
// Create dialog
|
||||
CommentsDialog c(this);
|
||||
|
||||
if (c.exec()) {
|
||||
// Get new function name
|
||||
QString comment = c.getComment();
|
||||
// Rename function in r2 core
|
||||
Core()->setComment(offset, comment);
|
||||
// Seek to new renamed function
|
||||
Core()->seekAndShow(offset);
|
||||
}
|
||||
CommentsDialog::addOrEditComment(offset, this);
|
||||
}
|
||||
|
||||
void AddressableItemContextMenu::aboutToShowSlot()
|
||||
@ -101,3 +100,11 @@ void AddressableItemContextMenu::aboutToShowSlot()
|
||||
actionShowInMenu.setMenu(mainWindow->createShowInMenu(this, offset));
|
||||
}
|
||||
|
||||
void AddressableItemContextMenu::setHasTarget(bool hasTarget)
|
||||
{
|
||||
this->hasTarget = hasTarget;
|
||||
for (const auto &action : this->actions()) {
|
||||
action->setEnabled(hasTarget);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,9 @@ public:
|
||||
public slots:
|
||||
void setOffset(RVA offset);
|
||||
void setTarget(RVA offset, QString name = QString());
|
||||
void clearTarget();
|
||||
signals:
|
||||
void xrefsTriggered();
|
||||
private:
|
||||
void onActionCopyAddress();
|
||||
void onActionShowXrefs();
|
||||
@ -31,7 +34,9 @@ private:
|
||||
MainWindow *mainWindow;
|
||||
|
||||
RVA offset;
|
||||
bool hasTarget = false;
|
||||
protected:
|
||||
void setHasTarget(bool hasTarget);
|
||||
QAction actionShowInMenu;
|
||||
QAction actionCopyAddress;
|
||||
QAction actionShowXrefs;
|
||||
|
@ -671,26 +671,7 @@ void DisassemblyContextMenu::on_actionSetPC_triggered()
|
||||
|
||||
void DisassemblyContextMenu::on_actionAddComment_triggered()
|
||||
{
|
||||
QString oldComment = Core()->cmd("CC." + RAddressString(offset));
|
||||
// Remove newline at the end added by cmd
|
||||
oldComment.remove(oldComment.length() - 1, 1);
|
||||
CommentsDialog c(this);
|
||||
|
||||
if (oldComment.isNull() || oldComment.isEmpty()) {
|
||||
c.setWindowTitle(tr("Add Comment at %1").arg(RAddressString(offset)));
|
||||
} else {
|
||||
c.setWindowTitle(tr("Edit Comment at %1").arg(RAddressString(offset)));
|
||||
}
|
||||
|
||||
c.setComment(oldComment);
|
||||
if (c.exec()) {
|
||||
QString comment = c.getComment();
|
||||
if (comment.isEmpty()) {
|
||||
Core()->delComment(offset);
|
||||
} else {
|
||||
Core()->setComment(offset, comment);
|
||||
}
|
||||
}
|
||||
CommentsDialog::addOrEditComment(offset, this);
|
||||
}
|
||||
|
||||
void DisassemblyContextMenu::on_actionAnalyzeFunction_triggered()
|
||||
@ -796,7 +777,7 @@ void DisassemblyContextMenu::on_actionSetFunctionVarTypes_triggered()
|
||||
|
||||
void DisassemblyContextMenu::on_actionXRefs_triggered()
|
||||
{
|
||||
XrefsDialog dialog(nullptr);
|
||||
XrefsDialog dialog(mainWindow, nullptr);
|
||||
dialog.fillRefsForAddress(offset, RAddressString(offset), false);
|
||||
dialog.exec();
|
||||
}
|
||||
|
103
src/widgets/AddressableItemList.h
Normal file
103
src/widgets/AddressableItemList.h
Normal file
@ -0,0 +1,103 @@
|
||||
#ifndef ADDRESSABLE_ITEM_LIST_H
|
||||
#define ADDRESSABLE_ITEM_LIST_H
|
||||
|
||||
#include <memory>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QAbstractItemView>
|
||||
#include <QMenu>
|
||||
|
||||
#include "core/Cutter.h"
|
||||
#include "common/AddressableItemModel.h"
|
||||
#include "CutterDockWidget.h"
|
||||
#include "CutterTreeWidget.h"
|
||||
#include "menus/AddressableItemContextMenu.h"
|
||||
#include "CutterTreeView.h"
|
||||
|
||||
class MainWindow;
|
||||
|
||||
template<class BaseListWidget = CutterTreeView>
|
||||
class AddressableItemList : public BaseListWidget
|
||||
{
|
||||
static_assert (std::is_base_of<QAbstractItemView, BaseListWidget>::value,
|
||||
"ParentModel needs to inherit from QAbstractItemModel");
|
||||
|
||||
public:
|
||||
explicit AddressableItemList(QWidget *parent = nullptr) :
|
||||
BaseListWidget(parent)
|
||||
{
|
||||
this->connect(this, &QWidget::customContextMenuRequested, this,
|
||||
&AddressableItemList<BaseListWidget>::showItemContextMenu);
|
||||
this->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
this->connect(this, &QAbstractItemView::activated, this,
|
||||
&AddressableItemList<BaseListWidget>::onItemActivated);
|
||||
}
|
||||
|
||||
void setModel(AddressableItemModelI *addressableItemModel)
|
||||
{
|
||||
this->addressableModel = addressableItemModel;
|
||||
|
||||
BaseListWidget::setModel(this->addressableModel->asItemModel());
|
||||
|
||||
this->connect(this->selectionModel(), &QItemSelectionModel::currentChanged, this,
|
||||
&AddressableItemList<BaseListWidget>::onSelectedItemChanged);
|
||||
}
|
||||
void setMainWindow(MainWindow *mainWindow)
|
||||
{
|
||||
this->mainWindow = mainWindow;
|
||||
setItemContextMenu(new AddressableItemContextMenu(this, mainWindow));
|
||||
this->addActions(this->getItemContextMenu()->actions());
|
||||
}
|
||||
|
||||
AddressableItemContextMenu *getItemContextMenu()
|
||||
{
|
||||
return itemContextMenu;
|
||||
}
|
||||
void setItemContextMenu(AddressableItemContextMenu *menu)
|
||||
{
|
||||
if (itemContextMenu != menu && itemContextMenu) {
|
||||
itemContextMenu->deleteLater();
|
||||
}
|
||||
itemContextMenu = menu;
|
||||
}
|
||||
protected:
|
||||
virtual void showItemContextMenu(const QPoint &pt)
|
||||
{
|
||||
auto index = this->currentIndex();
|
||||
if (index.isValid() && itemContextMenu) {
|
||||
auto offset = addressableModel->address(index);
|
||||
auto name = addressableModel->name(index);
|
||||
itemContextMenu->setTarget(offset, name);
|
||||
itemContextMenu->exec(this->mapToGlobal(pt));
|
||||
}
|
||||
}
|
||||
|
||||
virtual void onItemActivated(const QModelIndex &index)
|
||||
{
|
||||
if (!index.isValid())
|
||||
return;
|
||||
|
||||
auto offset = addressableModel->address(index);
|
||||
Core()->seekAndShow(offset);
|
||||
}
|
||||
virtual void onSelectedItemChanged(const QModelIndex &index)
|
||||
{
|
||||
updateMenuFromItem(index);
|
||||
}
|
||||
void updateMenuFromItem(const QModelIndex &index)
|
||||
{
|
||||
if (index.isValid()) {
|
||||
auto offset = addressableModel->address(index);
|
||||
auto name = addressableModel->name(index);
|
||||
itemContextMenu->setTarget(offset, name);
|
||||
} else {
|
||||
itemContextMenu->clearTarget();
|
||||
}
|
||||
}
|
||||
private:
|
||||
AddressableItemModelI *addressableModel = nullptr;
|
||||
AddressableItemContextMenu *itemContextMenu = nullptr;
|
||||
MainWindow *mainWindow = nullptr;
|
||||
};
|
||||
|
||||
#endif // ADDRESSABLE_ITEM_LIST_H
|
@ -2,7 +2,6 @@
|
||||
#include "ui_FlagsWidget.h"
|
||||
#include "core/MainWindow.h"
|
||||
#include "dialogs/RenameDialog.h"
|
||||
#include "dialogs/XrefsDialog.h"
|
||||
#include "common/Helpers.h"
|
||||
|
||||
#include <QComboBox>
|
||||
@ -11,7 +10,7 @@
|
||||
#include <QTreeWidget>
|
||||
|
||||
FlagsModel::FlagsModel(QList<FlagDescription> *flags, QObject *parent)
|
||||
: QAbstractListModel(parent),
|
||||
: AddressableItemModel<QAbstractListModel>(parent),
|
||||
flags(flags)
|
||||
{
|
||||
}
|
||||
@ -71,14 +70,21 @@ 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
QString FlagsModel::name(const QModelIndex &index) const
|
||||
{
|
||||
const FlagDescription &flag = flags->at(index.row());
|
||||
return flag.name;
|
||||
}
|
||||
|
||||
FlagsSortFilterProxyModel::FlagsSortFilterProxyModel(FlagsModel *source_model, QObject *parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
: AddressableFilterProxyModel(source_model, parent)
|
||||
{
|
||||
setSourceModel(source_model);
|
||||
}
|
||||
|
||||
bool FlagsSortFilterProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) const
|
||||
@ -128,6 +134,7 @@ FlagsWidget::FlagsWidget(MainWindow *main, QAction *action) :
|
||||
flags_proxy_model = new FlagsSortFilterProxyModel(flags_model, this);
|
||||
connect(ui->filterLineEdit, SIGNAL(textChanged(const QString &)), flags_proxy_model,
|
||||
SLOT(setFilterWildcard(const QString &)));
|
||||
ui->flagsTreeView->setMainWindow(mainWindow);
|
||||
ui->flagsTreeView->setModel(flags_proxy_model);
|
||||
ui->flagsTreeView->sortByColumn(FlagsModel::OFFSET, Qt::AscendingOrder);
|
||||
|
||||
@ -151,32 +158,21 @@ FlagsWidget::FlagsWidget(MainWindow *main, QAction *action) :
|
||||
tree->showItemsNumber(flags_proxy_model->rowCount());
|
||||
});
|
||||
|
||||
auto xRefShortcut = new QShortcut(QKeySequence{Qt::CTRL + Qt::Key_X}, this);
|
||||
xRefShortcut->setContext(Qt::WidgetWithChildrenShortcut);
|
||||
ui->actionXrefs->setShortcut(Qt::CTRL + Qt::Key_X);
|
||||
connect(xRefShortcut, SIGNAL(activated()), this, SLOT(on_actionXrefs_triggered()));
|
||||
|
||||
setScrollMode();
|
||||
|
||||
ui->flagsTreeView->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(ui->flagsTreeView, SIGNAL(customContextMenuRequested(const QPoint &)), this,
|
||||
SLOT(showContextMenu(const QPoint &)));
|
||||
|
||||
connect(Core(), SIGNAL(flagsChanged()), this, SLOT(flagsChanged()));
|
||||
connect(Core(), SIGNAL(refreshAll()), this, SLOT(refreshFlagspaces()));
|
||||
|
||||
auto menu = ui->flagsTreeView->getItemContextMenu();
|
||||
menu->addSeparator();
|
||||
menu->addAction(ui->actionRename);
|
||||
menu->addAction(ui->actionDelete);
|
||||
addAction(ui->actionRename);
|
||||
addAction(ui->actionDelete);
|
||||
}
|
||||
|
||||
FlagsWidget::~FlagsWidget() {}
|
||||
|
||||
void FlagsWidget::on_flagsTreeView_doubleClicked(const QModelIndex &index)
|
||||
{
|
||||
if (!index.isValid())
|
||||
return;
|
||||
|
||||
FlagDescription flag = index.data(FlagsModel::FlagDescriptionRole).value<FlagDescription>();
|
||||
Core()->seekAndShow(flag.offset);
|
||||
}
|
||||
|
||||
void FlagsWidget::on_flagspaceCombo_currentTextChanged(const QString &arg1)
|
||||
{
|
||||
Q_UNUSED(arg1);
|
||||
@ -204,28 +200,6 @@ void FlagsWidget::on_actionDelete_triggered()
|
||||
Core()->delFlag(flag.name);
|
||||
}
|
||||
|
||||
void FlagsWidget::on_actionXrefs_triggered()
|
||||
{
|
||||
FlagDescription flag = ui->flagsTreeView->selectionModel()->currentIndex().data(
|
||||
FlagsModel::FlagDescriptionRole).value<FlagDescription>();
|
||||
|
||||
XrefsDialog xresfDialog(nullptr);
|
||||
xresfDialog.fillRefsForAddress(flag.offset, RAddressString(flag.offset), false);
|
||||
xresfDialog.exec();
|
||||
}
|
||||
|
||||
void FlagsWidget::showContextMenu(const QPoint &pt)
|
||||
{
|
||||
QMenu *menu = new QMenu(ui->flagsTreeView);
|
||||
menu->addAction(ui->actionRename);
|
||||
menu->addAction(ui->actionDelete);
|
||||
menu->addSeparator();
|
||||
menu->addAction(ui->actionXrefs);
|
||||
menu->exec(ui->flagsTreeView->mapToGlobal(pt));
|
||||
delete menu;
|
||||
}
|
||||
|
||||
|
||||
void FlagsWidget::flagsChanged()
|
||||
{
|
||||
refreshFlagspaces();
|
||||
|
@ -9,16 +9,16 @@
|
||||
#include "core/Cutter.h"
|
||||
#include "CutterDockWidget.h"
|
||||
#include "CutterTreeWidget.h"
|
||||
#include "AddressableItemList.h"
|
||||
#include "AddressableItemModel.h"
|
||||
|
||||
class MainWindow;
|
||||
class QTreeWidgetItem;
|
||||
class FlagsWidget;
|
||||
|
||||
|
||||
class FlagsModel: public QAbstractListModel
|
||||
class FlagsModel: public AddressableItemModel<QAbstractListModel>
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
friend FlagsWidget;
|
||||
|
||||
private:
|
||||
@ -30,16 +30,19 @@ public:
|
||||
|
||||
FlagsModel(QList<FlagDescription> *flags, QObject *parent = nullptr);
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
|
||||
QVariant data(const QModelIndex &index, int role) const;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||
QVariant data(const QModelIndex &index, int role) 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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class FlagsSortFilterProxyModel : public QSortFilterProxyModel
|
||||
class FlagsSortFilterProxyModel : public AddressableFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@ -66,14 +69,10 @@ public:
|
||||
~FlagsWidget();
|
||||
|
||||
private slots:
|
||||
void on_flagsTreeView_doubleClicked(const QModelIndex &index);
|
||||
void on_flagspaceCombo_currentTextChanged(const QString &arg1);
|
||||
|
||||
void on_actionRename_triggered();
|
||||
void on_actionDelete_triggered();
|
||||
void on_actionXrefs_triggered();
|
||||
|
||||
void showContextMenu(const QPoint &pt);
|
||||
|
||||
void flagsChanged();
|
||||
void refreshFlagspaces();
|
||||
|
@ -31,7 +31,7 @@
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="CutterTreeView" name="flagsTreeView">
|
||||
<widget class="AddressableItemList<>" name="flagsTreeView">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">CutterTreeView::item
|
||||
{
|
||||
@ -99,7 +99,7 @@
|
||||
<string>Rename</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+N</string>
|
||||
<string>N</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDelete">
|
||||
@ -110,23 +110,12 @@
|
||||
<string>Del</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionXrefs">
|
||||
<property name="text">
|
||||
<string>X-Refs</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Show X-Refs of this flag</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+X</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>CutterTreeView</class>
|
||||
<class>AddressableItemList<></class>
|
||||
<extends>QTreeView</extends>
|
||||
<header>widgets/CutterTreeView.h</header>
|
||||
<header>widgets/AddressableItemList.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
|
@ -3,9 +3,7 @@
|
||||
|
||||
#include "core/MainWindow.h"
|
||||
#include "common/Helpers.h"
|
||||
#include "dialogs/CommentsDialog.h"
|
||||
#include "dialogs/RenameDialog.h"
|
||||
#include "dialogs/XrefsDialog.h"
|
||||
#include "common/FunctionsTask.h"
|
||||
#include "common/TempConfig.h"
|
||||
#include "menus/AddressableItemContextMenu.h"
|
||||
@ -18,6 +16,7 @@
|
||||
#include <QShortcut>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QResizeEvent>
|
||||
|
||||
namespace {
|
||||
|
||||
@ -467,7 +466,7 @@ FunctionsWidget::FunctionsWidget(MainWindow *main, QAction *action) :
|
||||
connect(&actionUndefine, &QAction::triggered, this,
|
||||
&FunctionsWidget::onActionFunctionsUndefineTriggered);
|
||||
|
||||
auto itemConextMenu = getItemContextMenu();
|
||||
auto itemConextMenu = ui->treeView->getItemContextMenu();
|
||||
itemConextMenu->addSeparator();
|
||||
itemConextMenu->addAction(&actionRename);
|
||||
itemConextMenu->addAction(&actionUndefine);
|
||||
|
@ -34,14 +34,9 @@ ListDockWidget::ListDockWidget(MainWindow *main, QAction *action, SearchBarPolic
|
||||
clearShortcut->setContext(Qt::WidgetWithChildrenShortcut);
|
||||
}
|
||||
|
||||
connect(ui->treeView, &QTreeView::activated, this, &ListDockWidget::onItemActivated);
|
||||
|
||||
qhelpers::setVerticalScrollMode(ui->treeView);
|
||||
|
||||
itemContextMenu = new AddressableItemContextMenu(ui->treeView, mainWindow);
|
||||
ui->treeView->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(ui->treeView, &QWidget::customContextMenuRequested,
|
||||
this, &ListDockWidget::showItemContextMenu);
|
||||
ui->treeView->setMainWindow(mainWindow);
|
||||
|
||||
if (searchBarPolicy != SearchBarPolicy::ShowByDefault) {
|
||||
ui->quickFilterView->closeFilter();
|
||||
@ -59,6 +54,7 @@ void ListDockWidget::setModels(AddressableFilterProxyModel *objectFilterProxyMod
|
||||
{
|
||||
this->objectFilterProxyModel = objectFilterProxyModel;
|
||||
|
||||
|
||||
ui->treeView->setModel(objectFilterProxyModel);
|
||||
|
||||
|
||||
@ -71,48 +67,4 @@ void ListDockWidget::setModels(AddressableFilterProxyModel *objectFilterProxyMod
|
||||
connect(ui->quickFilterView, &QuickFilterView::filterTextChanged, this, [this] {
|
||||
tree->showItemsNumber(this->objectFilterProxyModel->rowCount());
|
||||
});
|
||||
|
||||
connect(ui->treeView->selectionModel(), &QItemSelectionModel::currentChanged, this,
|
||||
&ListDockWidget::onSelectedItemChanged);
|
||||
|
||||
addActions(this->getItemContextMenu()->actions());
|
||||
}
|
||||
|
||||
AddressableItemContextMenu *ListDockWidget::getItemContextMenu()
|
||||
{
|
||||
return itemContextMenu;
|
||||
}
|
||||
|
||||
void ListDockWidget::setItemContextMenu(AddressableItemContextMenu *menu)
|
||||
{
|
||||
this->itemContextMenu = menu;
|
||||
}
|
||||
|
||||
void ListDockWidget::showItemContextMenu(const QPoint &pt)
|
||||
{
|
||||
auto index = ui->treeView->currentIndex();
|
||||
if (index.isValid()) {
|
||||
auto offset = objectFilterProxyModel->address(index);
|
||||
auto name = objectFilterProxyModel->name(index);
|
||||
itemContextMenu->setTarget(offset, name);
|
||||
itemContextMenu->exec(ui->treeView->mapToGlobal(pt));
|
||||
}
|
||||
}
|
||||
|
||||
void ListDockWidget::onItemActivated(const QModelIndex &index)
|
||||
{
|
||||
if (!index.isValid())
|
||||
return;
|
||||
|
||||
auto offset = objectFilterProxyModel->address(index);
|
||||
Core()->seekAndShow(offset);
|
||||
}
|
||||
|
||||
void ListDockWidget::onSelectedItemChanged(const QModelIndex &index)
|
||||
{
|
||||
if (index.isValid()) {
|
||||
auto offset = objectFilterProxyModel->address(index);
|
||||
auto name = objectFilterProxyModel->name(index);
|
||||
itemContextMenu->setTarget(offset, name);
|
||||
}
|
||||
}
|
||||
|
@ -39,18 +39,10 @@ public:
|
||||
protected:
|
||||
void setModels(AddressableFilterProxyModel *objectFilterProxyModel);
|
||||
|
||||
AddressableItemContextMenu *getItemContextMenu();
|
||||
void setItemContextMenu(AddressableItemContextMenu *menu);
|
||||
virtual void showItemContextMenu(const QPoint &pt);
|
||||
|
||||
virtual void onItemActivated(const QModelIndex &index);
|
||||
void onSelectedItemChanged(const QModelIndex &index);
|
||||
|
||||
std::unique_ptr<Ui::ListDockWidget> ui;
|
||||
private:
|
||||
AddressableFilterProxyModel *objectFilterProxyModel;
|
||||
CutterTreeWidget *tree;
|
||||
AddressableItemContextMenu *itemContextMenu;
|
||||
SearchBarPolicy searchBarPolicy;
|
||||
};
|
||||
|
||||
|
@ -28,7 +28,7 @@
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="CutterTreeView" name="treeView">
|
||||
<widget class="AddressableItemList<>" name="treeView">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">CutterTreeView::item
|
||||
{
|
||||
@ -58,9 +58,9 @@
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>CutterTreeView</class>
|
||||
<class>AddressableItemList<></class>
|
||||
<extends>QTreeView</extends>
|
||||
<header>widgets/CutterTreeView.h</header>
|
||||
<header>widgets/AddressableItemList.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
|
@ -1,10 +1,10 @@
|
||||
#include "MemoryMapWidget.h"
|
||||
#include "ui_MemoryMapWidget.h"
|
||||
#include "ui_ListDockWidget.h"
|
||||
#include "core/MainWindow.h"
|
||||
#include "common/Helpers.h"
|
||||
|
||||
MemoryMapModel::MemoryMapModel(QList<MemoryMapDescription> *memoryMaps, QObject *parent)
|
||||
: QAbstractListModel(parent),
|
||||
: AddressableItemModel<QAbstractListModel>(parent),
|
||||
memoryMaps(memoryMaps)
|
||||
{
|
||||
}
|
||||
@ -68,10 +68,15 @@ QVariant MemoryMapModel::headerData(int section, Qt::Orientation, int role) cons
|
||||
}
|
||||
}
|
||||
|
||||
MemoryProxyModel::MemoryProxyModel(MemoryMapModel *sourceModel, QObject *parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
RVA MemoryMapModel::address(const QModelIndex &index) const
|
||||
{
|
||||
const MemoryMapDescription &memoryMap = memoryMaps->at(index.row());
|
||||
return memoryMap.addrStart;
|
||||
}
|
||||
|
||||
MemoryProxyModel::MemoryProxyModel(MemoryMapModel *sourceModel, QObject *parent)
|
||||
: AddressableFilterProxyModel(sourceModel, parent)
|
||||
{
|
||||
setSourceModel(sourceModel);
|
||||
}
|
||||
|
||||
bool MemoryProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) const
|
||||
@ -106,17 +111,15 @@ bool MemoryProxyModel::lessThan(const QModelIndex &left, const QModelIndex &righ
|
||||
}
|
||||
|
||||
MemoryMapWidget::MemoryMapWidget(MainWindow *main, QAction *action) :
|
||||
CutterDockWidget(main, action),
|
||||
ui(new Ui::MemoryMapWidget)
|
||||
ListDockWidget(main, action, ListDockWidget::SearchBarPolicy::HideByDefault)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setWindowTitle(tr("Memory Map"));
|
||||
setObjectName("MemoryMapWidget");
|
||||
|
||||
memoryModel = new MemoryMapModel(&memoryMaps, this);
|
||||
memoryProxyModel = new MemoryProxyModel(memoryModel, this);
|
||||
ui->memoryTreeView->setModel(memoryProxyModel);
|
||||
ui->memoryTreeView->sortByColumn(MemoryMapModel::AddrStartColumn, Qt::AscendingOrder);
|
||||
|
||||
setScrollMode();
|
||||
setModels(memoryProxyModel);
|
||||
ui->treeView->sortByColumn(MemoryMapModel::AddrStartColumn, Qt::AscendingOrder);
|
||||
|
||||
refreshDeferrer = createRefreshDeferrer([this]() {
|
||||
refreshMemoryMap();
|
||||
@ -124,6 +127,8 @@ MemoryMapWidget::MemoryMapWidget(MainWindow *main, QAction *action) :
|
||||
|
||||
connect(Core(), &CutterCore::refreshAll, this, &MemoryMapWidget::refreshMemoryMap);
|
||||
connect(Core(), &CutterCore::registersChanged, this, &MemoryMapWidget::refreshMemoryMap);
|
||||
|
||||
showCount(false);
|
||||
}
|
||||
|
||||
MemoryMapWidget::~MemoryMapWidget() = default;
|
||||
@ -138,19 +143,7 @@ void MemoryMapWidget::refreshMemoryMap()
|
||||
memoryMaps = Core()->getMemoryMap();
|
||||
memoryModel->endResetModel();
|
||||
|
||||
ui->memoryTreeView->resizeColumnToContents(0);
|
||||
ui->memoryTreeView->resizeColumnToContents(1);
|
||||
ui->memoryTreeView->resizeColumnToContents(2);
|
||||
}
|
||||
|
||||
void MemoryMapWidget::setScrollMode()
|
||||
{
|
||||
qhelpers::setVerticalScrollMode(ui->memoryTreeView);
|
||||
}
|
||||
|
||||
void MemoryMapWidget::on_memoryTreeView_doubleClicked(const QModelIndex &index)
|
||||
{
|
||||
MemoryMapDescription item = index.data(
|
||||
MemoryMapModel::MemoryDescriptionRole).value<MemoryMapDescription>();
|
||||
Core()->seekAndShow(item.addrStart);
|
||||
ui->treeView->resizeColumnToContents(0);
|
||||
ui->treeView->resizeColumnToContents(1);
|
||||
ui->treeView->resizeColumnToContents(2);
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "core/Cutter.h"
|
||||
#include "CutterDockWidget.h"
|
||||
#include "ListDockWidget.h"
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
@ -21,7 +22,7 @@ class MainWindow;
|
||||
class QTreeWidgetItem;
|
||||
|
||||
|
||||
class MemoryMapModel: public QAbstractListModel
|
||||
class MemoryMapModel: public AddressableItemModel<QAbstractListModel>
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@ -34,18 +35,20 @@ public:
|
||||
enum Column { AddrStartColumn = 0, AddrEndColumn, NameColumn, PermColumn, ColumnCount };
|
||||
enum Role { MemoryDescriptionRole = Qt::UserRole };
|
||||
|
||||
MemoryMapModel(QList<MemoryMapDescription> *memoryMaps, QObject *parent = 0);
|
||||
MemoryMapModel(QList<MemoryMapDescription> *memoryMaps, QObject *parent = nullptr);
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
|
||||
QVariant data(const QModelIndex &index, int role) const;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||
|
||||
RVA address(const QModelIndex &index) const override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class MemoryProxyModel : public QSortFilterProxyModel
|
||||
class MemoryProxyModel : public AddressableFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@ -59,7 +62,7 @@ protected:
|
||||
|
||||
|
||||
|
||||
class MemoryMapWidget : public CutterDockWidget
|
||||
class MemoryMapWidget : public ListDockWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@ -68,18 +71,13 @@ public:
|
||||
~MemoryMapWidget();
|
||||
|
||||
private slots:
|
||||
void on_memoryTreeView_doubleClicked(const QModelIndex &index);
|
||||
|
||||
void refreshMemoryMap();
|
||||
|
||||
private:
|
||||
std::unique_ptr<Ui::MemoryMapWidget> ui;
|
||||
|
||||
MemoryMapModel *memoryModel;
|
||||
MemoryProxyModel *memoryProxyModel;
|
||||
QList<MemoryMapDescription> memoryMaps;
|
||||
|
||||
void setScrollMode();
|
||||
|
||||
RefreshDeferrer *refreshDeferrer;
|
||||
};
|
||||
|
@ -1,66 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MemoryMapWidget</class>
|
||||
<widget class="QDockWidget" name="MemoryMapWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Memory Map</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="dockWidgetContents">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<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="CutterTreeView" name="memoryTreeView">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">CutterTreeView::item
|
||||
{
|
||||
padding-top: 1px;
|
||||
padding-bottom: 1px;
|
||||
}</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="indentation">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="sortingEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>CutterTreeView</class>
|
||||
<extends>QTreeView</extends>
|
||||
<header>widgets/CutterTreeView.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
@ -4,7 +4,7 @@
|
||||
#include <QVBoxLayout>
|
||||
|
||||
ResourcesModel::ResourcesModel(QList<ResourcesDescription> *resources, QObject *parent)
|
||||
: QAbstractListModel(parent),
|
||||
: AddressableItemModel<QAbstractListModel>(parent),
|
||||
resources(resources)
|
||||
{
|
||||
}
|
||||
@ -27,11 +27,11 @@ QVariant ResourcesModel::data(const QModelIndex &index, int role) const
|
||||
case Qt::DisplayRole:
|
||||
switch (index.column()) {
|
||||
case NAME:
|
||||
return res.name;
|
||||
return QString::number(res.name);
|
||||
case VADDR:
|
||||
return RAddressString(res.vaddr);
|
||||
case INDEX:
|
||||
return res.index;
|
||||
return QString::number(res.index);
|
||||
case TYPE:
|
||||
return res.type;
|
||||
case SIZE:
|
||||
@ -73,25 +73,27 @@ QVariant ResourcesModel::headerData(int section, Qt::Orientation, int role) cons
|
||||
}
|
||||
}
|
||||
|
||||
RVA ResourcesModel::address(const QModelIndex &index) const
|
||||
{
|
||||
const ResourcesDescription &res = resources->at(index.row());
|
||||
return res.vaddr;
|
||||
}
|
||||
|
||||
ResourcesWidget::ResourcesWidget(MainWindow *main, QAction *action) :
|
||||
CutterDockWidget(main, action)
|
||||
ListDockWidget(main, action, ListDockWidget::SearchBarPolicy::HideByDefault)
|
||||
{
|
||||
setObjectName("ResourcesWidget");
|
||||
|
||||
model = new ResourcesModel(&resources, this);
|
||||
filterModel = new AddressableFilterProxyModel(model, this);
|
||||
setModels(filterModel);
|
||||
|
||||
showCount(false);
|
||||
|
||||
// Configure widget
|
||||
this->setWindowTitle(tr("Resources"));
|
||||
|
||||
// Add resources tree view
|
||||
view = new CutterTreeView(this);
|
||||
view->setModel(model);
|
||||
view->show();
|
||||
this->setWidget(view);
|
||||
|
||||
connect(Core(), SIGNAL(refreshAll()), this, SLOT(refreshResources()));
|
||||
connect(view, SIGNAL(doubleClicked(const QModelIndex &)), this,
|
||||
SLOT(onDoubleClicked(const QModelIndex &)));
|
||||
}
|
||||
|
||||
void ResourcesWidget::refreshResources()
|
||||
@ -100,12 +102,3 @@ void ResourcesWidget::refreshResources()
|
||||
resources = Core()->getAllResources();
|
||||
model->endResetModel();
|
||||
}
|
||||
|
||||
void ResourcesWidget::onDoubleClicked(const QModelIndex &index)
|
||||
{
|
||||
if (!index.isValid())
|
||||
return;
|
||||
|
||||
ResourcesDescription res = index.data(Qt::UserRole).value<ResourcesDescription>();
|
||||
Core()->seekAndShow(res.vaddr);
|
||||
}
|
||||
|
@ -4,13 +4,14 @@
|
||||
#include "core/Cutter.h"
|
||||
#include "CutterDockWidget.h"
|
||||
#include "CutterTreeView.h"
|
||||
#include "common/AddressableItemModel.h"
|
||||
#include "widgets/ListDockWidget.h"
|
||||
|
||||
#include <QAbstractListModel>
|
||||
|
||||
class MainWindow;
|
||||
class ResourcesWidget;
|
||||
|
||||
class ResourcesModel : public QAbstractListModel
|
||||
class ResourcesModel : public AddressableItemModel<QAbstractListModel>
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@ -29,14 +30,17 @@ public:
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
QVariant headerData(int section, Qt::Orientation orientation,
|
||||
int role = Qt::DisplayRole) const override;
|
||||
|
||||
RVA address(const QModelIndex &index) const override;
|
||||
};
|
||||
|
||||
class ResourcesWidget : public CutterDockWidget
|
||||
class ResourcesWidget : public ListDockWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
ResourcesModel *model;
|
||||
AddressableFilterProxyModel *filterModel;
|
||||
CutterTreeView *view;
|
||||
QList<ResourcesDescription> resources;
|
||||
|
||||
@ -45,7 +49,6 @@ public:
|
||||
|
||||
private slots:
|
||||
void refreshResources();
|
||||
void onDoubleClicked(const QModelIndex &);
|
||||
};
|
||||
|
||||
#endif // RESOURCESWIDGET_H
|
||||
|
@ -30,7 +30,7 @@ static const QMap<QString, QString> kSearchBoundariesValues {
|
||||
};
|
||||
|
||||
SearchModel::SearchModel(QList<SearchDescription> *search, QObject *parent)
|
||||
: QAbstractListModel(parent),
|
||||
: AddressableItemModel<QAbstractListModel>(parent),
|
||||
search(search)
|
||||
{
|
||||
}
|
||||
@ -119,11 +119,16 @@ QVariant SearchModel::headerData(int section, Qt::Orientation, int role) const
|
||||
}
|
||||
}
|
||||
|
||||
RVA SearchModel::address(const QModelIndex &index) const
|
||||
{
|
||||
const SearchDescription &exp = search->at(index.row());
|
||||
return exp.offset;
|
||||
}
|
||||
|
||||
|
||||
SearchSortFilterProxyModel::SearchSortFilterProxyModel(SearchModel *source_model, QObject *parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
: AddressableFilterProxyModel(source_model, parent)
|
||||
{
|
||||
setSourceModel(source_model);
|
||||
}
|
||||
|
||||
bool SearchSortFilterProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) const
|
||||
@ -174,6 +179,7 @@ SearchWidget::SearchWidget(MainWindow *main, QAction *action) :
|
||||
search_model = new SearchModel(&search, this);
|
||||
search_proxy_model = new SearchSortFilterProxyModel(search_model, this);
|
||||
ui->searchTreeView->setModel(search_proxy_model);
|
||||
ui->searchTreeView->setMainWindow(main);
|
||||
ui->searchTreeView->sortByColumn(SearchModel::OFFSET, Qt::AscendingOrder);
|
||||
|
||||
setScrollMode();
|
||||
@ -199,16 +205,6 @@ SearchWidget::SearchWidget(MainWindow *main, QAction *action) :
|
||||
|
||||
SearchWidget::~SearchWidget() {}
|
||||
|
||||
void SearchWidget::on_searchTreeView_doubleClicked(const QModelIndex &index)
|
||||
{
|
||||
if (!index.isValid())
|
||||
return;
|
||||
|
||||
SearchDescription search = index.data(
|
||||
SearchModel::SearchDescriptionRole).value<SearchDescription>();
|
||||
Core()->seekAndShow(search.offset);
|
||||
}
|
||||
|
||||
void SearchWidget::searchChanged()
|
||||
{
|
||||
refreshSearchspaces();
|
||||
|
@ -8,13 +8,14 @@
|
||||
|
||||
#include "core/Cutter.h"
|
||||
#include "CutterDockWidget.h"
|
||||
#include "AddressableItemList.h"
|
||||
|
||||
class MainWindow;
|
||||
class QTreeWidgetItem;
|
||||
class SearchWidget;
|
||||
|
||||
|
||||
class SearchModel: public QAbstractListModel
|
||||
class SearchModel: public AddressableItemModel<QAbstractListModel>
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@ -29,16 +30,18 @@ public:
|
||||
|
||||
SearchModel(QList<SearchDescription> *search, QObject *parent = nullptr);
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
|
||||
QVariant data(const QModelIndex &index, int role) const;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||
|
||||
RVA address(const QModelIndex &index) const override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class SearchSortFilterProxyModel : public QSortFilterProxyModel
|
||||
class SearchSortFilterProxyModel : public AddressableFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@ -65,7 +68,6 @@ public:
|
||||
~SearchWidget();
|
||||
|
||||
private slots:
|
||||
void on_searchTreeView_doubleClicked(const QModelIndex &index);
|
||||
void on_searchInCombo_currentIndexChanged(int index);
|
||||
void searchChanged();
|
||||
void refreshSearchspaces();
|
||||
|
@ -31,7 +31,7 @@
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="CutterTreeView" name="searchTreeView">
|
||||
<widget class="AddressableItemList<>" name="searchTreeView">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">CutterTreeView::item
|
||||
{
|
||||
@ -118,9 +118,9 @@
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>CutterTreeView</class>
|
||||
<class>AddressableItemList<></class>
|
||||
<extends>QTreeView</extends>
|
||||
<header>widgets/CutterTreeView.h</header>
|
||||
<header>widgets/AddressableItemList.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
|
@ -2,7 +2,6 @@
|
||||
#include "ui_StringsWidget.h"
|
||||
#include "core/MainWindow.h"
|
||||
#include "common/Helpers.h"
|
||||
#include "dialogs/XrefsDialog.h"
|
||||
#include "WidgetShortcuts.h"
|
||||
|
||||
#include <QClipboard>
|
||||
@ -11,7 +10,7 @@
|
||||
#include <QShortcut>
|
||||
|
||||
StringsModel::StringsModel(QList<StringDescription> *strings, QObject *parent)
|
||||
: QAbstractListModel(parent),
|
||||
: AddressableItemModel<QAbstractListModel>(parent),
|
||||
strings(strings)
|
||||
{
|
||||
}
|
||||
@ -43,9 +42,9 @@ QVariant StringsModel::data(const QModelIndex &index, int role) const
|
||||
case StringsModel::TypeColumn:
|
||||
return str.type.toUpper();
|
||||
case StringsModel::LengthColumn:
|
||||
return str.length;
|
||||
return QString::number(str.length);
|
||||
case StringsModel::SizeColumn:
|
||||
return str.size;
|
||||
return QString::number(str.size);
|
||||
case StringsModel::SectionColumn:
|
||||
return str.section;
|
||||
default:
|
||||
@ -83,10 +82,15 @@ QVariant StringsModel::headerData(int section, Qt::Orientation, int role) const
|
||||
}
|
||||
}
|
||||
|
||||
StringsProxyModel::StringsProxyModel(StringsModel *sourceModel, QObject *parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
RVA StringsModel::address(const QModelIndex &index) const
|
||||
{
|
||||
const StringDescription &str = strings->at(index.row());
|
||||
return str.vaddr;
|
||||
}
|
||||
|
||||
StringsProxyModel::StringsProxyModel(StringsModel *sourceModel, QObject *parent)
|
||||
: AddressableFilterProxyModel(sourceModel, parent)
|
||||
{
|
||||
setSourceModel(sourceModel);
|
||||
setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||
setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||
}
|
||||
@ -149,10 +153,6 @@ StringsWidget::StringsWidget(MainWindow *main, QAction *action) :
|
||||
} );
|
||||
|
||||
connect(ui->actionCopy_String, SIGNAL(triggered()), this, SLOT(on_actionCopy()));
|
||||
connect(ui->actionCopy_Address, SIGNAL(triggered()), this, SLOT(on_actionCopy()));
|
||||
|
||||
connect(ui->stringsTreeView, SIGNAL(customContextMenuRequested(const QPoint &)),
|
||||
this, SLOT(showStringsContextMenu(const QPoint &)));
|
||||
|
||||
ui->actionFilter->setShortcut(QKeySequence::Find);
|
||||
|
||||
@ -160,13 +160,13 @@ StringsWidget::StringsWidget(MainWindow *main, QAction *action) :
|
||||
|
||||
model = new StringsModel(&strings, this);
|
||||
proxyModel = new StringsProxyModel(model, this);
|
||||
ui->stringsTreeView->setMainWindow(main);
|
||||
ui->stringsTreeView->setModel(proxyModel);
|
||||
ui->stringsTreeView->sortByColumn(StringsModel::OffsetColumn, Qt::AscendingOrder);
|
||||
|
||||
auto xRefShortcut = new QShortcut(QKeySequence{Qt::CTRL + Qt::Key_X}, this);
|
||||
xRefShortcut->setContext(Qt::WidgetWithChildrenShortcut);
|
||||
ui->actionX_refs->setShortcut(Qt::CTRL + Qt::Key_X);
|
||||
connect(xRefShortcut, SIGNAL(activated()), this, SLOT(on_actionX_refs_triggered()));
|
||||
//
|
||||
auto menu = ui->stringsTreeView->getItemContextMenu();
|
||||
menu->addAction(ui->actionCopy_String);
|
||||
|
||||
connect(ui->quickFilterView, SIGNAL(filterTextChanged(const QString &)), proxyModel,
|
||||
SLOT(setFilterWildcard(const QString &)));
|
||||
@ -180,7 +180,10 @@ StringsWidget::StringsWidget(MainWindow *main, QAction *action) :
|
||||
searchShortcut->setContext(Qt::WidgetWithChildrenShortcut);
|
||||
|
||||
QShortcut *clearShortcut = new QShortcut(QKeySequence(Qt::Key_Escape), this);
|
||||
connect(clearShortcut, &QShortcut::activated, ui->quickFilterView, &ComboQuickFilterView::clearFilter);
|
||||
connect(clearShortcut, &QShortcut::activated, this, [this]() {
|
||||
ui->quickFilterView->clearFilter();
|
||||
ui->stringsTreeView->setFocus();
|
||||
});
|
||||
clearShortcut->setContext(Qt::WidgetWithChildrenShortcut);
|
||||
|
||||
connect(Core(), SIGNAL(refreshAll()), this, SLOT(refreshStrings()));
|
||||
@ -197,16 +200,6 @@ StringsWidget::StringsWidget(MainWindow *main, QAction *action) :
|
||||
|
||||
StringsWidget::~StringsWidget() {}
|
||||
|
||||
void StringsWidget::on_stringsTreeView_doubleClicked(const QModelIndex &index)
|
||||
{
|
||||
if (!index.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
StringDescription str = index.data(StringsModel::StringDescriptionRole).value<StringDescription>();
|
||||
Core()->seekAndShow(str.vaddr);
|
||||
}
|
||||
|
||||
void StringsWidget::refreshStrings()
|
||||
{
|
||||
if (task) {
|
||||
@ -250,32 +243,6 @@ void StringsWidget::stringSearchFinished(const QList<StringDescription> &strings
|
||||
task = nullptr;
|
||||
}
|
||||
|
||||
void StringsWidget::showStringsContextMenu(const QPoint &pt)
|
||||
{
|
||||
QMenu *menu = new QMenu(ui->stringsTreeView);
|
||||
|
||||
menu->clear();
|
||||
menu->addAction(ui->actionCopy_String);
|
||||
menu->addAction(ui->actionCopy_Address);
|
||||
menu->addAction(ui->actionFilter);
|
||||
menu->addSeparator();
|
||||
menu->addAction(ui->actionX_refs);
|
||||
|
||||
menu->exec(ui->stringsTreeView->mapToGlobal(pt));
|
||||
|
||||
delete menu;
|
||||
}
|
||||
|
||||
void StringsWidget::on_actionX_refs_triggered()
|
||||
{
|
||||
StringDescription str = ui->stringsTreeView->selectionModel()->currentIndex().data(
|
||||
StringsModel::StringDescriptionRole).value<StringDescription>();
|
||||
|
||||
XrefsDialog x(nullptr);
|
||||
x.fillRefsForAddress(str.vaddr, RAddressString(str.vaddr), false);
|
||||
x.exec();
|
||||
}
|
||||
|
||||
void StringsWidget::on_actionCopy()
|
||||
{
|
||||
QModelIndex current_item = ui->stringsTreeView->currentIndex();
|
||||
@ -283,11 +250,7 @@ void StringsWidget::on_actionCopy()
|
||||
|
||||
QModelIndex index;
|
||||
|
||||
if (sender() == ui->actionCopy_String) {
|
||||
index = ui->stringsTreeView->model()->index(row, 1);
|
||||
} else if (sender() == ui->actionCopy_Address) {
|
||||
index = ui->stringsTreeView->model()->index(row, 0);
|
||||
}
|
||||
index = ui->stringsTreeView->model()->index(row, 1);
|
||||
|
||||
QClipboard *clipboard = QApplication::clipboard();
|
||||
clipboard->setText(index.data().toString());
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "CutterDockWidget.h"
|
||||
#include "common/StringsTask.h"
|
||||
#include "CutterTreeWidget.h"
|
||||
#include "AddressableItemModel.h"
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
@ -19,7 +20,7 @@ namespace Ui {
|
||||
class StringsWidget;
|
||||
}
|
||||
|
||||
class StringsModel: public QAbstractListModel
|
||||
class StringsModel: public AddressableItemModel<QAbstractListModel>
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@ -34,16 +35,18 @@ public:
|
||||
|
||||
StringsModel(QList<StringDescription> *strings, QObject *parent = nullptr);
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
|
||||
QVariant data(const QModelIndex &index, int role) const;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||
|
||||
RVA address(const QModelIndex &index) const override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class StringsProxyModel : public QSortFilterProxyModel
|
||||
class StringsProxyModel : public AddressableFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@ -69,14 +72,10 @@ public:
|
||||
~StringsWidget();
|
||||
|
||||
private slots:
|
||||
void on_stringsTreeView_doubleClicked(const QModelIndex &index);
|
||||
|
||||
void refreshStrings();
|
||||
void stringSearchFinished(const QList<StringDescription> &strings);
|
||||
void refreshSectionCombo();
|
||||
|
||||
void showStringsContextMenu(const QPoint &pt);
|
||||
void on_actionX_refs_triggered();
|
||||
void on_actionCopy();
|
||||
|
||||
private:
|
||||
|
@ -31,7 +31,7 @@
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="CutterTreeView" name="stringsTreeView">
|
||||
<widget class="AddressableItemList<>" name="stringsTreeView">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@ -71,21 +71,11 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<action name="actionCopy_Address">
|
||||
<property name="text">
|
||||
<string>Copy Address</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionCopy_String">
|
||||
<property name="text">
|
||||
<string>Copy String</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionX_refs">
|
||||
<property name="text">
|
||||
<string>Xrefs</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionFilter">
|
||||
<property name="text">
|
||||
<string>Filter</string>
|
||||
@ -94,9 +84,9 @@
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>CutterTreeView</class>
|
||||
<class>AddressableItemList<></class>
|
||||
<extends>QTreeView</extends>
|
||||
<header>widgets/CutterTreeView.h</header>
|
||||
<header>widgets/AddressableItemList.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
|
Loading…
Reference in New Issue
Block a user