mirror of
https://github.com/rizinorg/cutter.git
synced 2025-01-19 02:48:49 +00:00
Common behaviour for lists with items that have address (#1700)
This commit is contained in:
parent
cd2dbc4a29
commit
0aa91c328c
@ -360,7 +360,10 @@ SOURCES += \
|
|||||||
widgets/GraphGridLayout.cpp \
|
widgets/GraphGridLayout.cpp \
|
||||||
widgets/HexWidget.cpp \
|
widgets/HexWidget.cpp \
|
||||||
common/SelectionHighlight.cpp \
|
common/SelectionHighlight.cpp \
|
||||||
common/Decompiler.cpp
|
common/Decompiler.cpp \
|
||||||
|
menus/AddressableItemContextMenu.cpp \
|
||||||
|
common/AddressableItemModel.cpp \
|
||||||
|
widgets/ListDockWidget.cpp
|
||||||
|
|
||||||
GRAPHVIZ_SOURCES = \
|
GRAPHVIZ_SOURCES = \
|
||||||
widgets/GraphvizLayout.cpp
|
widgets/GraphvizLayout.cpp
|
||||||
@ -490,7 +493,10 @@ HEADERS += \
|
|||||||
widgets/GraphLayout.h \
|
widgets/GraphLayout.h \
|
||||||
widgets/HexWidget.h \
|
widgets/HexWidget.h \
|
||||||
common/SelectionHighlight.h \
|
common/SelectionHighlight.h \
|
||||||
common/Decompiler.h
|
common/Decompiler.h \
|
||||||
|
menus/AddressableItemContextMenu.h \
|
||||||
|
common/AddressableItemModel.h \
|
||||||
|
widgets/ListDockWidget.h
|
||||||
|
|
||||||
GRAPHVIZ_HEADERS = widgets/GraphGridLayout.h
|
GRAPHVIZ_HEADERS = widgets/GraphGridLayout.h
|
||||||
|
|
||||||
@ -506,17 +512,11 @@ FORMS += \
|
|||||||
dialogs/InitialOptionsDialog.ui \
|
dialogs/InitialOptionsDialog.ui \
|
||||||
dialogs/EditFunctionDialog.ui \
|
dialogs/EditFunctionDialog.ui \
|
||||||
core/MainWindow.ui \
|
core/MainWindow.ui \
|
||||||
widgets/CommentsWidget.ui \
|
|
||||||
widgets/ConsoleWidget.ui \
|
widgets/ConsoleWidget.ui \
|
||||||
widgets/Dashboard.ui \
|
widgets/Dashboard.ui \
|
||||||
widgets/EntrypointWidget.ui \
|
widgets/EntrypointWidget.ui \
|
||||||
widgets/FlagsWidget.ui \
|
widgets/FlagsWidget.ui \
|
||||||
widgets/ExportsWidget.ui \
|
|
||||||
widgets/FunctionsWidget.ui \
|
|
||||||
widgets/ImportsWidget.ui \
|
|
||||||
widgets/RelocsWidget.ui \
|
|
||||||
widgets/StringsWidget.ui \
|
widgets/StringsWidget.ui \
|
||||||
widgets/SymbolsWidget.ui \
|
|
||||||
widgets/HexdumpWidget.ui \
|
widgets/HexdumpWidget.ui \
|
||||||
dialogs/SaveProjectDialog.ui \
|
dialogs/SaveProjectDialog.ui \
|
||||||
dialogs/preferences/PreferencesDialog.ui \
|
dialogs/preferences/PreferencesDialog.ui \
|
||||||
@ -527,7 +527,6 @@ FORMS += \
|
|||||||
widgets/ClassesWidget.ui \
|
widgets/ClassesWidget.ui \
|
||||||
widgets/VTablesWidget.ui \
|
widgets/VTablesWidget.ui \
|
||||||
widgets/TypesWidget.ui \
|
widgets/TypesWidget.ui \
|
||||||
widgets/HeadersWidget.ui \
|
|
||||||
widgets/SearchWidget.ui \
|
widgets/SearchWidget.ui \
|
||||||
dialogs/R2PluginsDialog.ui \
|
dialogs/R2PluginsDialog.ui \
|
||||||
dialogs/VersionInfoDialog.ui \
|
dialogs/VersionInfoDialog.ui \
|
||||||
@ -554,7 +553,8 @@ FORMS += \
|
|||||||
widgets/SdbWidget.ui \
|
widgets/SdbWidget.ui \
|
||||||
dialogs/LinkTypeDialog.ui \
|
dialogs/LinkTypeDialog.ui \
|
||||||
widgets/ColorPicker.ui \
|
widgets/ColorPicker.ui \
|
||||||
dialogs/preferences/ColorThemeEditDialog.ui
|
dialogs/preferences/ColorThemeEditDialog.ui \
|
||||||
|
widgets/ListDockWidget.ui
|
||||||
|
|
||||||
RESOURCES += \
|
RESOURCES += \
|
||||||
resources.qrc \
|
resources.qrc \
|
||||||
|
30
src/common/AddressableItemModel.cpp
Normal file
30
src/common/AddressableItemModel.cpp
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#include "AddressableItemModel.h"
|
||||||
|
|
||||||
|
AddressableFilterProxyModel::AddressableFilterProxyModel(AddressableItemModelI *sourceModel,
|
||||||
|
QObject *parent) :
|
||||||
|
AddressableItemModel<QSortFilterProxyModel>(parent)
|
||||||
|
{
|
||||||
|
setSourceModel(sourceModel);
|
||||||
|
addressableSourceModel = sourceModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
RVA AddressableFilterProxyModel::address(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
return addressableSourceModel->address(this->mapToSource(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
QString AddressableFilterProxyModel::name(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
return addressableSourceModel->name(this->mapToSource(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddressableFilterProxyModel::setSourceModel(QAbstractItemModel *)
|
||||||
|
{
|
||||||
|
throw new std::runtime_error("Not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddressableFilterProxyModel::setSourceModel(AddressableItemModelI *sourceModel)
|
||||||
|
{
|
||||||
|
ParentClass::setSourceModel(sourceModel->asItemModel());
|
||||||
|
addressableSourceModel = sourceModel;
|
||||||
|
}
|
49
src/common/AddressableItemModel.h
Normal file
49
src/common/AddressableItemModel.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
|
||||||
|
#ifndef ADDRESSABLEITEMMODEL_H
|
||||||
|
#define ADDRESSABLEITEMMODEL_H
|
||||||
|
|
||||||
|
#include <QAbstractItemModel>
|
||||||
|
#include <QSortFilterProxyModel>
|
||||||
|
#include <QAbstractItemModel>
|
||||||
|
|
||||||
|
#include <core/CutterCommon.h>
|
||||||
|
|
||||||
|
class AddressableItemModelI
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual RVA address(const QModelIndex &index) const = 0;
|
||||||
|
/**
|
||||||
|
* @brief Get name for item, optional.
|
||||||
|
* @param index item intex
|
||||||
|
* @return Item name or empty QString if item doesn't have short descriptive name.
|
||||||
|
*/
|
||||||
|
virtual QString name(const QModelIndex &index) const { Q_UNUSED(index) return QString(); }
|
||||||
|
virtual QAbstractItemModel *asItemModel() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class ParentModel = QAbstractItemModel>
|
||||||
|
class AddressableItemModel : public ParentModel, public AddressableItemModelI
|
||||||
|
{
|
||||||
|
static_assert (std::is_base_of<QAbstractItemModel, ParentModel>::value,
|
||||||
|
"ParentModel needs to inherit from QAbstractItemModel");
|
||||||
|
public:
|
||||||
|
explicit AddressableItemModel(QObject *parent = nullptr) : ParentModel(parent) {}
|
||||||
|
virtual ~AddressableItemModel() {}
|
||||||
|
QAbstractItemModel *asItemModel() { return this; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class AddressableFilterProxyModel : public AddressableItemModel<QSortFilterProxyModel>
|
||||||
|
{
|
||||||
|
using ParentClass = AddressableItemModel<QSortFilterProxyModel>;
|
||||||
|
public:
|
||||||
|
AddressableFilterProxyModel(AddressableItemModelI *sourceModel, QObject *parent);
|
||||||
|
|
||||||
|
RVA address(const QModelIndex &index) const override;
|
||||||
|
QString name(const QModelIndex &) const override;
|
||||||
|
void setSourceModel(AddressableItemModelI *sourceModel);
|
||||||
|
private:
|
||||||
|
void setSourceModel(QAbstractItemModel *sourceModel) override; // Don't use this directly
|
||||||
|
AddressableItemModelI *addressableSourceModel;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ADDRESSABLEITEMMODEL_H
|
@ -2597,6 +2597,17 @@ void CutterCore::addFlag(RVA offset, QString name, RVA size)
|
|||||||
emit flagsChanged();
|
emit flagsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString CutterCore::nearestFlag(RVA offset, RVA *flagOffsetOut)
|
||||||
|
{
|
||||||
|
auto r = cmdj(QString("fdj @") + QString::number(offset)).object();
|
||||||
|
QString name = r.value("name").toString();
|
||||||
|
if (flagOffsetOut) {
|
||||||
|
int queryOffset = r.value("offset").toInt(0);
|
||||||
|
*flagOffsetOut = offset + static_cast<RVA>(-queryOffset);
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
void CutterCore::handleREvent(int type, void *data)
|
void CutterCore::handleREvent(int type, void *data)
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
@ -91,6 +91,13 @@ public:
|
|||||||
void delFlag(RVA addr);
|
void delFlag(RVA addr);
|
||||||
void delFlag(const QString &name);
|
void delFlag(const QString &name);
|
||||||
void addFlag(RVA offset, QString name, RVA size);
|
void addFlag(RVA offset, QString name, RVA size);
|
||||||
|
/**
|
||||||
|
* @brief Get nearest flag at or before offset.
|
||||||
|
* @param offset search position
|
||||||
|
* @param flagOffsetOut adress of returned flag
|
||||||
|
* @return flag name
|
||||||
|
*/
|
||||||
|
QString nearestFlag(RVA offset, RVA *flagOffsetOut);
|
||||||
void triggerFlagsChanged();
|
void triggerFlagsChanged();
|
||||||
|
|
||||||
/* Edition functions */
|
/* Edition functions */
|
||||||
|
103
src/menus/AddressableItemContextMenu.cpp
Normal file
103
src/menus/AddressableItemContextMenu.cpp
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
#include "AddressableItemContextMenu.h"
|
||||||
|
#include "dialogs/XrefsDialog.h"
|
||||||
|
#include "MainWindow.h"
|
||||||
|
#include "dialogs/CommentsDialog.h"
|
||||||
|
|
||||||
|
#include <QtCore>
|
||||||
|
#include <QShortcut>
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QClipboard>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QPushButton>
|
||||||
|
|
||||||
|
AddressableItemContextMenu::AddressableItemContextMenu(QWidget *parent, MainWindow *mainWindow)
|
||||||
|
: QMenu(parent)
|
||||||
|
, mainWindow(mainWindow)
|
||||||
|
, actionShowInMenu(tr("Show in"), this)
|
||||||
|
, actionCopyAddress(tr("Copy address"), this)
|
||||||
|
, actionShowXrefs(tr("Show X-Refs"), this)
|
||||||
|
, actionAddcomment(tr("Add comment"), this)
|
||||||
|
{
|
||||||
|
connect(&actionCopyAddress, &QAction::triggered, this,
|
||||||
|
&AddressableItemContextMenu::onActionCopyAddress);
|
||||||
|
actionCopyAddress.setShortcuts({Qt::CTRL + Qt::SHIFT + Qt::Key_C});
|
||||||
|
actionCopyAddress.setShortcutContext(Qt::ShortcutContext::WidgetWithChildrenShortcut);
|
||||||
|
|
||||||
|
connect(&actionShowXrefs, &QAction::triggered, this,
|
||||||
|
&AddressableItemContextMenu::onActionShowXrefs);
|
||||||
|
actionShowXrefs.setShortcut({Qt::Key_X});
|
||||||
|
actionShowXrefs.setShortcutContext(Qt::ShortcutContext::WidgetWithChildrenShortcut);
|
||||||
|
|
||||||
|
connect(&actionAddcomment, &QAction::triggered, this,
|
||||||
|
&AddressableItemContextMenu::onActionAddComment);
|
||||||
|
|
||||||
|
|
||||||
|
addAction(&actionShowInMenu);
|
||||||
|
addAction(&actionCopyAddress);
|
||||||
|
addAction(&actionShowXrefs);
|
||||||
|
addSeparator();
|
||||||
|
addAction(&actionAddcomment);
|
||||||
|
|
||||||
|
connect(this, &QMenu::aboutToShow, this, &AddressableItemContextMenu::aboutToShowSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
AddressableItemContextMenu::~AddressableItemContextMenu()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddressableItemContextMenu::setWholeFunction(bool wholeFunciton)
|
||||||
|
{
|
||||||
|
this->wholeFunction = wholeFunciton;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddressableItemContextMenu::setOffset(RVA offset)
|
||||||
|
{
|
||||||
|
setTarget(offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddressableItemContextMenu::setTarget(RVA offset, QString name)
|
||||||
|
{
|
||||||
|
this->offset = offset;
|
||||||
|
this->name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddressableItemContextMenu::onActionCopyAddress()
|
||||||
|
{
|
||||||
|
auto clipboard = QApplication::clipboard();
|
||||||
|
clipboard->setText(RAddressString(offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddressableItemContextMenu::onActionShowXrefs()
|
||||||
|
{
|
||||||
|
XrefsDialog dialog(nullptr);
|
||||||
|
QString tmpName = name;
|
||||||
|
if (name.isEmpty()) {
|
||||||
|
name = RAddressString(offset);
|
||||||
|
}
|
||||||
|
dialog.fillRefsForAddress(offset, name, wholeFunction);
|
||||||
|
dialog.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddressableItemContextMenu::aboutToShowSlot()
|
||||||
|
{
|
||||||
|
if (actionShowInMenu.menu()) {
|
||||||
|
actionShowInMenu.menu()->deleteLater();
|
||||||
|
}
|
||||||
|
actionShowInMenu.setMenu(mainWindow->createShowInMenu(this, offset));
|
||||||
|
}
|
||||||
|
|
43
src/menus/AddressableItemContextMenu.h
Normal file
43
src/menus/AddressableItemContextMenu.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#ifndef ADDRESSABLEITEMCONTEXTMENU_H
|
||||||
|
#define ADDRESSABLEITEMCONTEXTMENU_H
|
||||||
|
|
||||||
|
#include "core/Cutter.h"
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QKeySequence>
|
||||||
|
|
||||||
|
class AddressableItemContextMenu : public QMenu
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
AddressableItemContextMenu(QWidget *parent, MainWindow *mainWindow);
|
||||||
|
~AddressableItemContextMenu();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configure if addressable item refers to whole function or specific address
|
||||||
|
* @param wholeFunciton
|
||||||
|
*/
|
||||||
|
void setWholeFunction(bool wholeFunciton);
|
||||||
|
public slots:
|
||||||
|
void setOffset(RVA offset);
|
||||||
|
void setTarget(RVA offset, QString name = QString());
|
||||||
|
private:
|
||||||
|
void onActionCopyAddress();
|
||||||
|
void onActionShowXrefs();
|
||||||
|
void onActionAddComment();
|
||||||
|
|
||||||
|
virtual void aboutToShowSlot();
|
||||||
|
|
||||||
|
MainWindow *mainWindow;
|
||||||
|
|
||||||
|
RVA offset;
|
||||||
|
protected:
|
||||||
|
QAction actionShowInMenu;
|
||||||
|
QAction actionCopyAddress;
|
||||||
|
QAction actionShowXrefs;
|
||||||
|
QAction actionAddcomment;
|
||||||
|
|
||||||
|
QString name;
|
||||||
|
bool wholeFunction = false;
|
||||||
|
};
|
||||||
|
#endif // ADDRESSABLEITEMCONTEXTMENU_H
|
@ -1,5 +1,5 @@
|
|||||||
#include "CommentsWidget.h"
|
#include "CommentsWidget.h"
|
||||||
#include "ui_CommentsWidget.h"
|
#include "ui_ListDockWidget.h"
|
||||||
#include "core/MainWindow.h"
|
#include "core/MainWindow.h"
|
||||||
#include "common/Helpers.h"
|
#include "common/Helpers.h"
|
||||||
|
|
||||||
@ -8,9 +8,9 @@
|
|||||||
#include <QShortcut>
|
#include <QShortcut>
|
||||||
|
|
||||||
CommentsModel::CommentsModel(QList<CommentDescription> *comments,
|
CommentsModel::CommentsModel(QList<CommentDescription> *comments,
|
||||||
QMap<QString, QList<CommentDescription> > *nestedComments,
|
QList<CommentGroup> *nestedComments,
|
||||||
QObject *parent)
|
QObject *parent)
|
||||||
: QAbstractItemModel(parent),
|
: AddressableItemModel<>(parent),
|
||||||
comments(comments),
|
comments(comments),
|
||||||
nestedComments(nestedComments),
|
nestedComments(nestedComments),
|
||||||
nested(false)
|
nested(false)
|
||||||
@ -28,6 +28,20 @@ void CommentsModel::setNested(bool nested)
|
|||||||
endResetModel();
|
endResetModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RVA CommentsModel::address(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
if (isNested()) {
|
||||||
|
if (index.internalId() != 0) {
|
||||||
|
auto &group = nestedComments->at(index.parent().row());
|
||||||
|
return group.comments.at(index.row()).offset;
|
||||||
|
} else {
|
||||||
|
return nestedComments->at(index.row()).offset;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return comments->at(index.row()).offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QModelIndex CommentsModel::index(int row, int column, const QModelIndex &parent) const
|
QModelIndex CommentsModel::index(int row, int column, const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
if (!parent.isValid()) {
|
if (!parent.isValid()) {
|
||||||
@ -37,7 +51,8 @@ QModelIndex CommentsModel::index(int row, int column, const QModelIndex &parent)
|
|||||||
return createIndex(row, column, (quintptr)(parent.row() + 1));
|
return createIndex(row, column, (quintptr)(parent.row() + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
QModelIndex CommentsModel::parent(const QModelIndex &index) const {
|
QModelIndex CommentsModel::parent(const QModelIndex &index) const
|
||||||
|
{
|
||||||
/* Ignore invalid indexes and root nodes */
|
/* Ignore invalid indexes and root nodes */
|
||||||
if (!index.isValid() || index.internalId() == 0) {
|
if (!index.isValid() || index.internalId() == 0) {
|
||||||
return QModelIndex();
|
return QModelIndex();
|
||||||
@ -52,8 +67,7 @@ int CommentsModel::rowCount(const QModelIndex &parent) const
|
|||||||
return (isNested() ? nestedComments->size() : comments->count());
|
return (isNested() ? nestedComments->size() : comments->count());
|
||||||
|
|
||||||
if (isNested() && parent.internalId() == 0) {
|
if (isNested() && parent.internalId() == 0) {
|
||||||
QString fcnName = nestedComments->keys().at(parent.row());
|
return nestedComments->at(parent.row()).comments.size();
|
||||||
return nestedComments->operator[](fcnName).size();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -83,12 +97,13 @@ QVariant CommentsModel::data(const QModelIndex &index, int role) const
|
|||||||
isSubnode = false;
|
isSubnode = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString offset;
|
QString groupName;
|
||||||
CommentDescription comment;
|
CommentDescription comment;
|
||||||
if (isNested()) {
|
if (isNested()) {
|
||||||
offset = nestedComments->keys().at(commentIndex);
|
auto &group = nestedComments->at(commentIndex);
|
||||||
|
groupName = group.name;
|
||||||
if (isSubnode) {
|
if (isSubnode) {
|
||||||
comment = nestedComments->operator[](offset).at(index.row());
|
comment = group.comments.at(index.row());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
comment = comments->at(commentIndex);
|
comment = comments->at(commentIndex);
|
||||||
@ -107,7 +122,7 @@ QVariant CommentsModel::data(const QModelIndex &index, int role) const
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (index.column() == OffsetNestedColumn) {
|
} else if (index.column() == OffsetNestedColumn) {
|
||||||
return offset;
|
return groupName;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch (index.column()) {
|
switch (index.column()) {
|
||||||
@ -164,9 +179,8 @@ QVariant CommentsModel::headerData(int section, Qt::Orientation, int role) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
CommentsProxyModel::CommentsProxyModel(CommentsModel *sourceModel, QObject *parent)
|
CommentsProxyModel::CommentsProxyModel(CommentsModel *sourceModel, QObject *parent)
|
||||||
: QSortFilterProxyModel(parent)
|
: AddressableFilterProxyModel(sourceModel, parent)
|
||||||
{
|
{
|
||||||
setSourceModel(sourceModel);
|
|
||||||
setFilterCaseSensitivity(Qt::CaseInsensitive);
|
setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||||
setSortCaseSensitivity(Qt::CaseInsensitive);
|
setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||||
}
|
}
|
||||||
@ -217,45 +231,33 @@ bool CommentsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &ri
|
|||||||
}
|
}
|
||||||
|
|
||||||
CommentsWidget::CommentsWidget(MainWindow *main, QAction *action) :
|
CommentsWidget::CommentsWidget(MainWindow *main, QAction *action) :
|
||||||
CutterDockWidget(main, action),
|
ListDockWidget(main, action),
|
||||||
ui(new Ui::CommentsWidget),
|
actionHorizontal(tr("Horizontal"), this),
|
||||||
main(main),
|
actionVertical(tr("Vertical"), this)
|
||||||
tree(new CutterTreeWidget(this))
|
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
setWindowTitle(tr("Comments"));
|
||||||
|
setObjectName("CommentsWidget");
|
||||||
// Add Status Bar footer
|
|
||||||
tree->addStatusBar(ui->verticalLayout);
|
|
||||||
|
|
||||||
commentsModel = new CommentsModel(&comments, &nestedComments, this);
|
commentsModel = new CommentsModel(&comments, &nestedComments, this);
|
||||||
commentsProxyModel = new CommentsProxyModel(commentsModel, this);
|
commentsProxyModel = new CommentsProxyModel(commentsModel, this);
|
||||||
ui->commentsTreeView->setModel(commentsProxyModel);
|
setModels(commentsProxyModel);
|
||||||
ui->commentsTreeView->sortByColumn(CommentsModel::CommentColumn, Qt::AscendingOrder);
|
ui->treeView->sortByColumn(CommentsModel::CommentColumn, Qt::AscendingOrder);
|
||||||
|
|
||||||
// Ctrl-F to show/hide the filter entry
|
titleContextMenu = new QMenu(this);
|
||||||
QShortcut *searchShortcut = new QShortcut(QKeySequence::Find, this);
|
auto viewTypeGroup = new QActionGroup(titleContextMenu);
|
||||||
connect(searchShortcut, &QShortcut::activated, ui->quickFilterView, &QuickFilterView::showFilter);
|
actionHorizontal.setCheckable(true);
|
||||||
searchShortcut->setContext(Qt::WidgetWithChildrenShortcut);
|
actionHorizontal.setActionGroup(viewTypeGroup);
|
||||||
|
connect(&actionHorizontal, &QAction::toggled, this, &CommentsWidget::onActionHorizontalToggled);
|
||||||
|
actionVertical.setCheckable(true);
|
||||||
|
actionVertical.setActionGroup(viewTypeGroup);
|
||||||
|
connect(&actionVertical, &QAction::toggled, this, &CommentsWidget::onActionVerticalToggled);
|
||||||
|
titleContextMenu->addActions(viewTypeGroup->actions());
|
||||||
|
|
||||||
// Esc to clear the filter entry
|
|
||||||
QShortcut *clearShortcut = new QShortcut(QKeySequence(Qt::Key_Escape), this);
|
|
||||||
connect(clearShortcut, &QShortcut::activated, ui->quickFilterView, &QuickFilterView::clearFilter);
|
|
||||||
clearShortcut->setContext(Qt::WidgetWithChildrenShortcut);
|
|
||||||
|
|
||||||
connect(ui->quickFilterView, SIGNAL(filterTextChanged(const QString &)),
|
actionHorizontal.setChecked(true);
|
||||||
commentsProxyModel, SLOT(setFilterWildcard(const QString &)));
|
|
||||||
connect(ui->quickFilterView, SIGNAL(filterClosed()), ui->commentsTreeView, SLOT(setFocus()));
|
|
||||||
|
|
||||||
connect(ui->quickFilterView, &QuickFilterView::filterTextChanged, this, [this] {
|
|
||||||
tree->showItemsNumber(commentsProxyModel->rowCount());
|
|
||||||
});
|
|
||||||
|
|
||||||
setScrollMode();
|
|
||||||
|
|
||||||
ui->actionHorizontal->setChecked(true);
|
|
||||||
this->setContextMenuPolicy(Qt::CustomContextMenu);
|
this->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
connect(this, SIGNAL(customContextMenuRequested(const QPoint &)),
|
connect(this, &QWidget::customContextMenuRequested,
|
||||||
this, SLOT(showTitleContextMenu(const QPoint &)));
|
this, &CommentsWidget::showTitleContextMenu);
|
||||||
|
|
||||||
connect(Core(), SIGNAL(commentsChanged()), this, SLOT(refreshTree()));
|
connect(Core(), SIGNAL(commentsChanged()), this, SLOT(refreshTree()));
|
||||||
connect(Core(), SIGNAL(refreshAll()), this, SLOT(refreshTree()));
|
connect(Core(), SIGNAL(refreshAll()), this, SLOT(refreshTree()));
|
||||||
@ -263,61 +265,36 @@ CommentsWidget::CommentsWidget(MainWindow *main, QAction *action) :
|
|||||||
|
|
||||||
CommentsWidget::~CommentsWidget() {}
|
CommentsWidget::~CommentsWidget() {}
|
||||||
|
|
||||||
void CommentsWidget::on_commentsTreeView_doubleClicked(const QModelIndex &index)
|
void CommentsWidget::onActionHorizontalToggled(bool checked)
|
||||||
{
|
{
|
||||||
if (!index.isValid())
|
if (checked) {
|
||||||
return;
|
commentsModel->setNested(false);
|
||||||
|
ui->treeView->setIndentation(8);
|
||||||
if (commentsModel->isNested() && !index.parent().isValid())
|
}
|
||||||
return;
|
|
||||||
|
|
||||||
auto comment = index.data(CommentsModel::CommentDescriptionRole).value<CommentDescription>();
|
|
||||||
Core()->seekAndShow(comment.offset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommentsWidget::on_actionHorizontal_triggered()
|
void CommentsWidget::onActionVerticalToggled(bool checked)
|
||||||
{
|
{
|
||||||
commentsModel->setNested(false);
|
if (checked) {
|
||||||
ui->commentsTreeView->setIndentation(8);
|
commentsModel->setNested(true);
|
||||||
}
|
ui->treeView->setIndentation(20);
|
||||||
|
}
|
||||||
void CommentsWidget::on_actionVertical_triggered()
|
|
||||||
{
|
|
||||||
commentsModel->setNested(true);
|
|
||||||
ui->commentsTreeView->setIndentation(20);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommentsWidget::showTitleContextMenu(const QPoint &pt)
|
void CommentsWidget::showTitleContextMenu(const QPoint &pt)
|
||||||
{
|
{
|
||||||
// Set functions popup menu
|
titleContextMenu->exec(this->mapToGlobal(pt));
|
||||||
QMenu *menu = new QMenu(this);
|
|
||||||
menu->clear();
|
|
||||||
menu->addAction(ui->actionHorizontal);
|
|
||||||
menu->addAction(ui->actionVertical);
|
|
||||||
|
|
||||||
if (!commentsModel->isNested()) {
|
|
||||||
ui->actionHorizontal->setChecked(true);
|
|
||||||
ui->actionVertical->setChecked(false);
|
|
||||||
} else {
|
|
||||||
ui->actionVertical->setChecked(true);
|
|
||||||
ui->actionHorizontal->setChecked(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
this->setContextMenuPolicy(Qt::CustomContextMenu);
|
|
||||||
|
|
||||||
menu->exec(this->mapToGlobal(pt));
|
|
||||||
delete menu;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommentsWidget::resizeEvent(QResizeEvent *event)
|
void CommentsWidget::resizeEvent(QResizeEvent *event)
|
||||||
{
|
{
|
||||||
if (main->responsive && isVisible()) {
|
if (mainWindow->responsive && isVisible()) {
|
||||||
if (event->size().width() >= event->size().height()) {
|
if (event->size().width() >= event->size().height()) {
|
||||||
// Set horizontal view (list)
|
// Set horizontal view (list)
|
||||||
on_actionHorizontal_triggered();
|
actionHorizontal.setChecked(true);
|
||||||
} else {
|
} else {
|
||||||
// Set vertical view (Tree)
|
// Set vertical view (Tree)
|
||||||
on_actionVertical_triggered();
|
actionVertical.setChecked(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
QDockWidget::resizeEvent(event);
|
QDockWidget::resizeEvent(event);
|
||||||
@ -329,19 +306,22 @@ void CommentsWidget::refreshTree()
|
|||||||
|
|
||||||
comments = Core()->getAllComments("CCu");
|
comments = Core()->getAllComments("CCu");
|
||||||
nestedComments.clear();
|
nestedComments.clear();
|
||||||
|
QMap<QString, size_t> nestedCommentMapping;
|
||||||
for (const CommentDescription &comment : comments) {
|
for (const CommentDescription &comment : comments) {
|
||||||
QString fcnName = Core()->cmdFunctionAt(comment.offset);
|
RVA offset = RVA_INVALID;
|
||||||
nestedComments[fcnName].append(comment);
|
QString fcnName = Core()->nearestFlag(comment.offset, &offset);
|
||||||
|
auto nestedCommentIt = nestedCommentMapping.find(fcnName);
|
||||||
|
if (nestedCommentIt == nestedCommentMapping.end()) {
|
||||||
|
nestedCommentMapping.insert(fcnName, nestedComments.size());
|
||||||
|
nestedComments.push_back({fcnName, offset, {comment}});
|
||||||
|
} else {
|
||||||
|
auto &commentGroup = nestedComments[nestedCommentIt.value()];
|
||||||
|
commentGroup.comments.append(comment);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
commentsModel->endResetModel();
|
commentsModel->endResetModel();
|
||||||
|
|
||||||
qhelpers::adjustColumns(ui->commentsTreeView, 3, 0);
|
qhelpers::adjustColumns(ui->treeView, 3, 0);
|
||||||
|
|
||||||
tree->showItemsNumber(commentsProxyModel->rowCount());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommentsWidget::setScrollMode()
|
|
||||||
{
|
|
||||||
qhelpers::setVerticalScrollMode(ui->commentsTreeView);
|
|
||||||
}
|
|
||||||
|
@ -6,18 +6,23 @@
|
|||||||
#include <QSortFilterProxyModel>
|
#include <QSortFilterProxyModel>
|
||||||
|
|
||||||
#include "core/Cutter.h"
|
#include "core/Cutter.h"
|
||||||
|
#include "common/AddressableItemModel.h"
|
||||||
#include "CutterDockWidget.h"
|
#include "CutterDockWidget.h"
|
||||||
#include "CutterTreeWidget.h"
|
#include "CutterTreeWidget.h"
|
||||||
|
#include "widgets/ListDockWidget.h"
|
||||||
|
|
||||||
class MainWindow;
|
class MainWindow;
|
||||||
class QTreeWidgetItem;
|
class QTreeWidgetItem;
|
||||||
class CommentsWidget;
|
class CommentsWidget;
|
||||||
|
|
||||||
namespace Ui {
|
struct CommentGroup
|
||||||
class CommentsWidget;
|
{
|
||||||
}
|
QString name;
|
||||||
|
RVA offset;
|
||||||
|
QList<CommentDescription> comments;
|
||||||
|
};
|
||||||
|
|
||||||
class CommentsModel : public QAbstractItemModel
|
class CommentsModel : public AddressableItemModel<>
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -25,7 +30,7 @@ class CommentsModel : public QAbstractItemModel
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
QList<CommentDescription> *comments;
|
QList<CommentDescription> *comments;
|
||||||
QMap<QString, QList<CommentDescription>> *nestedComments;
|
QList<CommentGroup> *nestedComments;
|
||||||
bool nested;
|
bool nested;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -34,23 +39,26 @@ public:
|
|||||||
enum Role { CommentDescriptionRole = Qt::UserRole, FunctionRole };
|
enum Role { CommentDescriptionRole = Qt::UserRole, FunctionRole };
|
||||||
|
|
||||||
CommentsModel(QList<CommentDescription> *comments,
|
CommentsModel(QList<CommentDescription> *comments,
|
||||||
QMap<QString, QList<CommentDescription>> *nestedComments,
|
QList<CommentGroup> *nestedComments,
|
||||||
QObject *parent = nullptr);
|
QObject *parent = nullptr);
|
||||||
|
|
||||||
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
|
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
|
||||||
QModelIndex parent(const QModelIndex &index) const;
|
QModelIndex parent(const QModelIndex &index) const override;
|
||||||
|
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
|
||||||
QVariant data(const QModelIndex &index, int role) const;
|
QVariant data(const QModelIndex &index, int role) const override;
|
||||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
QVariant headerData(int section, Qt::Orientation orientation,
|
||||||
|
int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
bool isNested() const;
|
bool isNested() const;
|
||||||
void setNested(bool nested);
|
void setNested(bool nested);
|
||||||
|
|
||||||
|
RVA address(const QModelIndex &index) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CommentsProxyModel : public QSortFilterProxyModel
|
class CommentsProxyModel : public AddressableFilterProxyModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -62,39 +70,35 @@ protected:
|
|||||||
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
|
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CommentsWidget : public CutterDockWidget
|
class CommentsWidget : public ListDockWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit CommentsWidget(MainWindow *main, QAction *action = nullptr);
|
explicit CommentsWidget(MainWindow *main, QAction *action = nullptr);
|
||||||
~CommentsWidget();
|
~CommentsWidget() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void resizeEvent(QResizeEvent *event) override;
|
void resizeEvent(QResizeEvent *event) override;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void on_commentsTreeView_doubleClicked(const QModelIndex &index);
|
void onActionHorizontalToggled(bool checked);
|
||||||
|
void onActionVerticalToggled(bool checked);
|
||||||
void on_actionHorizontal_triggered();
|
|
||||||
void on_actionVertical_triggered();
|
|
||||||
|
|
||||||
void showTitleContextMenu(const QPoint &pt);
|
void showTitleContextMenu(const QPoint &pt);
|
||||||
|
|
||||||
void refreshTree();
|
void refreshTree();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<Ui::CommentsWidget> ui;
|
|
||||||
MainWindow *main;
|
|
||||||
|
|
||||||
CommentsModel *commentsModel;
|
CommentsModel *commentsModel;
|
||||||
CommentsProxyModel *commentsProxyModel;
|
CommentsProxyModel *commentsProxyModel;
|
||||||
CutterTreeWidget *tree;
|
QAction actionHorizontal;
|
||||||
|
QAction actionVertical;
|
||||||
|
|
||||||
QList<CommentDescription> comments;
|
QList<CommentDescription> comments;
|
||||||
QMap<QString, QList<CommentDescription>> nestedComments;
|
QList<CommentGroup> nestedComments;
|
||||||
|
|
||||||
void setScrollMode();
|
QMenu *titleContextMenu;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // COMMENTSWIDGET_H
|
#endif // COMMENTSWIDGET_H
|
||||||
|
@ -1,87 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<class>CommentsWidget</class>
|
|
||||||
<widget class="QDockWidget" name="CommentsWidget">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>645</width>
|
|
||||||
<height>250</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string notr="true">Comments</string>
|
|
||||||
</property>
|
|
||||||
<widget class="QWidget" name="dockWidgetContents">
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
|
||||||
<property name="spacing">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<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="commentsTreeView">
|
|
||||||
<property name="sortingEnabled">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<attribute name="headerShowSortIndicator" stdset="0">
|
|
||||||
<bool>true</bool>
|
|
||||||
</attribute>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QuickFilterView" name="quickFilterView" native="true"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<action name="actionHorizontal">
|
|
||||||
<property name="checkable">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Horizontal</string>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Horizontal view</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionVertical">
|
|
||||||
<property name="checkable">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Vertical</string>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Vertical view</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
</widget>
|
|
||||||
<customwidgets>
|
|
||||||
<customwidget>
|
|
||||||
<class>CutterTreeView</class>
|
|
||||||
<extends>QTreeView</extends>
|
|
||||||
<header>widgets/CutterTreeView.h</header>
|
|
||||||
<container>1</container>
|
|
||||||
</customwidget>
|
|
||||||
<customwidget>
|
|
||||||
<class>QuickFilterView</class>
|
|
||||||
<extends>QWidget</extends>
|
|
||||||
<header>widgets/QuickFilterView.h</header>
|
|
||||||
<container>1</container>
|
|
||||||
</customwidget>
|
|
||||||
</customwidgets>
|
|
||||||
<resources/>
|
|
||||||
<connections/>
|
|
||||||
</ui>
|
|
@ -23,4 +23,9 @@ void CutterTreeWidget::showItemsNumber(int count)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CutterTreeWidget::showStatusBar(bool show)
|
||||||
|
{
|
||||||
|
bar->setVisible(show);
|
||||||
|
}
|
||||||
|
|
||||||
CutterTreeWidget::~CutterTreeWidget() {}
|
CutterTreeWidget::~CutterTreeWidget() {}
|
||||||
|
@ -16,6 +16,7 @@ public:
|
|||||||
~CutterTreeWidget();
|
~CutterTreeWidget();
|
||||||
void addStatusBar(QVBoxLayout *pos);
|
void addStatusBar(QVBoxLayout *pos);
|
||||||
void showItemsNumber(int count);
|
void showItemsNumber(int count);
|
||||||
|
void showStatusBar(bool show);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QStatusBar *bar;
|
QStatusBar *bar;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#include "ExportsWidget.h"
|
#include "ExportsWidget.h"
|
||||||
#include "ui_ExportsWidget.h"
|
#include "ui_ListDockWidget.h"
|
||||||
#include "core/MainWindow.h"
|
#include "core/MainWindow.h"
|
||||||
#include "common/Helpers.h"
|
#include "common/Helpers.h"
|
||||||
#include "WidgetShortcuts.h"
|
#include "WidgetShortcuts.h"
|
||||||
@ -7,7 +7,7 @@
|
|||||||
#include <QShortcut>
|
#include <QShortcut>
|
||||||
|
|
||||||
ExportsModel::ExportsModel(QList<ExportDescription> *exports, QObject *parent)
|
ExportsModel::ExportsModel(QList<ExportDescription> *exports, QObject *parent)
|
||||||
: QAbstractListModel(parent),
|
: AddressableItemModel<QAbstractListModel>(parent),
|
||||||
exports(exports)
|
exports(exports)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -71,10 +71,21 @@ QVariant ExportsModel::headerData(int section, Qt::Orientation, int role) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ExportsProxyModel::ExportsProxyModel(ExportsModel *source_model, QObject *parent)
|
RVA ExportsModel::address(const QModelIndex &index) const
|
||||||
: QSortFilterProxyModel(parent)
|
{
|
||||||
|
const ExportDescription &exp = exports->at(index.row());
|
||||||
|
return exp.vaddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ExportsModel::name(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
const ExportDescription &exp = exports->at(index.row());
|
||||||
|
return exp.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExportsProxyModel::ExportsProxyModel(ExportsModel *source_model, QObject *parent)
|
||||||
|
: AddressableFilterProxyModel(source_model, parent)
|
||||||
{
|
{
|
||||||
setSourceModel(source_model);
|
|
||||||
setFilterCaseSensitivity(Qt::CaseInsensitive);
|
setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||||
setSortCaseSensitivity(Qt::CaseInsensitive);
|
setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||||
}
|
}
|
||||||
@ -115,19 +126,15 @@ bool ExportsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &rig
|
|||||||
}
|
}
|
||||||
|
|
||||||
ExportsWidget::ExportsWidget(MainWindow *main, QAction *action) :
|
ExportsWidget::ExportsWidget(MainWindow *main, QAction *action) :
|
||||||
CutterDockWidget(main, action),
|
ListDockWidget(main, action)
|
||||||
ui(new Ui::ExportsWidget),
|
|
||||||
tree(new CutterTreeWidget(this))
|
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
setWindowTitle(tr("Exports"));
|
||||||
|
setObjectName("ExportsWidget");
|
||||||
// Add Status Bar footer
|
|
||||||
tree->addStatusBar(ui->verticalLayout);
|
|
||||||
|
|
||||||
exportsModel = new ExportsModel(&exports, this);
|
exportsModel = new ExportsModel(&exports, this);
|
||||||
exportsProxyModel = new ExportsProxyModel(exportsModel, this);
|
exportsProxyModel = new ExportsProxyModel(exportsModel, this);
|
||||||
ui->exportsTreeView->setModel(exportsProxyModel);
|
setModels(exportsProxyModel);
|
||||||
ui->exportsTreeView->sortByColumn(ExportsModel::OffsetColumn, Qt::AscendingOrder);
|
ui->treeView->sortByColumn(ExportsModel::OffsetColumn, Qt::AscendingOrder);
|
||||||
|
|
||||||
QShortcut *toggle_shortcut = new QShortcut(widgetShortcuts["ExportsWidget"], main);
|
QShortcut *toggle_shortcut = new QShortcut(widgetShortcuts["ExportsWidget"], main);
|
||||||
connect(toggle_shortcut, &QShortcut::activated, this, [=] (){
|
connect(toggle_shortcut, &QShortcut::activated, this, [=] (){
|
||||||
@ -135,26 +142,6 @@ ExportsWidget::ExportsWidget(MainWindow *main, QAction *action) :
|
|||||||
main->updateDockActionChecked(action);
|
main->updateDockActionChecked(action);
|
||||||
} );
|
} );
|
||||||
|
|
||||||
// Ctrl-F to show/hide the filter entry
|
|
||||||
QShortcut *searchShortcut = new QShortcut(QKeySequence::Find, this);
|
|
||||||
connect(searchShortcut, &QShortcut::activated, ui->quickFilterView, &QuickFilterView::showFilter);
|
|
||||||
searchShortcut->setContext(Qt::WidgetWithChildrenShortcut);
|
|
||||||
|
|
||||||
// Esc to clear the filter entry
|
|
||||||
QShortcut *clearShortcut = new QShortcut(QKeySequence(Qt::Key_Escape), this);
|
|
||||||
connect(clearShortcut, &QShortcut::activated, ui->quickFilterView, &QuickFilterView::clearFilter);
|
|
||||||
clearShortcut->setContext(Qt::WidgetWithChildrenShortcut);
|
|
||||||
|
|
||||||
connect(ui->quickFilterView, SIGNAL(filterTextChanged(const QString &)),
|
|
||||||
exportsProxyModel, SLOT(setFilterWildcard(const QString &)));
|
|
||||||
connect(ui->quickFilterView, SIGNAL(filterClosed()), ui->exportsTreeView, SLOT(setFocus()));
|
|
||||||
|
|
||||||
connect(ui->quickFilterView, &QuickFilterView::filterTextChanged, this, [this] {
|
|
||||||
tree->showItemsNumber(exportsProxyModel->rowCount());
|
|
||||||
});
|
|
||||||
|
|
||||||
setScrollMode();
|
|
||||||
|
|
||||||
connect(Core(), SIGNAL(refreshAll()), this, SLOT(refreshExports()));
|
connect(Core(), SIGNAL(refreshAll()), this, SLOT(refreshExports()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,22 +153,5 @@ void ExportsWidget::refreshExports()
|
|||||||
exports = Core()->getAllExports();
|
exports = Core()->getAllExports();
|
||||||
exportsModel->endResetModel();
|
exportsModel->endResetModel();
|
||||||
|
|
||||||
qhelpers::adjustColumns(ui->exportsTreeView, 3, 0);
|
qhelpers::adjustColumns(ui->treeView, 3, 0);
|
||||||
|
|
||||||
tree->showItemsNumber(exportsProxyModel->rowCount());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ExportsWidget::setScrollMode()
|
|
||||||
{
|
|
||||||
qhelpers::setVerticalScrollMode(ui->exportsTreeView);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExportsWidget::on_exportsTreeView_doubleClicked(const QModelIndex &index)
|
|
||||||
{
|
|
||||||
if (!index.isValid())
|
|
||||||
return;
|
|
||||||
|
|
||||||
ExportDescription exp = index.data(ExportsModel::ExportDescriptionRole).value<ExportDescription>();
|
|
||||||
Core()->seekAndShow(exp.vaddr);
|
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
#include "core/Cutter.h"
|
#include "core/Cutter.h"
|
||||||
#include "CutterDockWidget.h"
|
#include "CutterDockWidget.h"
|
||||||
#include "CutterTreeWidget.h"
|
#include "widgets/ListDockWidget.h"
|
||||||
|
|
||||||
#include <QAbstractListModel>
|
#include <QAbstractListModel>
|
||||||
#include <QSortFilterProxyModel>
|
#include <QSortFilterProxyModel>
|
||||||
@ -18,7 +18,7 @@ namespace Ui {
|
|||||||
class ExportsWidget;
|
class ExportsWidget;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ExportsModel : public QAbstractListModel
|
class ExportsModel : public AddressableItemModel<QAbstractListModel>
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -33,14 +33,17 @@ public:
|
|||||||
|
|
||||||
ExportsModel(QList<ExportDescription> *exports, QObject *parent = nullptr);
|
ExportsModel(QList<ExportDescription> *exports, QObject *parent = nullptr);
|
||||||
|
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
|
||||||
QVariant data(const QModelIndex &index, int role) const;
|
QVariant data(const QModelIndex &index, int role) const override;
|
||||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
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 ExportsProxyModel : public QSortFilterProxyModel
|
class ExportsProxyModel : public AddressableFilterProxyModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -52,7 +55,7 @@ protected:
|
|||||||
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
|
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ExportsWidget : public CutterDockWidget
|
class ExportsWidget : public ListDockWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -61,19 +64,12 @@ public:
|
|||||||
~ExportsWidget();
|
~ExportsWidget();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void on_exportsTreeView_doubleClicked(const QModelIndex &index);
|
|
||||||
|
|
||||||
void refreshExports();
|
void refreshExports();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<Ui::ExportsWidget> ui;
|
|
||||||
|
|
||||||
ExportsModel *exportsModel;
|
ExportsModel *exportsModel;
|
||||||
ExportsProxyModel *exportsProxyModel;
|
ExportsProxyModel *exportsProxyModel;
|
||||||
QList<ExportDescription> exports;
|
QList<ExportDescription> exports;
|
||||||
CutterTreeWidget *tree;
|
|
||||||
|
|
||||||
void setScrollMode();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // EXPORTSWIDGET_H
|
#endif // EXPORTSWIDGET_H
|
||||||
|
@ -1,75 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<class>ExportsWidget</class>
|
|
||||||
<widget class="QDockWidget" name="ExportsWidget">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>400</width>
|
|
||||||
<height>300</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string notr="true">Exports</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="exportsTreeView">
|
|
||||||
<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>
|
|
||||||
<item>
|
|
||||||
<widget class="QuickFilterView" name="quickFilterView" native="true"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</widget>
|
|
||||||
<customwidgets>
|
|
||||||
<customwidget>
|
|
||||||
<class>CutterTreeView</class>
|
|
||||||
<extends>QTreeView</extends>
|
|
||||||
<header>widgets/CutterTreeView.h</header>
|
|
||||||
<container>1</container>
|
|
||||||
</customwidget>
|
|
||||||
<customwidget>
|
|
||||||
<class>QuickFilterView</class>
|
|
||||||
<extends>QWidget</extends>
|
|
||||||
<header>widgets/QuickFilterView.h</header>
|
|
||||||
<container>1</container>
|
|
||||||
</customwidget>
|
|
||||||
</customwidgets>
|
|
||||||
<resources/>
|
|
||||||
<connections/>
|
|
||||||
</ui>
|
|
@ -1,5 +1,5 @@
|
|||||||
#include "FunctionsWidget.h"
|
#include "FunctionsWidget.h"
|
||||||
#include "ui_FunctionsWidget.h"
|
#include "ui_ListDockWidget.h"
|
||||||
|
|
||||||
#include "core/MainWindow.h"
|
#include "core/MainWindow.h"
|
||||||
#include "common/Helpers.h"
|
#include "common/Helpers.h"
|
||||||
@ -8,6 +8,7 @@
|
|||||||
#include "dialogs/XrefsDialog.h"
|
#include "dialogs/XrefsDialog.h"
|
||||||
#include "common/FunctionsTask.h"
|
#include "common/FunctionsTask.h"
|
||||||
#include "common/TempConfig.h"
|
#include "common/TempConfig.h"
|
||||||
|
#include "menus/AddressableItemContextMenu.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
@ -28,7 +29,7 @@ static const int kMaxTooltipHighlightsLines = 5;
|
|||||||
|
|
||||||
FunctionModel::FunctionModel(QList<FunctionDescription> *functions, QSet<RVA> *importAddresses,
|
FunctionModel::FunctionModel(QList<FunctionDescription> *functions, QSet<RVA> *importAddresses,
|
||||||
ut64 *mainAdress, bool nested, QFont default_font, QFont highlight_font, QObject *parent)
|
ut64 *mainAdress, bool nested, QFont default_font, QFont highlight_font, QObject *parent)
|
||||||
: QAbstractItemModel(parent),
|
: AddressableItemModel<>(parent),
|
||||||
functions(functions),
|
functions(functions),
|
||||||
importAddresses(importAddresses),
|
importAddresses(importAddresses),
|
||||||
mainAdress(mainAdress),
|
mainAdress(mainAdress),
|
||||||
@ -147,21 +148,21 @@ QVariant FunctionModel::data(const QModelIndex &index, int role) const
|
|||||||
case NameColumn:
|
case NameColumn:
|
||||||
return function.name;
|
return function.name;
|
||||||
case SizeColumn:
|
case SizeColumn:
|
||||||
return function.size;
|
return QString::number(function.size);
|
||||||
case OffsetColumn:
|
case OffsetColumn:
|
||||||
return RAddressString(function.offset);
|
return RAddressString(function.offset);
|
||||||
case NargsColumn:
|
case NargsColumn:
|
||||||
return function.nargs;
|
return QString::number(function.nargs);
|
||||||
case NlocalsColumn:
|
case NlocalsColumn:
|
||||||
return function.nlocals;
|
return QString::number(function.nlocals);
|
||||||
case NbbsColumn:
|
case NbbsColumn:
|
||||||
return function.nbbs;
|
return QString::number(function.nbbs);
|
||||||
case CalltypeColumn:
|
case CalltypeColumn:
|
||||||
return function.calltype;
|
return function.calltype;
|
||||||
case EdgesColumn:
|
case EdgesColumn:
|
||||||
return function.edges;
|
return QString::number(function.edges);
|
||||||
case FrameColumn:
|
case FrameColumn:
|
||||||
return function.stackframe;
|
return QString::number(function.stackframe);
|
||||||
default:
|
default:
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
@ -187,7 +188,8 @@ QVariant FunctionModel::data(const QModelIndex &index, int role) const
|
|||||||
|
|
||||||
case Qt::ToolTipRole: {
|
case Qt::ToolTipRole: {
|
||||||
|
|
||||||
QStringList disasmPreview = Core()->getDisassemblyPreview(function.offset, kMaxTooltipDisasmPreviewLines);
|
QStringList disasmPreview = Core()->getDisassemblyPreview(function.offset,
|
||||||
|
kMaxTooltipDisasmPreviewLines);
|
||||||
const QStringList &summary = Core()->cmdList(QString("pdsf @ %1").arg(function.offset));
|
const QStringList &summary = Core()->cmdList(QString("pdsf @ %1").arg(function.offset));
|
||||||
const QFont &fnt = Config()->getFont();
|
const QFont &fnt = Config()->getFont();
|
||||||
QFontMetrics fm{ fnt };
|
QFontMetrics fm{ fnt };
|
||||||
@ -204,17 +206,20 @@ QVariant FunctionModel::data(const QModelIndex &index, int role) const
|
|||||||
if (disasmPreview.isEmpty() && highlights.isEmpty())
|
if (disasmPreview.isEmpty() && highlights.isEmpty())
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
|
||||||
QString toolTipContent = QString("<html><div style=\"font-family: %1; font-size: %2pt; white-space: nowrap;\">")
|
QString toolTipContent =
|
||||||
.arg(fnt.family())
|
QString("<html><div style=\"font-family: %1; font-size: %2pt; white-space: nowrap;\">")
|
||||||
.arg(qMax(6, fnt.pointSize() - 1)); // slightly decrease font size, to keep more text in the same box
|
.arg(fnt.family())
|
||||||
|
.arg(qMax(6, fnt.pointSize() -
|
||||||
|
1)); // slightly decrease font size, to keep more text in the same box
|
||||||
|
|
||||||
if (!disasmPreview.isEmpty())
|
if (!disasmPreview.isEmpty())
|
||||||
toolTipContent += tr("<div style=\"margin-bottom: 10px;\"><strong>Disassembly preview</strong>:<br>%1</div>")
|
toolTipContent +=
|
||||||
|
tr("<div style=\"margin-bottom: 10px;\"><strong>Disassembly preview</strong>:<br>%1</div>")
|
||||||
.arg(disasmPreview.join("<br>"));
|
.arg(disasmPreview.join("<br>"));
|
||||||
|
|
||||||
if (!highlights.isEmpty()) {
|
if (!highlights.isEmpty()) {
|
||||||
toolTipContent += tr("<div><strong>Highlights</strong>:<br>%1</div>")
|
toolTipContent += tr("<div><strong>Highlights</strong>:<br>%1</div>")
|
||||||
.arg(highlights.join(QLatin1Char('\n')).toHtmlEscaped().replace(QLatin1Char('\n'), "<br>"));
|
.arg(highlights.join(QLatin1Char('\n')).toHtmlEscaped().replace(QLatin1Char('\n'), "<br>"));
|
||||||
}
|
}
|
||||||
toolTipContent += "</div></html>";
|
toolTipContent += "</div></html>";
|
||||||
return toolTipContent;
|
return toolTipContent;
|
||||||
@ -282,6 +287,18 @@ void FunctionModel::setNested(bool nested)
|
|||||||
endResetModel();
|
endResetModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RVA FunctionModel::address(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
auto function = data(index, FunctionDescriptionRole).value<FunctionDescription>();
|
||||||
|
return function.offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString FunctionModel::name(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
auto function = data(index, FunctionDescriptionRole).value<FunctionDescription>();
|
||||||
|
return function.name;
|
||||||
|
}
|
||||||
|
|
||||||
void FunctionModel::seekChanged(RVA)
|
void FunctionModel::seekChanged(RVA)
|
||||||
{
|
{
|
||||||
int previousIndex = currentIndex;
|
int previousIndex = currentIndex;
|
||||||
@ -332,9 +349,8 @@ void FunctionModel::functionRenamed(const QString &prev_name, const QString &new
|
|||||||
|
|
||||||
FunctionSortFilterProxyModel::FunctionSortFilterProxyModel(FunctionModel *source_model,
|
FunctionSortFilterProxyModel::FunctionSortFilterProxyModel(FunctionModel *source_model,
|
||||||
QObject *parent)
|
QObject *parent)
|
||||||
: QSortFilterProxyModel(parent)
|
: AddressableFilterProxyModel(source_model, parent)
|
||||||
{
|
{
|
||||||
setSourceModel(source_model);
|
|
||||||
setFilterCaseSensitivity(Qt::CaseInsensitive);
|
setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||||
setSortCaseSensitivity(Qt::CaseInsensitive);
|
setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||||
}
|
}
|
||||||
@ -411,64 +427,56 @@ bool FunctionSortFilterProxyModel::lessThan(const QModelIndex &left, const QMode
|
|||||||
}
|
}
|
||||||
|
|
||||||
FunctionsWidget::FunctionsWidget(MainWindow *main, QAction *action) :
|
FunctionsWidget::FunctionsWidget(MainWindow *main, QAction *action) :
|
||||||
CutterDockWidget(main, action),
|
ListDockWidget(main, action),
|
||||||
ui(new Ui::FunctionsWidget),
|
actionRename(tr("Rename"), this),
|
||||||
tree(new CutterTreeWidget(this))
|
actionUndefine(tr("Undefine"), this),
|
||||||
|
actionHorizontal(tr("Horizontal"), this),
|
||||||
|
actionVertical(tr("Vertical"), this)
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
setWindowTitle(tr("Functions"));
|
||||||
|
setObjectName("FunctionsWidget");
|
||||||
|
|
||||||
// Add Status Bar footer
|
|
||||||
tree->addStatusBar(ui->verticalLayout);
|
|
||||||
|
|
||||||
// Radare core found in:
|
|
||||||
this->main = main;
|
|
||||||
setTooltipStylesheet();
|
setTooltipStylesheet();
|
||||||
connect(Config(), SIGNAL(colorsUpdated()), this, SLOT(setTooltipStylesheet()));
|
connect(Config(), SIGNAL(colorsUpdated()), this, SLOT(setTooltipStylesheet()));
|
||||||
|
|
||||||
|
QFontInfo font_info = ui->treeView->fontInfo();
|
||||||
// leave the filter visible by default so users know it exists
|
|
||||||
//ui->filterLineEdit->setVisible(false);
|
|
||||||
|
|
||||||
// Ctrl-F to show/hide the filter entry
|
|
||||||
QShortcut *search_shortcut = new QShortcut(QKeySequence::Find, this);
|
|
||||||
connect(search_shortcut, &QShortcut::activated, ui->quickFilterView, &QuickFilterView::showFilter);
|
|
||||||
search_shortcut->setContext(Qt::WidgetWithChildrenShortcut);
|
|
||||||
|
|
||||||
// Esc to clear the filter entry
|
|
||||||
QShortcut *clear_shortcut = new QShortcut(QKeySequence(Qt::Key_Escape), this);
|
|
||||||
connect(clear_shortcut, &QShortcut::activated, ui->quickFilterView, &QuickFilterView::clearFilter);
|
|
||||||
clear_shortcut->setContext(Qt::WidgetWithChildrenShortcut);
|
|
||||||
|
|
||||||
QFontInfo font_info = ui->functionsTreeView->fontInfo();
|
|
||||||
QFont default_font = QFont(font_info.family(), font_info.pointSize());
|
QFont default_font = QFont(font_info.family(), font_info.pointSize());
|
||||||
QFont highlight_font = QFont(font_info.family(), font_info.pointSize(), QFont::Bold);
|
QFont highlight_font = QFont(font_info.family(), font_info.pointSize(), QFont::Bold);
|
||||||
|
|
||||||
functionModel = new FunctionModel(&functions, &importAddresses, &mainAdress, false, default_font,
|
functionModel = new FunctionModel(&functions, &importAddresses, &mainAdress, false, default_font,
|
||||||
highlight_font, this);
|
highlight_font, this);
|
||||||
functionProxyModel = new FunctionSortFilterProxyModel(functionModel, this);
|
functionProxyModel = new FunctionSortFilterProxyModel(functionModel, this);
|
||||||
ui->functionsTreeView->setModel(functionProxyModel);
|
setModels(functionProxyModel);
|
||||||
ui->functionsTreeView->sortByColumn(FunctionModel::NameColumn, Qt::AscendingOrder);
|
ui->treeView->sortByColumn(FunctionModel::NameColumn, Qt::AscendingOrder);
|
||||||
|
|
||||||
connect(ui->quickFilterView, SIGNAL(filterTextChanged(const QString &)), functionProxyModel,
|
|
||||||
SLOT(setFilterWildcard(const QString &)));
|
|
||||||
connect(ui->quickFilterView, SIGNAL(filterClosed()), ui->functionsTreeView, SLOT(setFocus()));
|
|
||||||
|
|
||||||
connect(ui->quickFilterView, &QuickFilterView::filterTextChanged, this, [this] {
|
titleContextMenu = new QMenu(this);
|
||||||
tree->showItemsNumber(functionProxyModel->rowCount());
|
auto viewTypeGroup = new QActionGroup(titleContextMenu);
|
||||||
});
|
actionHorizontal.setCheckable(true);
|
||||||
|
actionHorizontal.setActionGroup(viewTypeGroup);
|
||||||
|
connect(&actionHorizontal, &QAction::toggled, this, &FunctionsWidget::onActionHorizontalToggled);
|
||||||
|
actionVertical.setCheckable(true);
|
||||||
|
actionVertical.setActionGroup(viewTypeGroup);
|
||||||
|
connect(&actionVertical, &QAction::toggled, this, &FunctionsWidget::onActionVerticalToggled);
|
||||||
|
titleContextMenu->addActions(viewTypeGroup->actions());
|
||||||
|
|
||||||
setScrollMode();
|
actionRename.setShortcut({Qt::Key_N});
|
||||||
|
actionRename.setShortcutContext(Qt::ShortcutContext::WidgetWithChildrenShortcut);
|
||||||
|
connect(&actionRename, &QAction::triggered, this,
|
||||||
|
&FunctionsWidget::onActionFunctionsRenameTriggered);
|
||||||
|
connect(&actionUndefine, &QAction::triggered, this,
|
||||||
|
&FunctionsWidget::onActionFunctionsUndefineTriggered);
|
||||||
|
|
||||||
// Set Functions context menu
|
auto itemConextMenu = getItemContextMenu();
|
||||||
connect(ui->functionsTreeView, SIGNAL(customContextMenuRequested(const QPoint &)),
|
itemConextMenu->addSeparator();
|
||||||
this, SLOT(showFunctionsContextMenu(const QPoint &)));
|
itemConextMenu->addAction(&actionRename);
|
||||||
|
itemConextMenu->addAction(&actionUndefine);
|
||||||
|
itemConextMenu->setWholeFunction(true);
|
||||||
|
|
||||||
connect(ui->functionsTreeView, SIGNAL(doubleClicked(const QModelIndex &)), this,
|
addActions(itemConextMenu->actions());
|
||||||
SLOT(onFunctionsDoubleClicked(const QModelIndex &)));
|
|
||||||
|
|
||||||
// Use a custom context menu on the dock title bar
|
// Use a custom context menu on the dock title bar
|
||||||
//this->title_bar = this->titleBarWidget();
|
actionHorizontal.setChecked(true);
|
||||||
ui->actionHorizontal->setChecked(true);
|
|
||||||
this->setContextMenuPolicy(Qt::CustomContextMenu);
|
this->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
connect(this, SIGNAL(customContextMenuRequested(const QPoint &)),
|
connect(this, SIGNAL(customContextMenuRequested(const QPoint &)),
|
||||||
this, SLOT(showTitleContextMenu(const QPoint &)));
|
this, SLOT(showTitleContextMenu(const QPoint &)));
|
||||||
@ -503,9 +511,7 @@ void FunctionsWidget::refreshTree()
|
|||||||
functionModel->endResetModel();
|
functionModel->endResetModel();
|
||||||
|
|
||||||
// resize offset and size columns
|
// resize offset and size columns
|
||||||
qhelpers::adjustColumns(ui->functionsTreeView, 3, 0);
|
qhelpers::adjustColumns(ui->treeView, 3, 0);
|
||||||
|
|
||||||
tree->showItemsNumber(functionProxyModel->rowCount());
|
|
||||||
});
|
});
|
||||||
Core()->getAsyncTaskManager()->start(task);
|
Core()->getAsyncTaskManager()->start(task);
|
||||||
}
|
}
|
||||||
@ -515,56 +521,10 @@ void FunctionsWidget::changeSizePolicy(QSizePolicy::Policy hor, QSizePolicy::Pol
|
|||||||
ui->dockWidgetContents->setSizePolicy(hor, ver);
|
ui->dockWidgetContents->setSizePolicy(hor, ver);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FunctionsWidget::onFunctionsDoubleClicked(const QModelIndex &index)
|
void FunctionsWidget::onActionFunctionsRenameTriggered()
|
||||||
{
|
|
||||||
if (!index.isValid())
|
|
||||||
return;
|
|
||||||
|
|
||||||
FunctionDescription function = index.data(
|
|
||||||
FunctionModel::FunctionDescriptionRole).value<FunctionDescription>();
|
|
||||||
Core()->seekAndShow(function.offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FunctionsWidget::showFunctionsContextMenu(const QPoint &pt)
|
|
||||||
{
|
|
||||||
// Set functions popup menu
|
|
||||||
QMenu *menu = new QMenu(ui->functionsTreeView);
|
|
||||||
menu->clear();
|
|
||||||
menu->addAction(ui->actionDisasAdd_comment);
|
|
||||||
menu->addAction(ui->actionFunctionsRename);
|
|
||||||
menu->addAction(ui->actionFunctionsUndefine);
|
|
||||||
menu->addSeparator();
|
|
||||||
menu->addAction(ui->action_References);
|
|
||||||
|
|
||||||
menu->exec(ui->functionsTreeView->mapToGlobal(pt));
|
|
||||||
|
|
||||||
delete menu;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FunctionsWidget::on_actionDisasAdd_comment_triggered()
|
|
||||||
{
|
{
|
||||||
// Get selected item in functions tree view
|
// Get selected item in functions tree view
|
||||||
FunctionDescription function = ui->functionsTreeView->selectionModel()->currentIndex().data(
|
FunctionDescription function = ui->treeView->selectionModel()->currentIndex().data(
|
||||||
FunctionModel::FunctionDescriptionRole).value<FunctionDescription>();
|
|
||||||
|
|
||||||
// Create dialog
|
|
||||||
CommentsDialog c(this);
|
|
||||||
|
|
||||||
if (c.exec()) {
|
|
||||||
// Get new function name
|
|
||||||
QString comment = c.getComment();
|
|
||||||
// Rename function in r2 core
|
|
||||||
Core()->setComment(function.offset, comment);
|
|
||||||
// Seek to new renamed function
|
|
||||||
Core()->seekAndShow(function.offset);
|
|
||||||
// TODO: Refresh functions tree widget
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FunctionsWidget::on_actionFunctionsRename_triggered()
|
|
||||||
{
|
|
||||||
// Get selected item in functions tree view
|
|
||||||
FunctionDescription function = ui->functionsTreeView->selectionModel()->currentIndex().data(
|
|
||||||
FunctionModel::FunctionDescriptionRole).value<FunctionDescription>();
|
FunctionModel::FunctionDescriptionRole).value<FunctionDescription>();
|
||||||
|
|
||||||
// Create dialog
|
// Create dialog
|
||||||
@ -585,76 +545,55 @@ void FunctionsWidget::on_actionFunctionsRename_triggered()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FunctionsWidget::on_actionFunctionsUndefine_triggered()
|
|
||||||
{
|
|
||||||
FunctionDescription function = ui->functionsTreeView->selectionModel()->currentIndex().data(
|
|
||||||
FunctionModel::FunctionDescriptionRole).value<FunctionDescription>();
|
|
||||||
Core()->delFunction(function.offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FunctionsWidget::on_action_References_triggered()
|
void FunctionsWidget::onActionFunctionsUndefineTriggered()
|
||||||
{
|
{
|
||||||
// Get selected item in functions tree view
|
const auto selection = ui->treeView->selectionModel()->selection().indexes();
|
||||||
FunctionDescription function = ui->functionsTreeView->selectionModel()->currentIndex().data(
|
std::vector<RVA> offsets;
|
||||||
FunctionModel::FunctionDescriptionRole).value<FunctionDescription>();
|
offsets.reserve(selection.size());
|
||||||
XrefsDialog x(nullptr);
|
for (const auto &index : selection) {
|
||||||
x.fillRefsForAddress(function.offset, function.name, true);
|
offsets.push_back(functionProxyModel->address(index));
|
||||||
x.exec();
|
}
|
||||||
|
for (RVA offset : offsets) {
|
||||||
|
Core()->delFunction(offset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FunctionsWidget::showTitleContextMenu(const QPoint &pt)
|
void FunctionsWidget::showTitleContextMenu(const QPoint &pt)
|
||||||
{
|
{
|
||||||
// Set functions popup menu
|
titleContextMenu->exec(this->mapToGlobal(pt));
|
||||||
QMenu *menu = new QMenu(this);
|
}
|
||||||
menu->clear();
|
|
||||||
menu->addAction(ui->actionHorizontal);
|
|
||||||
menu->addAction(ui->actionVertical);
|
|
||||||
|
|
||||||
if (!functionModel->isNested()) {
|
void FunctionsWidget::onActionHorizontalToggled(bool enable)
|
||||||
ui->actionHorizontal->setChecked(true);
|
{
|
||||||
ui->actionVertical->setChecked(false);
|
if (enable) {
|
||||||
} else {
|
functionModel->setNested(false);
|
||||||
ui->actionVertical->setChecked(true);
|
ui->treeView->setIndentation(8);
|
||||||
ui->actionHorizontal->setChecked(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this->setContextMenuPolicy(Qt::CustomContextMenu);
|
|
||||||
|
|
||||||
menu->exec(this->mapToGlobal(pt));
|
|
||||||
delete menu;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FunctionsWidget::on_actionHorizontal_triggered()
|
void FunctionsWidget::onActionVerticalToggled(bool enable)
|
||||||
{
|
{
|
||||||
functionModel->setNested(false);
|
if (enable) {
|
||||||
ui->functionsTreeView->setIndentation(8);
|
functionModel->setNested(true);
|
||||||
}
|
ui->treeView->setIndentation(20);
|
||||||
|
}
|
||||||
void FunctionsWidget::on_actionVertical_triggered()
|
|
||||||
{
|
|
||||||
functionModel->setNested(true);
|
|
||||||
ui->functionsTreeView->setIndentation(20);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FunctionsWidget::resizeEvent(QResizeEvent *event)
|
void FunctionsWidget::resizeEvent(QResizeEvent *event)
|
||||||
{
|
{
|
||||||
if (main->responsive && isVisible()) {
|
if (mainWindow->responsive && isVisible()) {
|
||||||
if (event->size().width() >= event->size().height()) {
|
if (event->size().width() >= event->size().height()) {
|
||||||
// Set horizontal view (list)
|
// Set horizontal view (list)
|
||||||
on_actionHorizontal_triggered();
|
actionHorizontal.setChecked(true);
|
||||||
} else {
|
} else {
|
||||||
// Set vertical view (Tree)
|
// Set vertical view (Tree)
|
||||||
on_actionVertical_triggered();
|
actionVertical.setChecked(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
QDockWidget::resizeEvent(event);
|
QDockWidget::resizeEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FunctionsWidget::setScrollMode()
|
|
||||||
{
|
|
||||||
qhelpers::setVerticalScrollMode(ui->functionsTreeView);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief a SLOT to set the stylesheet for a tooltip
|
* @brief a SLOT to set the stylesheet for a tooltip
|
||||||
*/
|
*/
|
||||||
|
@ -3,24 +3,15 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include <QSortFilterProxyModel>
|
|
||||||
|
|
||||||
#include "core/Cutter.h"
|
#include "core/Cutter.h"
|
||||||
#include "CutterDockWidget.h"
|
#include "CutterDockWidget.h"
|
||||||
#include "CutterTreeWidget.h"
|
#include "widgets/ListDockWidget.h"
|
||||||
#include "CutterTreeView.h"
|
|
||||||
|
|
||||||
class MainWindow;
|
class MainWindow;
|
||||||
class QTreeWidgetItem;
|
|
||||||
class FunctionsTask;
|
class FunctionsTask;
|
||||||
class FunctionsWidget;
|
class FunctionsWidget;
|
||||||
|
|
||||||
namespace Ui {
|
class FunctionModel : public AddressableItemModel<>
|
||||||
class FunctionsWidget;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class FunctionModel : public QAbstractItemModel
|
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -53,14 +44,15 @@ public:
|
|||||||
FunctionModel(QList<FunctionDescription> *functions, QSet<RVA> *importAddresses, ut64 *mainAdress,
|
FunctionModel(QList<FunctionDescription> *functions, QSet<RVA> *importAddresses, ut64 *mainAdress,
|
||||||
bool nested, QFont defaultFont, QFont highlightFont, QObject *parent = nullptr);
|
bool nested, QFont defaultFont, QFont highlightFont, QObject *parent = nullptr);
|
||||||
|
|
||||||
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
|
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
|
||||||
QModelIndex parent(const QModelIndex &index) const;
|
QModelIndex parent(const QModelIndex &index) const override;
|
||||||
|
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
|
||||||
QVariant data(const QModelIndex &index, int role) const;
|
QVariant data(const QModelIndex &index, int role) const override;
|
||||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
QVariant headerData(int section, Qt::Orientation orientation,
|
||||||
|
int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true if the index changed
|
* @return true if the index changed
|
||||||
@ -73,13 +65,15 @@ public:
|
|||||||
return nested;
|
return nested;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RVA address(const QModelIndex &index) const override;
|
||||||
|
QString name(const QModelIndex &index) const override;
|
||||||
private slots:
|
private slots:
|
||||||
void seekChanged(RVA addr);
|
void seekChanged(RVA addr);
|
||||||
void functionRenamed(const QString &prev_name, const QString &new_name);
|
void functionRenamed(const QString &prev_name, const QString &new_name);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class FunctionSortFilterProxyModel : public QSortFilterProxyModel
|
class FunctionSortFilterProxyModel : public AddressableFilterProxyModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -93,24 +87,20 @@ protected:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
class FunctionsWidget : public CutterDockWidget
|
class FunctionsWidget : public ListDockWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit FunctionsWidget(MainWindow *main, QAction *action = nullptr);
|
explicit FunctionsWidget(MainWindow *main, QAction *action = nullptr);
|
||||||
~FunctionsWidget();
|
~FunctionsWidget() override;
|
||||||
void changeSizePolicy(QSizePolicy::Policy hor, QSizePolicy::Policy ver);
|
void changeSizePolicy(QSizePolicy::Policy hor, QSizePolicy::Policy ver);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onFunctionsDoubleClicked(const QModelIndex &index);
|
void onActionFunctionsRenameTriggered();
|
||||||
void showFunctionsContextMenu(const QPoint &pt);
|
void onActionFunctionsUndefineTriggered();
|
||||||
void on_actionDisasAdd_comment_triggered();
|
void onActionHorizontalToggled(bool enable);
|
||||||
void on_actionFunctionsRename_triggered();
|
void onActionVerticalToggled(bool enable);
|
||||||
void on_action_References_triggered();
|
|
||||||
void on_actionFunctionsUndefine_triggered();
|
|
||||||
void on_actionHorizontal_triggered();
|
|
||||||
void on_actionVertical_triggered();
|
|
||||||
void showTitleContextMenu(const QPoint &pt);
|
void showTitleContextMenu(const QPoint &pt);
|
||||||
void setTooltipStylesheet();
|
void setTooltipStylesheet();
|
||||||
void refreshTree();
|
void refreshTree();
|
||||||
@ -119,16 +109,19 @@ protected:
|
|||||||
void resizeEvent(QResizeEvent *event) override;
|
void resizeEvent(QResizeEvent *event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<Ui::FunctionsWidget> ui;
|
|
||||||
MainWindow *main;
|
|
||||||
QSharedPointer<FunctionsTask> task;
|
QSharedPointer<FunctionsTask> task;
|
||||||
QList<FunctionDescription> functions;
|
QList<FunctionDescription> functions;
|
||||||
QSet<RVA> importAddresses;
|
QSet<RVA> importAddresses;
|
||||||
ut64 mainAdress;
|
ut64 mainAdress;
|
||||||
FunctionModel *functionModel;
|
FunctionModel *functionModel;
|
||||||
FunctionSortFilterProxyModel *functionProxyModel;
|
FunctionSortFilterProxyModel *functionProxyModel;
|
||||||
CutterTreeWidget *tree;
|
|
||||||
void setScrollMode();
|
QMenu *titleContextMenu;
|
||||||
|
|
||||||
|
QAction actionRename;
|
||||||
|
QAction actionUndefine;
|
||||||
|
QAction actionHorizontal;
|
||||||
|
QAction actionVertical;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // FUNCTIONSWIDGET_H
|
#endif // FUNCTIONSWIDGET_H
|
||||||
|
@ -1,146 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<class>FunctionsWidget</class>
|
|
||||||
<widget class="QDockWidget" name="FunctionsWidget">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>289</width>
|
|
||||||
<height>359</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="styleSheet">
|
|
||||||
<string notr="true"/>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string notr="true">Functions</string>
|
|
||||||
</property>
|
|
||||||
<widget class="QWidget" name="dockWidgetContents">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
|
||||||
<horstretch>1</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>200</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
|
||||||
<property name="spacing">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<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="functionsTreeView">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Ignored" vsizetype="Expanding">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="contextMenuPolicy">
|
|
||||||
<enum>Qt::CustomContextMenu</enum>
|
|
||||||
</property>
|
|
||||||
<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="sizeAdjustPolicy">
|
|
||||||
<enum>QAbstractScrollArea::AdjustToContents</enum>
|
|
||||||
</property>
|
|
||||||
<property name="indentation">
|
|
||||||
<number>8</number>
|
|
||||||
</property>
|
|
||||||
<property name="sortingEnabled">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QuickFilterView" name="quickFilterView" native="true"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<action name="actionDisasAdd_comment">
|
|
||||||
<property name="text">
|
|
||||||
<string>Add comment</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionFunctionsRename">
|
|
||||||
<property name="text">
|
|
||||||
<string>Rename</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionFunctionsUndefine">
|
|
||||||
<property name="text">
|
|
||||||
<string>Undefine</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="action_References">
|
|
||||||
<property name="text">
|
|
||||||
<string>X-Refs</string>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Cross references</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionHorizontal">
|
|
||||||
<property name="checkable">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Horizontal</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionVertical">
|
|
||||||
<property name="checkable">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Vertical</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
</widget>
|
|
||||||
<customwidgets>
|
|
||||||
<customwidget>
|
|
||||||
<class>CutterTreeView</class>
|
|
||||||
<extends>QTreeView</extends>
|
|
||||||
<header>widgets/CutterTreeView.h</header>
|
|
||||||
<container>1</container>
|
|
||||||
</customwidget>
|
|
||||||
<customwidget>
|
|
||||||
<class>QuickFilterView</class>
|
|
||||||
<extends>QWidget</extends>
|
|
||||||
<header>widgets/QuickFilterView.h</header>
|
|
||||||
<container>1</container>
|
|
||||||
</customwidget>
|
|
||||||
</customwidgets>
|
|
||||||
<resources/>
|
|
||||||
<connections/>
|
|
||||||
</ui>
|
|
@ -1,10 +1,10 @@
|
|||||||
#include "HeadersWidget.h"
|
#include "HeadersWidget.h"
|
||||||
#include "ui_HeadersWidget.h"
|
#include "ui_ListDockWidget.h"
|
||||||
#include "core/MainWindow.h"
|
#include "core/MainWindow.h"
|
||||||
#include "common/Helpers.h"
|
#include "common/Helpers.h"
|
||||||
|
|
||||||
HeadersModel::HeadersModel(QList<HeaderDescription> *headers, QObject *parent)
|
HeadersModel::HeadersModel(QList<HeaderDescription> *headers, QObject *parent)
|
||||||
: QAbstractListModel(parent),
|
: AddressableItemModel<QAbstractListModel>(parent),
|
||||||
headers(headers)
|
headers(headers)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -64,10 +64,21 @@ QVariant HeadersModel::headerData(int section, Qt::Orientation, int role) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HeadersProxyModel::HeadersProxyModel(HeadersModel *sourceModel, QObject *parent)
|
RVA HeadersModel::address(const QModelIndex &index) const
|
||||||
: QSortFilterProxyModel(parent)
|
{
|
||||||
|
const HeaderDescription &header = headers->at(index.row());
|
||||||
|
return header.vaddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString HeadersModel::name(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
const HeaderDescription &header = headers->at(index.row());
|
||||||
|
return header.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
HeadersProxyModel::HeadersProxyModel(HeadersModel *sourceModel, QObject *parent)
|
||||||
|
: AddressableFilterProxyModel(sourceModel, parent)
|
||||||
{
|
{
|
||||||
setSourceModel(sourceModel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HeadersProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) const
|
bool HeadersProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) const
|
||||||
@ -99,17 +110,18 @@ bool HeadersProxyModel::lessThan(const QModelIndex &left, const QModelIndex &rig
|
|||||||
}
|
}
|
||||||
|
|
||||||
HeadersWidget::HeadersWidget(MainWindow *main, QAction *action) :
|
HeadersWidget::HeadersWidget(MainWindow *main, QAction *action) :
|
||||||
CutterDockWidget(main, action),
|
ListDockWidget(main, action)
|
||||||
ui(new Ui::HeadersWidget)
|
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
setWindowTitle(tr("Headers"));
|
||||||
|
setObjectName("HeadersWidget");
|
||||||
|
|
||||||
headersModel = new HeadersModel(&headers, this);
|
headersModel = new HeadersModel(&headers, this);
|
||||||
headersProxyModel = new HeadersProxyModel(headersModel, this);
|
headersProxyModel = new HeadersProxyModel(headersModel, this);
|
||||||
ui->headersTreeView->setModel(headersProxyModel);
|
setModels(headersProxyModel);
|
||||||
ui->headersTreeView->sortByColumn(HeadersModel::OffsetColumn, Qt::AscendingOrder);
|
ui->treeView->sortByColumn(HeadersModel::OffsetColumn, Qt::AscendingOrder);
|
||||||
|
|
||||||
setScrollMode();
|
ui->quickFilterView->closeFilter();
|
||||||
|
showCount(false);
|
||||||
|
|
||||||
connect(Core(), &CutterCore::refreshAll, this, &HeadersWidget::refreshHeaders);
|
connect(Core(), &CutterCore::refreshAll, this, &HeadersWidget::refreshHeaders);
|
||||||
}
|
}
|
||||||
@ -122,17 +134,6 @@ void HeadersWidget::refreshHeaders()
|
|||||||
headers = Core()->getAllHeaders();
|
headers = Core()->getAllHeaders();
|
||||||
headersModel->endResetModel();
|
headersModel->endResetModel();
|
||||||
|
|
||||||
ui->headersTreeView->resizeColumnToContents(0);
|
ui->treeView->resizeColumnToContents(0);
|
||||||
ui->headersTreeView->resizeColumnToContents(1);
|
ui->treeView->resizeColumnToContents(1);
|
||||||
}
|
|
||||||
|
|
||||||
void HeadersWidget::setScrollMode()
|
|
||||||
{
|
|
||||||
qhelpers::setVerticalScrollMode(ui->headersTreeView);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HeadersWidget::on_headersTreeView_doubleClicked(const QModelIndex &index)
|
|
||||||
{
|
|
||||||
HeaderDescription item = index.data(HeadersModel::HeaderDescriptionRole).value<HeaderDescription>();
|
|
||||||
Core()->seekAndShow(item.vaddr);
|
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "core/Cutter.h"
|
#include "core/Cutter.h"
|
||||||
#include "CutterDockWidget.h"
|
#include "ListDockWidget.h"
|
||||||
|
|
||||||
#include <QAbstractListModel>
|
#include <QAbstractListModel>
|
||||||
#include <QSortFilterProxyModel>
|
#include <QSortFilterProxyModel>
|
||||||
@ -22,7 +22,7 @@ class QTreeWidgetItem;
|
|||||||
class HeadersWidget;
|
class HeadersWidget;
|
||||||
|
|
||||||
|
|
||||||
class HeadersModel: public QAbstractListModel
|
class HeadersModel: public AddressableItemModel<QAbstractListModel>
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -35,18 +35,21 @@ public:
|
|||||||
enum Column { OffsetColumn = 0, NameColumn, ValueColumn, ColumnCount };
|
enum Column { OffsetColumn = 0, NameColumn, ValueColumn, ColumnCount };
|
||||||
enum Role { HeaderDescriptionRole = Qt::UserRole };
|
enum Role { HeaderDescriptionRole = Qt::UserRole };
|
||||||
|
|
||||||
HeadersModel(QList<HeaderDescription> *headers, QObject *parent = 0);
|
HeadersModel(QList<HeaderDescription> *headers, QObject *parent = nullptr);
|
||||||
|
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
|
||||||
QVariant data(const QModelIndex &index, int role) const;
|
QVariant data(const QModelIndex &index, int role) const override;
|
||||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
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 HeadersProxyModel : public QSortFilterProxyModel
|
class HeadersProxyModel : public AddressableFilterProxyModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -60,7 +63,7 @@ protected:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
class HeadersWidget : public CutterDockWidget
|
class HeadersWidget : public ListDockWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -69,18 +72,12 @@ public:
|
|||||||
~HeadersWidget();
|
~HeadersWidget();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void on_headersTreeView_doubleClicked(const QModelIndex &index);
|
|
||||||
|
|
||||||
void refreshHeaders();
|
void refreshHeaders();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<Ui::HeadersWidget> ui;
|
|
||||||
|
|
||||||
HeadersModel *headersModel;
|
HeadersModel *headersModel;
|
||||||
HeadersProxyModel *headersProxyModel;
|
HeadersProxyModel *headersProxyModel;
|
||||||
QList<HeaderDescription> headers;
|
QList<HeaderDescription> headers;
|
||||||
|
|
||||||
void setScrollMode();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,66 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<class>HeadersWidget</class>
|
|
||||||
<widget class="QDockWidget" name="HeadersWidget">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>400</width>
|
|
||||||
<height>300</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string notr="true">Headers</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="headersTreeView">
|
|
||||||
<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>
|
|
@ -1,5 +1,5 @@
|
|||||||
#include "ImportsWidget.h"
|
#include "ImportsWidget.h"
|
||||||
#include "ui_ImportsWidget.h"
|
#include "ui_ListDockWidget.h"
|
||||||
#include "WidgetShortcuts.h"
|
#include "WidgetShortcuts.h"
|
||||||
#include "core/MainWindow.h"
|
#include "core/MainWindow.h"
|
||||||
#include "common/Helpers.h"
|
#include "common/Helpers.h"
|
||||||
@ -10,7 +10,7 @@
|
|||||||
#include <QTreeWidget>
|
#include <QTreeWidget>
|
||||||
|
|
||||||
ImportsModel::ImportsModel(QList<ImportDescription> *imports, QObject *parent) :
|
ImportsModel::ImportsModel(QList<ImportDescription> *imports, QObject *parent) :
|
||||||
QAbstractTableModel(parent),
|
AddressableItemModel(parent),
|
||||||
imports(imports)
|
imports(imports)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
@ -81,10 +81,21 @@ QVariant ImportsModel::headerData(int section, Qt::Orientation, int role) const
|
|||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImportsProxyModel::ImportsProxyModel(ImportsModel *sourceModel, QObject *parent)
|
RVA ImportsModel::address(const QModelIndex &index) const
|
||||||
: QSortFilterProxyModel(parent)
|
{
|
||||||
|
const ImportDescription &import = imports->at(index.row());
|
||||||
|
return import.plt;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ImportsModel::name(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
const ImportDescription &import = imports->at(index.row());
|
||||||
|
return import.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImportsProxyModel::ImportsProxyModel(ImportsModel *sourceModel, QObject *parent)
|
||||||
|
: AddressableFilterProxyModel(sourceModel, parent)
|
||||||
{
|
{
|
||||||
setSourceModel(sourceModel);
|
|
||||||
setFilterCaseSensitivity(Qt::CaseInsensitive);
|
setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||||
setSortCaseSensitivity(Qt::CaseInsensitive);
|
setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||||
}
|
}
|
||||||
@ -129,46 +140,21 @@ bool ImportsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &rig
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
ImportsWidget::ImportsWidget(MainWindow *main, QAction *action) :
|
ImportsWidget::ImportsWidget(MainWindow *main, QAction *action) :
|
||||||
CutterDockWidget(main, action),
|
ListDockWidget(main, action),
|
||||||
ui(new Ui::ImportsWidget),
|
|
||||||
importsModel(new ImportsModel(&imports, this)),
|
importsModel(new ImportsModel(&imports, this)),
|
||||||
importsProxyModel(new ImportsProxyModel(importsModel, this)),
|
importsProxyModel(new ImportsProxyModel(importsModel, this))
|
||||||
tree(new CutterTreeWidget(this))
|
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
setWindowTitle(tr("Imports"));
|
||||||
|
setObjectName("ImportsWidget");
|
||||||
// Add Status Bar footer
|
|
||||||
tree->addStatusBar(ui->verticalLayout);
|
|
||||||
|
|
||||||
ui->importsTreeView->setModel(importsProxyModel);
|
|
||||||
ui->importsTreeView->sortByColumn(ImportsModel::NameColumn, Qt::AscendingOrder);
|
|
||||||
|
|
||||||
|
setModels(importsProxyModel);
|
||||||
|
ui->treeView->sortByColumn(ImportsModel::NameColumn, Qt::AscendingOrder);
|
||||||
QShortcut *toggle_shortcut = new QShortcut(widgetShortcuts["ImportsWidget"], main);
|
QShortcut *toggle_shortcut = new QShortcut(widgetShortcuts["ImportsWidget"], main);
|
||||||
connect(toggle_shortcut, &QShortcut::activated, this, [=] (){
|
connect(toggle_shortcut, &QShortcut::activated, this, [=] (){
|
||||||
toggleDockWidget(true);
|
toggleDockWidget(true);
|
||||||
main->updateDockActionChecked(action);
|
main->updateDockActionChecked(action);
|
||||||
} );
|
} );
|
||||||
|
|
||||||
// Ctrl-F to show/hide the filter entry
|
|
||||||
QShortcut *searchShortcut = new QShortcut(QKeySequence::Find, this);
|
|
||||||
connect(searchShortcut, &QShortcut::activated, ui->quickFilterView, &QuickFilterView::showFilter);
|
|
||||||
searchShortcut->setContext(Qt::WidgetWithChildrenShortcut);
|
|
||||||
|
|
||||||
// Esc to clear the filter entry
|
|
||||||
QShortcut *clearShortcut = new QShortcut(QKeySequence(Qt::Key_Escape), this);
|
|
||||||
connect(clearShortcut, &QShortcut::activated, ui->quickFilterView, &QuickFilterView::clearFilter);
|
|
||||||
clearShortcut->setContext(Qt::WidgetWithChildrenShortcut);
|
|
||||||
|
|
||||||
connect(ui->quickFilterView, SIGNAL(filterTextChanged(const QString &)),
|
|
||||||
importsProxyModel, SLOT(setFilterWildcard(const QString &)));
|
|
||||||
connect(ui->quickFilterView, SIGNAL(filterClosed()), ui->importsTreeView, SLOT(setFocus()));
|
|
||||||
|
|
||||||
connect(ui->quickFilterView, &QuickFilterView::filterTextChanged, this, [this] {
|
|
||||||
tree->showItemsNumber(importsProxyModel->rowCount());
|
|
||||||
});
|
|
||||||
|
|
||||||
setScrollMode();
|
|
||||||
|
|
||||||
connect(Core(), SIGNAL(refreshAll()), this, SLOT(refreshImports()));
|
connect(Core(), SIGNAL(refreshAll()), this, SLOT(refreshImports()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,20 +165,5 @@ void ImportsWidget::refreshImports()
|
|||||||
importsModel->beginResetModel();
|
importsModel->beginResetModel();
|
||||||
imports = Core()->getAllImports();
|
imports = Core()->getAllImports();
|
||||||
importsModel->endResetModel();
|
importsModel->endResetModel();
|
||||||
qhelpers::adjustColumns(ui->importsTreeView, 4, 0);
|
qhelpers::adjustColumns(ui->treeView, 4, 0);
|
||||||
|
|
||||||
tree->showItemsNumber(importsProxyModel->rowCount());
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImportsWidget::setScrollMode()
|
|
||||||
{
|
|
||||||
qhelpers::setVerticalScrollMode(ui->importsTreeView);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImportsWidget::on_importsTreeView_doubleClicked(const QModelIndex &index)
|
|
||||||
{
|
|
||||||
if (!index.isValid())
|
|
||||||
return;
|
|
||||||
|
|
||||||
Core()->seekAndShow(index.data(ImportsModel::AddressRole).toLongLong());
|
|
||||||
}
|
}
|
||||||
|
@ -11,17 +11,14 @@
|
|||||||
|
|
||||||
#include "CutterDockWidget.h"
|
#include "CutterDockWidget.h"
|
||||||
#include "core/Cutter.h"
|
#include "core/Cutter.h"
|
||||||
#include "CutterTreeWidget.h"
|
#include "widgets/ListDockWidget.h"
|
||||||
|
#include "common/AddressableItemModel.h"
|
||||||
|
|
||||||
class MainWindow;
|
class MainWindow;
|
||||||
class QTreeWidget;
|
class QTreeWidget;
|
||||||
class ImportsWidget;
|
class ImportsWidget;
|
||||||
|
|
||||||
namespace Ui {
|
class ImportsModel : public AddressableItemModel<QAbstractTableModel>
|
||||||
class ImportsWidget;
|
|
||||||
}
|
|
||||||
|
|
||||||
class ImportsModel : public QAbstractTableModel
|
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -51,14 +48,17 @@ public:
|
|||||||
|
|
||||||
ImportsModel(QList<ImportDescription> *imports, QObject *parent = nullptr);
|
ImportsModel(QList<ImportDescription> *imports, QObject *parent = nullptr);
|
||||||
|
|
||||||
int rowCount(const QModelIndex &parent) const;
|
int rowCount(const QModelIndex &parent) const override;
|
||||||
int columnCount(const QModelIndex &parent) const;
|
int columnCount(const QModelIndex &parent) const override;
|
||||||
|
|
||||||
QVariant data(const QModelIndex &index, int role) const;
|
QVariant data(const QModelIndex &index, int role) const override;
|
||||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
|
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
||||||
|
|
||||||
|
RVA address(const QModelIndex &index) const override;
|
||||||
|
QString name(const QModelIndex &index) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ImportsProxyModel : public QSortFilterProxyModel
|
class ImportsProxyModel : public AddressableFilterProxyModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -70,7 +70,7 @@ protected:
|
|||||||
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
|
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ImportsWidget : public CutterDockWidget
|
class ImportsWidget : public ListDockWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -79,20 +79,13 @@ public:
|
|||||||
~ImportsWidget();
|
~ImportsWidget();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void on_importsTreeView_doubleClicked(const QModelIndex &index);
|
|
||||||
|
|
||||||
void refreshImports();
|
void refreshImports();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<Ui::ImportsWidget> ui;
|
|
||||||
|
|
||||||
ImportsModel *importsModel;
|
ImportsModel *importsModel;
|
||||||
ImportsProxyModel *importsProxyModel;
|
ImportsProxyModel *importsProxyModel;
|
||||||
QList<ImportDescription> imports;
|
QList<ImportDescription> imports;
|
||||||
CutterTreeWidget *tree;
|
|
||||||
|
|
||||||
void highlightUnsafe();
|
void highlightUnsafe();
|
||||||
void setScrollMode();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // IMPORTSWIDGET_H
|
#endif // IMPORTSWIDGET_H
|
||||||
|
@ -1,75 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<class>ImportsWidget</class>
|
|
||||||
<widget class="QDockWidget" name="ImportsWidget">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>400</width>
|
|
||||||
<height>300</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string notr="true">Imports</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="importsTreeView">
|
|
||||||
<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>
|
|
||||||
<item>
|
|
||||||
<widget class="QuickFilterView" name="quickFilterView" native="true"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</widget>
|
|
||||||
<customwidgets>
|
|
||||||
<customwidget>
|
|
||||||
<class>CutterTreeView</class>
|
|
||||||
<extends>QTreeView</extends>
|
|
||||||
<header>widgets/CutterTreeView.h</header>
|
|
||||||
<container>1</container>
|
|
||||||
</customwidget>
|
|
||||||
<customwidget>
|
|
||||||
<class>QuickFilterView</class>
|
|
||||||
<extends>QWidget</extends>
|
|
||||||
<header>widgets/QuickFilterView.h</header>
|
|
||||||
<container>1</container>
|
|
||||||
</customwidget>
|
|
||||||
</customwidgets>
|
|
||||||
<resources/>
|
|
||||||
<connections/>
|
|
||||||
</ui>
|
|
118
src/widgets/ListDockWidget.cpp
Normal file
118
src/widgets/ListDockWidget.cpp
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
#include "ListDockWidget.h"
|
||||||
|
#include "ui_ListDockWidget.h"
|
||||||
|
#include "core/MainWindow.h"
|
||||||
|
#include "common/Helpers.h"
|
||||||
|
#include "menus/AddressableItemContextMenu.h"
|
||||||
|
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QResizeEvent>
|
||||||
|
#include <QShortcut>
|
||||||
|
|
||||||
|
ListDockWidget::ListDockWidget(MainWindow *main, QAction *action, SearchBarPolicy searchBarPolicy) :
|
||||||
|
CutterDockWidget(main, action),
|
||||||
|
ui(new Ui::ListDockWidget),
|
||||||
|
tree(new CutterTreeWidget(this)),
|
||||||
|
searchBarPolicy(searchBarPolicy)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
// Add Status Bar footer
|
||||||
|
tree->addStatusBar(ui->verticalLayout);
|
||||||
|
|
||||||
|
if (searchBarPolicy != SearchBarPolicy::Hide) {
|
||||||
|
// Ctrl-F to show/hide the filter entry
|
||||||
|
QShortcut *searchShortcut = new QShortcut(QKeySequence::Find, this);
|
||||||
|
connect(searchShortcut, &QShortcut::activated, ui->quickFilterView, &QuickFilterView::showFilter);
|
||||||
|
searchShortcut->setContext(Qt::WidgetWithChildrenShortcut);
|
||||||
|
|
||||||
|
// Esc to clear the filter entry
|
||||||
|
QShortcut *clearShortcut = new QShortcut(QKeySequence(Qt::Key_Escape), this);
|
||||||
|
connect(clearShortcut, &QShortcut::activated, [this]() {
|
||||||
|
ui->quickFilterView->clearFilter();
|
||||||
|
ui->treeView->setFocus();
|
||||||
|
});
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (searchBarPolicy != SearchBarPolicy::ShowByDefault) {
|
||||||
|
ui->quickFilterView->closeFilter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ListDockWidget::~ListDockWidget() {}
|
||||||
|
|
||||||
|
void ListDockWidget::showCount(bool show)
|
||||||
|
{
|
||||||
|
tree->showStatusBar(show);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ListDockWidget::setModels(AddressableFilterProxyModel *objectFilterProxyModel)
|
||||||
|
{
|
||||||
|
this->objectFilterProxyModel = objectFilterProxyModel;
|
||||||
|
|
||||||
|
ui->treeView->setModel(objectFilterProxyModel);
|
||||||
|
|
||||||
|
|
||||||
|
connect(ui->quickFilterView, &QuickFilterView::filterTextChanged,
|
||||||
|
objectFilterProxyModel, &QSortFilterProxyModel::setFilterWildcard);
|
||||||
|
connect(ui->quickFilterView, &QuickFilterView::filterClosed, ui->treeView,
|
||||||
|
static_cast<void(QWidget::*)()>(&QWidget::setFocus));
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
57
src/widgets/ListDockWidget.h
Normal file
57
src/widgets/ListDockWidget.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#ifndef LISTDOCKWIDGET_H
|
||||||
|
#define LISTDOCKWIDGET_H
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <QAbstractItemModel>
|
||||||
|
#include <QSortFilterProxyModel>
|
||||||
|
#include <QMenu>
|
||||||
|
|
||||||
|
#include "core/Cutter.h"
|
||||||
|
#include "common/AddressableItemModel.h"
|
||||||
|
#include "CutterDockWidget.h"
|
||||||
|
#include "CutterTreeWidget.h"
|
||||||
|
#include "menus/AddressableItemContextMenu.h"
|
||||||
|
|
||||||
|
class MainWindow;
|
||||||
|
class QTreeWidgetItem;
|
||||||
|
class CommentsWidget;
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class ListDockWidget;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ListDockWidget : public CutterDockWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum class SearchBarPolicy {
|
||||||
|
ShowByDefault,
|
||||||
|
HideByDefault,
|
||||||
|
Hide,
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit ListDockWidget(MainWindow *main, QAction *action = nullptr, SearchBarPolicy searchBarPolicy = SearchBarPolicy::ShowByDefault);
|
||||||
|
~ListDockWidget() override;
|
||||||
|
|
||||||
|
void showCount(bool show);
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // LISTDOCKWIDGET_H
|
@ -1,20 +1,20 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<ui version="4.0">
|
<ui version="4.0">
|
||||||
<class>RelocsWidget</class>
|
<class>ListDockWidget</class>
|
||||||
<widget class="QDockWidget" name="RelocsWidget">
|
<widget class="QDockWidget" name="ListDockWidget">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>400</width>
|
<width>645</width>
|
||||||
<height>300</height>
|
<height>250</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
|
||||||
<string notr="true">Relocs</string>
|
|
||||||
</property>
|
|
||||||
<widget class="QWidget" name="dockWidgetContents">
|
<widget class="QWidget" name="dockWidgetContents">
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
<property name="leftMargin">
|
<property name="leftMargin">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
@ -28,7 +28,7 @@
|
|||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<widget class="CutterTreeView" name="relocsTreeView">
|
<widget class="CutterTreeView" name="treeView">
|
||||||
<property name="styleSheet">
|
<property name="styleSheet">
|
||||||
<string notr="true">CutterTreeView::item
|
<string notr="true">CutterTreeView::item
|
||||||
{
|
{
|
||||||
@ -45,6 +45,9 @@
|
|||||||
<property name="sortingEnabled">
|
<property name="sortingEnabled">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
|
<attribute name="headerShowSortIndicator" stdset="0">
|
||||||
|
<bool>true</bool>
|
||||||
|
</attribute>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
@ -1,5 +1,5 @@
|
|||||||
#include "RelocsWidget.h"
|
#include "RelocsWidget.h"
|
||||||
#include "ui_RelocsWidget.h"
|
#include "ui_ListDockWidget.h"
|
||||||
#include "core/MainWindow.h"
|
#include "core/MainWindow.h"
|
||||||
#include "common/Helpers.h"
|
#include "common/Helpers.h"
|
||||||
|
|
||||||
@ -7,7 +7,7 @@
|
|||||||
#include <QTreeWidget>
|
#include <QTreeWidget>
|
||||||
|
|
||||||
RelocsModel::RelocsModel(QList<RelocDescription> *relocs, QObject *parent) :
|
RelocsModel::RelocsModel(QList<RelocDescription> *relocs, QObject *parent) :
|
||||||
QAbstractTableModel(parent),
|
AddressableItemModel<QAbstractTableModel>(parent),
|
||||||
relocs(relocs)
|
relocs(relocs)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
@ -61,10 +61,21 @@ QVariant RelocsModel::headerData(int section, Qt::Orientation, int role) const
|
|||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
RelocsProxyModel::RelocsProxyModel(RelocsModel *sourceModel, QObject *parent)
|
RVA RelocsModel::address(const QModelIndex &index) const
|
||||||
: QSortFilterProxyModel(parent)
|
{
|
||||||
|
const RelocDescription &reloc = relocs->at(index.row());
|
||||||
|
return reloc.vaddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString RelocsModel::name(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
const RelocDescription &reloc = relocs->at(index.row());
|
||||||
|
return reloc.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
RelocsProxyModel::RelocsProxyModel(RelocsModel *sourceModel, QObject *parent)
|
||||||
|
: AddressableFilterProxyModel(sourceModel, parent)
|
||||||
{
|
{
|
||||||
setSourceModel(sourceModel);
|
|
||||||
setFilterCaseSensitivity(Qt::CaseInsensitive);
|
setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||||
setSortCaseSensitivity(Qt::CaseInsensitive);
|
setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||||
}
|
}
|
||||||
@ -103,64 +114,25 @@ bool RelocsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &righ
|
|||||||
}
|
}
|
||||||
|
|
||||||
RelocsWidget::RelocsWidget(MainWindow *main, QAction *action) :
|
RelocsWidget::RelocsWidget(MainWindow *main, QAction *action) :
|
||||||
CutterDockWidget(main, action),
|
ListDockWidget(main, action),
|
||||||
ui(new Ui::RelocsWidget),
|
|
||||||
relocsModel(new RelocsModel(&relocs, this)),
|
relocsModel(new RelocsModel(&relocs, this)),
|
||||||
relocsProxyModel(new RelocsProxyModel(relocsModel, this)),
|
relocsProxyModel(new RelocsProxyModel(relocsModel, this))
|
||||||
tree(new CutterTreeWidget(this))
|
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
setWindowTitle(tr("Relocs"));
|
||||||
|
setObjectName("RelocsWidget");
|
||||||
|
|
||||||
// Add Status Bar footer
|
setModels(relocsProxyModel);
|
||||||
tree->addStatusBar(ui->verticalLayout);
|
ui->treeView->sortByColumn(RelocsModel::NameColumn, Qt::AscendingOrder);
|
||||||
|
|
||||||
ui->relocsTreeView->setModel(relocsProxyModel);
|
connect(Core(), &CutterCore::refreshAll, this, &RelocsWidget::refreshRelocs);
|
||||||
ui->relocsTreeView->sortByColumn(RelocsModel::NameColumn, Qt::AscendingOrder);
|
|
||||||
|
|
||||||
// Ctrl-F to show/hide the filter entry
|
|
||||||
QShortcut *searchShortcut = new QShortcut(QKeySequence::Find, this);
|
|
||||||
connect(searchShortcut, &QShortcut::activated, ui->quickFilterView, &QuickFilterView::showFilter);
|
|
||||||
searchShortcut->setContext(Qt::WidgetWithChildrenShortcut);
|
|
||||||
|
|
||||||
// Esc to clear the filter entry
|
|
||||||
QShortcut *clearShortcut = new QShortcut(QKeySequence(Qt::Key_Escape), this);
|
|
||||||
connect(clearShortcut, &QShortcut::activated, ui->quickFilterView, &QuickFilterView::clearFilter);
|
|
||||||
clearShortcut->setContext(Qt::WidgetWithChildrenShortcut);
|
|
||||||
|
|
||||||
connect(ui->quickFilterView, SIGNAL(filterTextChanged(const QString &)),
|
|
||||||
relocsProxyModel, SLOT(setFilterWildcard(const QString &)));
|
|
||||||
connect(ui->quickFilterView, SIGNAL(filterClosed()), ui->relocsTreeView, SLOT(setFocus()));
|
|
||||||
|
|
||||||
connect(ui->quickFilterView, &QuickFilterView::filterTextChanged, this, [this] {
|
|
||||||
tree->showItemsNumber(relocsProxyModel->rowCount());
|
|
||||||
});
|
|
||||||
|
|
||||||
setScrollMode();
|
|
||||||
|
|
||||||
connect(Core(), SIGNAL(refreshAll()), this, SLOT(refreshRelocs()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RelocsWidget::~RelocsWidget() {}
|
RelocsWidget::~RelocsWidget() {}
|
||||||
|
|
||||||
void RelocsWidget::on_relocsTreeView_doubleClicked(const QModelIndex &index)
|
|
||||||
{
|
|
||||||
if (!index.isValid())
|
|
||||||
return;
|
|
||||||
|
|
||||||
Core()->seekAndShow(index.data(RelocsModel::AddressRole).toLongLong());
|
|
||||||
}
|
|
||||||
|
|
||||||
void RelocsWidget::refreshRelocs()
|
void RelocsWidget::refreshRelocs()
|
||||||
{
|
{
|
||||||
relocsModel->beginResetModel();
|
relocsModel->beginResetModel();
|
||||||
relocs = Core()->getAllRelocs();
|
relocs = Core()->getAllRelocs();
|
||||||
relocsModel->endResetModel();
|
relocsModel->endResetModel();
|
||||||
qhelpers::adjustColumns(ui->relocsTreeView, 3, 0);
|
qhelpers::adjustColumns(ui->treeView, 3, 0);
|
||||||
|
|
||||||
tree->showItemsNumber(relocsProxyModel->rowCount());
|
|
||||||
}
|
|
||||||
|
|
||||||
void RelocsWidget::setScrollMode()
|
|
||||||
{
|
|
||||||
qhelpers::setVerticalScrollMode(ui->relocsTreeView);
|
|
||||||
}
|
}
|
||||||
|
@ -7,16 +7,12 @@
|
|||||||
|
|
||||||
#include "CutterDockWidget.h"
|
#include "CutterDockWidget.h"
|
||||||
#include "core/Cutter.h"
|
#include "core/Cutter.h"
|
||||||
#include "CutterTreeWidget.h"
|
#include "widgets/ListDockWidget.h"
|
||||||
|
|
||||||
class MainWindow;
|
class MainWindow;
|
||||||
class RelocsWidget;
|
class RelocsWidget;
|
||||||
|
|
||||||
namespace Ui {
|
class RelocsModel : public AddressableItemModel<QAbstractTableModel>
|
||||||
class RelocsWidget;
|
|
||||||
}
|
|
||||||
|
|
||||||
class RelocsModel : public QAbstractTableModel
|
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -31,14 +27,17 @@ public:
|
|||||||
|
|
||||||
RelocsModel(QList<RelocDescription> *relocs, QObject *parent = nullptr);
|
RelocsModel(QList<RelocDescription> *relocs, QObject *parent = nullptr);
|
||||||
|
|
||||||
int rowCount(const QModelIndex &parent) const;
|
int rowCount(const QModelIndex &parent) const override;
|
||||||
int columnCount(const QModelIndex &parent) const;
|
int columnCount(const QModelIndex &parent) const override;
|
||||||
|
|
||||||
QVariant data(const QModelIndex &index, int role) const;
|
QVariant data(const QModelIndex &index, int role) const override;
|
||||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
|
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
||||||
|
|
||||||
|
RVA address(const QModelIndex &index) const override;
|
||||||
|
QString name(const QModelIndex &index) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RelocsProxyModel : public QSortFilterProxyModel
|
class RelocsProxyModel : public AddressableFilterProxyModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -50,7 +49,7 @@ protected:
|
|||||||
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
|
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RelocsWidget : public CutterDockWidget
|
class RelocsWidget : public ListDockWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -59,18 +58,12 @@ public:
|
|||||||
~RelocsWidget();
|
~RelocsWidget();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void on_relocsTreeView_doubleClicked(const QModelIndex &index);
|
|
||||||
void refreshRelocs();
|
void refreshRelocs();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<Ui::RelocsWidget> ui;
|
|
||||||
|
|
||||||
RelocsModel *relocsModel;
|
RelocsModel *relocsModel;
|
||||||
RelocsProxyModel *relocsProxyModel;
|
RelocsProxyModel *relocsProxyModel;
|
||||||
QList<RelocDescription> relocs;
|
QList<RelocDescription> relocs;
|
||||||
CutterTreeWidget *tree;
|
|
||||||
|
|
||||||
void setScrollMode();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // RELOCSWIDGET_H
|
#endif // RELOCSWIDGET_H
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
#include "SectionsWidget.h"
|
#include "SectionsWidget.h"
|
||||||
#include "CutterTreeView.h"
|
|
||||||
#include "QuickFilterView.h"
|
#include "QuickFilterView.h"
|
||||||
#include "core/MainWindow.h"
|
#include "core/MainWindow.h"
|
||||||
#include "common/Helpers.h"
|
#include "common/Helpers.h"
|
||||||
#include "common/Configuration.h"
|
#include "common/Configuration.h"
|
||||||
|
#include "ui_ListDockWidget.h"
|
||||||
|
|
||||||
#include <QGraphicsSceneMouseEvent>
|
#include <QGraphicsSceneMouseEvent>
|
||||||
#include <QGraphicsTextItem>
|
#include <QGraphicsTextItem>
|
||||||
@ -14,7 +14,7 @@
|
|||||||
#include <QToolTip>
|
#include <QToolTip>
|
||||||
|
|
||||||
SectionsModel::SectionsModel(QList<SectionDescription> *sections, QObject *parent)
|
SectionsModel::SectionsModel(QList<SectionDescription> *sections, QObject *parent)
|
||||||
: QAbstractListModel(parent),
|
: AddressableItemModel<QAbstractListModel>(parent),
|
||||||
sections(sections)
|
sections(sections)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -105,10 +105,21 @@ QVariant SectionsModel::headerData(int section, Qt::Orientation, int role) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SectionsProxyModel::SectionsProxyModel(SectionsModel *sourceModel, QObject *parent)
|
RVA SectionsModel::address(const QModelIndex &index) const
|
||||||
: QSortFilterProxyModel(parent)
|
{
|
||||||
|
const SectionDescription §ion = sections->at(index.row());
|
||||||
|
return section.vaddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SectionsModel::name(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
const SectionDescription §ion = sections->at(index.row());
|
||||||
|
return section.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
SectionsProxyModel::SectionsProxyModel(SectionsModel *sourceModel, QObject *parent)
|
||||||
|
: AddressableFilterProxyModel(sourceModel, parent)
|
||||||
{
|
{
|
||||||
setSourceModel(sourceModel);
|
|
||||||
setFilterCaseSensitivity(Qt::CaseInsensitive);
|
setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||||
setSortCaseSensitivity(Qt::CaseInsensitive);
|
setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||||
}
|
}
|
||||||
@ -138,8 +149,7 @@ bool SectionsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &ri
|
|||||||
}
|
}
|
||||||
|
|
||||||
SectionsWidget::SectionsWidget(MainWindow *main, QAction *action) :
|
SectionsWidget::SectionsWidget(MainWindow *main, QAction *action) :
|
||||||
CutterDockWidget(main, action),
|
ListDockWidget(main, action)
|
||||||
main(main)
|
|
||||||
{
|
{
|
||||||
setObjectName("SectionsWidget");
|
setObjectName("SectionsWidget");
|
||||||
setWindowTitle(QStringLiteral("Sections"));
|
setWindowTitle(QStringLiteral("Sections"));
|
||||||
@ -158,42 +168,22 @@ SectionsWidget::~SectionsWidget() = default;
|
|||||||
|
|
||||||
void SectionsWidget::initSectionsTable()
|
void SectionsWidget::initSectionsTable()
|
||||||
{
|
{
|
||||||
sectionsTable = new CutterTreeView;
|
|
||||||
sectionsModel = new SectionsModel(§ions, this);
|
sectionsModel = new SectionsModel(§ions, this);
|
||||||
proxyModel = new SectionsProxyModel(sectionsModel, this);
|
proxyModel = new SectionsProxyModel(sectionsModel, this);
|
||||||
|
setModels(proxyModel);
|
||||||
|
|
||||||
sectionsTable->setModel(proxyModel);
|
ui->treeView->sortByColumn(SectionsModel::NameColumn, Qt::AscendingOrder);
|
||||||
sectionsTable->setIndentation(10);
|
|
||||||
sectionsTable->setSortingEnabled(true);
|
|
||||||
sectionsTable->sortByColumn(SectionsModel::NameColumn, Qt::AscendingOrder);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SectionsWidget::initQuickFilter()
|
void SectionsWidget::initQuickFilter()
|
||||||
{
|
{
|
||||||
quickFilterView = new QuickFilterView(this, false);
|
ui->quickFilterView->closeFilter();
|
||||||
quickFilterView->setObjectName(QStringLiteral("quickFilterView"));
|
|
||||||
QSizePolicy sizePolicy1(QSizePolicy::Preferred, QSizePolicy::Maximum);
|
|
||||||
sizePolicy1.setHorizontalStretch(0);
|
|
||||||
sizePolicy1.setVerticalStretch(0);
|
|
||||||
sizePolicy1.setHeightForWidth(quickFilterView->sizePolicy().hasHeightForWidth());
|
|
||||||
quickFilterView->setSizePolicy(sizePolicy1);
|
|
||||||
|
|
||||||
QShortcut *search_shortcut = new QShortcut(QKeySequence::Find, this);
|
|
||||||
search_shortcut->setContext(Qt::WidgetWithChildrenShortcut);
|
|
||||||
connect(search_shortcut, &QShortcut::activated, quickFilterView, &QuickFilterView::showFilter);
|
|
||||||
|
|
||||||
QShortcut *clear_shortcut = new QShortcut(QKeySequence(Qt::Key_Escape), this);
|
|
||||||
clear_shortcut->setContext(Qt::WidgetWithChildrenShortcut);
|
|
||||||
connect(clear_shortcut, &QShortcut::activated, quickFilterView, &QuickFilterView::clearFilter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SectionsWidget::initAddrMapDocks()
|
void SectionsWidget::initAddrMapDocks()
|
||||||
{
|
{
|
||||||
dockWidgetContents = new QWidget(this);
|
QVBoxLayout *layout = ui->verticalLayout;
|
||||||
QVBoxLayout *layout = new QVBoxLayout();
|
showCount(false);
|
||||||
|
|
||||||
layout->addWidget(sectionsTable);
|
|
||||||
layout->addWidget(quickFilterView);
|
|
||||||
|
|
||||||
rawAddrDock = new RawAddrDock(sectionsModel, this);
|
rawAddrDock = new RawAddrDock(sectionsModel, this);
|
||||||
virtualAddrDock = new VirtualAddrDock(sectionsModel, this);
|
virtualAddrDock = new VirtualAddrDock(sectionsModel, this);
|
||||||
@ -220,20 +210,11 @@ void SectionsWidget::initAddrMapDocks()
|
|||||||
toggleButton->setArrowType(Qt::NoArrow);
|
toggleButton->setArrowType(Qt::NoArrow);
|
||||||
toggleButton->hide();
|
toggleButton->hide();
|
||||||
layout->addWidget(toggleButton);
|
layout->addWidget(toggleButton);
|
||||||
|
|
||||||
layout->setMargin(0);
|
|
||||||
dockWidgetContents->setLayout(layout);
|
|
||||||
setWidget(dockWidgetContents);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SectionsWidget::initConnects()
|
void SectionsWidget::initConnects()
|
||||||
{
|
{
|
||||||
connect(sectionsTable, SIGNAL(doubleClicked(const QModelIndex &)),
|
connect(Core(), &CutterCore::refreshAll, this, &SectionsWidget::refreshSections);
|
||||||
this, SLOT(onSectionsDoubleClicked(const QModelIndex &)));
|
|
||||||
connect(Core(), SIGNAL(refreshAll()), this, SLOT(refreshSections()));
|
|
||||||
connect(quickFilterView, SIGNAL(filterTextChanged(const QString &)), proxyModel,
|
|
||||||
SLOT(setFilterWildcard(const QString &)));
|
|
||||||
connect(quickFilterView, SIGNAL(filterClosed()), sectionsTable, SLOT(setFocus()));
|
|
||||||
connect(this, &QDockWidget::visibilityChanged, this, [ = ](bool visibility) {
|
connect(this, &QDockWidget::visibilityChanged, this, [ = ](bool visibility) {
|
||||||
if (visibility) {
|
if (visibility) {
|
||||||
refreshSections();
|
refreshSections();
|
||||||
@ -261,7 +242,7 @@ void SectionsWidget::refreshSections()
|
|||||||
sectionsModel->beginResetModel();
|
sectionsModel->beginResetModel();
|
||||||
sections = Core()->getAllSections();
|
sections = Core()->getAllSections();
|
||||||
sectionsModel->endResetModel();
|
sectionsModel->endResetModel();
|
||||||
qhelpers::adjustColumns(sectionsTable, SectionsModel::ColumnCount, 0);
|
qhelpers::adjustColumns(ui->treeView, SectionsModel::ColumnCount, 0);
|
||||||
refreshDocks();
|
refreshDocks();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,16 +277,6 @@ void SectionsWidget::drawIndicatorOnAddrDocks()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SectionsWidget::onSectionsDoubleClicked(const QModelIndex &index)
|
|
||||||
{
|
|
||||||
if (!index.isValid()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto section = index.data(SectionsModel::SectionDescriptionRole).value<SectionDescription>();
|
|
||||||
Core()->seekAndShow(section.vaddr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SectionsWidget::resizeEvent(QResizeEvent *event) {
|
void SectionsWidget::resizeEvent(QResizeEvent *event) {
|
||||||
CutterDockWidget::resizeEvent(event);
|
CutterDockWidget::resizeEvent(event);
|
||||||
refreshDocks();
|
refreshDocks();
|
||||||
|
@ -13,10 +13,9 @@
|
|||||||
|
|
||||||
#include "core/Cutter.h"
|
#include "core/Cutter.h"
|
||||||
#include "CutterDockWidget.h"
|
#include "CutterDockWidget.h"
|
||||||
|
#include "widgets/ListDockWidget.h"
|
||||||
|
|
||||||
class CutterTreeView;
|
|
||||||
class QAbstractItemView;
|
class QAbstractItemView;
|
||||||
class MainWindow;
|
|
||||||
class SectionsWidget;
|
class SectionsWidget;
|
||||||
class AbstractAddrDock;
|
class AbstractAddrDock;
|
||||||
class AddrDockScene;
|
class AddrDockScene;
|
||||||
@ -27,7 +26,7 @@ class QuickFilterView;
|
|||||||
class QGraphicsView;
|
class QGraphicsView;
|
||||||
class QGraphicsRectItem;
|
class QGraphicsRectItem;
|
||||||
|
|
||||||
class SectionsModel : public QAbstractListModel
|
class SectionsModel : public AddressableItemModel<QAbstractListModel>
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -47,9 +46,12 @@ public:
|
|||||||
|
|
||||||
QVariant data(const QModelIndex &index, int role) const;
|
QVariant data(const QModelIndex &index, int role) const;
|
||||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||||
|
|
||||||
|
RVA address(const QModelIndex &index) const override;
|
||||||
|
QString name(const QModelIndex &index) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SectionsProxyModel : public QSortFilterProxyModel
|
class SectionsProxyModel : public AddressableFilterProxyModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -60,7 +62,7 @@ protected:
|
|||||||
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
|
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SectionsWidget : public CutterDockWidget
|
class SectionsWidget : public ListDockWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -71,9 +73,6 @@ public:
|
|||||||
private slots:
|
private slots:
|
||||||
void refreshSections();
|
void refreshSections();
|
||||||
void refreshDocks();
|
void refreshDocks();
|
||||||
|
|
||||||
void onSectionsDoubleClicked(const QModelIndex &index);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void resizeEvent(QResizeEvent *event) override;
|
void resizeEvent(QResizeEvent *event) override;
|
||||||
|
|
||||||
@ -81,10 +80,6 @@ private:
|
|||||||
QList<SectionDescription> sections;
|
QList<SectionDescription> sections;
|
||||||
SectionsModel *sectionsModel;
|
SectionsModel *sectionsModel;
|
||||||
SectionsProxyModel *proxyModel;
|
SectionsProxyModel *proxyModel;
|
||||||
CutterTreeView *sectionsTable;
|
|
||||||
MainWindow *main;
|
|
||||||
QWidget *dockWidgetContents;
|
|
||||||
QuickFilterView *quickFilterView;
|
|
||||||
|
|
||||||
QWidget *addrDockWidget;
|
QWidget *addrDockWidget;
|
||||||
RawAddrDock *rawAddrDock;
|
RawAddrDock *rawAddrDock;
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
#include "SegmentsWidget.h"
|
#include "SegmentsWidget.h"
|
||||||
#include "CutterTreeView.h"
|
|
||||||
#include "core/MainWindow.h"
|
#include "core/MainWindow.h"
|
||||||
#include "QuickFilterView.h"
|
|
||||||
#include "common/Helpers.h"
|
#include "common/Helpers.h"
|
||||||
|
#include "ui_ListDockWidget.h"
|
||||||
|
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
#include <QShortcut>
|
#include <QShortcut>
|
||||||
|
|
||||||
SegmentsModel::SegmentsModel(QList<SegmentDescription> *segments, QObject *parent)
|
SegmentsModel::SegmentsModel(QList<SegmentDescription> *segments, QObject *parent)
|
||||||
: QAbstractListModel(parent),
|
: AddressableItemModel<QAbstractListModel>(parent),
|
||||||
segments(segments)
|
segments(segments)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -50,7 +49,7 @@ QVariant SegmentsModel::data(const QModelIndex &index, int role) const
|
|||||||
case SegmentsModel::NameColumn:
|
case SegmentsModel::NameColumn:
|
||||||
return segment.name;
|
return segment.name;
|
||||||
case SegmentsModel::SizeColumn:
|
case SegmentsModel::SizeColumn:
|
||||||
return segment.size;
|
return QString::number(segment.size);
|
||||||
case SegmentsModel::AddressColumn:
|
case SegmentsModel::AddressColumn:
|
||||||
return RAddressString(segment.vaddr);
|
return RAddressString(segment.vaddr);
|
||||||
case SegmentsModel::EndAddressColumn:
|
case SegmentsModel::EndAddressColumn:
|
||||||
@ -94,10 +93,21 @@ QVariant SegmentsModel::headerData(int segment, Qt::Orientation, int role) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SegmentsProxyModel::SegmentsProxyModel(SegmentsModel *sourceModel, QObject *parent)
|
RVA SegmentsModel::address(const QModelIndex &index) const
|
||||||
: QSortFilterProxyModel(parent)
|
{
|
||||||
|
const SegmentDescription &segment = segments->at(index.row());
|
||||||
|
return segment.vaddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SegmentsModel::name(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
const SegmentDescription &segment = segments->at(index.row());
|
||||||
|
return segment.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
SegmentsProxyModel::SegmentsProxyModel(SegmentsModel *sourceModel, QObject *parent)
|
||||||
|
: AddressableFilterProxyModel(sourceModel, parent)
|
||||||
{
|
{
|
||||||
setSourceModel(sourceModel);
|
|
||||||
setFilterCaseSensitivity(Qt::CaseInsensitive);
|
setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||||
setSortCaseSensitivity(Qt::CaseInsensitive);
|
setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||||
}
|
}
|
||||||
@ -121,54 +131,21 @@ bool SegmentsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &ri
|
|||||||
}
|
}
|
||||||
|
|
||||||
SegmentsWidget::SegmentsWidget(MainWindow *main, QAction *action) :
|
SegmentsWidget::SegmentsWidget(MainWindow *main, QAction *action) :
|
||||||
CutterDockWidget(main, action),
|
ListDockWidget(main, action)
|
||||||
main(main)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
setObjectName("SegmentsWidget");
|
setObjectName("SegmentsWidget");
|
||||||
setWindowTitle(QStringLiteral("Segments"));
|
setWindowTitle(QStringLiteral("Segments"));
|
||||||
|
|
||||||
segmentsTable = new CutterTreeView;
|
|
||||||
segmentsModel = new SegmentsModel(&segments, this);
|
segmentsModel = new SegmentsModel(&segments, this);
|
||||||
auto proxyModel = new SegmentsProxyModel(segmentsModel, this);
|
auto proxyModel = new SegmentsProxyModel(segmentsModel, this);
|
||||||
|
setModels(proxyModel);
|
||||||
|
|
||||||
segmentsTable->setModel(proxyModel);
|
ui->treeView->sortByColumn(SegmentsModel::NameColumn, Qt::AscendingOrder);
|
||||||
segmentsTable->setIndentation(10);
|
|
||||||
segmentsTable->setSortingEnabled(true);
|
ui->quickFilterView->closeFilter();
|
||||||
segmentsTable->sortByColumn(SegmentsModel::NameColumn, Qt::AscendingOrder);
|
showCount(false);
|
||||||
|
|
||||||
connect(segmentsTable, SIGNAL(doubleClicked(const QModelIndex &)),
|
|
||||||
this, SLOT(onSegmentsDoubleClicked(const QModelIndex &)));
|
|
||||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
|
||||||
connect(Core(), SIGNAL(refreshAll()), this, SLOT(refreshSegments()));
|
connect(Core(), SIGNAL(refreshAll()), this, SLOT(refreshSegments()));
|
||||||
|
|
||||||
quickFilterView = new QuickFilterView(this, false);
|
|
||||||
quickFilterView->setObjectName(QStringLiteral("quickFilterView"));
|
|
||||||
QSizePolicy sizePolicy1(QSizePolicy::Preferred, QSizePolicy::Maximum);
|
|
||||||
sizePolicy1.setHorizontalStretch(0);
|
|
||||||
sizePolicy1.setVerticalStretch(0);
|
|
||||||
sizePolicy1.setHeightForWidth(quickFilterView->sizePolicy().hasHeightForWidth());
|
|
||||||
quickFilterView->setSizePolicy(sizePolicy1);
|
|
||||||
|
|
||||||
QShortcut *search_shortcut = new QShortcut(QKeySequence::Find, this);
|
|
||||||
connect(search_shortcut, &QShortcut::activated, quickFilterView, &QuickFilterView::showFilter);
|
|
||||||
search_shortcut->setContext(Qt::WidgetWithChildrenShortcut);
|
|
||||||
|
|
||||||
QShortcut *clear_shortcut = new QShortcut(QKeySequence(Qt::Key_Escape), this);
|
|
||||||
connect(clear_shortcut, &QShortcut::activated, quickFilterView, &QuickFilterView::clearFilter);
|
|
||||||
clear_shortcut->setContext(Qt::WidgetWithChildrenShortcut);
|
|
||||||
|
|
||||||
connect(quickFilterView, SIGNAL(filterTextChanged(const QString &)), proxyModel,
|
|
||||||
SLOT(setFilterWildcard(const QString &)));
|
|
||||||
connect(quickFilterView, SIGNAL(filterClosed()), segmentsTable, SLOT(setFocus()));
|
|
||||||
|
|
||||||
dockWidgetContents = new QWidget(this);
|
|
||||||
QVBoxLayout *layout = new QVBoxLayout();
|
|
||||||
layout->addWidget(segmentsTable);
|
|
||||||
layout->addWidget(quickFilterView);
|
|
||||||
layout->setMargin(0);
|
|
||||||
dockWidgetContents->setLayout(layout);
|
|
||||||
setWidget(dockWidgetContents);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SegmentsWidget::~SegmentsWidget() {}
|
SegmentsWidget::~SegmentsWidget() {}
|
||||||
@ -179,14 +156,5 @@ void SegmentsWidget::refreshSegments()
|
|||||||
segments = Core()->getAllSegments();
|
segments = Core()->getAllSegments();
|
||||||
segmentsModel->endResetModel();
|
segmentsModel->endResetModel();
|
||||||
|
|
||||||
qhelpers::adjustColumns(segmentsTable, SegmentsModel::ColumnCount, 0);
|
qhelpers::adjustColumns(ui->treeView, SegmentsModel::ColumnCount, 0);
|
||||||
}
|
|
||||||
|
|
||||||
void SegmentsWidget::onSegmentsDoubleClicked(const QModelIndex &index)
|
|
||||||
{
|
|
||||||
if (!index.isValid())
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto segment = index.data(SegmentsModel::SegmentDescriptionRole).value<SegmentDescription>();
|
|
||||||
Core()->seekAndShow(segment.vaddr);
|
|
||||||
}
|
}
|
||||||
|
@ -7,16 +7,12 @@
|
|||||||
#include <QSortFilterProxyModel>
|
#include <QSortFilterProxyModel>
|
||||||
|
|
||||||
#include "core/Cutter.h"
|
#include "core/Cutter.h"
|
||||||
#include "CutterTreeView.h"
|
#include "widgets/ListDockWidget.h"
|
||||||
#include "CutterDockWidget.h"
|
|
||||||
|
|
||||||
class CutterTreeView;
|
|
||||||
class QAbstractItemView;
|
class QAbstractItemView;
|
||||||
class MainWindow;
|
|
||||||
class SegmentsWidget;
|
class SegmentsWidget;
|
||||||
class QuickFilterView;
|
|
||||||
|
|
||||||
class SegmentsModel : public QAbstractListModel
|
class SegmentsModel : public AddressableItemModel<QAbstractListModel>
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -31,14 +27,17 @@ public:
|
|||||||
|
|
||||||
SegmentsModel(QList<SegmentDescription> *segments, QObject *parent = nullptr);
|
SegmentsModel(QList<SegmentDescription> *segments, QObject *parent = nullptr);
|
||||||
|
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
|
||||||
QVariant data(const QModelIndex &index, int role) const;
|
QVariant data(const QModelIndex &index, int role) const override;
|
||||||
QVariant headerData(int segment, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
QVariant headerData(int segment, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
|
RVA address(const QModelIndex &index) const override;
|
||||||
|
QString name(const QModelIndex &index) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SegmentsProxyModel : public QSortFilterProxyModel
|
class SegmentsProxyModel : public AddressableFilterProxyModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -49,7 +48,7 @@ protected:
|
|||||||
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
|
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SegmentsWidget : public CutterDockWidget
|
class SegmentsWidget : public ListDockWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -59,15 +58,9 @@ public:
|
|||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void refreshSegments();
|
void refreshSegments();
|
||||||
void onSegmentsDoubleClicked(const QModelIndex &index);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<SegmentDescription> segments;
|
QList<SegmentDescription> segments;
|
||||||
SegmentsModel *segmentsModel;
|
SegmentsModel *segmentsModel;
|
||||||
CutterTreeView *segmentsTable;
|
|
||||||
MainWindow *main;
|
|
||||||
QWidget *dockWidgetContents;
|
|
||||||
QuickFilterView *quickFilterView;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SEGMENTSWIDGET_H
|
#endif // SEGMENTSWIDGET_H
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
#include "SymbolsWidget.h"
|
#include "SymbolsWidget.h"
|
||||||
#include "ui_SymbolsWidget.h"
|
#include "ui_ListDockWidget.h"
|
||||||
#include "core/MainWindow.h"
|
#include "core/MainWindow.h"
|
||||||
#include "common/Helpers.h"
|
#include "common/Helpers.h"
|
||||||
|
|
||||||
#include <QShortcut>
|
#include <QShortcut>
|
||||||
|
|
||||||
SymbolsModel::SymbolsModel(QList<SymbolDescription> *symbols, QObject *parent)
|
SymbolsModel::SymbolsModel(QList<SymbolDescription> *symbols, QObject *parent)
|
||||||
: QAbstractListModel(parent),
|
: AddressableItemModel<QAbstractListModel>(parent),
|
||||||
symbols(symbols)
|
symbols(symbols)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -67,10 +67,21 @@ QVariant SymbolsModel::headerData(int section, Qt::Orientation, int role) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SymbolsProxyModel::SymbolsProxyModel(SymbolsModel *sourceModel, QObject *parent)
|
RVA SymbolsModel::address(const QModelIndex &index) const
|
||||||
: QSortFilterProxyModel(parent)
|
{
|
||||||
|
const SymbolDescription &symbol = symbols->at(index.row());
|
||||||
|
return symbol.vaddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SymbolsModel::name(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
const SymbolDescription &symbol = symbols->at(index.row());
|
||||||
|
return symbol.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
SymbolsProxyModel::SymbolsProxyModel(SymbolsModel *sourceModel, QObject *parent)
|
||||||
|
: AddressableFilterProxyModel(sourceModel, parent)
|
||||||
{
|
{
|
||||||
setSourceModel(sourceModel);
|
|
||||||
setFilterCaseSensitivity(Qt::CaseInsensitive);
|
setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||||
setSortCaseSensitivity(Qt::CaseInsensitive);
|
setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||||
}
|
}
|
||||||
@ -103,68 +114,26 @@ bool SymbolsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &rig
|
|||||||
}
|
}
|
||||||
|
|
||||||
SymbolsWidget::SymbolsWidget(MainWindow *main, QAction *action) :
|
SymbolsWidget::SymbolsWidget(MainWindow *main, QAction *action) :
|
||||||
CutterDockWidget(main, action),
|
ListDockWidget(main, action)
|
||||||
ui(new Ui::SymbolsWidget),
|
|
||||||
tree(new CutterTreeWidget(this))
|
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
setWindowTitle(tr("Symbols"));
|
||||||
|
setObjectName("SymbolsWidget");
|
||||||
// Add Status Bar footer
|
|
||||||
tree->addStatusBar(ui->verticalLayout);
|
|
||||||
|
|
||||||
symbolsModel = new SymbolsModel(&symbols, this);
|
symbolsModel = new SymbolsModel(&symbols, this);
|
||||||
symbolsProxyModel = new SymbolsProxyModel(symbolsModel, this);
|
symbolsProxyModel = new SymbolsProxyModel(symbolsModel, this);
|
||||||
ui->symbolsTreeView->setModel(symbolsProxyModel);
|
setModels(symbolsProxyModel);
|
||||||
ui->symbolsTreeView->sortByColumn(SymbolsModel::AddressColumn, Qt::AscendingOrder);
|
ui->treeView->sortByColumn(SymbolsModel::AddressColumn, Qt::AscendingOrder);
|
||||||
|
|
||||||
// Ctrl-F to show/hide the filter entry
|
connect(Core(), &CutterCore::refreshAll, this, &SymbolsWidget::refreshSymbols);
|
||||||
QShortcut *searchShortcut = new QShortcut(QKeySequence::Find, this);
|
|
||||||
connect(searchShortcut, &QShortcut::activated, ui->quickFilterView, &QuickFilterView::showFilter);
|
|
||||||
searchShortcut->setContext(Qt::WidgetWithChildrenShortcut);
|
|
||||||
|
|
||||||
// Esc to clear the filter entry
|
|
||||||
QShortcut *clearShortcut = new QShortcut(QKeySequence(Qt::Key_Escape), this);
|
|
||||||
connect(clearShortcut, &QShortcut::activated, ui->quickFilterView, &QuickFilterView::clearFilter);
|
|
||||||
clearShortcut->setContext(Qt::WidgetWithChildrenShortcut);
|
|
||||||
|
|
||||||
connect(ui->quickFilterView, SIGNAL(filterTextChanged(const QString &)),
|
|
||||||
symbolsProxyModel, SLOT(setFilterWildcard(const QString &)));
|
|
||||||
connect(ui->quickFilterView, SIGNAL(filterClosed()), ui->symbolsTreeView, SLOT(setFocus()));
|
|
||||||
|
|
||||||
connect(ui->quickFilterView, &QuickFilterView::filterTextChanged, this, [this] {
|
|
||||||
tree->showItemsNumber(symbolsProxyModel->rowCount());
|
|
||||||
});
|
|
||||||
|
|
||||||
setScrollMode();
|
|
||||||
|
|
||||||
connect(Core(), SIGNAL(refreshAll()), this, SLOT(refreshSymbols()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SymbolsWidget::~SymbolsWidget() {}
|
SymbolsWidget::~SymbolsWidget() {}
|
||||||
|
|
||||||
|
|
||||||
void SymbolsWidget::on_symbolsTreeView_doubleClicked(const QModelIndex &index)
|
|
||||||
{
|
|
||||||
if (!index.isValid()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto symbol = index.data(SymbolsModel::SymbolDescriptionRole).value<SymbolDescription>();
|
|
||||||
Core()->seekAndShow(symbol.vaddr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SymbolsWidget::refreshSymbols()
|
void SymbolsWidget::refreshSymbols()
|
||||||
{
|
{
|
||||||
symbolsModel->beginResetModel();
|
symbolsModel->beginResetModel();
|
||||||
symbols = Core()->getAllSymbols();
|
symbols = Core()->getAllSymbols();
|
||||||
symbolsModel->endResetModel();
|
symbolsModel->endResetModel();
|
||||||
|
|
||||||
qhelpers::adjustColumns(ui->symbolsTreeView, SymbolsModel::ColumnCount, 0);
|
qhelpers::adjustColumns(ui->treeView, SymbolsModel::ColumnCount, 0);
|
||||||
|
|
||||||
tree->showItemsNumber(symbolsProxyModel->rowCount());
|
|
||||||
}
|
|
||||||
|
|
||||||
void SymbolsWidget::setScrollMode()
|
|
||||||
{
|
|
||||||
qhelpers::setVerticalScrollMode(ui->symbolsTreeView);
|
|
||||||
}
|
}
|
||||||
|
@ -7,17 +7,15 @@
|
|||||||
|
|
||||||
#include "core/Cutter.h"
|
#include "core/Cutter.h"
|
||||||
#include "CutterDockWidget.h"
|
#include "CutterDockWidget.h"
|
||||||
#include "CutterTreeWidget.h"
|
#include "widgets/ListDockWidget.h"
|
||||||
|
|
||||||
|
|
||||||
class MainWindow;
|
class MainWindow;
|
||||||
class QTreeWidgetItem;
|
class QTreeWidgetItem;
|
||||||
class SymbolsWidget;
|
class SymbolsWidget;
|
||||||
|
|
||||||
namespace Ui {
|
|
||||||
class SymbolsWidget;
|
|
||||||
}
|
|
||||||
|
|
||||||
class SymbolsModel: public QAbstractListModel
|
class SymbolsModel: public AddressableItemModel<QAbstractListModel>
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -32,14 +30,17 @@ public:
|
|||||||
|
|
||||||
SymbolsModel(QList<SymbolDescription> *exports, QObject *parent = nullptr);
|
SymbolsModel(QList<SymbolDescription> *exports, QObject *parent = nullptr);
|
||||||
|
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
|
||||||
QVariant data(const QModelIndex &index, int role) const;
|
QVariant data(const QModelIndex &index, int role) const override;
|
||||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
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 SymbolsProxyModel : public QSortFilterProxyModel
|
class SymbolsProxyModel : public AddressableFilterProxyModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -52,7 +53,7 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class SymbolsWidget : public CutterDockWidget
|
class SymbolsWidget : public ListDockWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -61,19 +62,12 @@ public:
|
|||||||
~SymbolsWidget();
|
~SymbolsWidget();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void on_symbolsTreeView_doubleClicked(const QModelIndex &index);
|
|
||||||
|
|
||||||
void refreshSymbols();
|
void refreshSymbols();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<Ui::SymbolsWidget> ui;
|
|
||||||
|
|
||||||
QList<SymbolDescription> symbols;
|
QList<SymbolDescription> symbols;
|
||||||
SymbolsModel *symbolsModel;
|
SymbolsModel *symbolsModel;
|
||||||
SymbolsProxyModel *symbolsProxyModel;
|
SymbolsProxyModel *symbolsProxyModel;
|
||||||
CutterTreeWidget *tree;
|
|
||||||
|
|
||||||
void setScrollMode();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SYMBOLSWIDGET_H
|
#endif // SYMBOLSWIDGET_H
|
||||||
|
@ -1,62 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<class>SymbolsWidget</class>
|
|
||||||
<widget class="QDockWidget" name="SymbolsWidget">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>400</width>
|
|
||||||
<height>300</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string notr="true">Symbols</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="symbolsTreeView">
|
|
||||||
<property name="sortingEnabled">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<attribute name="headerShowSortIndicator" stdset="0">
|
|
||||||
<bool>true</bool>
|
|
||||||
</attribute>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QuickFilterView" name="quickFilterView" native="true"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</widget>
|
|
||||||
<customwidgets>
|
|
||||||
<customwidget>
|
|
||||||
<class>CutterTreeView</class>
|
|
||||||
<extends>QTreeView</extends>
|
|
||||||
<header>widgets/CutterTreeView.h</header>
|
|
||||||
<container>1</container>
|
|
||||||
</customwidget>
|
|
||||||
<customwidget>
|
|
||||||
<class>QuickFilterView</class>
|
|
||||||
<extends>QWidget</extends>
|
|
||||||
<header>widgets/QuickFilterView.h</header>
|
|
||||||
<container>1</container>
|
|
||||||
</customwidget>
|
|
||||||
</customwidgets>
|
|
||||||
<resources/>
|
|
||||||
<connections/>
|
|
||||||
</ui>
|
|
@ -146,6 +146,7 @@ VTablesWidget::VTablesWidget(MainWindow *main, QAction *action) :
|
|||||||
// Esc to clear the filter entry
|
// Esc to clear the filter entry
|
||||||
QShortcut *clear_shortcut = new QShortcut(QKeySequence(Qt::Key_Escape), this);
|
QShortcut *clear_shortcut = new QShortcut(QKeySequence(Qt::Key_Escape), this);
|
||||||
connect(clear_shortcut, &QShortcut::activated, ui->quickFilterView, &QuickFilterView::clearFilter);
|
connect(clear_shortcut, &QShortcut::activated, ui->quickFilterView, &QuickFilterView::clearFilter);
|
||||||
|
clear_shortcut->setContext(Qt::WidgetWithChildrenShortcut);
|
||||||
|
|
||||||
// Ctrl-F to show/hide the filter entry
|
// Ctrl-F to show/hide the filter entry
|
||||||
QShortcut *search_shortcut = new QShortcut(QKeySequence::Find, this);
|
QShortcut *search_shortcut = new QShortcut(QKeySequence::Find, this);
|
||||||
|
Loading…
Reference in New Issue
Block a user