From 280e10d154e2a2cf4909b9f7417538269cbde522 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Thu, 7 Feb 2019 17:19:05 +0100 Subject: [PATCH] Subclass CutterDockWidget in Python Plugin Refactor CutterPlugin::setupInterface() and fix C++ sample --- src/CMakeLists.txt | 29 +++++---- src/MainWindow.cpp | 14 +++-- src/MainWindow.h | 2 + src/bindings/bindings.h | 4 +- src/bindings/bindings.xml | 7 ++- src/plugins/CutterPlugin.h | 3 +- src/plugins/CutterPythonPlugin.cpp | 20 +----- src/plugins/CutterPythonPlugin.h | 2 +- src/plugins/PluginSample.pro | 13 ---- src/plugins/plugin_sample.py | 51 --------------- .../{ => sample-cpp}/CutterSamplePlugin.cpp | 18 +++--- .../{ => sample-cpp}/CutterSamplePlugin.h | 2 +- src/plugins/sample-cpp/CutterSamplePlugin.pro | 10 +++ src/plugins/sample_python.py | 62 +++++++++++++++++++ src/python/cutter_plugin.py | 7 --- src/widgets/DebugActions.cpp | 1 + src/widgets/HexdumpWidget.h | 5 +- src/widgets/RegistersWidget.cpp | 3 + 18 files changed, 133 insertions(+), 120 deletions(-) delete mode 100644 src/plugins/PluginSample.pro delete mode 100644 src/plugins/plugin_sample.py rename src/plugins/{ => sample-cpp}/CutterSamplePlugin.cpp (75%) rename src/plugins/{ => sample-cpp}/CutterSamplePlugin.h (87%) create mode 100644 src/plugins/sample-cpp/CutterSamplePlugin.pro create mode 100644 src/plugins/sample_python.py diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2acbea37..480d9305 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -97,17 +97,11 @@ or, if you don't want to build with Python at all, use -DCUTTER_ENABLE_PYTHON=OF endif() include_directories(${SHIBOKEN_INCLUDE_DIR}) - include_directories(${PYSIDE_INCLUDE_DIR}) - include_directories(${PYSIDE_INCLUDE_DIR}/QtCore) + include_directories(${PYSIDE_INCLUDE_DIR} ${PYSIDE_INCLUDE_DIR}/QtCore ${PYSIDE_INCLUDE_DIR}/QtGui ${PYSIDE_INCLUDE_DIR}/QtWidgets) endif() endif() -if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" - OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - add_definitions(-Wall -Wextra) -endif() - message(STATUS "") message(STATUS "Building Cutter version ${CUTTER_VERSION_FULL}") @@ -126,21 +120,32 @@ qmake_configure_file("${CMAKE_CURRENT_SOURCE_DIR}/CutterConfig.h.in" set(BINDINGS_SOURCE "${CMAKE_CURRENT_BINARY_DIR}/bindings/CutterBindings/cutterbindings_module_wrapper.cpp" - #"${CMAKE_CURRENT_BINARY_DIR}/bindings/CutterBindings/cutterdockwidget_wrapper.cpp" - "${CMAKE_CURRENT_BINARY_DIR}/bindings/CutterBindings/cuttercore_wrapper.cpp") + "${CMAKE_CURRENT_BINARY_DIR}/bindings/CutterBindings/cuttercore_wrapper.cpp" + "${CMAKE_CURRENT_BINARY_DIR}/bindings/CutterBindings/configuration_wrapper.cpp" + "${CMAKE_CURRENT_BINARY_DIR}/bindings/CutterBindings/cutterdockwidget_wrapper.cpp" + "${CMAKE_CURRENT_BINARY_DIR}/bindings/CutterBindings/mainwindow_wrapper.cpp") set_property(SOURCE ${BINDINGS_SOURCE} PROPERTY SKIP_AUTOGEN ON) include_directories("${CMAKE_CURRENT_BINARY_DIR}/bindings/CutterBindings") include_directories("${CMAKE_CURRENT_SOURCE_DIR}/widgets") +include_directories("${CMAKE_CURRENT_SOURCE_DIR}/common") add_custom_command(OUTPUT ${BINDINGS_SOURCE} - COMMAND shiboken2 --project-file=${CMAKE_CURRENT_BINARY_DIR}/bindings/bindings.txt - #DEPENDS ${sample_TYPESYSTEM} ${CMAKE_CURRENT_SOURCE_DIR}/global.h shiboken2 - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMAND shiboken2 --project-file="${CMAKE_CURRENT_BINARY_DIR}/bindings/bindings.txt" + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/bindings/bindings.xml" + IMPLICIT_DEPENDS CXX "${CMAKE_CURRENT_SOURCE_DIR}/bindings/bindings.h" COMMENT "Generating Python bindings with shiboken2") + +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" + OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + add_definitions(-Wall -Wextra) + set_source_files_properties(${BINDINGS_SOURCE} PROPERTIES COMPILE_FLAGS -w) +endif() + + add_executable(Cutter ${UI_FILES} ${QRC_FILES} ${SOURCE_FILES} ${HEADER_FILES} ${BINDINGS_SOURCE}) target_link_libraries(Cutter Qt5::Core Qt5::Widgets Qt5::Gui Qt5::Svg Qt5::Network) diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 64668c5c..dea444f3 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -278,10 +278,7 @@ void MainWindow::initUI() /* Setup plugins interfaces */ QList plugins = core->getCutterPlugins(); for (auto plugin : plugins) { - QDockWidget *pluginDock = plugin->setupInterface(this); - if (pluginDock) { - tabifyDockWidget(dashboardDock, pluginDock); - } + plugin->setupInterface(this); } } @@ -383,6 +380,15 @@ void MainWindow::addExtraWidget(QDockWidget *extraDock) restoreExtraDock.restoreWidth(extraDock->widget()); } +void MainWindow::addPluginDockWidget(QDockWidget *dockWidget, QAction *action) +{ + addDockWidget(Qt::TopDockWidgetArea, dockWidget); + addDockWidgetAction(dockWidget, action); + ui->menuWindows->addAction(action); + tabifyDockWidget(dashboardDock, dockWidget); + updateDockActionChecked(action); +} + void MainWindow::openNewFile(InitialOptions options, bool skipOptionsDialog) { setFilename(options.filename); diff --git a/src/MainWindow.h b/src/MainWindow.h index 7e102f8d..6c5fdbee 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -103,6 +103,8 @@ public: void addDockWidgetAction(QDockWidget *dockWidget, QAction *action); void addExtraWidget(QDockWidget *extraDock); + void addPluginDockWidget(QDockWidget *dockWidget, QAction *action); + void updateDockActionChecked(QAction * action); QString getFilename() const diff --git a/src/bindings/bindings.h b/src/bindings/bindings.h index d3a81668..181050be 100644 --- a/src/bindings/bindings.h +++ b/src/bindings/bindings.h @@ -2,7 +2,9 @@ #ifndef CUTTER_BINDINGS_H #define CUTTER_BINDINGS_H -//#include "../widgets/CutterDockWidget.h" #include "../Cutter.h" +#include "../common/Configuration.h" +#include "../MainWindow.h" +#include "../widgets/CutterDockWidget.h" #endif //CUTTER_BINDINGS_H diff --git a/src/bindings/bindings.xml b/src/bindings/bindings.xml index 81868fd5..e6b95808 100644 --- a/src/bindings/bindings.xml +++ b/src/bindings/bindings.xml @@ -1,8 +1,11 @@ + + - - + + + \ No newline at end of file diff --git a/src/plugins/CutterPlugin.h b/src/plugins/CutterPlugin.h index 46d4c1bc..3cb5d354 100644 --- a/src/plugins/CutterPlugin.h +++ b/src/plugins/CutterPlugin.h @@ -12,7 +12,7 @@ class CutterPlugin public: virtual ~CutterPlugin() {} virtual void setupPlugin(CutterCore *core) = 0; - virtual QDockWidget *setupInterface(MainWindow *main, QAction *action = nullptr) = 0; + virtual void setupInterface(MainWindow *main) = 0; QString name; QString description; @@ -21,7 +21,6 @@ public: protected: CutterCore *core; - CutterDockWidget *dockable; }; #define CutterPlugin_iid "org.radare.cutter.plugins.CutterPlugin" diff --git a/src/plugins/CutterPythonPlugin.cpp b/src/plugins/CutterPythonPlugin.cpp index 86761c37..f066ea76 100644 --- a/src/plugins/CutterPythonPlugin.cpp +++ b/src/plugins/CutterPythonPlugin.cpp @@ -93,10 +93,9 @@ QString CutterPythonPlugin::getAttributeFromPython(const char *attribute) return result; } -QDockWidget *CutterPythonPlugin::setupInterface(MainWindow *main, QAction *action) +void CutterPythonPlugin::setupInterface(MainWindow *main) { Q_UNUSED(main) - Q_UNUSED(action) PyObject *pWidget = nullptr; Python()->restoreThread(); @@ -106,23 +105,8 @@ QDockWidget *CutterPythonPlugin::setupInterface(MainWindow *main, QAction *actio qWarning() << "Error in setupInterface()."; PyErr_Print(); Python()->saveThread(); - return nullptr; - } - - if (!PyLong_Check(pWidget)) { - qWarning() << "Value returned by setupInterface() is not PyLong."; - Python()->saveThread(); - return nullptr; - } - - auto dockWidget = reinterpret_cast(PyLong_AsLong(pWidget)); - if (!dockWidget) { - qWarning() << "Cannot instantiate QDockWidget."; - Python()->saveThread(); - return nullptr; + return; } Python()->saveThread(); - - return dockWidget; } diff --git a/src/plugins/CutterPythonPlugin.h b/src/plugins/CutterPythonPlugin.h index 9a05bb36..34a754a1 100644 --- a/src/plugins/CutterPythonPlugin.h +++ b/src/plugins/CutterPythonPlugin.h @@ -10,7 +10,7 @@ public: CutterPythonPlugin(PyObject* pluginModule); ~CutterPythonPlugin(); void setupPlugin(CutterCore *core); - QDockWidget *setupInterface(MainWindow *main, QAction *action); + void setupInterface(MainWindow *main); private: PyObject *pluginModule = nullptr; diff --git a/src/plugins/PluginSample.pro b/src/plugins/PluginSample.pro deleted file mode 100644 index 12771154..00000000 --- a/src/plugins/PluginSample.pro +++ /dev/null @@ -1,13 +0,0 @@ -HEADERS += CutterSamplePlugin.h CutterPlugin.h -INCLUDEPATH += ../ -SOURCES += CutterSamplePlugin.cpp - -# Needed for r_core include TODO cross platform -unix:exists(/usr/include/libr) { - INCLUDEPATH += /usr/include/libr -} - -TEMPLATE = lib -CONFIG += plugin -QT += widgets -TARGET = PluginSample diff --git a/src/plugins/plugin_sample.py b/src/plugins/plugin_sample.py deleted file mode 100644 index a9abfbfb..00000000 --- a/src/plugins/plugin_sample.py +++ /dev/null @@ -1,51 +0,0 @@ -import cutter -from cutter_plugin import CutterPlugin -from PySide2 import QtWidgets -from PySide2.QtCore import QObject, SIGNAL, Qt -from PySide2.QtGui import QFont -import CutterBindings - -class CutterSamplePlugin(CutterPlugin): - name = "SamplePlugin" - description = "A sample plugin written in python." - version = "1.0" - author = "xarkes and thestr4ng3r :-P" - - def setupInterface(self): - super().setupInterface() - - # Create dock widget and content widget - dock_widget = QtWidgets.QDockWidget(self.main) - dock_widget.setObjectName("FancyDockWidgetFromCoolPlugin") - dock_widget.setWindowTitle("Test Widget") - content = QtWidgets.QWidget() - dock_widget.setWidget(content) - - # Create layout and label - layout = QtWidgets.QVBoxLayout(dock_widget) - content.setLayout(layout) - self.text = QtWidgets.QLabel(content) - self.text.setSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) - layout.addWidget(self.text) - - button = QtWidgets.QPushButton(content) - button.setText("Want a fortune?") - button.setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum) - button.setMaximumHeight(50) - button.setMaximumWidth(200) - layout.addWidget(button) - layout.setAlignment(button, Qt.AlignHCenter) - - QObject.connect(CutterBindings.CutterCore.getInstance(), SIGNAL("seekChanged(RVA)"), self.generate_fortune) - QObject.connect(button, SIGNAL("clicked()"), self.generate_fortune) - - return self.makeCppPointer(dock_widget) - - - def generate_fortune(self): - res = cutter.cmd("?E `fo`") - self.text.setText(res) - - -# Instantiate our plugin -plugin = CutterSamplePlugin() diff --git a/src/plugins/CutterSamplePlugin.cpp b/src/plugins/sample-cpp/CutterSamplePlugin.cpp similarity index 75% rename from src/plugins/CutterSamplePlugin.cpp rename to src/plugins/sample-cpp/CutterSamplePlugin.cpp index d6068c75..0b45c0f3 100644 --- a/src/plugins/CutterSamplePlugin.cpp +++ b/src/plugins/sample-cpp/CutterSamplePlugin.cpp @@ -1,10 +1,12 @@ #include #include #include +#include #include "CutterSamplePlugin.h" #include "common/TempConfig.h" #include "common/Configuration.h" +#include "MainWindow.h" void CutterSamplePlugin::setupPlugin(CutterCore *core) { @@ -15,22 +17,23 @@ void CutterSamplePlugin::setupPlugin(CutterCore *core) this->author = "xarkes"; } -CutterDockWidget* CutterSamplePlugin::setupInterface(MainWindow *main, QAction* actions) +void CutterSamplePlugin::setupInterface(MainWindow *main) { - // Instantiate dock widget - dockable = new CutterSamplePluginWidget(main, actions); - return dockable; + QAction *action = new QAction("Sample C++ Plugin", main); + action->setCheckable(true); + CutterSamplePluginWidget *widget = new CutterSamplePluginWidget(main, action); + main->addPluginDockWidget(widget, action); } CutterSamplePluginWidget::CutterSamplePluginWidget(MainWindow *main, QAction *action) : CutterDockWidget(main, action) { this->setObjectName("CutterSamplePluginWidget"); - this->setWindowTitle("Sample Plugin"); + this->setWindowTitle("Sample C++ Plugin"); QWidget *content = new QWidget(); this->setWidget(content); - QVBoxLayout *layout = new QVBoxLayout(this); + QVBoxLayout *layout = new QVBoxLayout(content); content->setLayout(layout); text = new QLabel(content); text->setFont(Config()->getFont()); @@ -63,6 +66,7 @@ void CutterSamplePluginWidget::on_seekChanged(RVA addr) void CutterSamplePluginWidget::on_buttonClicked() { - QString res = Core()->cmd("?E `fo`"); + QString fortune = Core()->cmd("fo").replace("\n", ""); + QString res = Core()->cmdRaw("?E " + fortune); text->setText(res); } diff --git a/src/plugins/CutterSamplePlugin.h b/src/plugins/sample-cpp/CutterSamplePlugin.h similarity index 87% rename from src/plugins/CutterSamplePlugin.h rename to src/plugins/sample-cpp/CutterSamplePlugin.h index 557abb61..8b45be7c 100644 --- a/src/plugins/CutterSamplePlugin.h +++ b/src/plugins/sample-cpp/CutterSamplePlugin.h @@ -13,7 +13,7 @@ class CutterSamplePlugin : public QObject, CutterPlugin public: void setupPlugin(CutterCore *core) override; - CutterDockWidget* setupInterface(MainWindow *main, QAction *action = nullptr) override; + void setupInterface(MainWindow *main) override; }; class CutterSamplePluginWidget : public CutterDockWidget diff --git a/src/plugins/sample-cpp/CutterSamplePlugin.pro b/src/plugins/sample-cpp/CutterSamplePlugin.pro new file mode 100644 index 00000000..7805313e --- /dev/null +++ b/src/plugins/sample-cpp/CutterSamplePlugin.pro @@ -0,0 +1,10 @@ +HEADERS += ../CutterSamplePlugin.h ../CutterPlugin.h +INCLUDEPATH += ../ ../../ +SOURCES += CutterSamplePlugin.cpp + +QMAKE_CXXFLAGS += $$system("pkg-config --cflags r_core") + +TEMPLATE = lib +CONFIG += plugin +QT += widgets +TARGET = PluginSample diff --git a/src/plugins/sample_python.py b/src/plugins/sample_python.py new file mode 100644 index 00000000..81792070 --- /dev/null +++ b/src/plugins/sample_python.py @@ -0,0 +1,62 @@ + +import cutter +from cutter_plugin import CutterPlugin +import CutterBindings + +from PySide2.QtCore import QObject, SIGNAL, Qt +from PySide2.QtWidgets import QAction, QVBoxLayout, QLabel, QWidget, QSizePolicy, QPushButton + + +class FortuneWidget(CutterBindings.CutterDockWidget): + def __init__(self, main, action): + super(FortuneWidget, self).__init__(main, action) + self.setObjectName("FancyDockWidgetFromCoolPlugin") + self.setWindowTitle("Sample Python Plugin") + + content = QWidget() + self.setWidget(content) + + # Create layout and label + layout = QVBoxLayout(content) + content.setLayout(layout) + self.text = QLabel(content) + self.text.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) + self.text.setFont(CutterBindings.Configuration.instance().getFont()) + layout.addWidget(self.text) + + button = QPushButton(content) + button.setText("Want a fortune?") + button.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) + button.setMaximumHeight(50) + button.setMaximumWidth(200) + layout.addWidget(button) + layout.setAlignment(button, Qt.AlignHCenter) + + QObject.connect(CutterBindings.CutterCore.getInstance(), SIGNAL("seekChanged(RVA)"), self.generate_fortune) + QObject.connect(button, SIGNAL("clicked()"), self.generate_fortune) + + self.show() + + def generate_fortune(self): + fortune = cutter.cmd("fo").replace("\n", "") + res = CutterBindings.CutterCore.getInstance().cmdRaw(f"?E {fortune}") + self.text.setText(res) + + +class CutterSamplePlugin(CutterPlugin): + name = "SamplePlugin" + description = "A sample plugin written in python." + version = "1.0" + author = "xarkes and thestr4ng3r :-P" + + def setupInterface(self): + super().setupInterface() + + self.action = QAction("Sample Python Plugin", self.main) + self.action.setCheckable(True) + self.widget = FortuneWidget(self.main, self.action) # we MUST keep a reference to this! + self.main.addPluginDockWidget(self.widget, self.action) + + +# Instantiate our plugin +plugin = CutterSamplePlugin() diff --git a/src/python/cutter_plugin.py b/src/python/cutter_plugin.py index ce7809f2..8291d647 100644 --- a/src/python/cutter_plugin.py +++ b/src/python/cutter_plugin.py @@ -16,10 +16,3 @@ class CutterPlugin(object): if widget.objectName() == "MainWindow": self.main = widget break - - def makeCppPointer(self, widget): - ptr = shiboken2.getCppPointer(widget)[0] - return ptr - - - diff --git a/src/widgets/DebugActions.cpp b/src/widgets/DebugActions.cpp index 2b166214..93e29f7b 100644 --- a/src/widgets/DebugActions.cpp +++ b/src/widgets/DebugActions.cpp @@ -8,6 +8,7 @@ #include #include #include +#include DebugActions::DebugActions(QToolBar *toolBar, MainWindow *main) : QObject(main), diff --git a/src/widgets/HexdumpWidget.h b/src/widgets/HexdumpWidget.h index 7febbfd3..f4fab8a2 100644 --- a/src/widgets/HexdumpWidget.h +++ b/src/widgets/HexdumpWidget.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -19,7 +20,9 @@ #include "Dashboard.h" -#include "ui_HexdumpWidget.h" +namespace Ui { + class HexdumpWidget; +} class RefreshDeferrer; diff --git a/src/widgets/RegistersWidget.cpp b/src/widgets/RegistersWidget.cpp index 944f2f74..6555059c 100644 --- a/src/widgets/RegistersWidget.cpp +++ b/src/widgets/RegistersWidget.cpp @@ -4,6 +4,9 @@ #include "MainWindow.h" +#include +#include + RegistersWidget::RegistersWidget(MainWindow *main, QAction *action) : CutterDockWidget(main, action), ui(new Ui::RegistersWidget)