Basic Jupyter Integration

This commit is contained in:
Florian Märkl 2017-12-13 18:36:00 +01:00 committed by xarkes
parent f01fa9d4ea
commit 1ba8e03f04
10 changed files with 265 additions and 9 deletions

View File

@ -12,7 +12,7 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON) set(CMAKE_AUTORCC ON)
find_package(Qt5 REQUIRED COMPONENTS Core Widgets Gui Svg) find_package(Qt5 REQUIRED COMPONENTS Core Widgets Gui Svg WebEngineWidgets)
if(WIN32) if(WIN32)
@ -65,6 +65,6 @@ add_definitions("-DAPP_VERSION=\"${CUTTER_VERSION_FULL}\"")
add_executable(cutter ${UI_FILES} ${QRC_FILES} ${SOURCE_FILES} ${HEADER_FILES}) add_executable(cutter ${UI_FILES} ${QRC_FILES} ${SOURCE_FILES} ${HEADER_FILES})
qt5_use_modules(cutter Core Widgets Gui Svg) qt5_use_modules(cutter Core Widgets Gui Svg WebEngineWidgets)
target_link_libraries(cutter ${RADARE2_LIBRARIES}) target_link_libraries(cutter ${RADARE2_LIBRARIES})

View File

@ -66,6 +66,7 @@
#include "widgets/ClassesWidget.h" #include "widgets/ClassesWidget.h"
#include "widgets/ResourcesWidget.h" #include "widgets/ResourcesWidget.h"
#include "widgets/VTablesWidget.h" #include "widgets/VTablesWidget.h"
#include "widgets/JupyterWidget.h"
// graphics // graphics
#include <QGraphicsEllipseItem> #include <QGraphicsEllipseItem>
@ -219,6 +220,7 @@ void MainWindow::initUI()
ADD_DOCK(CommentsWidget, commentsDock, ui->actionComments); ADD_DOCK(CommentsWidget, commentsDock, ui->actionComments);
ADD_DOCK(StringsWidget, stringsDock, ui->actionStrings); ADD_DOCK(StringsWidget, stringsDock, ui->actionStrings);
ADD_DOCK(FlagsWidget, flagsDock, ui->actionFlags); ADD_DOCK(FlagsWidget, flagsDock, ui->actionFlags);
ADD_DOCK(JupyterWidget, jupyterDock, ui->actionJupyter);
ADD_DOCK(Notepad, notepadDock, ui->actionNotepad); ADD_DOCK(Notepad, notepadDock, ui->actionNotepad);
ADD_DOCK(Dashboard, dashboardDock, ui->actionDashboard); ADD_DOCK(Dashboard, dashboardDock, ui->actionDashboard);
ADD_DOCK(SdbDock, sdbDock, ui->actionSDBBrowser); ADD_DOCK(SdbDock, sdbDock, ui->actionSDBBrowser);
@ -548,6 +550,7 @@ void MainWindow::restoreDocks()
tabifyDockWidget(dashboardDock, classesDock); tabifyDockWidget(dashboardDock, classesDock);
tabifyDockWidget(dashboardDock, resourcesDock); tabifyDockWidget(dashboardDock, resourcesDock);
tabifyDockWidget(dashboardDock, vTablesDock); tabifyDockWidget(dashboardDock, vTablesDock);
tabifyDockWidget(dashboardDock, jupyterDock);
updateDockActionsChecked(); updateDockActionsChecked();
} }
@ -587,7 +590,8 @@ void MainWindow::showDefaultDocks()
sidebarDock, sidebarDock,
hexdumpDock, hexdumpDock,
pseudocodeDock, pseudocodeDock,
dashboardDock dashboardDock,
jupyterDock
}; };
for (auto w : dockWidgets) for (auto w : dockWidgets)

View File

@ -40,7 +40,7 @@ class DisassemblerGraphView;
class ClassesWidget; class ClassesWidget;
class ResourcesWidget; class ResourcesWidget;
class VTablesWidget; class VTablesWidget;
class JupyterWidget;
class QDockWidget; class QDockWidget;
namespace Ui namespace Ui
@ -151,6 +151,7 @@ private slots:
private: private:
CutterCore *core; CutterCore *core;
bool panelLock; bool panelLock;
bool tabsOnTop; bool tabsOnTop;
ut64 hexdumpTopOffset; ut64 hexdumpTopOffset;
@ -192,6 +193,7 @@ private:
QDockWidget *asmDock = nullptr; QDockWidget *asmDock = nullptr;
QDockWidget *calcDock = nullptr; QDockWidget *calcDock = nullptr;
NewFileDialog *newFileDialog = nullptr; NewFileDialog *newFileDialog = nullptr;
JupyterWidget *jupyterDock = nullptr;
void toggleDockWidget(QDockWidget *dock_widget, bool show); void toggleDockWidget(QDockWidget *dock_widget, bool show);

View File

@ -260,6 +260,7 @@ border-top: 0px;
<addaction name="actionComments"/> <addaction name="actionComments"/>
<addaction name="actionNotepad"/> <addaction name="actionNotepad"/>
<addaction name="actionConsole"/> <addaction name="actionConsole"/>
<addaction name="actionJupyter"/>
</widget> </widget>
<addaction name="menuFile"/> <addaction name="menuFile"/>
<addaction name="menuEdit"/> <addaction name="menuEdit"/>
@ -1062,6 +1063,14 @@ QToolButton:pressed {
<string>Show/Hide VTables panel</string> <string>Show/Hide VTables panel</string>
</property> </property>
</action> </action>
<action name="actionJupyter">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Jupyter</string>
</property>
</action>
</widget> </widget>
<layoutdefault spacing="6" margin="11"/> <layoutdefault spacing="6" margin="11"/>
<resources> <resources>

View File

@ -7,7 +7,7 @@ VERSION = 1.2
ICON = img/cutter.icns ICON = img/cutter.icns
QT += core gui widgets svg QT += core gui widgets svg webenginewidgets
QT_CONFIG -= no-pkg-config QT_CONFIG -= no-pkg-config
CONFIG += c++11 CONFIG += c++11
@ -91,7 +91,9 @@ SOURCES += \
widgets/ClassesWidget.cpp \ widgets/ClassesWidget.cpp \
widgets/ResourcesWidget.cpp \ widgets/ResourcesWidget.cpp \
widgets/VTablesWidget.cpp \ widgets/VTablesWidget.cpp \
CutterApplication.cpp CutterApplication.cpp \
utils/JupyterConnection.cpp \
widgets/JupyterWidget.cpp
HEADERS += \ HEADERS += \
cutter.h \ cutter.h \
@ -152,7 +154,9 @@ HEADERS += \
widgets/ClassesWidget.h \ widgets/ClassesWidget.h \
widgets/ResourcesWidget.h \ widgets/ResourcesWidget.h \
CutterApplication.h \ CutterApplication.h \
widgets/VTablesWidget.h widgets/VTablesWidget.h \
utils/JupyterConnection.h \
widgets/JupyterWidget.h
FORMS += \ FORMS += \
dialogs/AboutDialog.ui \ dialogs/AboutDialog.ui \
@ -189,7 +193,9 @@ FORMS += \
widgets/QuickFilterView.ui \ widgets/QuickFilterView.ui \
widgets/PseudocodeWidget.ui \ widgets/PseudocodeWidget.ui \
widgets/ClassesWidget.ui \ widgets/ClassesWidget.ui \
widgets/VTablesWidget.ui widgets/VTablesWidget.ui \
widgets/PseudocodeWidget.ui \
widgets/JupyterWidget.ui
RESOURCES += \ RESOURCES += \
resources.qrc \ resources.qrc \

View File

@ -0,0 +1,61 @@
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
#include "JupyterConnection.h"
JupyterConnection::JupyterConnection(QObject *parent) : QObject(parent)
{
process = nullptr;
}
JupyterConnection::~JupyterConnection()
{
}
const char *urlPy = "from notebook import notebookapp\n"
"import json\n"
"import time\n"
"\n"
"time.sleep(3)\n"
"\n"
"servers = [si for si in notebookapp.list_running_servers()]\n"
"print(json.dumps(servers))";
void JupyterConnection::start()
{
process = new QProcess(this);
connect(process, &QProcess::readyReadStandardError, this, &JupyterConnection::readStandardError);
connect(process, &QProcess::readyReadStandardOutput, this, &JupyterConnection::readStandardOutput);
process->start("jupyter", {"notebook", "--no-browser", "-y"});
urlProcess = new QProcess(this);
connect(urlProcess, &QProcess::readyReadStandardOutput, this, &JupyterConnection::readUrlStandardOutput);
urlProcess->start("python3", {"-c", urlPy});
}
void JupyterConnection::readStandardError()
{
auto data = process->readAllStandardError();
printf("jupyter stderr: %s\n", data.constData());
}
void JupyterConnection::readStandardOutput()
{
auto data = process->readAllStandardOutput();
printf("jupyter stdout: %s\n", data.constData());
}
void JupyterConnection::readUrlStandardOutput()
{
QJsonDocument doc = QJsonDocument::fromJson(urlProcess->readAllStandardOutput());
for(QJsonValue value : doc.array())
{
QJsonObject serverObject = value.toObject();
QString url = serverObject["url"].toString() + "?token=" + serverObject["token"].toString();
emit urlReceived(url);
break;
}
}

View File

@ -0,0 +1,31 @@
#ifndef JUPYTERCONNECTION_H
#define JUPYTERCONNECTION_H
#include <QProcess>
class JupyterConnection : public QObject
{
Q_OBJECT
public:
JupyterConnection(QObject *parent = nullptr);
~JupyterConnection();
void start();
signals:
void urlReceived(const QString &url);
private:
QProcess *process;
QProcess *urlProcess;
private slots:
void readStandardError();
void readStandardOutput();
void readUrlStandardOutput();
};
#endif //JUPYTERCONNECTION_H

View File

@ -0,0 +1,52 @@
#include "ui_JupyterWidget.h"
#include "JupyterWidget.h"
#include <QWebEngineSettings>
JupyterWidget::JupyterWidget(QWidget *parent, Qt::WindowFlags flags) :
QDockWidget(parent, flags),
ui(new Ui::JupyterWidget)
{
ui->setupUi(this);
jupyter = new JupyterConnection(this);
connect(jupyter, &JupyterConnection::urlReceived, this, &JupyterWidget::urlReceived);
jupyter->start();
}
JupyterWidget::~JupyterWidget()
{
}
JupyterWebView *JupyterWidget::createNewTab()
{
auto webView = new JupyterWebView(this);
ui->tabWidget->addTab(webView, "Tab");
return webView;
}
void JupyterWidget::urlReceived(const QString &url)
{
createNewTab()->load(QUrl(url));
}
JupyterWebView::JupyterWebView(JupyterWidget *mainWidget, QWidget *parent) : QWebEngineView(parent)
{
this->mainWidget = mainWidget;
}
QWebEngineView *JupyterWebView::createWindow(QWebEnginePage::WebWindowType type)
{
switch (type)
{
case QWebEnginePage::WebBrowserTab:
return mainWidget->createNewTab();
default:
return nullptr;
}
}

View File

@ -0,0 +1,53 @@
#ifndef JUPYTERWIDGET_H
#define JUPYTERWIDGET_H
#include <memory>
#include <QDockWidget>
#include <QWebEngineView>
#include "utils/JupyterConnection.h"
namespace Ui
{
class JupyterWidget;
}
class JupyterWebView;
class JupyterWidget : public QDockWidget
{
Q_OBJECT
public:
JupyterWidget(QWidget *parent = nullptr, Qt::WindowFlags flags = Qt::WindowFlags());
~JupyterWidget();
JupyterWebView *createNewTab();
private slots:
void urlReceived(const QString &url);
private:
std::unique_ptr<Ui::JupyterWidget> ui;
JupyterConnection *jupyter;
};
class JupyterWebView : public QWebEngineView
{
Q_OBJECT
public:
JupyterWebView(JupyterWidget *mainWidget, QWidget *parent = nullptr);
protected:
QWebEngineView *createWindow(QWebEnginePage::WebWindowType type) override;
private:
JupyterWidget *mainWidget;
};
#endif //JUPYTERWIDGET_H

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>JupyterWidget</class>
<widget class="QDockWidget" name="JupyterWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>644</width>
<height>484</height>
</rect>
</property>
<property name="windowTitle">
<string>Jupyter</string>
</property>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QTabWidget" name="tabWidget"/>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>