mirror of
https://github.com/rizinorg/cutter.git
synced 2024-12-20 03:46:11 +00:00
Subclass CutterDockWidget in Python Plugin
Refactor CutterPlugin::setupInterface() and fix C++ sample
This commit is contained in:
parent
23115d7b1c
commit
280e10d154
@ -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)
|
||||
|
@ -278,10 +278,7 @@ void MainWindow::initUI()
|
||||
/* Setup plugins interfaces */
|
||||
QList<CutterPlugin *> 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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -1,8 +1,11 @@
|
||||
<?xml version="1.0"?>
|
||||
<typesystem package="CutterBindings">
|
||||
<load-typesystem name="typesystem_core.xml" generate="no" />
|
||||
<load-typesystem name="typesystem_gui.xml" generate="no" />
|
||||
<load-typesystem name="typesystem_widgets.xml" generate="no" />
|
||||
<primitive-type name="bool"/>
|
||||
<primitive-type name="std::string"/>
|
||||
<!--<object-type name="CutterDockWidget" />-->
|
||||
<object-type name="CutterCore" />
|
||||
<object-type name="Configuration" />
|
||||
<object-type name="MainWindow" />
|
||||
<object-type name="CutterDockWidget" />
|
||||
</typesystem>
|
@ -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"
|
||||
|
@ -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<QDockWidget *>(PyLong_AsLong(pWidget));
|
||||
if (!dockWidget) {
|
||||
qWarning() << "Cannot instantiate QDockWidget.";
|
||||
Python()->saveThread();
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
Python()->saveThread();
|
||||
|
||||
return dockWidget;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
@ -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()
|
@ -1,10 +1,12 @@
|
||||
#include <QLabel>
|
||||
#include <QHBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <QAction>
|
||||
|
||||
#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);
|
||||
}
|
@ -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
|
10
src/plugins/sample-cpp/CutterSamplePlugin.pro
Normal file
10
src/plugins/sample-cpp/CutterSamplePlugin.pro
Normal file
@ -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
|
62
src/plugins/sample_python.py
Normal file
62
src/plugins/sample_python.py
Normal file
@ -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()
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <QList>
|
||||
#include <QFileInfo>
|
||||
#include <QToolBar>
|
||||
#include <QToolButton>
|
||||
|
||||
DebugActions::DebugActions(QToolBar *toolBar, MainWindow *main) :
|
||||
QObject(main),
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <QDebug>
|
||||
#include <QTextEdit>
|
||||
#include <QMouseEvent>
|
||||
#include <QAction>
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
@ -19,7 +20,9 @@
|
||||
|
||||
#include "Dashboard.h"
|
||||
|
||||
#include "ui_HexdumpWidget.h"
|
||||
namespace Ui {
|
||||
class HexdumpWidget;
|
||||
}
|
||||
|
||||
class RefreshDeferrer;
|
||||
|
||||
|
@ -4,6 +4,9 @@
|
||||
|
||||
#include "MainWindow.h"
|
||||
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
|
||||
RegistersWidget::RegistersWidget(MainWindow *main, QAction *action) :
|
||||
CutterDockWidget(main, action),
|
||||
ui(new Ui::RegistersWidget)
|
||||
|
Loading…
Reference in New Issue
Block a user