From ea9f3f1831c68b709f15d2753aefa8814a47e746 Mon Sep 17 00:00:00 2001 From: NIRMAL MANOJ C Date: Tue, 23 Jun 2020 01:55:30 +0530 Subject: [PATCH] Skelton for dedicated context menu + action to copy selection (#2256) --- src/Cutter.pro | 2 + src/menus/DecompilerContextMenu.cpp | 59 +++++++++++++++++++++++++++++ src/menus/DecompilerContextMenu.h | 59 +++++++++++++++++++++++++++++ src/widgets/DecompilerWidget.cpp | 14 +++---- src/widgets/DecompilerWidget.h | 4 +- 5 files changed, 128 insertions(+), 10 deletions(-) create mode 100644 src/menus/DecompilerContextMenu.cpp create mode 100644 src/menus/DecompilerContextMenu.h diff --git a/src/Cutter.pro b/src/Cutter.pro index bb86c765..2ba47edf 100644 --- a/src/Cutter.pro +++ b/src/Cutter.pro @@ -336,6 +336,7 @@ SOURCES += \ widgets/StringsWidget.cpp \ widgets/SymbolsWidget.cpp \ menus/DisassemblyContextMenu.cpp \ + menus/DecompilerContextMenu.cpp \ widgets/DisassemblyWidget.cpp \ widgets/HexdumpWidget.cpp \ common/Configuration.cpp \ @@ -485,6 +486,7 @@ HEADERS += \ widgets/StringsWidget.h \ widgets/SymbolsWidget.h \ menus/DisassemblyContextMenu.h \ + menus/DecompilerContextMenu.h \ widgets/DisassemblyWidget.h \ widgets/HexdumpWidget.h \ common/Configuration.h \ diff --git a/src/menus/DecompilerContextMenu.cpp b/src/menus/DecompilerContextMenu.cpp new file mode 100644 index 00000000..1e93fb48 --- /dev/null +++ b/src/menus/DecompilerContextMenu.cpp @@ -0,0 +1,59 @@ +#include "DecompilerContextMenu.h" +#include "dialogs/preferences/PreferencesDialog.h" +#include "MainWindow.h" + +#include +#include +#include +#include +#include +#include + +DecompilerContextMenu::DecompilerContextMenu(QWidget *parent, MainWindow *mainWindow) + : QMenu(parent), + offset(0), + mainWindow(mainWindow), + actionCopy(tr("Copy"), this) +{ + setActionCopy(); + addSeparator(); + + connect(this, &DecompilerContextMenu::aboutToShow, + this, &DecompilerContextMenu::aboutToShowSlot); +} + +DecompilerContextMenu::~DecompilerContextMenu() +{ +} + +void DecompilerContextMenu::setOffset(RVA offset) +{ + this->offset = offset; + + // this->actionSetFunctionVarTypes.setVisible(true); +} + +void DecompilerContextMenu::setCanCopy(bool enabled) +{ + actionCopy.setVisible(enabled); +} + +void DecompilerContextMenu::aboutToShowSlot() +{ +} + +// Set up actions + +void DecompilerContextMenu::setActionCopy(){ + connect(&actionCopy, &QAction::triggered, this, &DecompilerContextMenu::actionCopyTriggered); + addAction(&actionCopy); + actionCopy.setShortcut(QKeySequence::Copy); + actionCopy.setShortcutContext(Qt::WidgetWithChildrenShortcut); +} + +// Set up action responses + +void DecompilerContextMenu::actionCopyTriggered() +{ + emit copy(); +} diff --git a/src/menus/DecompilerContextMenu.h b/src/menus/DecompilerContextMenu.h new file mode 100644 index 00000000..bc8b432e --- /dev/null +++ b/src/menus/DecompilerContextMenu.h @@ -0,0 +1,59 @@ +#ifndef DECOMPILERCONTEXTMENU_H +#define DECOMPILERCONTEXTMENU_H + +#include "core/Cutter.h" +#include +#include + +class DecompilerContextMenu : public QMenu +{ + Q_OBJECT + +public: + DecompilerContextMenu(QWidget *parent, MainWindow *mainWindow); + ~DecompilerContextMenu(); + +signals: + void copy(); + +public slots: + void setOffset(RVA offset); + void setCanCopy(bool enabled); + +private slots: + void aboutToShowSlot(); + + void actionCopyTriggered(); + +private: + QKeySequence getCopySequence() const; + + RVA offset; + MainWindow *mainWindow; + + QAction actionCopy; + QAction *copySeparator; + + void setActionCopy(); + + // I left out the following part from RAnnotatedCode. Probably, we will be returning/passing annotations + // from/to the function getThingUsedHere() and updateTargetMenuActions(). This block of comment will get removed in + // future PRs. + // + // struct ThingUsedHere { + // QString name; + // RVA offset; + // enum class Type { + // Var, + // Function, + // Flag, + // Address + // }; + // Type type; + // }; + // QVector getThingUsedHere(RVA offset); + + // void updateTargetMenuActions(const QVector &targets); +}; + +#endif // DECOMPILERCONTEXTMENU_H \ No newline at end of file diff --git a/src/widgets/DecompilerWidget.cpp b/src/widgets/DecompilerWidget.cpp index 505138aa..77950ae1 100644 --- a/src/widgets/DecompilerWidget.cpp +++ b/src/widgets/DecompilerWidget.cpp @@ -1,6 +1,6 @@ #include "DecompilerWidget.h" #include "ui_DecompilerWidget.h" -#include "menus/DisassemblyContextMenu.h" +#include "menus/DecompilerContextMenu.h" #include "common/Configuration.h" #include "common/Helpers.h" @@ -17,7 +17,7 @@ DecompilerWidget::DecompilerWidget(MainWindow *main) : MemoryDockWidget(MemoryWidgetType::Decompiler, main), - mCtxMenu(new DisassemblyContextMenu(this, main)), + mCtxMenu(new DecompilerContextMenu(this, main)), ui(new Ui::DecompilerWidget), code(Decompiler::makeWarning(tr("Choose an offset and refresh to get decompiled code")), &r_annotated_code_free) { @@ -34,6 +34,7 @@ DecompilerWidget::DecompilerWidget(MainWindow *main) : connect(Config(), &Configuration::fontsUpdated, this, &DecompilerWidget::fontsUpdatedSlot); connect(Config(), &Configuration::colorsUpdated, this, &DecompilerWidget::colorsUpdatedSlot); connect(Core(), &CutterCore::registersChanged, this, &DecompilerWidget::highlightPC); + connect(mCtxMenu, &DecompilerContextMenu::copy, ui->textEdit, &QPlainTextEdit::copy); decompiledFunctionAddr = RVA_INVALID; decompilerWasBusy = false; @@ -61,7 +62,6 @@ DecompilerWidget::DecompilerWidget(MainWindow *main) : // If no decompiler was previously chosen. set r2ghidra as default decompiler selectedDecompilerId = "r2ghidra"; } - for (auto dec : decompilers) { ui->decompilerComboBox->addItem(dec->getName(), dec->getId()); if (dec->getId() == selectedDecompilerId) { @@ -278,12 +278,11 @@ void DecompilerWidget::connectCursorPositionChanged(bool disconnect) void DecompilerWidget::cursorPositionChanged() { + mCtxMenu->setCanCopy(ui->textEdit->textCursor().hasSelection()); // Do not perform seeks along with the cursor while selecting multiple lines - if (!ui->textEdit->textCursor().selectedText().isEmpty()) - { + if (!ui->textEdit->textCursor().selectedText().isEmpty()) { return; } - size_t pos = ui->textEdit->textCursor().position(); RVA offset = offsetForPosition(*code, pos); if (offset != RVA_INVALID && offset != Core()->getOffset()) { @@ -349,7 +348,6 @@ void DecompilerWidget::updateSelection() ui->textEdit->setExtraSelections(extraSelections); // Highlight PC after updating the selected line highlightPC(); - mCtxMenu->setCurHighlightedWord(searchString); } QString DecompilerWidget::getWindowTitle() const @@ -404,7 +402,7 @@ void DecompilerWidget::highlightPC() if (!cursor.isNull()) { colorLine(createLineHighlightPC(cursor)); } - + } void DecompilerWidget::highlightBreakpoints() diff --git a/src/widgets/DecompilerWidget.h b/src/widgets/DecompilerWidget.h index 5b66b253..04f80aa3 100644 --- a/src/widgets/DecompilerWidget.h +++ b/src/widgets/DecompilerWidget.h @@ -15,14 +15,14 @@ class DecompilerWidget; class QTextEdit; class QSyntaxHighlighter; class QTextCursor; -class DisassemblyContextMenu; +class DecompilerContextMenu; struct DecompiledCodeTextLine; class DecompilerWidget : public MemoryDockWidget { Q_OBJECT protected: - DisassemblyContextMenu *mCtxMenu; + DecompilerContextMenu *mCtxMenu; public: explicit DecompilerWidget(MainWindow *main);