Refactored CutterSeekableWidget to CutterSeekable (#1099)

This commit refactors the CutterSeekableWidget class
and adds some documentation.
This commit is contained in:
xarkes 2019-01-13 15:20:07 +01:00 committed by Itay Cohen
parent bdc684769f
commit f385cf26d5
12 changed files with 171 additions and 143 deletions

View File

@ -249,7 +249,7 @@ QString CutterCore::cmd(const char *str)
QString o = QString(res ? res : ""); QString o = QString(res ? res : "");
r_mem_free(res); r_mem_free(res);
if (offset != core_->offset) { if (offset != core_->offset) {
emit seekChanged(core_->offset); updateSeek();
} }
return o; return o;
} }

View File

@ -188,7 +188,6 @@ SOURCES += \
common/NestedIPyKernel.cpp \ common/NestedIPyKernel.cpp \
dialogs/R2PluginsDialog.cpp \ dialogs/R2PluginsDialog.cpp \
widgets/CutterDockWidget.cpp \ widgets/CutterDockWidget.cpp \
widgets/CutterSeekableWidget.cpp \
widgets/CutterTreeWidget.cpp \ widgets/CutterTreeWidget.cpp \
widgets/GraphWidget.cpp \ widgets/GraphWidget.cpp \
common/JsonTreeItem.cpp \ common/JsonTreeItem.cpp \
@ -219,7 +218,8 @@ SOURCES += \
widgets/CutterTreeView.cpp \ widgets/CutterTreeView.cpp \
widgets/ComboQuickFilterView.cpp \ widgets/ComboQuickFilterView.cpp \
dialogs/HexdumpRangeDialog.cpp \ dialogs/HexdumpRangeDialog.cpp \
common/QtResImporter.cpp common/QtResImporter.cpp \
widgets/CutterSeekable.cpp
HEADERS += \ HEADERS += \
Cutter.h \ Cutter.h \
@ -288,7 +288,6 @@ HEADERS += \
dialogs/R2PluginsDialog.h \ dialogs/R2PluginsDialog.h \
widgets/CutterDockWidget.h \ widgets/CutterDockWidget.h \
widgets/CutterTreeWidget.h \ widgets/CutterTreeWidget.h \
widgets/CutterSeekableWidget.h \
widgets/GraphWidget.h \ widgets/GraphWidget.h \
common/JsonTreeItem.h \ common/JsonTreeItem.h \
common/JsonModel.h \ common/JsonModel.h \
@ -322,7 +321,8 @@ HEADERS += \
widgets/CutterTreeView.h \ widgets/CutterTreeView.h \
widgets/ComboQuickFilterView.h \ widgets/ComboQuickFilterView.h \
dialogs/HexdumpRangeDialog.h \ dialogs/HexdumpRangeDialog.h \
common/QtResImporter.h common/QtResImporter.h \
widgets/CutterSeekable.h
FORMS += \ FORMS += \
dialogs/AboutDialog.ui \ dialogs/AboutDialog.ui \

View File

@ -0,0 +1,59 @@
#include "MainWindow.h"
#include "CutterSeekable.h"
#include <QPlainTextEdit>
CutterSeekable::CutterSeekable(QObject *parent)
:
QObject(parent)
{
connect(Core(), &CutterCore::seekChanged, this, &CutterSeekable::onCoreSeekChanged);
}
CutterSeekable::~CutterSeekable() {}
void CutterSeekable::onCoreSeekChanged(RVA addr)
{
if (synchronized && widgetOffset != addr) {
synchronized = false;
seek(addr);
synchronized = true;
}
}
void CutterSeekable::seek(RVA addr)
{
previousOffset = widgetOffset;
widgetOffset = addr;
if (synchronized) {
Core()->seek(addr);
}
emit seekableSeekChanged(addr);
}
void CutterSeekable::seekPrev()
{
if (synchronized) {
Core()->seekPrev();
} else {
this->seek(previousOffset);
}
}
RVA CutterSeekable::getOffset()
{
return (synchronized) ? Core()->getOffset() : widgetOffset;
}
void CutterSeekable::toggleSynchronization()
{
synchronized = !synchronized;
}
bool CutterSeekable::isSynchronized()
{
return synchronized;
}

View File

@ -0,0 +1,80 @@
#pragma once
#include "Cutter.h"
class MainWindow;
class CutterSeekable : public QObject
{
Q_OBJECT
public:
explicit CutterSeekable(QObject *parent = nullptr);
~CutterSeekable();
/**
* @brief seek changes current offset.
* If the seekable is synchronized with Core, then
* the Core offset will be modified and then the CutterCore::seekChanged
* signal will be emitted.
* In any case, CutterSeekable::seekableSeekChanged is emitted.
* @param addr the location to seek at.
*/
void seek(RVA addr);
/**
* @brief toggleSyncWithCore toggles
* Core seek synchronization.
*/
void toggleSynchronization();
/**
* @brief getOffset returns the seekable offset.
* If the seekable is synchronized with Core, this function
* is similar to Core()->getOffset.
* If it's not synchronized, it will return the seekable current seek.
* @return the seekable current offset.
*/
RVA getOffset();
/**
* @brief isSynchronized tells whether the seekable
* is synchronized with Core or not.
* @return boolean
*/
bool isSynchronized();
public slots:
/**
* @brief seekPrev seeks to last location.
*/
void seekPrev();
private slots:
/**
* @brief onCoreSeekChanged
*/
void onCoreSeekChanged(RVA addr);
private:
/**
* @brief widgetOffset widget seek location.
*/
RVA widgetOffset = RVA_INVALID;
/**
* @brief previousOffset last seek location.
* @todo maybe use an actual history?
*/
RVA previousOffset = RVA_INVALID;
/**
* @brief synchronized tells with the seekable's offset is
* synchronized with core or not.
*/
bool synchronized = true;
signals:
void seekableSeekChanged(RVA addr);
};

View File

@ -1,66 +0,0 @@
#include "MainWindow.h"
#include "CutterSeekableWidget.h"
CutterSeekableWidget::CutterSeekableWidget(QObject *parent)
:
QObject(parent)
{
connect(Core(), &CutterCore::seekChanged, this, &CutterSeekableWidget::onSeekChanged);
}
void CutterSeekableWidget::onSeekChanged(RVA addr)
{
if (isInSyncWithCore) {
emit seekChanged(addr);
}
}
void CutterSeekableWidget::seek(RVA addr)
{
if (isInSyncWithCore) {
Core()->seek(addr);
} else {
prevIdenpendentOffset = independentOffset;
independentOffset = addr;
emit seekChanged(addr);
}
}
RVA CutterSeekableWidget::getOffset()
{
RVA addr;
if (isInSyncWithCore) {
addr = Core()->getOffset();
} else {
addr = independentOffset;
}
return addr;
}
void CutterSeekableWidget::toggleSyncWithCore()
{
isInSyncWithCore = !isInSyncWithCore;
}
RVA CutterSeekableWidget::getIndependentOffset()
{
return independentOffset;
}
RVA CutterSeekableWidget::getPrevIndependentOffset()
{
return prevIdenpendentOffset;
}
bool CutterSeekableWidget::getSyncWithCore()
{
return isInSyncWithCore;
}
void CutterSeekableWidget::setIndependentOffset(RVA addr)
{
independentOffset = addr;
}
CutterSeekableWidget::~CutterSeekableWidget() {}

View File

@ -1,31 +0,0 @@
#pragma once
#include "Cutter.h"
class MainWindow;
class CutterSeekableWidget : public QObject
{
Q_OBJECT
public:
explicit CutterSeekableWidget(QObject *parent = nullptr);
~CutterSeekableWidget();
void seek(RVA addr);
void toggleSyncWithCore();
RVA getOffset();
RVA getIndependentOffset();
RVA getPrevIndependentOffset();
bool getSyncWithCore();
void setIndependentOffset(RVA addr);
void onSeekChanged(RVA addr);
private:
RVA independentOffset = RVA_INVALID;
RVA prevIdenpendentOffset = RVA_INVALID;
bool isInSyncWithCore = true;
signals:
void seekChanged(RVA addr);
};

View File

@ -1,5 +1,5 @@
#include "DisassemblerGraphView.h" #include "DisassemblerGraphView.h"
#include "CutterSeekableWidget.h" #include "CutterSeekable.h"
#include <QPainter> #include <QPainter>
#include <QJsonObject> #include <QJsonObject>
#include <QJsonArray> #include <QJsonArray>
@ -26,7 +26,7 @@ DisassemblerGraphView::DisassemblerGraphView(QWidget *parent)
: GraphView(parent), : GraphView(parent),
mFontMetrics(nullptr), mFontMetrics(nullptr),
mMenu(new DisassemblyContextMenu(this)), mMenu(new DisassemblyContextMenu(this)),
seekable(new CutterSeekableWidget(this)) seekable(new CutterSeekable(this))
{ {
highlight_token = nullptr; highlight_token = nullptr;
// Signals that require a refresh all // Signals that require a refresh all
@ -56,7 +56,7 @@ DisassemblerGraphView::DisassemblerGraphView(QWidget *parent)
// ESC for previous // ESC for previous
QShortcut *shortcut_escape = new QShortcut(QKeySequence(Qt::Key_Escape), this); QShortcut *shortcut_escape = new QShortcut(QKeySequence(Qt::Key_Escape), this);
shortcut_escape->setContext(Qt::WidgetShortcut); shortcut_escape->setContext(Qt::WidgetShortcut);
connect(shortcut_escape, SIGNAL(activated()), this, SLOT(seekPrev())); connect(shortcut_escape, SIGNAL(activated()), seekable, SLOT(seekPrev()));
// Zoom shortcuts // Zoom shortcuts
QShortcut *shortcut_zoom_in = new QShortcut(QKeySequence(Qt::Key_Plus), this); QShortcut *shortcut_zoom_in = new QShortcut(QKeySequence(Qt::Key_Plus), this);
@ -100,7 +100,7 @@ DisassemblerGraphView::DisassemblerGraphView(QWidget *parent)
shortcuts.append(shortcut_next_instr_arrow); shortcuts.append(shortcut_next_instr_arrow);
shortcuts.append(shortcut_prev_instr_arrow); shortcuts.append(shortcut_prev_instr_arrow);
//Export Graph menu // Export Graph menu
mMenu->addSeparator(); mMenu->addSeparator();
actionExportGraph.setText(tr("Export Graph")); actionExportGraph.setText(tr("Export Graph"));
mMenu->addAction(&actionExportGraph); mMenu->addAction(&actionExportGraph);
@ -124,10 +124,10 @@ DisassemblerGraphView::DisassemblerGraphView(QWidget *parent)
void DisassemblerGraphView::connectSeekChanged(bool disconn) void DisassemblerGraphView::connectSeekChanged(bool disconn)
{ {
if (disconn) { if (disconn) {
disconnect(seekable, &CutterSeekableWidget::seekChanged, this, disconnect(seekable, &CutterSeekable::seekableSeekChanged, this,
&DisassemblerGraphView::onSeekChanged); &DisassemblerGraphView::onSeekChanged);
} else { } else {
connect(seekable, &CutterSeekableWidget::seekChanged, this, &DisassemblerGraphView::onSeekChanged); connect(seekable, &CutterSeekable::seekableSeekChanged, this, &DisassemblerGraphView::onSeekChanged);
} }
} }
@ -140,12 +140,11 @@ DisassemblerGraphView::~DisassemblerGraphView()
void DisassemblerGraphView::toggleSync() void DisassemblerGraphView::toggleSync()
{ {
seekable->toggleSyncWithCore(); seekable->toggleSynchronization();
if (seekable->getSyncWithCore()) { if (seekable->isSynchronized()) {
parentWidget()->setWindowTitle(windowTitle); parentWidget()->setWindowTitle(windowTitle);
} else { } else {
parentWidget()->setWindowTitle(windowTitle + CutterSeekableWidget::tr(" (unsynced)")); parentWidget()->setWindowTitle(windowTitle + CutterSeekable::tr(" (unsynced)"));
seekable->setIndependentOffset(Core()->getOffset());
} }
} }
@ -214,8 +213,8 @@ void DisassemblerGraphView::loadCurrentGraph()
} else if (!funcName.isEmpty()) { } else if (!funcName.isEmpty()) {
windowTitle += " (" + funcName + ")"; windowTitle += " (" + funcName + ")";
} }
if (!seekable->getSyncWithCore()) { if (!seekable->isSynchronized()) {
parentWidget()->setWindowTitle(windowTitle + CutterSeekableWidget::tr(" (unsynced)")); parentWidget()->setWindowTitle(windowTitle + CutterSeekable::tr(" (unsynced)"));
} else { } else {
parentWidget()->setWindowTitle(windowTitle); parentWidget()->setWindowTitle(windowTitle);
} }
@ -775,15 +774,6 @@ void DisassemblerGraphView::seekLocal(RVA addr, bool update_viewport)
} }
} }
void DisassemblerGraphView::seekPrev()
{
if (seekable->getSyncWithCore()) {
Core()->seekPrev();
} else {
seekable->seek(seekable->getPrevIndependentOffset());
}
}
DisassemblerGraphView::Token *DisassemblerGraphView::getToken(Instr *instr, int x) DisassemblerGraphView::Token *DisassemblerGraphView::getToken(Instr *instr, int x)
{ {
x -= (3 * charWidth); // Ignore left margin x -= (3 * charWidth); // Ignore left margin

View File

@ -11,7 +11,7 @@
#include "widgets/GraphView.h" #include "widgets/GraphView.h"
#include "menus/DisassemblyContextMenu.h" #include "menus/DisassemblyContextMenu.h"
#include "common/RichTextPainter.h" #include "common/RichTextPainter.h"
#include "CutterSeekableWidget.h" #include "CutterSeekable.h"
class QTextEdit; class QTextEdit;
class SyntaxHighlighter; class SyntaxHighlighter;
@ -149,8 +149,6 @@ protected:
virtual void wheelEvent(QWheelEvent *event) override; virtual void wheelEvent(QWheelEvent *event) override;
private slots: private slots:
void seekPrev();
void on_actionExportGraph_triggered(); void on_actionExportGraph_triggered();
private: private:
@ -179,7 +177,7 @@ private:
DisassemblyBlock *blockForAddress(RVA addr); DisassemblyBlock *blockForAddress(RVA addr);
void seekLocal(RVA addr, bool update_viewport = true); void seekLocal(RVA addr, bool update_viewport = true);
void seekInstruction(bool previous_instr); void seekInstruction(bool previous_instr);
CutterSeekableWidget *seekable = nullptr; CutterSeekable *seekable = nullptr;
QList<QShortcut *> shortcuts; QList<QShortcut *> shortcuts;
QList<RVA> breakpoints; QList<RVA> breakpoints;

View File

@ -41,7 +41,7 @@ DisassemblyWidget::DisassemblyWidget(MainWindow *main, QAction *action)
, mCtxMenu(new DisassemblyContextMenu(this)) , mCtxMenu(new DisassemblyContextMenu(this))
, mDisasScrollArea(new DisassemblyScrollArea(this)) , mDisasScrollArea(new DisassemblyScrollArea(this))
, mDisasTextEdit(new DisassemblyTextEdit(this)) , mDisasTextEdit(new DisassemblyTextEdit(this))
, seekable(new CutterSeekableWidget(this)) , seekable(new CutterSeekable(this))
{ {
topOffset = bottomOffset = RVA_INVALID; topOffset = bottomOffset = RVA_INVALID;
cursorLineOffset = 0; cursorLineOffset = 0;
@ -147,7 +147,7 @@ DisassemblyWidget::DisassemblyWidget(MainWindow *main, QAction *action)
syncIt.setText(tr("Sync/unsync offset")); syncIt.setText(tr("Sync/unsync offset"));
mCtxMenu->addAction(&syncIt); mCtxMenu->addAction(&syncIt);
connect(&syncIt, SIGNAL(triggered(bool)), this, SLOT(toggleSync())); connect(&syncIt, SIGNAL(triggered(bool)), this, SLOT(toggleSync()));
connect(seekable, &CutterSeekableWidget::seekChanged, this, &DisassemblyWidget::on_seekChanged); connect(seekable, &CutterSeekable::seekableSeekChanged, this, &DisassemblyWidget::on_seekChanged);
#define ADD_SHORTCUT(ksq, slot) { \ #define ADD_SHORTCUT(ksq, slot) { \
QShortcut *s = new QShortcut((ksq), this); \ QShortcut *s = new QShortcut((ksq), this); \
@ -180,12 +180,11 @@ DisassemblyWidget::DisassemblyWidget(MainWindow *main, QAction *action)
void DisassemblyWidget::toggleSync() void DisassemblyWidget::toggleSync()
{ {
QString windowTitle = tr("Disassembly"); QString windowTitle = tr("Disassembly");
seekable->toggleSyncWithCore(); seekable->toggleSynchronization();
if (seekable->getSyncWithCore()) { if (seekable->isSynchronized()) {
setWindowTitle(windowTitle); setWindowTitle(windowTitle);
} else { } else {
setWindowTitle(windowTitle + CutterSeekableWidget::tr(" (unsynced)")); setWindowTitle(windowTitle + CutterSeekable::tr(" (unsynced)"));
seekable->setIndependentOffset(Core()->getOffset());
} }
} }

View File

@ -3,7 +3,7 @@
#include "Cutter.h" #include "Cutter.h"
#include "CutterDockWidget.h" #include "CutterDockWidget.h"
#include "CutterSeekableWidget.h" #include "CutterSeekable.h"
#include <QTextEdit> #include <QTextEdit>
#include <QPlainTextEdit> #include <QPlainTextEdit>
#include <QShortcut> #include <QShortcut>
@ -72,7 +72,7 @@ private:
void moveCursorRelative(bool up, bool page); void moveCursorRelative(bool up, bool page);
QAction syncIt; QAction syncIt;
CutterSeekableWidget *seekable; CutterSeekable *seekable;
}; };
class DisassemblyScrollArea : public QAbstractScrollArea class DisassemblyScrollArea : public QAbstractScrollArea

View File

@ -17,7 +17,7 @@
HexdumpWidget::HexdumpWidget(MainWindow *main, QAction *action) : HexdumpWidget::HexdumpWidget(MainWindow *main, QAction *action) :
CutterDockWidget(main, action), CutterDockWidget(main, action),
ui(new Ui::HexdumpWidget), ui(new Ui::HexdumpWidget),
seekable(new CutterSeekableWidget(this)) seekable(new CutterSeekable(this))
{ {
ui->setupUi(this); ui->setupUi(this);
@ -116,7 +116,7 @@ HexdumpWidget::HexdumpWidget(MainWindow *main, QAction *action) :
connect(ui->hexHexText, &QTextEdit::cursorPositionChanged, this, &HexdumpWidget::selectionChanged); connect(ui->hexHexText, &QTextEdit::cursorPositionChanged, this, &HexdumpWidget::selectionChanged);
connect(ui->hexASCIIText, &QTextEdit::cursorPositionChanged, this, connect(ui->hexASCIIText, &QTextEdit::cursorPositionChanged, this,
&HexdumpWidget::selectionChanged); &HexdumpWidget::selectionChanged);
connect(seekable, &CutterSeekableWidget::seekChanged, this, &HexdumpWidget::on_seekChanged); connect(seekable, &CutterSeekable::seekableSeekChanged, this, &HexdumpWidget::on_seekChanged);
connect(&rangeDialog, &QDialog::accepted, this, &HexdumpWidget::on_rangeDialogAccepted); connect(&rangeDialog, &QDialog::accepted, this, &HexdumpWidget::on_rangeDialogAccepted);
format = Format::Hex; format = Format::Hex;
@ -652,12 +652,11 @@ void HexdumpWidget::showHexdumpContextMenu(const QPoint &pt)
void HexdumpWidget::toggleSync() void HexdumpWidget::toggleSync()
{ {
QString windowTitle = tr("Hexdump"); QString windowTitle = tr("Hexdump");
seekable->toggleSyncWithCore(); seekable->toggleSynchronization();
if (seekable->getSyncWithCore()) { if (seekable->isSynchronized()) {
setWindowTitle(windowTitle); setWindowTitle(windowTitle);
} else { } else {
setWindowTitle(windowTitle + CutterSeekableWidget::tr(" (unsynced)")); setWindowTitle(windowTitle + CutterSeekable::tr(" (unsynced)"));
seekable->setIndependentOffset(Core()->getOffset());
} }
} }

View File

@ -10,7 +10,7 @@
#include "Cutter.h" #include "Cutter.h"
#include "CutterDockWidget.h" #include "CutterDockWidget.h"
#include "CutterSeekableWidget.h" #include "CutterSeekable.h"
#include "dialogs/HexdumpRangeDialog.h" #include "dialogs/HexdumpRangeDialog.h"
#include "common/Highlighter.h" #include "common/Highlighter.h"
#include "common/HexAsciiHighlighter.h" #include "common/HexAsciiHighlighter.h"
@ -107,7 +107,7 @@ private:
ut64 requestedSelectionEndAddress=0; ut64 requestedSelectionEndAddress=0;
HexdumpRangeDialog rangeDialog; HexdumpRangeDialog rangeDialog;
QAction syncAction; QAction syncAction;
CutterSeekableWidget *seekable; CutterSeekable *seekable;
private slots: private slots:
void on_seekChanged(RVA addr); void on_seekChanged(RVA addr);