Rewrite raise memory widget functionality (#1654)

* Seperate seek from seeking and changing focused widget.
* Change memory widget priorities
* Add Show in context menu
This commit is contained in:
karliss 2019-07-19 22:21:12 +03:00 committed by GitHub
parent 914b35e637
commit 6c40191cce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 307 additions and 142 deletions

View File

@ -628,25 +628,38 @@ void CutterCore::seek(ut64 offset)
}
cmd(QString("s %1").arg(offset));
// cmd already does emit seekChanged(core_->offset);
triggerRaisePrioritizedMemoryWidget();
}
void CutterCore::showMemoryWidget()
{
emit showMemoryWidgetRequested();
}
void CutterCore::seekAndShow(ut64 offset)
{
seek(offset);
showMemoryWidget();
}
void CutterCore::seekAndShow(QString offset)
{
seek(offset);
showMemoryWidget();
}
void CutterCore::seek(QString thing)
{
cmdRaw(QString("s %1").arg(thing));
triggerRaisePrioritizedMemoryWidget();
}
void CutterCore::seekPrev()
{
cmd("s-");
triggerRaisePrioritizedMemoryWidget();
}
void CutterCore::seekNext()
{
cmd("s+");
triggerRaisePrioritizedMemoryWidget();
}
void CutterCore::updateSeek()
@ -1116,7 +1129,7 @@ void CutterCore::attachDebug(int pid)
// attach to process with dbg plugin
cmd("o-*; e cfg.debug = true; o+ dbg://" + QString::number(pid));
QString programCounterValue = cmd("dr?`drn PC`").trimmed();
seek(programCounterValue);
seekAndShow(programCounterValue);
emit registersChanged();
if (!currentlyDebugging || !currentlyEmulating) {
// prevent register flags from appearing during debug/emul
@ -1141,7 +1154,7 @@ void CutterCore::stopDebug()
} else {
cmd("dk 9; oo; .ar-");
}
seek(offsetPriorDebugging);
seekAndShow(offsetPriorDebugging);
setConfig("asm.flags", true);
setConfig("io.cache", false);
currentlyDebugging = false;
@ -1185,7 +1198,7 @@ void CutterCore::continueUntilCall()
cmd("dcc");
}
QString programCounterValue = cmd("dr?`drn PC`").trimmed();
seek(programCounterValue);
seekAndShow(programCounterValue);
emit registersChanged();
}
}
@ -1199,7 +1212,7 @@ void CutterCore::continueUntilSyscall()
cmd("dcs");
}
QString programCounterValue = cmd("dr?`drn PC`").trimmed();
seek(programCounterValue);
seekAndShow(programCounterValue);
emit registersChanged();
}
}
@ -1209,7 +1222,7 @@ void CutterCore::stepDebug()
if (currentlyDebugging) {
cmdEsil("ds");
QString programCounterValue = cmd("dr?`drn PC`").trimmed();
seek(programCounterValue);
seekAndShow(programCounterValue);
emit registersChanged();
}
}
@ -1219,7 +1232,7 @@ void CutterCore::stepOverDebug()
if (currentlyDebugging) {
cmdEsil("dso");
QString programCounterValue = cmd("dr?`drn PC`").trimmed();
seek(programCounterValue);
seekAndShow(programCounterValue);
emit registersChanged();
}
}
@ -1229,7 +1242,7 @@ void CutterCore::stepOutDebug()
if (currentlyDebugging) {
cmd("dsf");
QString programCounterValue = cmd("dr?`drn PC`").trimmed();
seek(programCounterValue);
seekAndShow(programCounterValue);
emit registersChanged();
}
}

View File

@ -35,7 +35,6 @@ public:
RCore *operator->() const;
};
class CutterCore: public QObject
{
Q_OBJECT
@ -150,25 +149,25 @@ public:
void seekPrev();
void seekNext();
void updateSeek();
/**
* @brief Raise a memory widget showing current offset, prefer last active
* memory widget.
*/
void showMemoryWidget();
/**
* @brief Seek to \p offset and raise a memory widget showing it.
* @param offset
*/
void seekAndShow(ut64 offset);
/**
* @brief \see CutterCore::show(ut64)
* @param thing - addressable expression
*/
void seekAndShow(QString thing);
RVA getOffset();
RVA prevOpAddr(RVA startAddr, int count);
RVA nextOpAddr(RVA startAddr, int count);
/* Disassembly/Graph/Hexdump/Pseudocode view priority */
enum class MemoryWidgetType { Disassembly, Graph, Hexdump, Pseudocode };
MemoryWidgetType getMemoryWidgetPriority() const
{
return memoryWidgetPriority;
}
void setMemoryWidgetPriority(MemoryWidgetType type)
{
memoryWidgetPriority = type;
}
void triggerRaisePrioritizedMemoryWidget()
{
emit raisePrioritizedMemoryWidget(memoryWidgetPriority);
}
/* Math functions */
ut64 math(const QString &expr);
ut64 num(const QString &expr);
@ -444,16 +443,15 @@ signals:
*/
void seekChanged(RVA offset);
void raisePrioritizedMemoryWidget(CutterCore::MemoryWidgetType type);
void changeDefinedView();
void changeDebugView();
void newMessage(const QString &msg);
void newDebugMessage(const QString &msg);
private:
MemoryWidgetType memoryWidgetPriority;
void showMemoryWidgetRequested();
private:
QString notes;
RCore *core_ = nullptr;
AsyncTaskManager *asyncTaskManager;

View File

@ -171,6 +171,9 @@ void MainWindow::initUI()
connect(core, SIGNAL(newDebugMessage(const QString &)),
this->consoleDock, SLOT(addDebugOutput(const QString &)));
connect(core, &CutterCore::showMemoryWidgetRequested,
this, static_cast<void(MainWindow::*)()>(&MainWindow::showMemoryWidget));
updateTasksIndicator();
connect(core->getAsyncTaskManager(), &AsyncTaskManager::tasksChanged, this,
&MainWindow::updateTasksIndicator);
@ -178,7 +181,7 @@ void MainWindow::initUI()
//Undo and redo seek
ui->actionBackward->setShortcut(QKeySequence::Back);
ui->actionForward->setShortcut(QKeySequence::Forward);
/* Setup plugins interfaces */
for (auto plugin : Plugins()->getPlugins()) {
plugin->setupInterface(this);
@ -190,7 +193,7 @@ void MainWindow::initUI()
void MainWindow::initToolBar()
{
chooseThemeIcons();
// Sepparator between undo/redo and goto lineEdit
QWidget *spacer3 = new QWidget();
spacer3->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
@ -319,7 +322,7 @@ void MainWindow::initDocks()
QString className;
for (const auto &it : docks) {
if (std::none_of(dockWidgets.constBegin(), dockWidgets.constEnd(),
[&it](QDockWidget *w) { return w->objectName() == it; })) {
[&it](QDockWidget * w) { return w->objectName() == it; })) {
className = it.split(';').at(0);
if (widgetTypeToConstructorMap.contains(className)) {
auto widget = widgetTypeToConstructorMap[className](this, nullptr);
@ -839,6 +842,14 @@ void MainWindow::updateDockActionsChecked()
}
}
MemoryWidgetType MainWindow::getMemoryWidgetTypeToRestore()
{
if (lastMemoryWidget) {
return lastMemoryWidget->getType();
}
return MemoryWidgetType::Disassembly;
}
QString MainWindow::getUniqueObjectName(const QString &widgetType) const
{
QStringList docks;
@ -863,6 +874,90 @@ QString MainWindow::getUniqueObjectName(const QString &widgetType) const
return widgetType + ";" + QString::number(id);
}
void MainWindow::showMemoryWidget()
{
if (lastMemoryWidget) {
if (lastMemoryWidget->tryRaiseMemoryWidget()) {
return;
}
}
showMemoryWidget(MemoryWidgetType::Disassembly);
}
void MainWindow::showMemoryWidget(MemoryWidgetType type)
{
for (auto &dock : dockWidgets) {
if (auto memoryWidget = qobject_cast<MemoryDockWidget *>(dock)) {
if (memoryWidget->getType() == type && memoryWidget->getSeekable()->isSynchronized()) {
memoryWidget->tryRaiseMemoryWidget();
return;
}
}
}
auto memoryDockWidget = addNewMemoryWidget(type, Core()->getOffset());
memoryDockWidget->raiseMemoryWidget();
}
QMenu *MainWindow::createShowInMenu(QWidget *parent, RVA address)
{
QMenu *menu = new QMenu(parent);
for (auto &dock : dockWidgets) {
if (auto memoryWidget = qobject_cast<MemoryDockWidget *>(dock)) {
QAction *action = new QAction(memoryWidget->windowTitle(), menu);
connect(action, &QAction::triggered, this, [this, memoryWidget, address](){
memoryWidget->getSeekable()->seek(address);
memoryWidget->raiseMemoryWidget();
});
menu->addAction(action);
}
}
menu->addSeparator();
auto createAddNewWidgetAction = [this, menu, address](QString label, MemoryWidgetType type) {
QAction *action = new QAction(label, menu);
connect(action, &QAction::triggered, this, [this, address, type](){
addNewMemoryWidget(type, address, true);
});
menu->addAction(action);
};
createAddNewWidgetAction(tr("New disassembly"), MemoryWidgetType::Disassembly);
createAddNewWidgetAction(tr("New graph"), MemoryWidgetType::Graph);
createAddNewWidgetAction(tr("New hexdump"), MemoryWidgetType::Hexdump);
return menu;
}
void MainWindow::setCurrentMemoryWidget(MemoryDockWidget *memoryWidget)
{
if (memoryWidget->getSeekable()->isSynchronized()) {
lastMemoryWidget = memoryWidget;
}
}
MemoryDockWidget *MainWindow::addNewMemoryWidget(MemoryWidgetType type, RVA address,
bool synchronized)
{
MemoryDockWidget *memoryWidget = nullptr;
switch (type) {
case MemoryWidgetType::Graph:
memoryWidget = new GraphWidget(this);
break;
case MemoryWidgetType::Hexdump:
memoryWidget = new HexdumpWidget(this);
break;
case MemoryWidgetType::Disassembly:
memoryWidget = new DisassemblyWidget(this);
break;
case MemoryWidgetType::Pseudocode:
memoryWidget = new PseudocodeWidget(this);
break;
}
auto seekable = memoryWidget->getSeekable();
seekable->setSynchronization(synchronized);
seekable->seek(address);
addExtraWidget(memoryWidget);
return memoryWidget;
}
void MainWindow::initCorners()
{
// TODO: Allow the user to select this option visually in the GUI settings
@ -889,12 +984,24 @@ void MainWindow::addWidget(QDockWidget* widget)
}
updateDockActionsChecked();
});
}
}
}
void MainWindow::addMemoryDockWidget(MemoryDockWidget *widget)
{
connect(widget, &QDockWidget::visibilityChanged, this, [this, widget](bool visibility) {
if (visibility) {
setCurrentMemoryWidget(widget);
}
});
}
void MainWindow::removeWidget(QDockWidget *widget)
{
dockWidgets.removeAll(widget);
if (lastMemoryWidget == widget) {
lastMemoryWidget = nullptr;
}
}
void MainWindow::updateDockActionChecked(QAction *action)
@ -968,11 +1075,11 @@ void MainWindow::resetToDefaultLayout()
void MainWindow::resetToDebugLayout()
{
CutterCore::MemoryWidgetType memType = core->getMemoryWidgetPriority();
MemoryWidgetType memType = getMemoryWidgetTypeToRestore();
hideAllDocks();
restoreDocks();
showDebugDocks();
core->raisePrioritizedMemoryWidget(memType);
showMemoryWidget(memType);
auto restoreStackDock = qhelpers::forceWidth(stackDock->widget(), 400);
qApp->processEvents();
@ -981,13 +1088,13 @@ void MainWindow::resetToDebugLayout()
void MainWindow::restoreDebugLayout()
{
CutterCore::MemoryWidgetType memType = core->getMemoryWidgetPriority();
MemoryWidgetType memType = getMemoryWidgetTypeToRestore();
bool isMaxim = isMaximized();
hideAllDocks();
restoreDocks();
showDebugDocks();
readDebugSettings();
core->raisePrioritizedMemoryWidget(memType);
showMemoryWidget(memType);
if (isMaxim) {
showMaximized();
} else {
@ -1319,12 +1426,12 @@ void MainWindow::changeDebugView()
void MainWindow::changeDefinedView()
{
saveDebugSettings();
CutterCore::MemoryWidgetType memType = core->getMemoryWidgetPriority();
MemoryWidgetType memType = getMemoryWidgetTypeToRestore();
hideAllDocks();
restoreDocks();
readSettingsOrDefault();
enableDebugWidgetsMenu(false);
core->raisePrioritizedMemoryWidget(memType);
showMemoryWidget(memType);
}
void MainWindow::mousePressEvent(QMouseEvent *event)

View File

@ -6,6 +6,7 @@
#include "dialogs/WelcomeDialog.h"
#include "common/Configuration.h"
#include "common/InitialOptions.h"
#include "MemoryDockWidget.h"
#include <memory>
@ -54,7 +55,6 @@ namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
@ -95,8 +95,11 @@ public:
void refreshOmniBar(const QStringList &flags);
void addWidget(QDockWidget *widget);
void addMemoryDockWidget(MemoryDockWidget *widget);
void removeWidget(QDockWidget *widget);
void addExtraWidget(CutterDockWidget *extraDock);
MemoryDockWidget *addNewMemoryWidget(MemoryWidgetType type, RVA address, bool synchronized = true);
void addPluginDockWidget(QDockWidget *dockWidget, QAction *action);
enum class MenuType { File, Edit, View, Windows, Debug, Help, Plugins };
@ -112,6 +115,11 @@ public:
void messageBoxWarning(QString title, QString message);
QString getUniqueObjectName(const QString &widgetType) const;
void showMemoryWidget();
void showMemoryWidget(MemoryWidgetType type);
QMenu *createShowInMenu(QWidget *parent, RVA address);
void setCurrentMemoryWidget(MemoryDockWidget* memoryWidget);
public slots:
void finalizeOpen();
@ -271,10 +279,14 @@ private:
void setOverviewData();
bool isOverviewActive();
MemoryWidgetType getMemoryWidgetTypeToRestore();
/**
* @brief Map from a widget type (e.g. DisassemblyWidget::getWidgetType()) to the respective contructor of the widget
*/
QMap<QString, std::function<CutterDockWidget*(MainWindow*, QAction*)>> widgetTypeToConstructorMap;
MemoryDockWidget* lastMemoryWidget = nullptr;
};
#endif // MAINWINDOW_H

View File

@ -67,7 +67,7 @@ void LinkTypeDialog::done(int r)
QDialog::done(r);
// Seek to the specified address
Core()->seek(address);
Core()->seekAndShow(address);
// Refresh the views
emit Core()->refreshCodeViews();

View File

@ -75,7 +75,7 @@ void XrefsDialog::on_fromTreeWidget_itemDoubleClicked(QTreeWidgetItem *item, int
Q_UNUSED(column);
XrefDescription xref = item->data(0, Qt::UserRole).value<XrefDescription>();
Core()->seek(xref.to);
Core()->seekAndShow(xref.to);
this->close();
}
@ -84,7 +84,7 @@ void XrefsDialog::on_toTreeWidget_itemDoubleClicked(QTreeWidgetItem *item, int c
Q_UNUSED(column);
XrefDescription xref = item->data(0, Qt::UserRole).value<XrefDescription>();
Core()->seek(xref.from);
Core()->seekAndShow(xref.from);
this->close();
}

View File

@ -9,6 +9,7 @@
#include "dialogs/SetToDataDialog.h"
#include "dialogs/EditFunctionDialog.h"
#include "dialogs/LinkTypeDialog.h"
#include "MainWindow.h"
#include <QtCore>
#include <QShortcut>
@ -17,10 +18,11 @@
#include <QApplication>
#include <QPushButton>
DisassemblyContextMenu::DisassemblyContextMenu(QWidget *parent)
DisassemblyContextMenu::DisassemblyContextMenu(QWidget *parent, MainWindow* mainWindow)
: QMenu(parent),
offset(0),
canCopy(false)
canCopy(false),
mainWindow(mainWindow)
{
initAction(&actionCopy, tr("Copy"), SLOT(on_actionCopy_triggered()), getCopySequence());
addAction(&actionCopy);
@ -28,6 +30,9 @@ DisassemblyContextMenu::DisassemblyContextMenu(QWidget *parent)
initAction(&actionCopyAddr, tr("Copy address"), SLOT(on_actionCopyAddr_triggered()), getCopyAddressSequence());
addAction(&actionCopyAddr);
initAction(&showInSubmenu, tr("Show in"), nullptr);
addAction(&showInSubmenu);
copySeparator = addSeparator();
initAction(&actionAddComment, tr("Add Comment"),
@ -379,6 +384,11 @@ void DisassemblyContextMenu::aboutToShowSlot()
// Decide to show Reverse jmp option
showReverseJmpQuery();
if (showInSubmenu.menu() != nullptr) {
showInSubmenu.menu()->deleteLater();
}
showInSubmenu.setMenu(mainWindow->createShowInMenu(this, offset));
// Only show debug options if we are currently debugging
debugMenu->menuAction()->setVisible(Core()->currentlyDebugging);
QString progCounterName = Core()->getRegisterName("PC");

View File

@ -10,7 +10,7 @@ class DisassemblyContextMenu : public QMenu
Q_OBJECT
public:
DisassemblyContextMenu(QWidget *parent = nullptr);
DisassemblyContextMenu(QWidget *parent, MainWindow* mainWindow);
~DisassemblyContextMenu();
signals:
@ -101,6 +101,7 @@ private:
RVA offset;
bool canCopy;
QString curHighlightedWord; // The current highlighted word
MainWindow* mainWindow;
QList<QAction *> anonymousActions;
@ -164,6 +165,8 @@ private:
QAction actionSetToDataDword;
QAction actionSetToDataQword;
QAction showInSubmenu;
// For creating anonymous entries (that are always visible)
QAction *addAnonymousAction(QString name, const char *slot, QKeySequence shortcut);

View File

@ -168,7 +168,7 @@ void BreakpointWidget::on_breakpointTreeView_doubleClicked(const QModelIndex &in
{
BreakpointDescription item = index.data(
BreakpointModel::BreakpointDescriptionRole).value<BreakpointDescription>();
Core()->seek(item.addr);
Core()->seekAndShow(item.addr);
}
void BreakpointWidget::showBreakpointContextMenu(const QPoint &pt)

View File

@ -634,7 +634,7 @@ void ClassesWidget::on_classesTreeView_doubleClicked(const QModelIndex &index)
return;
}
RVA offset = offsetData.value<RVA>();
Core()->seek(offset);
Core()->seekAndShow(offset);
}
void ClassesWidget::showContextMenu(const QPoint &pt)
@ -696,7 +696,7 @@ void ClassesWidget::on_seekToVTableAction_triggered()
return;
}
Core()->seek(vtables[0].addr + desc.vtableOffset);
Core()->seekAndShow(vtables[0].addr + desc.vtableOffset);
}
void ClassesWidget::on_addMethodAction_triggered()

View File

@ -272,7 +272,7 @@ void CommentsWidget::on_commentsTreeView_doubleClicked(const QModelIndex &index)
return;
auto comment = index.data(CommentsModel::CommentDescriptionRole).value<CommentDescription>();
Core()->seek(comment.offset);
Core()->seekAndShow(comment.offset);
}
void CommentsWidget::on_actionHorizontal_triggered()

View File

@ -86,3 +86,15 @@ QAction *CutterDockWidget::getBoundAction() const
return action;
}
QString CutterDockWidget::getDockNumber()
{
auto name = this->objectName();
if (name.contains(';')) {
auto parts = name.split(';');
if (parts.size() >= 2) {
return parts[1];
}
}
return QString();
}

View File

@ -67,9 +67,11 @@ protected:
void closeEvent(QCloseEvent *event) override;
QAction *getBoundAction() const;
QString getDockNumber();
MainWindow *mainWindow;
private:
MainWindow *mainWindow;
QAction *action;
bool isTransient = false;

View File

@ -29,10 +29,10 @@
#include <cmath>
DisassemblerGraphView::DisassemblerGraphView(QWidget *parent, CutterSeekable* seekable)
DisassemblerGraphView::DisassemblerGraphView(QWidget *parent, CutterSeekable* seekable, MainWindow* mainWindow)
: GraphView(parent),
mFontMetrics(nullptr),
blockMenu(new DisassemblyContextMenu(this)),
blockMenu(new DisassemblyContextMenu(this, mainWindow)),
contextMenu(new QMenu(this)),
seekable(seekable)
{
@ -55,13 +55,6 @@ DisassemblerGraphView::DisassemblerGraphView(QWidget *parent, CutterSeekable* se
connect(Config(), SIGNAL(fontsUpdated()), this, SLOT(fontsUpdatedSlot()));
connectSeekChanged(false);
// Space to switch to disassembly
QShortcut *shortcut_disassembly = new QShortcut(QKeySequence(Qt::Key_Space), this);
shortcut_disassembly->setContext(Qt::WidgetShortcut);
connect(shortcut_disassembly, &QShortcut::activated, this, [] {
Core()->setMemoryWidgetPriority(CutterCore::MemoryWidgetType::Disassembly);
Core()->triggerRaisePrioritizedMemoryWidget();
});
// ESC for previous
QShortcut *shortcut_escape = new QShortcut(QKeySequence(Qt::Key_Escape), this);
shortcut_escape->setContext(Qt::WidgetShortcut);
@ -95,7 +88,6 @@ DisassemblerGraphView::DisassemblerGraphView(QWidget *parent, CutterSeekable* se
QShortcut *shortcut_prev_instr = new QShortcut(QKeySequence(Qt::Key_K), this);
shortcut_prev_instr->setContext(Qt::WidgetShortcut);
connect(shortcut_prev_instr, SIGNAL(activated()), this, SLOT(prevInstr()));
shortcuts.append(shortcut_disassembly);
shortcuts.append(shortcut_escape);
shortcuts.append(shortcut_zoom_in);
shortcuts.append(shortcut_zoom_out);

View File

@ -87,7 +87,7 @@ class DisassemblerGraphView : public GraphView
};
public:
DisassemblerGraphView(QWidget *parent, CutterSeekable* seekable);
DisassemblerGraphView(QWidget *parent, CutterSeekable* seekable, MainWindow* mainWindow);
~DisassemblerGraphView() override;
std::unordered_map<ut64, DisassemblyBlock> disassembly_blocks;
virtual void drawBlock(QPainter &p, GraphView::GraphBlock &block) override;

View File

@ -39,8 +39,8 @@ static DisassemblyTextBlockUserData *getUserData(const QTextBlock &block)
}
DisassemblyWidget::DisassemblyWidget(MainWindow *main, QAction *action)
: MemoryDockWidget(CutterCore::MemoryWidgetType::Disassembly, main, action)
, mCtxMenu(new DisassemblyContextMenu(this))
: MemoryDockWidget(MemoryWidgetType::Disassembly, main, action)
, mCtxMenu(new DisassemblyContextMenu(this, main))
, mDisasScrollArea(new DisassemblyScrollArea(this))
, mDisasTextEdit(new DisassemblyTextEdit(this))
{
@ -161,14 +161,6 @@ DisassemblyWidget::DisassemblyWidget(MainWindow *main, QAction *action)
connect(Config(), SIGNAL(fontsUpdated()), this, SLOT(fontsUpdatedSlot()));
connect(Config(), SIGNAL(colorsUpdated()), this, SLOT(colorsUpdatedSlot()));
connect(this, &QDockWidget::visibilityChanged, this, [](bool visibility) {
bool emptyGraph = (Core()->getMemoryWidgetPriority() == CutterCore::MemoryWidgetType::Graph
&& Core()->isGraphEmpty());
if (visibility && !emptyGraph) {
Core()->setMemoryWidgetPriority(CutterCore::MemoryWidgetType::Disassembly);
}
});
connect(Core(), &CutterCore::refreshAll, this, [this]() {
refreshDisasm(seekable->getOffset());
});
@ -192,9 +184,8 @@ DisassemblyWidget::DisassemblyWidget(MainWindow *main, QAction *action)
connect(a, &QAction::triggered, this, (slot)); }
// Space to switch to graph
ADD_ACTION(Qt::Key_Space, Qt::WidgetWithChildrenShortcut, [] {
Core()->setMemoryWidgetPriority(CutterCore::MemoryWidgetType::Graph);
Core()->triggerRaisePrioritizedMemoryWidget();
ADD_ACTION(Qt::Key_Space, Qt::WidgetWithChildrenShortcut, [this] {
mainWindow->showMemoryWidget(MemoryWidgetType::Graph);
})
ADD_ACTION(Qt::Key_Escape, Qt::WidgetWithChildrenShortcut, &DisassemblyWidget::seekPrev)

View File

@ -51,5 +51,5 @@ void EntrypointWidget::on_entrypointTreeWidget_itemDoubleClicked(QTreeWidgetItem
return;
EntrypointDescription ep = item->data(0, Qt::UserRole).value<EntrypointDescription>();
Core()->seek(ep.vaddr);
Core()->seekAndShow(ep.vaddr);
}

View File

@ -183,5 +183,5 @@ void ExportsWidget::on_exportsTreeView_doubleClicked(const QModelIndex &index)
return;
ExportDescription exp = index.data(ExportsModel::ExportDescriptionRole).value<ExportDescription>();
Core()->seek(exp.vaddr);
Core()->seekAndShow(exp.vaddr);
}

View File

@ -174,7 +174,7 @@ void FlagsWidget::on_flagsTreeView_doubleClicked(const QModelIndex &index)
return;
FlagDescription flag = index.data(FlagsModel::FlagDescriptionRole).value<FlagDescription>();
Core()->seek(flag.offset);
Core()->seekAndShow(flag.offset);
}
void FlagsWidget::on_flagspaceCombo_currentTextChanged(const QString &arg1)

View File

@ -522,7 +522,7 @@ void FunctionsWidget::onFunctionsDoubleClicked(const QModelIndex &index)
FunctionDescription function = index.data(
FunctionModel::FunctionDescriptionRole).value<FunctionDescription>();
Core()->seek(function.offset);
Core()->seekAndShow(function.offset);
}
void FunctionsWidget::showFunctionsContextMenu(const QPoint &pt)
@ -556,7 +556,7 @@ void FunctionsWidget::on_actionDisasAdd_comment_triggered()
// Rename function in r2 core
Core()->setComment(function.offset, comment);
// Seek to new renamed function
Core()->seek(function.offset);
Core()->seekAndShow(function.offset);
// TODO: Refresh functions tree widget
}
}
@ -581,7 +581,7 @@ void FunctionsWidget::on_actionFunctionsRename_triggered()
Core()->renameFunction(function.name, new_name);
// Seek to new renamed function
Core()->seek(function.offset);
Core()->seekAndShow(function.offset);
}
}

View File

@ -5,7 +5,7 @@
#include <QVBoxLayout>
GraphWidget::GraphWidget(MainWindow *main, QAction *action) :
MemoryDockWidget(CutterCore::MemoryWidgetType::Graph, main, action)
MemoryDockWidget(MemoryWidgetType::Graph, main, action)
{
setObjectName(main
? main->getUniqueObjectName(getWidgetType())
@ -23,7 +23,7 @@ GraphWidget::GraphWidget(MainWindow *main, QAction *action) :
header->setReadOnly(true);
layout->addWidget(header);
graphView = new DisassemblerGraphView(layoutWidget, seekable);
graphView = new DisassemblerGraphView(layoutWidget, seekable, main);
layout->addWidget(graphView);
// getting the name of the class is implementation defined, and cannot be
@ -40,16 +40,24 @@ GraphWidget::GraphWidget(MainWindow *main, QAction *action) :
connect(this, &QDockWidget::visibilityChanged, this, [ = ](bool visibility) {
main->toggleOverview(visibility, this);
if (visibility) {
Core()->setMemoryWidgetPriority(CutterCore::MemoryWidgetType::Graph);
graphView->onSeekChanged(Core()->getOffset());
}
});
QAction *switchAction = new QAction(this);
switchAction->setShortcut(Qt::Key_Space);
switchAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
addAction(switchAction);
connect(switchAction, &QAction::triggered, this, [this] {
mainWindow->showMemoryWidget(MemoryWidgetType::Disassembly);
});
connect(graphView, &DisassemblerGraphView::graphMoved, this, [ = ]() {
main->toggleOverview(true, this);
});
connect(seekable, &CutterSeekable::seekableSeekChanged, this, &GraphWidget::prepareHeader);
connect(Core(), &CutterCore::functionRenamed, this, &GraphWidget::prepareHeader);
graphView->installEventFilter(this);
}
QWidget *GraphWidget::widgetToFocusOnRaise()

View File

@ -134,5 +134,5 @@ void HeadersWidget::setScrollMode()
void HeadersWidget::on_headersTreeView_doubleClicked(const QModelIndex &index)
{
HeaderDescription item = index.data(HeadersModel::HeaderDescriptionRole).value<HeaderDescription>();
Core()->seek(item.vaddr);
Core()->seekAndShow(item.vaddr);
}

View File

@ -17,7 +17,7 @@
#include <QShortcut>
HexdumpWidget::HexdumpWidget(MainWindow *main, QAction *action) :
MemoryDockWidget(CutterCore::MemoryWidgetType::Hexdump, main, action),
MemoryDockWidget(MemoryWidgetType::Hexdump, main, action),
ui(new Ui::HexdumpWidget)
{
ui->setupUi(this);
@ -78,13 +78,6 @@ HexdumpWidget::HexdumpWidget(MainWindow *main, QAction *action) :
this->ui->hexTextView->addAction(&syncAction);
connect(Config(), SIGNAL(fontsUpdated()), this, SLOT(fontsUpdated()));
connect(this, &QDockWidget::visibilityChanged, this, [](bool visibility) {
if (visibility) {
Core()->setMemoryWidgetPriority(CutterCore::MemoryWidgetType::Hexdump);
}
});
connect(Core(), &CutterCore::refreshAll, this, [this]() { refresh(); });
connect(seekable, &CutterSeekable::seekableSeekChanged, this, &HexdumpWidget::onSeekChanged);
@ -97,6 +90,7 @@ HexdumpWidget::HexdumpWidget(MainWindow *main, QAction *action) :
});
connect(ui->hexTextView, &HexWidget::selectionChanged, this, &HexdumpWidget::selectionChanged);
connect(ui->hexSideTab_2, &QTabWidget::currentChanged, this, &HexdumpWidget::refreshSelectionInfo);
ui->hexTextView->installEventFilter(this);
initParsing();
selectHexPreview();

View File

@ -194,5 +194,5 @@ void ImportsWidget::on_importsTreeView_doubleClicked(const QModelIndex &index)
if (!index.isValid())
return;
Core()->seek(index.data(ImportsModel::AddressRole).toLongLong());
Core()->seekAndShow(index.data(ImportsModel::AddressRole).toLongLong());
}

View File

@ -1,44 +1,64 @@
#include "MemoryDockWidget.h"
#include "common/CutterSeekable.h"
#include "MainWindow.h"
#include <QAction>
#include <QEvent>
MemoryDockWidget::MemoryDockWidget(CutterCore::MemoryWidgetType type, MainWindow *parent, QAction *action)
MemoryDockWidget::MemoryDockWidget(MemoryWidgetType type, MainWindow *parent, QAction *action)
: CutterDockWidget(parent, action)
, mType(type), seekable(new CutterSeekable(this))
{
connect(Core(), &CutterCore::raisePrioritizedMemoryWidget, this, &MemoryDockWidget::handleRaiseMemoryWidget);
if (parent) {
parent->addMemoryDockWidget(this);
}
connect(seekable, &CutterSeekable::syncChanged, this, &MemoryDockWidget::updateWindowTitle);
}
void MemoryDockWidget::handleRaiseMemoryWidget(CutterCore::MemoryWidgetType raiseType)
bool MemoryDockWidget::tryRaiseMemoryWidget()
{
if (!seekable->isSynchronized()) {
return;
}
bool raisingEmptyGraph = (raiseType == CutterCore::MemoryWidgetType::Graph && Core()->isGraphEmpty());
if (raisingEmptyGraph) {
raiseType = CutterCore::MemoryWidgetType::Disassembly;
return false;
}
if (raiseType == mType) {
if (getBoundAction()) {
getBoundAction()->setChecked(true);
}
show();
raise();
widgetToFocusOnRaise()->setFocus(Qt::FocusReason::TabFocusReason);
if (mType == MemoryWidgetType::Graph && Core()->isGraphEmpty()) {
return false;
}
raiseMemoryWidget();
return true;
}
void MemoryDockWidget::raiseMemoryWidget()
{
if (getBoundAction()) {
getBoundAction()->setChecked(true);
}
show();
raise();
widgetToFocusOnRaise()->setFocus(Qt::FocusReason::TabFocusReason);
}
bool MemoryDockWidget::eventFilter(QObject *object, QEvent *event)
{
if (event->type() == QEvent::FocusIn) {
mainWindow->setCurrentMemoryWidget(this);
}
return CutterDockWidget::eventFilter(object, event);
}
void MemoryDockWidget::updateWindowTitle()
{
if (seekable->isSynchronized()) {
setWindowTitle(getWindowTitle());
} else {
setWindowTitle(getWindowTitle() + CutterSeekable::tr(" (unsynced)"));
QString name = getWindowTitle();
QString id = getDockNumber();
if (!id.isEmpty()) {
name += " " + id;
}
if (!seekable->isSynchronized()) {
name += CutterSeekable::tr(" (unsynced)");
}
setWindowTitle(name);
}
CutterSeekable* MemoryDockWidget::getSeekable() const

View File

@ -6,19 +6,28 @@
class CutterSeekable;
/* Disassembly/Graph/Hexdump/Pseudocode view priority */
enum class MemoryWidgetType { Disassembly, Graph, Hexdump, Pseudocode };
class MemoryDockWidget : public CutterDockWidget
{
Q_OBJECT
public:
MemoryDockWidget(CutterCore::MemoryWidgetType type, MainWindow *parent, QAction *action = nullptr);
MemoryDockWidget(MemoryWidgetType type, MainWindow *parent, QAction *action = nullptr);
~MemoryDockWidget() {}
CutterSeekable* getSeekable() const;
bool tryRaiseMemoryWidget();
void raiseMemoryWidget();
MemoryWidgetType getType() const
{
return mType;
}
bool eventFilter(QObject *object, QEvent *event);
private:
void handleRaiseMemoryWidget(CutterCore::MemoryWidgetType raiseType);
CutterCore::MemoryWidgetType mType;
MemoryWidgetType mType;
public slots:
void updateWindowTitle();

View File

@ -152,5 +152,5 @@ void MemoryMapWidget::on_memoryTreeView_doubleClicked(const QModelIndex &index)
{
MemoryMapDescription item = index.data(
MemoryMapModel::MemoryDescriptionRole).value<MemoryMapDescription>();
Core()->seek(item.addrStart);
Core()->seekAndShow(item.addrStart);
}

View File

@ -69,7 +69,7 @@ void Omnibar::on_gotoEntry_returnPressed()
{
QString str = this->text();
if (!str.isEmpty()) {
Core()->seek(str);
Core()->seekAndShow(str);
}
this->setText("");

View File

@ -35,7 +35,7 @@ struct DecompiledCodeTextLine
PseudocodeWidget::PseudocodeWidget(MainWindow *main, QAction *action) :
MemoryDockWidget(CutterCore::MemoryWidgetType::Pseudocode, main, action),
MemoryDockWidget(MemoryWidgetType::Pseudocode, main, action),
ui(new Ui::PseudocodeWidget)
{
ui->setupUi(this);
@ -48,12 +48,6 @@ PseudocodeWidget::PseudocodeWidget(MainWindow *main, QAction *action) :
connect(Config(), SIGNAL(fontsUpdated()), this, SLOT(fontsUpdated()));
connect(Config(), SIGNAL(colorsUpdated()), this, SLOT(colorsUpdatedSlot()));
connect(this, &QDockWidget::visibilityChanged, this, [](bool visibility) {
if (visibility) {
Core()->setMemoryWidgetPriority(CutterCore::MemoryWidgetType::Pseudocode);
}
});
// TODO Use RefreshDeferrer and remove the refresh button
connect(ui->refreshButton, &QAbstractButton::clicked, this, [this]() {
doRefresh(Core()->getOffset());

View File

@ -179,7 +179,7 @@ void RegisterRefsWidget::on_registerRefTreeView_doubleClicked(const QModelIndex
{
RegisterRefDescription item = index.data(
RegisterRefModel::RegisterRefDescriptionRole).value<RegisterRefDescription>();
Core()->seek(item.value);
Core()->seekAndShow(item.value);
}
void RegisterRefsWidget::showRegRefContextMenu(const QPoint &pt)

View File

@ -147,7 +147,7 @@ void RelocsWidget::on_relocsTreeView_doubleClicked(const QModelIndex &index)
if (!index.isValid())
return;
Core()->seek(index.data(RelocsModel::AddressRole).toLongLong());
Core()->seekAndShow(index.data(RelocsModel::AddressRole).toLongLong());
}
void RelocsWidget::refreshRelocs()

View File

@ -107,5 +107,5 @@ void ResourcesWidget::onDoubleClicked(const QModelIndex &index)
return;
ResourcesDescription res = index.data(Qt::UserRole).value<ResourcesDescription>();
Core()->seek(res.vaddr);
Core()->seekAndShow(res.vaddr);
}

View File

@ -206,7 +206,7 @@ void SearchWidget::on_searchTreeView_doubleClicked(const QModelIndex &index)
SearchDescription search = index.data(
SearchModel::SearchDescriptionRole).value<SearchDescription>();
Core()->seek(search.offset);
Core()->seekAndShow(search.offset);
}
void SearchWidget::searchChanged()

View File

@ -303,7 +303,7 @@ void SectionsWidget::onSectionsDoubleClicked(const QModelIndex &index)
}
auto section = index.data(SectionsModel::SectionDescriptionRole).value<SectionDescription>();
Core()->seek(section.vaddr);
Core()->seekAndShow(section.vaddr);
}
void SectionsWidget::resizeEvent(QResizeEvent *event) {
@ -470,7 +470,7 @@ void AddrDockScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
if (event->buttons() & Qt::LeftButton) {
RVA seekAddr = getAddrFromPos((int)event->scenePos().y(), true);
disableCenterOn = true;
Core()->seek(seekAddr);
Core()->seekAndShow(seekAddr);
disableCenterOn = false;
return;
}

View File

@ -188,5 +188,5 @@ void SegmentsWidget::onSegmentsDoubleClicked(const QModelIndex &index)
return;
auto segment = index.data(SegmentsModel::SegmentDescriptionRole).value<SegmentDescription>();
Core()->seek(segment.vaddr);
Core()->seekAndShow(segment.vaddr);
}

View File

@ -108,7 +108,7 @@ void StackWidget::onDoubleClicked(const QModelIndex &index)
// Check if we are clicking on the offset or value columns and seek if it is the case
if (index.column() <= 1) {
QString item = index.data().toString();
Core()->seek(item);
Core()->seekAndShow(item);
}
}
@ -123,7 +123,7 @@ void StackWidget::customMenuRequested(QPoint pos)
void StackWidget::seekOffset()
{
QString offset = viewStack->selectionModel()->currentIndex().data().toString();
Core()->seek(offset);
Core()->seekAndShow(offset);
}
void StackWidget::editStack()

View File

@ -204,7 +204,7 @@ void StringsWidget::on_stringsTreeView_doubleClicked(const QModelIndex &index)
}
StringDescription str = index.data(StringsModel::StringDescriptionRole).value<StringDescription>();
Core()->seek(str.vaddr);
Core()->seekAndShow(str.vaddr);
}
void StringsWidget::refreshStrings()

View File

@ -150,7 +150,7 @@ void SymbolsWidget::on_symbolsTreeView_doubleClicked(const QModelIndex &index)
}
auto symbol = index.data(SymbolsModel::SymbolDescriptionRole).value<SymbolDescription>();
Core()->seek(symbol.vaddr);
Core()->seekAndShow(symbol.vaddr);
}
void SymbolsWidget::refreshSymbols()

View File

@ -188,10 +188,10 @@ void VTablesWidget::on_vTableTreeView_doubleClicked(const QModelIndex &index)
QModelIndex parent = index.parent();
if (parent.isValid()) {
Core()->seek(index.data(
Core()->seekAndShow(index.data(
VTableModel::VTableDescriptionRole).value<BinClassMethodDescription>().addr);
} else {
Core()->seek(index.data(
Core()->seekAndShow(index.data(
VTableModel::VTableDescriptionRole).value<VTableDescription>().addr);
}
}

View File

@ -151,5 +151,5 @@ void ZignaturesWidget::on_zignaturesTreeView_doubleClicked(const QModelIndex &in
{
ZignatureDescription item = index.data(
ZignaturesModel::ZignatureDescriptionRole).value<ZignatureDescription>();
Core()->seek(item.offset);
Core()->seekAndShow(item.offset);
}