From a9a85210aa1318f72291576696251fc90b16ccf5 Mon Sep 17 00:00:00 2001 From: arkpar Date: Wed, 17 Dec 2014 19:35:03 +0100 Subject: [PATCH 01/17] started CodeModel --- mix/CodeModel.cpp | 81 ++++++++++++++++++++++++++++++++++ mix/CodeModel.h | 109 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 190 insertions(+) create mode 100644 mix/CodeModel.cpp create mode 100644 mix/CodeModel.h diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp new file mode 100644 index 000000000..120a81ac7 --- /dev/null +++ b/mix/CodeModel.cpp @@ -0,0 +1,81 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file CodeModel.cpp + * @author Arkadiy Paronyan arkadiy@ethdev.com + * @date 2014 + * Ethereum IDE client. + */ + +#include "CodeModel.h" + +namespace dev +{ +namespace mix +{ + +void BackgroundWorker::queueCodeChange(int _jobId, QString const& _content) +{ + m_model->runCompilationJob(_jobId, _content); +} + + +CodeModel::CodeModel(QObject* _parent) : QObject(_parent), m_backgroundWorker(this) +{ + m_backgroundWorker.moveToThread(&m_backgroundThread); + + connect(this, &CodeModel::compilationComplete, this, &CodeModel::onCompilationComplete, Qt::QueuedConnection); + connect(this, &CodeModel::scheduleCompilationJob, &m_backgroundWorker, &BackgroundWorker::queueCodeChange, Qt::QueuedConnection); + m_backgroundThread.start(); +} + +CodeModel::~CodeModel() +{ + stop(); + disconnect(this); +} + +void CodeModel::stop() +{ + ///@todo: cancel bg job + m_backgroundThread.exit(); + m_backgroundThread.wait(); +} + +void CodeModel::registerCodeChange(const QString &_code) +{ + // launch the background thread + m_backgroundJobId++; + emit scheduleCompilationJob(m_backgroundJobId, _code); +} + +void CodeModel::onCompilationComplete(std::shared_ptr _compilationResult) +{ + m_result.swap(_compilationResult); +} + + +void CodeModel::runCompilationJob(int _jobId, QString const& _content) +{ + if (_jobId != m_backgroundJobId) + return; //obsolete job + + +} + + +} +} diff --git a/mix/CodeModel.h b/mix/CodeModel.h new file mode 100644 index 000000000..1667f19a4 --- /dev/null +++ b/mix/CodeModel.h @@ -0,0 +1,109 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file CodeModel.h + * @author Arkadiy Paronyan arkadiy@ethdev.com + * @date 2014 + * Ethereum IDE client. + */ + +#pragma once + +#include +#include +#include + +namespace dev +{ +namespace mix +{ + +class CodeModel; +class QContractDefinition; + +class BackgroundWorker: public QObject +{ + Q_OBJECT + +public: + BackgroundWorker(CodeModel* _model): QObject(), m_model(_model) {} + +public slots: + void queueCodeChange(int _jobId, QString const& _content); +private: + CodeModel* m_model; +}; + + +class CompilationResult : public QObject +{ + Q_OBJECT + Q_PROPERTY(QContractDefinition const* contract READ contract) + +public: + QContractDefinition const* contract() { return m_contract; } + +private: + bool m_successfull; + QContractDefinition* m_contract; + QString m_hexCode; + QString m_compilerMessage; ///< @todo: use some structure here + dev::bytes m_bytes; + ///@todo syntax highlighting, etc +}; + +class CodeModel : public QObject +{ + enum Status + { + Idle, + Compiling, + }; + + Q_OBJECT + +public: + CodeModel(QObject* _parent); + ~CodeModel(); + + CompilationResult* getLastCompilationResult(); + +signals: + void statusChanged(Status _from, Status _to); + void compilationComplete(std::shared_ptr _compilationResult); + void scheduleCompilationJob(int _jobId, QString const& _content); + +public slots: + void registerCodeChange(QString const& _code); + +private slots: + void onCompilationComplete(std::shared_ptr _compilationResult); + +private: + void runCompilationJob(int _jobId, QString const& _content); + void stop(); + + std::shared_ptr m_result; + QThread m_backgroundThread; + BackgroundWorker m_backgroundWorker; + int m_backgroundJobId = 0; //protects from starting obsolete compilation job + + friend class BackgroundWorker; +}; + +} + +} From ab89822535e2a4584d56515c46f7ed5d28d801d6 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sun, 21 Dec 2014 14:26:13 +0100 Subject: [PATCH 02/17] continue code model impl --- mix/AppContext.cpp | 37 +++++++-------- mix/AppContext.h | 37 +++++++++------ mix/AssemblyDebuggerCtrl.cpp | 43 ++++++++--------- mix/AssemblyDebuggerCtrl.h | 12 ++--- mix/AssemblyDebuggerModel.cpp | 15 ++++-- mix/CodeEditorExtensionManager.cpp | 51 +++++++++++--------- mix/CodeEditorExtensionManager.h | 5 +- mix/CodeModel.cpp | 55 ++++++++++++++++----- mix/CodeModel.h | 31 ++++++++---- mix/ConstantCompilationCtrl.cpp | 50 ++++++++------------ mix/ConstantCompilationCtrl.h | 9 +--- mix/ConstantCompilationModel.cpp | 66 -------------------------- mix/ConstantCompilationModel.h | 53 --------------------- mix/ContractCallDataEncoder.cpp | 6 +-- mix/ContractCallDataEncoder.h | 6 +-- mix/Extension.cpp | 21 +++++---- mix/Extension.h | 11 +++-- mix/KeyEventManager.cpp | 8 ++++ mix/KeyEventManager.h | 7 +++ mix/MixApplication.cpp | 26 +++++----- mix/MixApplication.h | 13 ++++- mix/QBasicNodeDefinition.h | 6 +-- mix/QContractDefinition.cpp | 22 ++------- mix/QContractDefinition.h | 10 ++-- mix/QFunctionDefinition.cpp | 6 +-- mix/QFunctionDefinition.h | 3 +- mix/QVariableDeclaration.h | 6 ++- mix/QVariableDefinition.h | 8 ++-- mix/TransactionListModel.cpp | 76 ++++++++++++------------------ mix/TransactionListModel.h | 8 ++-- mix/TransactionListView.cpp | 5 +- mix/TransactionListView.h | 4 +- mix/main.cpp | 13 +---- 33 files changed, 320 insertions(+), 409 deletions(-) delete mode 100644 mix/ConstantCompilationModel.cpp delete mode 100644 mix/ConstantCompilationModel.h diff --git a/mix/AppContext.cpp b/mix/AppContext.cpp index 3cafe219e..37cf4070a 100644 --- a/mix/AppContext.cpp +++ b/mix/AppContext.cpp @@ -27,26 +27,31 @@ #include #include #include "libdevcrypto/FileSystem.h" +#include "libwebthree/WebThree.h" #include "KeyEventManager.h" #include "AppContext.h" +#include "CodeModel.h" + using namespace dev; using namespace dev::eth; using namespace dev::solidity; using namespace dev::mix; -AppContext* AppContext::Instance = nullptr; - AppContext::AppContext(QQmlApplicationEngine* _engine) { - m_applicationEngine = std::unique_ptr(_engine); + m_applicationEngine = _engine; m_keyEventManager = std::unique_ptr(new KeyEventManager()); m_webThree = std::unique_ptr(new WebThreeDirect(std::string("Mix/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir() + "/Mix", false, {"eth", "shh"})); - m_compiler = std::unique_ptr(new CompilerStack()); + m_codeModel = std::unique_ptr(new CodeModel(this)); +} + +AppContext::~AppContext() +{ } QQmlApplicationEngine* AppContext::appEngine() { - return m_applicationEngine.get(); + return m_applicationEngine; } dev::eth::Client* AppContext::getEthereumClient() @@ -68,22 +73,10 @@ KeyEventManager* AppContext::getKeyEventManager() return m_keyEventManager.get(); } -CompilerStack* AppContext::compiler() -{ - m_compiler.reset(new CompilerStack()); - return m_compiler.get(); -} - -void AppContext::setApplicationContext(QQmlApplicationEngine* _engine) -{ - if (Instance == nullptr) - Instance = new AppContext(_engine); -} - void AppContext::displayMessageDialog(QString _title, QString _message) { - QObject* dialogWin = m_applicationEngine.get()->rootObjects().at(0)->findChild("alertMessageDialog", Qt::FindChildrenRecursively); - QObject* dialogWinComponent = m_applicationEngine.get()->rootObjects().at(0)->findChild("alertMessageDialogContent", Qt::FindChildrenRecursively); + QObject* dialogWin = m_applicationEngine->rootObjects().at(0)->findChild("alertMessageDialog", Qt::FindChildrenRecursively); + QObject* dialogWinComponent = m_applicationEngine->rootObjects().at(0)->findChild("alertMessageDialogContent", Qt::FindChildrenRecursively); dialogWinComponent->setProperty("source", QString("qrc:/qml/BasicMessage.qml")); dialogWin->setProperty("title", _title); dialogWin->setProperty("width", "250"); @@ -91,3 +84,9 @@ void AppContext::displayMessageDialog(QString _title, QString _message) dialogWin->findChild("messageContent", Qt::FindChildrenRecursively)->setProperty("text", _message); QMetaObject::invokeMethod(dialogWin, "open"); } + +void AppContext::resourceLoaded(QObject *_obj, QUrl _url) +{ + Q_UNUSED(_url); + initKeyEventManager(_obj); +} diff --git a/mix/AppContext.h b/mix/AppContext.h index 88e70f3f4..6657a675e 100644 --- a/mix/AppContext.h +++ b/mix/AppContext.h @@ -27,42 +27,51 @@ #pragma once -#include -#include "libsolidity/CompilerStack.h" -#include "libwebthree/WebThree.h" -#include "KeyEventManager.h" +#include +#include +#include + +class QQmlApplicationEngine; namespace dev { + +class WebThreeDirect; + +namespace eth +{ + class Client; +} + namespace mix { -class AppContext: public QObject +class CodeModel; +class KeyEventManager; + +class AppContext : public QObject { Q_OBJECT public: AppContext(QQmlApplicationEngine* _engine); - ~AppContext() {} - static AppContext* getInstance() { return Instance; } - static void setApplicationContext(QQmlApplicationEngine* _engine); + ~AppContext(); QQmlApplicationEngine* appEngine(); dev::eth::Client* getEthereumClient(); void initKeyEventManager(QObject* _obj); KeyEventManager* getKeyEventManager(); - dev::solidity::CompilerStack* compiler(); + CodeModel* codeModel() { return m_codeModel.get(); } void displayMessageDialog(QString _title, QString _message); private: - static AppContext* Instance; - std::unique_ptr m_applicationEngine; + QQmlApplicationEngine* m_applicationEngine; //owned by app std::unique_ptr m_webThree; std::unique_ptr m_keyEventManager; - std::unique_ptr m_compiler; + std::unique_ptr m_codeModel; public slots: - void quitApplication() { delete Instance; } - void resourceLoaded(QObject* _obj, QUrl _url) { Q_UNUSED(_url); initKeyEventManager(_obj); } + void quitApplication() {} + void resourceLoaded(QObject* _obj, QUrl _url); }; } diff --git a/mix/AssemblyDebuggerCtrl.cpp b/mix/AssemblyDebuggerCtrl.cpp index 3c82c5a16..588565628 100644 --- a/mix/AssemblyDebuggerCtrl.cpp +++ b/mix/AssemblyDebuggerCtrl.cpp @@ -19,12 +19,11 @@ #include #include -#include #include +#include #include #include -#include "libethereum/Transaction.h" -#include "AssemblyDebuggerModel.h" +#include #include "AssemblyDebuggerCtrl.h" #include "KeyEventManager.h" #include "AppContext.h" @@ -33,10 +32,14 @@ #include "QContractDefinition.h" #include "QVariableDeclaration.h" #include "ContractCallDataEncoder.h" +#include "KeyEventManager.h" +#include "CodeModel.h" +#include "AssemblyDebuggerModel.h" + using namespace dev::eth; using namespace dev::mix; -AssemblyDebuggerCtrl::AssemblyDebuggerCtrl(QTextDocument* _doc): Extension(ExtensionDisplayBehavior::ModalDialog) +AssemblyDebuggerCtrl::AssemblyDebuggerCtrl(AppContext* _context): Extension(_context, ExtensionDisplayBehavior::ModalDialog) { qRegisterMetaType("QVariableDefinition*"); qRegisterMetaType("QVariableDefinitionList*"); @@ -48,8 +51,6 @@ AssemblyDebuggerCtrl::AssemblyDebuggerCtrl(QTextDocument* _doc): Extension(Exten this, SLOT(updateGUI(bool, DebuggingStatusResult, QList, QList, AssemblyDebuggerData)), Qt::QueuedConnection); m_modelDebugger = std::unique_ptr(new AssemblyDebuggerModel); - m_compilation = std::unique_ptr(new ConstantCompilationModel); - m_doc = _doc; } QString AssemblyDebuggerCtrl::contentUrl() const @@ -74,41 +75,41 @@ void AssemblyDebuggerCtrl::keyPressed(int _key) { QtConcurrent::run([this]() { - deployContract(m_doc->toPlainText()); + deployContract(); }); } } void AssemblyDebuggerCtrl::callContract(dev::mix::TransactionSettings _tr) { - CompilerResult compilerRes = m_compilation.get()->compile(m_doc->toPlainText()); - if (!compilerRes.success) + auto compilerRes = m_ctx->codeModel()->lastCompilationResult(); + if (!compilerRes->successfull()) { - AppContext::getInstance()->displayMessageDialog("debugger","compilation failed"); + m_ctx->displayMessageDialog("debugger","compilation failed"); return; } ContractCallDataEncoder c; - std::shared_ptr contractDef = QContractDefinition::Contract(m_doc->toPlainText()); + QContractDefinition const* contractDef = compilerRes->contract(); - QFunctionDefinition* f = nullptr; - for (int k = 0; k < contractDef.get()->functions().size(); k++) + QFunctionDefinition const* f = nullptr; + for (int k = 0; k < contractDef->functions().size(); k++) { - if (contractDef.get()->functions().at(k)->name() == _tr.functionId) + if (contractDef->functions().at(k)->name() == _tr.functionId) { - f = (QFunctionDefinition*)contractDef->functions().at(k); + f = contractDef->functions().at(k); } } if (!f) { - AppContext::getInstance()->displayMessageDialog("debugger","contract code changed. redeploy contract"); + m_ctx->displayMessageDialog("debugger","contract code changed. redeploy contract"); return; } c.encode(f->index()); for (int k = 0; k < f->parameters().size(); k++) { - QVariableDeclaration* var = (QVariableDeclaration*)f->parameters().at(k); + QVariableDeclaration const* var = static_cast(f->parameters().at(k)); c.encode(var, _tr.parameterValues[var->name()]); } @@ -120,16 +121,16 @@ void AssemblyDebuggerCtrl::callContract(dev::mix::TransactionSettings _tr) finalizeExecution(debuggingContent); } -void AssemblyDebuggerCtrl::deployContract(QString _source) +void AssemblyDebuggerCtrl::deployContract() { - CompilerResult compilerRes = m_compilation.get()->compile(_source); - if (!compilerRes.success) + auto compilerRes = m_ctx->codeModel()->lastCompilationResult(); + if (!compilerRes->successfull()) { emit dataAvailable(false, DebuggingStatusResult::Compilationfailed); return; } - m_previousDebugResult = m_modelDebugger->getContractInitiationDebugStates(compilerRes.bytes); + m_previousDebugResult = m_modelDebugger->getContractInitiationDebugStates(compilerRes->bytes()); finalizeExecution(m_previousDebugResult); } diff --git a/mix/AssemblyDebuggerCtrl.h b/mix/AssemblyDebuggerCtrl.h index 03a0acfbe..61807cbb9 100644 --- a/mix/AssemblyDebuggerCtrl.h +++ b/mix/AssemblyDebuggerCtrl.h @@ -20,12 +20,9 @@ #pragma once #include -#include "QTextDocument" #include "Extension.h" -#include "ConstantCompilationModel.h" #include "TransactionListModel.h" #include "AssemblyDebuggerModel.h" -#include "AppContext.h" using AssemblyDebuggerData = std::tuple, dev::mix::QQMLMap*>; enum DebuggingStatusResult @@ -38,6 +35,8 @@ Q_DECLARE_METATYPE(AssemblyDebuggerData) Q_DECLARE_METATYPE(DebuggingStatusResult) Q_DECLARE_METATYPE(dev::mix::DebuggingContent) +class AppContext; + namespace dev { namespace mix @@ -48,7 +47,7 @@ class AssemblyDebuggerCtrl: public Extension Q_OBJECT public: - AssemblyDebuggerCtrl(QTextDocument*); + AssemblyDebuggerCtrl(AppContext* _context); ~AssemblyDebuggerCtrl() {} void start() const override; QString title() const override; @@ -56,9 +55,7 @@ public: private: std::unique_ptr m_modelDebugger; - std::unique_ptr m_compilation; - QTextDocument* m_doc; - void deployContract(QString _source); + void deployContract(); void callContract(dev::mix::TransactionSettings _contractAddress); void finalizeExecution(DebuggingContent _content); DebuggingContent m_previousDebugResult; //used for now to keep the contract address in case of transaction call. @@ -70,7 +67,6 @@ public slots: signals: void dataAvailable(bool _success, DebuggingStatusResult _reason, QList _returnParams = QList(), QList _wStates = QList(), AssemblyDebuggerData _code = AssemblyDebuggerData()); - }; } diff --git a/mix/AssemblyDebuggerModel.cpp b/mix/AssemblyDebuggerModel.cpp index af6de8ed7..994e2208c 100644 --- a/mix/AssemblyDebuggerModel.cpp +++ b/mix/AssemblyDebuggerModel.cpp @@ -23,15 +23,19 @@ #include #include #include +#include "AssemblyDebuggerModel.h" #include "AppContext.h" #include "TransactionListModel.h" -#include "AssemblyDebuggerModel.h" -#include "ConstantCompilationModel.h" #include "DebuggingStateWrapper.h" + using namespace std; using namespace dev; using namespace dev::eth; -using namespace dev::mix; + +namespace dev +{ +namespace mix +{ AssemblyDebuggerModel::AssemblyDebuggerModel(): m_userAccount(KeyPair::create()), @@ -44,11 +48,9 @@ AssemblyDebuggerModel::AssemblyDebuggerModel(): DebuggingContent AssemblyDebuggerModel::executeTransaction(bytesConstRef _rawTransaction) { - QList machineStates; // Reset the state back to our clean premine. m_currentExecution = std::unique_ptr(new Executive(m_executiveState, 0)); - QList states; m_currentExecution->setup(_rawTransaction); std::vector levels; bytes code; @@ -119,3 +121,6 @@ void AssemblyDebuggerModel::resetState() { m_executiveState = m_baseState; } + +} +} diff --git a/mix/CodeEditorExtensionManager.cpp b/mix/CodeEditorExtensionManager.cpp index a6f7e798a..cd5e725e3 100644 --- a/mix/CodeEditorExtensionManager.cpp +++ b/mix/CodeEditorExtensionManager.cpp @@ -30,9 +30,17 @@ #include "AssemblyDebuggerCtrl.h" #include "TransactionListView.h" #include "AppContext.h" +#include "MixApplication.h" +#include "CodeModel.h" #include "CodeEditorExtensionManager.h" + using namespace dev::mix; +CodeEditorExtensionManager::CodeEditorExtensionManager(): + m_appContext(static_cast(QApplication::instance())->context()) +{ +} + CodeEditorExtensionManager::~CodeEditorExtensionManager() { m_features.clear(); @@ -42,38 +50,26 @@ void CodeEditorExtensionManager::loadEditor(QQuickItem* _editor) { if (!_editor) return; - try + + QVariant doc = _editor->property("textDocument"); + if (doc.canConvert()) { - QVariant doc = _editor->property("textDocument"); - if (doc.canConvert()) + QQuickTextDocument* qqdoc = doc.value(); + if (qqdoc) { - QQuickTextDocument* qqdoc = doc.value(); - if (qqdoc) - { - m_doc = qqdoc->textDocument(); - auto args = QApplication::arguments(); - if (args.length() > 1) - { - QString path = args[1]; - QFile file(path); - if (file.exists() && file.open(QFile::ReadOnly)) - m_doc->setPlainText(file.readAll()); - } - } + m_doc = qqdoc->textDocument(); } } - catch (...) - { - qDebug() << "unable to load editor: "; - } } void CodeEditorExtensionManager::initExtensions() { - initExtension(std::make_shared(m_doc)); - std::shared_ptr debug = std::make_shared(m_doc); - std::shared_ptr tr = std::make_shared(m_doc); + initExtension(std::make_shared(m_appContext)); + std::shared_ptr debug = std::make_shared(m_appContext); + std::shared_ptr tr = std::make_shared(m_appContext); QObject::connect(tr->model(), &TransactionListModel::transactionStarted, debug.get(), &AssemblyDebuggerCtrl::runTransaction); + QObject::connect(m_doc, &QTextDocument::contentsChanged, [=]() { m_appContext->codeModel()->registerCodeChange(m_doc->toPlainText()); }); + initExtension(debug); initExtension(tr); } @@ -103,6 +99,15 @@ void CodeEditorExtensionManager::setEditor(QQuickItem* _editor) { this->loadEditor(_editor); this->initExtensions(); + + auto args = QApplication::arguments(); + if (args.length() > 1) + { + QString path = args[1]; + QFile file(path); + if (file.exists() && file.open(QFile::ReadOnly)) + m_doc->setPlainText(file.readAll()); + } } void CodeEditorExtensionManager::setRightTabView(QQuickItem* _tabView) diff --git a/mix/CodeEditorExtensionManager.h b/mix/CodeEditorExtensionManager.h index 9e931664d..475981cc9 100644 --- a/mix/CodeEditorExtensionManager.h +++ b/mix/CodeEditorExtensionManager.h @@ -33,6 +33,8 @@ namespace dev namespace mix { +class AppContext; + class CodeEditorExtensionManager: public QObject { Q_OBJECT @@ -42,7 +44,7 @@ class CodeEditorExtensionManager: public QObject Q_PROPERTY(QQuickItem* rightTabView MEMBER m_rightTabView WRITE setRightTabView) public: - CodeEditorExtensionManager() {} + CodeEditorExtensionManager(); ~CodeEditorExtensionManager(); void initExtensions(); void initExtension(std::shared_ptr); @@ -56,6 +58,7 @@ private: QQuickItem* m_tabView; QQuickItem* m_rightTabView; QTextDocument* m_doc; + AppContext* m_appContext; void loadEditor(QQuickItem*); }; diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index 120a81ac7..eebd9ed1f 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -20,6 +20,13 @@ * Ethereum IDE client. */ +#include +#include +#include +#include +#include +#include +#include "QContractDefinition.h" #include "CodeModel.h" namespace dev @@ -32,12 +39,27 @@ void BackgroundWorker::queueCodeChange(int _jobId, QString const& _content) m_model->runCompilationJob(_jobId, _content); } - -CodeModel::CodeModel(QObject* _parent) : QObject(_parent), m_backgroundWorker(this) +CompilationResult::CompilationResult(const solidity::CompilerStack& _compiler, QObject *_parent): + QObject(_parent), m_successfull(true), + m_contract(new QContractDefinition(&_compiler.getContractDefinition(std::string()))), + m_bytes(_compiler.getBytecode()), + m_assemblyCode(QString::fromStdString((dev::eth::disassemble(m_bytes)))) +{} + +CompilationResult::CompilationResult(CompilationResult const& _prev, QString const& _compilerMessage, QObject* _parent): + QObject(_parent), m_successfull(false), + m_contract(_prev.m_contract), + m_compilerMessage(_compilerMessage), + m_bytes(_prev.m_bytes), + m_assemblyCode(_prev.m_assemblyCode) +{} + +CodeModel::CodeModel(QObject* _parent) : QObject(_parent), + m_backgroundWorker(this), m_backgroundJobId(0) { m_backgroundWorker.moveToThread(&m_backgroundThread); - connect(this, &CodeModel::compilationComplete, this, &CodeModel::onCompilationComplete, Qt::QueuedConnection); + //connect(this, &CodeModel::compilationComplete, this, &CodeModel::onCompilationComplete, Qt::QueuedConnection); connect(this, &CodeModel::scheduleCompilationJob, &m_backgroundWorker, &BackgroundWorker::queueCodeChange, Qt::QueuedConnection); m_backgroundThread.start(); } @@ -62,20 +84,31 @@ void CodeModel::registerCodeChange(const QString &_code) emit scheduleCompilationJob(m_backgroundJobId, _code); } -void CodeModel::onCompilationComplete(std::shared_ptr _compilationResult) -{ - m_result.swap(_compilationResult); -} - -void CodeModel::runCompilationJob(int _jobId, QString const& _content) +void CodeModel::runCompilationJob(int _jobId, QString const& _code) { if (_jobId != m_backgroundJobId) return; //obsolete job - + solidity::CompilerStack cs; + try + { + cs.setSource(_code.toStdString()); + cs.compile(false); + std::shared_ptr result(new CompilationResult(cs, nullptr)); + m_result.swap(result); + qDebug() << QString(QApplication::tr("compilation succeeded")); + } + catch (dev::Exception const& _exception) + { + std::ostringstream error; + solidity::SourceReferenceFormatter::printExceptionInformation(error, _exception, "Error", cs); + std::shared_ptr result(new CompilationResult(*m_result, QString::fromStdString(error.str()), nullptr)); + m_result.swap(result); + qDebug() << QString(QApplication::tr("compilation failed") + " " + m_result->compilerMessage()); + } + emit compilationComplete(); } - } } diff --git a/mix/CodeModel.h b/mix/CodeModel.h index 1667f19a4..4c3b60089 100644 --- a/mix/CodeModel.h +++ b/mix/CodeModel.h @@ -22,12 +22,19 @@ #pragma once +#include #include #include #include namespace dev { + +namespace solidity +{ + class CompilerStack; +} + namespace mix { @@ -54,14 +61,24 @@ class CompilationResult : public QObject Q_PROPERTY(QContractDefinition const* contract READ contract) public: - QContractDefinition const* contract() { return m_contract; } + /// Successfull compilation result constructor + CompilationResult(solidity::CompilerStack const& _compiler, QObject* parent); + /// Failed compilation result constructor + CompilationResult(CompilationResult const& _prev, QString const& _compilerMessage, QObject* parent); + QContractDefinition const* contract() { return m_contract.get(); } + + bool successfull() const { return m_successfull; } + QContractDefinition const* contract() const { return m_contract.get(); } + QString compilerMessage() const { return m_compilerMessage; } + dev::bytes const& bytes() const { return m_bytes; } + QString assemblyCode() const { return m_assemblyCode; } private: bool m_successfull; - QContractDefinition* m_contract; - QString m_hexCode; + std::shared_ptr m_contract; QString m_compilerMessage; ///< @todo: use some structure here dev::bytes m_bytes; + QString m_assemblyCode; ///@todo syntax highlighting, etc }; @@ -79,19 +96,16 @@ public: CodeModel(QObject* _parent); ~CodeModel(); - CompilationResult* getLastCompilationResult(); + std::shared_ptr lastCompilationResult() { return m_result; } signals: void statusChanged(Status _from, Status _to); - void compilationComplete(std::shared_ptr _compilationResult); + void compilationComplete(); void scheduleCompilationJob(int _jobId, QString const& _content); public slots: void registerCodeChange(QString const& _code); -private slots: - void onCompilationComplete(std::shared_ptr _compilationResult); - private: void runCompilationJob(int _jobId, QString const& _content); void stop(); @@ -100,7 +114,6 @@ private: QThread m_backgroundThread; BackgroundWorker m_backgroundWorker; int m_backgroundJobId = 0; //protects from starting obsolete compilation job - friend class BackgroundWorker; }; diff --git a/mix/ConstantCompilationCtrl.cpp b/mix/ConstantCompilationCtrl.cpp index 012556c3a..14bb36033 100644 --- a/mix/ConstantCompilationCtrl.cpp +++ b/mix/ConstantCompilationCtrl.cpp @@ -27,15 +27,16 @@ #include #include #include -#include "ConstantCompilationCtrl.h" -#include "ConstantCompilationModel.h" #include "QContractDefinition.h" +#include "AppContext.h" +#include "CodeModel.h" +#include "ConstantCompilationCtrl.h" + using namespace dev::mix; -ConstantCompilationCtrl::ConstantCompilationCtrl(QTextDocument* _doc): Extension(ExtensionDisplayBehavior::Tab) +ConstantCompilationCtrl::ConstantCompilationCtrl(AppContext* _context): Extension(_context, ExtensionDisplayBehavior::Tab) { - m_editor = _doc; - m_compilationModel = std::unique_ptr(new ConstantCompilationModel()); + connect(_context->codeModel(), &CodeModel::compilationComplete, this, &ConstantCompilationCtrl::update); } QString ConstantCompilationCtrl::contentUrl() const @@ -50,45 +51,32 @@ QString ConstantCompilationCtrl::title() const void ConstantCompilationCtrl::start() const { - connect(m_editor, SIGNAL(contentsChange(int,int,int)), this, SLOT(compile())); } -void ConstantCompilationCtrl::compile() +void ConstantCompilationCtrl::update() { - QString codeContent = m_editor->toPlainText().replace("\n", ""); - if (codeContent.isEmpty()) - { - resetOutPut(); - return; - } - CompilerResult res = m_compilationModel->compile(m_editor->toPlainText().replace("\t", " ")); - writeOutPut(res); -} + auto result = m_ctx->codeModel()->lastCompilationResult(); -void ConstantCompilationCtrl::resetOutPut() -{ QObject* status = m_view->findChild("status", Qt::FindChildrenRecursively); QObject* content = m_view->findChild("content", Qt::FindChildrenRecursively); - status->setProperty("text", ""); - content->setProperty("text", ""); -} - -void ConstantCompilationCtrl::writeOutPut(CompilerResult const& _res) -{ - QObject* status = m_view->findChild("status", Qt::FindChildrenRecursively); - QObject* content = m_view->findChild("content", Qt::FindChildrenRecursively); - if (_res.success) + if (result->successfull()) { status->setProperty("text", "succeeded"); status->setProperty("color", "green"); - content->setProperty("text", _res.hexCode); - qDebug() << QString(QApplication::tr("compile succeeded") + " " + _res.hexCode); + content->setProperty("text", result->assemblyCode()); } else { status->setProperty("text", "failure"); status->setProperty("color", "red"); - content->setProperty("text", _res.comment); - qDebug() << QString(QApplication::tr("compile failed") + " " + _res.comment); + content->setProperty("text", result->compilerMessage()); } } + +void ConstantCompilationCtrl::resetOutPut() +{ + QObject* status = m_view->findChild("status", Qt::FindChildrenRecursively); + QObject* content = m_view->findChild("content", Qt::FindChildrenRecursively); + status->setProperty("text", ""); + content->setProperty("text", ""); +} diff --git a/mix/ConstantCompilationCtrl.h b/mix/ConstantCompilationCtrl.h index 4e6aa53de..8aad7a2db 100644 --- a/mix/ConstantCompilationCtrl.h +++ b/mix/ConstantCompilationCtrl.h @@ -19,8 +19,6 @@ #pragma once -#include -#include "ConstantCompilationModel.h" #include "Extension.h" namespace dev @@ -33,20 +31,17 @@ class ConstantCompilationCtrl: public Extension Q_OBJECT public: - ConstantCompilationCtrl(QTextDocument*); + ConstantCompilationCtrl(AppContext* _appContext); ~ConstantCompilationCtrl() {} void start() const override; QString title() const override; QString contentUrl() const override; private: - QTextDocument* m_editor; - std::unique_ptr m_compilationModel; - void writeOutPut(CompilerResult const&); void resetOutPut(); public slots: - void compile(); + void update(); }; } diff --git a/mix/ConstantCompilationModel.cpp b/mix/ConstantCompilationModel.cpp deleted file mode 100644 index 06141da26..000000000 --- a/mix/ConstantCompilationModel.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** @file ConstantCompilationModel.cpp - * @author Yann yann@ethdev.com - * @date 2014 - * Ethereum IDE client. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "ConstantCompilationModel.h" -using namespace std; -using namespace dev; -using namespace dev::eth; -using namespace dev::mix; -using namespace dev::solidity; - -CompilerResult ConstantCompilationModel::compile(QString _code) -{ - dev::solidity::CompilerStack compiler; - dev::bytes m_data; - CompilerResult res; - try - { - m_data = compiler.compile(_code.toStdString(), true); - res.success = true; - res.comment = "ok"; - res.hexCode = QString::fromStdString(dev::eth::disassemble(m_data)); - res.bytes = m_data; - } - catch (dev::Exception const& _exception) - { - ostringstream error; - solidity::SourceReferenceFormatter::printExceptionInformation(error, _exception, "Error", compiler); - res.success = false; - res.comment = QString::fromStdString(error.str()); - res.hexCode = ""; - } - catch (...) - { - res.success = false; - res.comment = QApplication::tr("Uncaught exception."); - res.hexCode = ""; - } - return res; -} diff --git a/mix/ConstantCompilationModel.h b/mix/ConstantCompilationModel.h deleted file mode 100644 index cecb0d817..000000000 --- a/mix/ConstantCompilationModel.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** @file ConstantCompilationModel.h - * @author Yann yann@ethdev.com - * @date 2014 - * Ethereum IDE client. - */ - -#pragma once - -#include -#include -#include - -namespace dev -{ -namespace mix -{ - -struct CompilerResult -{ - QString hexCode; - QString comment; - dev::bytes bytes; - bool success; -}; - -class ConstantCompilationModel -{ - -public: - ConstantCompilationModel() {} - ~ConstantCompilationModel() {} - CompilerResult compile(QString _code); -}; - -} - -} diff --git a/mix/ContractCallDataEncoder.cpp b/mix/ContractCallDataEncoder.cpp index 0254b7a21..5758e2174 100644 --- a/mix/ContractCallDataEncoder.cpp +++ b/mix/ContractCallDataEncoder.cpp @@ -46,19 +46,19 @@ void ContractCallDataEncoder::encode(int _functionIndex) m_encodedData.insert(m_encodedData.end(), i.begin(), i.end()); } -void ContractCallDataEncoder::encode(QVariableDeclaration* _dec, bool _value) +void ContractCallDataEncoder::encode(QVariableDeclaration const* _dec, bool _value) { return encode(_dec, QString(formatBool(_value))); } -void ContractCallDataEncoder::encode(QVariableDeclaration* _dec, QString _value) +void ContractCallDataEncoder::encode(QVariableDeclaration const* _dec, QString _value) { int padding = this->padding(_dec->type()); bytes data = padded(jsToBytes(_value.toStdString()), padding); m_encodedData.insert(m_encodedData.end(), data.begin(), data.end()); } -void ContractCallDataEncoder::encode(QVariableDeclaration* _dec, u256 _value) +void ContractCallDataEncoder::encode(QVariableDeclaration const* _dec, u256 _value) { int padding = this->padding(_dec->type()); std::ostringstream s; diff --git a/mix/ContractCallDataEncoder.h b/mix/ContractCallDataEncoder.h index 4677b97c8..01e346035 100644 --- a/mix/ContractCallDataEncoder.h +++ b/mix/ContractCallDataEncoder.h @@ -34,10 +34,10 @@ class ContractCallDataEncoder { public: ContractCallDataEncoder(); - void encode(QVariableDeclaration* _dec, QString _value); - void encode(QVariableDeclaration* _dec, u256 _value); + void encode(QVariableDeclaration const* _dec, QString _value); + void encode(QVariableDeclaration const* _dec, u256 _value); QList decode(QList _dec, bytes _value); - void encode(QVariableDeclaration* _dec, bool _value); + void encode(QVariableDeclaration const* _dec, bool _value); void encode(int _functionIndex); bytes encodedData(); diff --git a/mix/Extension.cpp b/mix/Extension.cpp index c6a41995a..2744fb6cb 100644 --- a/mix/Extension.cpp +++ b/mix/Extension.cpp @@ -19,26 +19,27 @@ #include #include +#include #include #include "Extension.h" #include "AppContext.h" using namespace dev; using namespace dev::mix; -Extension::Extension() +Extension::Extension(AppContext* _context) { - init(); + init(_context); } -Extension::Extension(ExtensionDisplayBehavior _displayBehavior) +Extension::Extension(AppContext* _context, ExtensionDisplayBehavior _displayBehavior) { - init(); + init(_context); m_displayBehavior = _displayBehavior; } -void Extension::init() +void Extension::init(AppContext* _context) { - m_ctx = AppContext::getInstance(); + m_ctx = _context; m_appEngine = m_ctx->appEngine(); } @@ -49,7 +50,7 @@ void Extension::addTabOn(QObject* _view) QVariant returnValue; QQmlComponent* component = new QQmlComponent( - AppContext::getInstance()->appEngine(), + m_appEngine, QUrl(contentUrl()), _view); QMetaObject::invokeMethod(_view, "addTab", @@ -65,9 +66,9 @@ void Extension::addContentOn(QObject* _view) Q_UNUSED(_view); if (m_displayBehavior == ExtensionDisplayBehavior::ModalDialog) { - QQmlComponent* component = new QQmlComponent(AppContext::getInstance()->appEngine(), QUrl(contentUrl()), _view); - QObject* dialogWin = AppContext::getInstance()->appEngine()->rootObjects().at(0)->findChild("dialog", Qt::FindChildrenRecursively); - QObject* dialogWinComponent = AppContext::getInstance()->appEngine()->rootObjects().at(0)->findChild("modalDialogContent", Qt::FindChildrenRecursively); + QQmlComponent* component = new QQmlComponent(m_appEngine, QUrl(contentUrl()), _view); + QObject* dialogWin = m_appEngine->rootObjects().at(0)->findChild("dialog", Qt::FindChildrenRecursively); + QObject* dialogWinComponent = m_appEngine->rootObjects().at(0)->findChild("modalDialogContent", Qt::FindChildrenRecursively); dialogWinComponent->setProperty("sourceComponent", QVariant::fromValue(component)); dialogWin->setProperty("title", title()); QMetaObject::invokeMethod(dialogWin, "open"); diff --git a/mix/Extension.h b/mix/Extension.h index f983cd74c..85ef52711 100644 --- a/mix/Extension.h +++ b/mix/Extension.h @@ -21,13 +21,16 @@ #include #include -#include "AppContext.h" + +class QQmlApplicationEngine; namespace dev { namespace mix { +class AppContext; + enum ExtensionDisplayBehavior { Tab, @@ -41,8 +44,8 @@ class Extension: public QObject Q_OBJECT public: - Extension(); - Extension(ExtensionDisplayBehavior _displayBehavior); + Extension(AppContext* _context); + Extension(AppContext* _context, ExtensionDisplayBehavior _displayBehavior); virtual QString contentUrl() const { return ""; } virtual QString title() const { return ""; } virtual void start() const {} @@ -58,7 +61,7 @@ protected: QQmlApplicationEngine* m_appEngine; private: - void init(); + void init(AppContext* _context); }; } diff --git a/mix/KeyEventManager.cpp b/mix/KeyEventManager.cpp index c32caadb8..f7af8270b 100644 --- a/mix/KeyEventManager.cpp +++ b/mix/KeyEventManager.cpp @@ -25,6 +25,11 @@ #include #include "KeyEventManager.h" +namespace dev +{ +namespace mix +{ + void KeyEventManager::registerEvent(const QObject* _receiver, const char* _slot) { QObject::connect(this, SIGNAL(onKeyPressed(int)), _receiver, _slot); @@ -39,3 +44,6 @@ void KeyEventManager::keyPressed(QVariant _event) { emit onKeyPressed(_event.toInt()); } + +} +} diff --git a/mix/KeyEventManager.h b/mix/KeyEventManager.h index f3343cc45..2710a804f 100644 --- a/mix/KeyEventManager.h +++ b/mix/KeyEventManager.h @@ -24,6 +24,11 @@ #include +namespace dev +{ +namespace mix +{ + class KeyEventManager: public QObject { Q_OBJECT @@ -40,3 +45,5 @@ public slots: void keyPressed(QVariant _event); }; +} +} diff --git a/mix/MixApplication.cpp b/mix/MixApplication.cpp index 0c217dace..ce0f78ccd 100644 --- a/mix/MixApplication.cpp +++ b/mix/MixApplication.cpp @@ -20,26 +20,22 @@ */ #include +#include +#include "CodeEditorExtensionManager.h" #include "MixApplication.h" +#include "AppContext.h" + using namespace dev::mix; -MixApplication::MixApplication(int _argc, char* _argv[]): QApplication(_argc, _argv) +MixApplication::MixApplication(int _argc, char* _argv[]): + QApplication(_argc, _argv), m_engine(new QQmlApplicationEngine()), m_appContext(new AppContext(m_engine.get())) { + qmlRegisterType("CodeEditorExtensionManager", 1, 0, "CodeEditorExtensionManager"); + m_engine->load(QUrl("qrc:/qml/main.qml")); + QObject::connect(this, SIGNAL(lastWindowClosed()), context(), SLOT(quitApplication())); //use to kill ApplicationContext and other stuff + QObject::connect(engine(), SIGNAL(objectCreated(QObject*, QUrl)), context(), SLOT(resourceLoaded(QObject*, QUrl))); } -bool MixApplication::notify(QObject* _receiver, QEvent* _event) +MixApplication::~MixApplication() { - try - { - return MixApplication::notify(_receiver, _event); - } - catch (std::exception& _ex) - { - qDebug() << "std::exception was caught " << _ex.what(); - } - catch (...) - { - qDebug() << "uncaught exception "; - } - return false; } diff --git a/mix/MixApplication.h b/mix/MixApplication.h index 383c5849c..7cb9b512f 100644 --- a/mix/MixApplication.h +++ b/mix/MixApplication.h @@ -23,21 +23,30 @@ #pragma once +#include #include +class QQmlApplicationEngine; + namespace dev { namespace mix { +class AppContext; + class MixApplication: public QApplication { Q_OBJECT public: MixApplication(int _argc, char* _argv[]); - virtual ~MixApplication() {} - virtual bool notify(QObject* _receiver, QEvent* _event); + virtual ~MixApplication(); + AppContext* context() { return m_appContext.get(); } + QQmlApplicationEngine* engine( ) { return m_engine.get(); } +private: + std::unique_ptr m_engine; + std::unique_ptr m_appContext; }; } diff --git a/mix/QBasicNodeDefinition.h b/mix/QBasicNodeDefinition.h index d5a22db30..399a92123 100644 --- a/mix/QBasicNodeDefinition.h +++ b/mix/QBasicNodeDefinition.h @@ -38,11 +38,11 @@ public: QBasicNodeDefinition(): QObject() {} ~QBasicNodeDefinition() { } - QBasicNodeDefinition(dev::solidity::Declaration* _d): QObject(), m_dec(_d) {} - QString name() const { return QString::fromStdString(m_dec->getName()); } + QBasicNodeDefinition(dev::solidity::Declaration const* _d): QObject(), m_name(QString::fromStdString(_d->getName())) {} + QString name() const { return m_name; } protected: - dev::solidity::Declaration* m_dec; + QString m_name; }; } diff --git a/mix/QContractDefinition.cpp b/mix/QContractDefinition.cpp index bf85030f5..fcc265241 100644 --- a/mix/QContractDefinition.cpp +++ b/mix/QContractDefinition.cpp @@ -31,27 +31,13 @@ using namespace dev::solidity; using namespace dev::mix; -std::shared_ptr QContractDefinition::Contract(QString _source) +QContractDefinition::QContractDefinition(dev::solidity::ContractDefinition const* _contract): QBasicNodeDefinition(_contract) { - CompilerStack* comp = AppContext::getInstance()->compiler(); - comp->addSource("contract", _source.toStdString()); - comp->parse(); - SourceUnit const& unit = comp->getAST("contract"); - ContractDefinition* def = (ContractDefinition*)unit.getNodes().at(0).get(); - return std::make_shared(def); -} - -QContractDefinition::QContractDefinition(ContractDefinition* _contract): QBasicNodeDefinition(_contract) -{ - initQFunctions(); -} - -void QContractDefinition::initQFunctions() -{ - std::vector functions = ((ContractDefinition*)m_dec)->getInterfaceFunctions(); + std::vector functions = _contract->getInterfaceFunctions(); for (unsigned i = 0; i < functions.size(); i++) { - FunctionDefinition* func = (FunctionDefinition*)functions.at(i); + FunctionDefinition const* func = functions.at(i); m_functions.append(new QFunctionDefinition(func, i)); } } + diff --git a/mix/QContractDefinition.h b/mix/QContractDefinition.h index 7cc145cf8..d4e2e609f 100644 --- a/mix/QContractDefinition.h +++ b/mix/QContractDefinition.h @@ -34,16 +34,14 @@ namespace mix class QContractDefinition: public QBasicNodeDefinition { Q_OBJECT - Q_PROPERTY(QList functions READ functions) + Q_PROPERTY(QList functions READ functions) public: - QContractDefinition(dev::solidity::ContractDefinition* _contract); - QList functions() const { return m_functions; } - static std::shared_ptr Contract(QString _code); + QContractDefinition(dev::solidity::ContractDefinition const* _contract); + QList functions() const { return m_functions; } private: - QList m_functions; - void initQFunctions(); + QList m_functions; }; } diff --git a/mix/QFunctionDefinition.cpp b/mix/QFunctionDefinition.cpp index 9923e5277..09e4ae89a 100644 --- a/mix/QFunctionDefinition.cpp +++ b/mix/QFunctionDefinition.cpp @@ -25,15 +25,15 @@ using namespace dev::solidity; using namespace dev::mix; -void QFunctionDefinition::initQParameters() +QFunctionDefinition::QFunctionDefinition(dev::solidity::FunctionDefinition const* _f, int _index): QBasicNodeDefinition(_f), m_index(_index) { - std::vector> parameters = ((FunctionDefinition*)m_dec)->getParameterList().getParameters(); + std::vector> parameters = _f->getParameterList().getParameters(); for (unsigned i = 0; i < parameters.size(); i++) { m_parameters.append(new QVariableDeclaration(parameters.at(i).get())); } - std::vector> returnParameters = ((FunctionDefinition*)m_dec)->getReturnParameters(); + std::vector> returnParameters = _f->getReturnParameters(); for (unsigned i = 0; i < returnParameters.size(); i++) { m_returnParameters.append(new QVariableDeclaration(returnParameters.at(i).get())); diff --git a/mix/QFunctionDefinition.h b/mix/QFunctionDefinition.h index 877e1bd53..1cfbbb15f 100644 --- a/mix/QFunctionDefinition.h +++ b/mix/QFunctionDefinition.h @@ -37,7 +37,7 @@ class QFunctionDefinition: public QBasicNodeDefinition Q_PROPERTY(int index READ index) public: - QFunctionDefinition(dev::solidity::FunctionDefinition* _f, int _index): QBasicNodeDefinition(_f), m_index(_index) { initQParameters(); } + QFunctionDefinition(dev::solidity::FunctionDefinition const* _f, int _index); QList parameters() const { return m_parameters; } QList returnParameters() const { return m_returnParameters; } int index() const { return m_index; } @@ -46,7 +46,6 @@ private: QList m_parameters; QList m_returnParameters; int m_index; - void initQParameters(); }; } diff --git a/mix/QVariableDeclaration.h b/mix/QVariableDeclaration.h index 8b7cb52bb..9be2baf66 100644 --- a/mix/QVariableDeclaration.h +++ b/mix/QVariableDeclaration.h @@ -35,8 +35,10 @@ class QVariableDeclaration: public QBasicNodeDefinition Q_PROPERTY(QString type READ type) public: - QVariableDeclaration(dev::solidity::VariableDeclaration* _v): QBasicNodeDefinition(_v){} - QString type() const { return QString::fromStdString(((solidity::VariableDeclaration*)m_dec)->getType()->toString()); } + QVariableDeclaration(dev::solidity::VariableDeclaration const* _v): QBasicNodeDefinition(_v), m_type(QString::fromStdString(_v->getType()->toString())) {} + QString type() const { return m_type; } +private: + QString m_type; }; } diff --git a/mix/QVariableDefinition.h b/mix/QVariableDefinition.h index 907ddd6c1..9ee532cfc 100644 --- a/mix/QVariableDefinition.h +++ b/mix/QVariableDefinition.h @@ -33,16 +33,16 @@ class QVariableDefinition: public QObject { Q_OBJECT Q_PROPERTY(QString value READ value) - Q_PROPERTY(QVariableDeclaration* declaration READ declaration) + Q_PROPERTY(QVariableDeclaration const* declaration READ declaration) public: - QVariableDefinition(QVariableDeclaration* _def, QString _value): QObject(_def->parent()), m_value(_value), m_dec(_def) {} + QVariableDefinition(QVariableDeclaration const* _dec, QString _value): QObject(_dec->parent()), m_dec(_dec), m_value(_value) {} - QVariableDeclaration* declaration() const { return m_dec; } + QVariableDeclaration const* declaration() const { return m_dec; } QString value() const { return m_value; } private: - QVariableDeclaration* m_dec; + QVariableDeclaration const* m_dec; QString m_value; }; diff --git a/mix/TransactionListModel.cpp b/mix/TransactionListModel.cpp index 44474a232..344301edd 100644 --- a/mix/TransactionListModel.cpp +++ b/mix/TransactionListModel.cpp @@ -24,11 +24,13 @@ #include #include #include +#include "libdevcore/CommonJS.h" #include "TransactionListModel.h" #include "QContractDefinition.h" #include "QFunctionDefinition.h" #include "QVariableDeclaration.h" -#include "libdevcore/CommonJS.h" +#include "AppContext.h" +#include "CodeModel.h" namespace dev { @@ -54,8 +56,8 @@ TransactionListItem::TransactionListItem(int _index, TransactionSettings const& m_gas(toQString(_t.gas)), m_gasPrice(toQString(_t.gasPrice)) {} -TransactionListModel::TransactionListModel(QObject* _parent, QTextDocument* _document): - QAbstractListModel(_parent), m_document(_document) +TransactionListModel::TransactionListModel(QObject* _parent, AppContext* _appContext): + QAbstractListModel(_parent), m_appContext(_appContext) {} QHash TransactionListModel::roleNames() const @@ -89,43 +91,34 @@ QVariant TransactionListModel::data(QModelIndex const& _index, int _role) const } ///@todo: get parameters from code model -QList buildParameters(QTextDocument* _document, TransactionSettings const& _transaction, QString const& _functionId) +QList buildParameters(CodeModel* _codeModel, TransactionSettings const& _transaction, QString const& _functionId) { QList params; - try + QContractDefinition const* contract = _codeModel->lastCompilationResult()->contract(); + auto functions = contract->functions(); + for (auto qf : functions) { - QString code = _document->toPlainText().replace("\n", ""); //TODO: is this required? - std::shared_ptr contract = QContractDefinition::Contract(code); - auto functions = contract->functions(); - for (auto qf : functions) - { - QFunctionDefinition const& f = (QFunctionDefinition const&) *qf; - if (f.name() != _functionId) - continue; + QFunctionDefinition const& f = (QFunctionDefinition const&) *qf; + if (f.name() != _functionId) + continue; - auto parameters = f.parameters(); - for (auto qp : parameters) + auto parameters = f.parameters(); + for (auto qp : parameters) + { + QVariableDeclaration const& p = (QVariableDeclaration const&) *qp; + QString paramValue; + if (f.name() == _transaction.functionId) { - QVariableDeclaration const& p = (QVariableDeclaration const&) *qp; - QString paramValue; - if (f.name() == _transaction.functionId) - { - auto paramValueIter = _transaction.parameterValues.find(p.name()); - if (paramValueIter != _transaction.parameterValues.cend()) - paramValue = toQString(paramValueIter->second); - } - - TransactionParameterItem* item = new TransactionParameterItem(p.name(), p.type(), paramValue); - QQmlEngine::setObjectOwnership(item, QQmlEngine::JavaScriptOwnership); - params.append(item); + auto paramValueIter = _transaction.parameterValues.find(p.name()); + if (paramValueIter != _transaction.parameterValues.cend()) + paramValue = toQString(paramValueIter->second); } + + TransactionParameterItem* item = new TransactionParameterItem(p.name(), p.type(), paramValue); + QQmlEngine::setObjectOwnership(item, QQmlEngine::JavaScriptOwnership); + params.append(item); } } - catch (boost::exception const&) - { - //TODO: - } - return params; } @@ -133,19 +126,12 @@ QList buildParameters(QTextDocument* _document, Trans QList TransactionListModel::getFunctions() { QList functionNames; - try - { - QString code = m_document->toPlainText().replace("\n", ""); //TODO: is this required? - std::shared_ptr contract(QContractDefinition::Contract(code)); - auto functions = contract->functions(); - for (auto qf : functions) - { - QFunctionDefinition const& f = (QFunctionDefinition const&) * qf; - functionNames.append(f.name()); - } - } - catch (boost::exception const&) + QContractDefinition const* contract = m_appContext->codeModel()->lastCompilationResult()->contract(); + auto functions = contract->functions(); + for (auto qf : functions) { + QFunctionDefinition const& f = (QFunctionDefinition const&) * qf; + functionNames.append(f.name()); } return functionNames; } @@ -153,7 +139,7 @@ QList TransactionListModel::getFunctions() QVariantList TransactionListModel::getParameters(int _index, QString const& _functionId) { TransactionSettings const& transaction = (_index >= 0 && _index < (int)m_transactions.size()) ? m_transactions[_index] : TransactionSettings(); - auto plist = buildParameters(m_document, transaction, _functionId); + auto plist = buildParameters(m_appContext->codeModel(), transaction, _functionId); QVariantList vl; for (QObject* p : plist) vl.append(QVariant::fromValue(p)); diff --git a/mix/TransactionListModel.h b/mix/TransactionListModel.h index 28800a4ff..9faf7d63f 100644 --- a/mix/TransactionListModel.h +++ b/mix/TransactionListModel.h @@ -30,13 +30,13 @@ #include #include -class QTextDocument; - namespace dev { namespace mix { +class AppContext; + /// Backend transaction config class struct TransactionSettings { @@ -132,7 +132,7 @@ class TransactionListModel: public QAbstractListModel }; public: - TransactionListModel(QObject* _parent, QTextDocument* _document); + TransactionListModel(QObject* _parent, AppContext* _appContext); ~TransactionListModel() {} QHash roleNames() const override; @@ -159,7 +159,7 @@ signals: private: std::vector m_transactions; - QTextDocument* m_document; + AppContext* m_appContext; }; } diff --git a/mix/TransactionListView.cpp b/mix/TransactionListView.cpp index 7e2bfaa25..55df90b8a 100644 --- a/mix/TransactionListView.cpp +++ b/mix/TransactionListView.cpp @@ -29,10 +29,9 @@ #include "TransactionListModel.h" using namespace dev::mix; -TransactionListView::TransactionListView(QTextDocument* _doc): Extension(ExtensionDisplayBehavior::RightTab) +TransactionListView::TransactionListView(AppContext* _context): Extension(_context, ExtensionDisplayBehavior::RightTab) { - m_editor = _doc; - m_model.reset(new TransactionListModel(this, _doc)); + m_model.reset(new TransactionListModel(this, _context)); m_appEngine->rootContext()->setContextProperty("transactionListModel", m_model.get()); } diff --git a/mix/TransactionListView.h b/mix/TransactionListView.h index be1aef905..e21d7ecd8 100644 --- a/mix/TransactionListView.h +++ b/mix/TransactionListView.h @@ -19,6 +19,7 @@ #pragma once +#include #include #include "TransactionListView.h" #include "Extension.h" @@ -37,7 +38,7 @@ class TransactionListView: public Extension Q_OBJECT public: - TransactionListView(QTextDocument*); + TransactionListView(AppContext* _context); ~TransactionListView(); void start() const override; QString title() const override; @@ -46,7 +47,6 @@ public: TransactionListModel* model() const { return m_model.get(); } private: - QTextDocument* m_editor; std::unique_ptr m_model; }; diff --git a/mix/main.cpp b/mix/main.cpp index 36a742f8f..e10903c80 100644 --- a/mix/main.cpp +++ b/mix/main.cpp @@ -20,22 +20,11 @@ * Ethereum IDE client. */ -#include -#include -#include -#include "CodeEditorExtensionManager.h" -#include "AppContext.h" #include "MixApplication.h" using namespace dev::mix; int main(int _argc, char *_argv[]) { - QApplication app(_argc, _argv); - qmlRegisterType("CodeEditorExtensionManager", 1, 0, "CodeEditorExtensionManager"); - QQmlApplicationEngine* engine = new QQmlApplicationEngine(); - AppContext::setApplicationContext(engine); - QObject::connect(&app, SIGNAL(lastWindowClosed()), AppContext::getInstance(), SLOT(quitApplication())); //use to kill ApplicationContext and other stuff - QObject::connect(engine, SIGNAL(objectCreated(QObject*, QUrl)), AppContext::getInstance(), SLOT(resourceLoaded(QObject*, QUrl))); - engine->load(QUrl("qrc:/qml/main.qml")); + MixApplication app(_argc, _argv); return app.exec(); } From 850ae83bdfc21d1eaccb2ea3679a05f11f7ea273 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sun, 21 Dec 2014 17:56:22 +0100 Subject: [PATCH 03/17] added doxygen comments --- mix/CodeModel.h | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/mix/CodeModel.h b/mix/CodeModel.h index 4c3b60089..a7665f6d6 100644 --- a/mix/CodeModel.h +++ b/mix/CodeModel.h @@ -41,6 +41,7 @@ namespace mix class CodeModel; class QContractDefinition; +//utility class to perform tasks in background thread class BackgroundWorker: public QObject { Q_OBJECT @@ -54,7 +55,7 @@ private: CodeModel* m_model; }; - +///Compilation result model. Contains all the compiled contract data required by UI class CompilationResult : public QObject { Q_OBJECT @@ -65,12 +66,20 @@ public: CompilationResult(solidity::CompilerStack const& _compiler, QObject* parent); /// Failed compilation result constructor CompilationResult(CompilationResult const& _prev, QString const& _compilerMessage, QObject* parent); - QContractDefinition const* contract() { return m_contract.get(); } - bool successfull() const { return m_successfull; } + /// @returns contract definition QContractDefinition const* contract() const { return m_contract.get(); } + + /// Indicates if the compilation was successfull + bool successfull() const { return m_successfull; } + + /// @returns compiler error message in case of unsuccessfull compilation QString compilerMessage() const { return m_compilerMessage; } + + /// @returns contract bytecode dev::bytes const& bytes() const { return m_bytes; } + + /// @returns contract bytecode in human-readable form QString assemblyCode() const { return m_assemblyCode; } private: @@ -82,12 +91,13 @@ private: ///@todo syntax highlighting, etc }; +/// Background code compiler class CodeModel : public QObject { enum Status { - Idle, - Compiling, + Idle, ///< No compiation in progress + Compiling, ///< Compilation currently in progress }; Q_OBJECT @@ -96,14 +106,19 @@ public: CodeModel(QObject* _parent); ~CodeModel(); + /// @returns latest compilation result std::shared_ptr lastCompilationResult() { return m_result; } signals: + /// Emited on compilation status change void statusChanged(Status _from, Status _to); + /// Emitted on compilation complete void compilationComplete(); + /// Internal signal used to transfer compilation job to background thread void scheduleCompilationJob(int _jobId, QString const& _content); public slots: + /// Update code model on source code change void registerCodeChange(QString const& _code); private: From 0594f792671709499c0a23555b1973918eb8f0e4 Mon Sep 17 00:00:00 2001 From: arkpar Date: Wed, 24 Dec 2014 13:28:31 +0100 Subject: [PATCH 04/17] Transaction QML model --- mix/AppContext.cpp | 3 ++ mix/AssemblyDebuggerControl.cpp | 14 ++++---- mix/CodeModel.cpp | 25 ++++++++++--- mix/CodeModel.h | 21 ++++++++--- mix/ConstantCompilationControl.cpp | 2 +- mix/ProjectFile.cpp | 36 +++++++++++++++++++ mix/ProjectFile.h | 57 ++++++++++++++++++++++++++++++ mix/QContractDefinition.h | 8 +++-- mix/QFunctionDefinition.h | 10 ++++-- mix/QVariableDeclaration.h | 3 +- mix/TransactionListModel.cpp | 23 +++++++++--- mix/TransactionListModel.h | 6 ++++ mix/TransactionListView.cpp | 2 +- mix/qml.qrc | 3 ++ mix/qml/TransactionDialog.qml | 22 +++++++----- mix/qml/TransactionItem.qml | 11 ++++++ mix/qml/TransactionList.qml | 36 ++++++++++++++++--- 17 files changed, 237 insertions(+), 45 deletions(-) create mode 100644 mix/ProjectFile.cpp create mode 100644 mix/ProjectFile.h create mode 100644 mix/qml/TransactionItem.qml diff --git a/mix/AppContext.cpp b/mix/AppContext.cpp index 4802f8ac2..e70d3d0b1 100644 --- a/mix/AppContext.cpp +++ b/mix/AppContext.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +44,8 @@ AppContext::AppContext(QQmlApplicationEngine* _engine) m_keyEventManager = std::unique_ptr(new KeyEventManager()); m_webThree = std::unique_ptr(new WebThreeDirect(std::string("Mix/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir() + "/Mix", false, {"eth", "shh"})); m_codeModel = std::unique_ptr(new CodeModel(this)); + m_applicationEngine->rootContext()->setContextProperty("codeModel", m_codeModel.get()); + } AppContext::~AppContext() diff --git a/mix/AssemblyDebuggerControl.cpp b/mix/AssemblyDebuggerControl.cpp index 4fdb08a6b..b6d839e25 100644 --- a/mix/AssemblyDebuggerControl.cpp +++ b/mix/AssemblyDebuggerControl.cpp @@ -90,7 +90,7 @@ void AssemblyDebuggerControl::keyPressed(int _key) void AssemblyDebuggerControl::callContract(TransactionSettings _tr, Address _contract) { - auto compilerRes = m_ctx->codeModel()->lastCompilationResult(); + auto compilerRes = m_ctx->codeModel()->code(); if (!compilerRes->successfull()) m_ctx->displayMessageDialog("debugger","compilation failed"); else @@ -98,11 +98,11 @@ void AssemblyDebuggerControl::callContract(TransactionSettings _tr, Address _con ContractCallDataEncoder c; QContractDefinition const* contractDef = compilerRes->contract(); QFunctionDefinition* f = nullptr; - for (int k = 0; k < contractDef->functions().size(); k++) + for (int k = 0; k < contractDef->functionsList().size(); k++) { - if (contractDef->functions().at(k)->name() == _tr.functionId) + if (contractDef->functionsList().at(k)->name() == _tr.functionId) { - f = (QFunctionDefinition*)contractDef->functions().at(k); + f = contractDef->functionsList().at(k); break; } } @@ -111,9 +111,9 @@ void AssemblyDebuggerControl::callContract(TransactionSettings _tr, Address _con else { c.encode(f->index()); - for (int k = 0; k < f->parameters().size(); k++) + for (int k = 0; k < f->parametersList().size(); k++) { - QVariableDeclaration* var = (QVariableDeclaration*)f->parameters().at(k); + QVariableDeclaration* var = (QVariableDeclaration*)f->parametersList().at(k); c.encode(var, _tr.parameterValues[var->name()]); } DebuggingContent debuggingContent = m_modelDebugger->callContract(_contract, c.encodedData(), _tr); @@ -125,7 +125,7 @@ void AssemblyDebuggerControl::callContract(TransactionSettings _tr, Address _con void AssemblyDebuggerControl::deployContract() { - auto compilerRes = m_ctx->codeModel()->lastCompilationResult(); + auto compilerRes = m_ctx->codeModel()->code(); if (!compilerRes->successfull()) emit dataAvailable(false, DebuggingStatusResult::Compilationfailed); else diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index 648c9b2cc..74d74fb6e 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -23,10 +23,13 @@ #include #include #include +#include #include #include #include #include "QContractDefinition.h" +#include "QFunctionDefinition.h" +#include "QVariableDeclaration.h" #include "CodeModel.h" namespace dev @@ -59,6 +62,13 @@ CodeModel::CodeModel(QObject* _parent) : QObject(_parent), { m_backgroundWorker.moveToThread(&m_backgroundThread); connect(this, &CodeModel::scheduleCompilationJob, &m_backgroundWorker, &BackgroundWorker::queueCodeChange, Qt::QueuedConnection); + connect(this, &CodeModel::compilationCompleteInternal, this, &CodeModel::onCompilationComplete, Qt::QueuedConnection); + qRegisterMetaType("CompilationResult*"); + qRegisterMetaType("QContractDefinition*"); + qRegisterMetaType("QFunctionDefinition*"); + qRegisterMetaType("QVariableDeclaration*"); + qmlRegisterType("org.ethereum.qml", 1, 0, "QFunctionDefinition"); + qmlRegisterType("org.ethereum.qml", 1, 0, "QVariableDeclaration"); m_backgroundThread.start(); } @@ -93,19 +103,26 @@ void CodeModel::runCompilationJob(int _jobId, QString const& _code) { cs.setSource(_code.toStdString()); cs.compile(false); - std::shared_ptr result(new CompilationResult(cs, nullptr)); - m_result.swap(result); + std::unique_ptr result(new CompilationResult(cs, nullptr)); qDebug() << QString(QApplication::tr("compilation succeeded")); + emit compilationCompleteInternal(result.release()); } catch (dev::Exception const& _exception) { std::ostringstream error; solidity::SourceReferenceFormatter::printExceptionInformation(error, _exception, "Error", cs); - std::shared_ptr result(new CompilationResult(*m_result, QString::fromStdString(error.str()), nullptr)); - m_result.swap(result); + std::unique_ptr result(new CompilationResult(*m_result, QString::fromStdString(error.str()), nullptr)); qDebug() << QString(QApplication::tr("compilation failed") + " " + m_result->compilerMessage()); + emit compilationCompleteInternal(result.release()); } +} + +void CodeModel::onCompilationComplete(CompilationResult*_newResult) +{ + m_result.reset(_newResult); emit compilationComplete(); + if (m_result->successfull()) + emit codeChanged(); } } diff --git a/mix/CodeModel.h b/mix/CodeModel.h index a7665f6d6..a70bdd500 100644 --- a/mix/CodeModel.h +++ b/mix/CodeModel.h @@ -59,7 +59,7 @@ private: class CompilationResult : public QObject { Q_OBJECT - Q_PROPERTY(QContractDefinition const* contract READ contract) + Q_PROPERTY(QContractDefinition* contract READ contract) public: /// Successfull compilation result constructor @@ -68,7 +68,7 @@ public: CompilationResult(CompilationResult const& _prev, QString const& _compilerMessage, QObject* parent); /// @returns contract definition - QContractDefinition const* contract() const { return m_contract.get(); } + QContractDefinition* contract() { return m_contract.get(); } /// Indicates if the compilation was successfull bool successfull() const { return m_successfull; } @@ -84,7 +84,7 @@ public: private: bool m_successfull; - std::shared_ptr m_contract; + std::shared_ptr m_contract; QString m_compilerMessage; ///< @todo: use some structure here dev::bytes m_bytes; QString m_assemblyCode; @@ -107,7 +107,11 @@ public: ~CodeModel(); /// @returns latest compilation result - std::shared_ptr lastCompilationResult() { return m_result; } + CompilationResult* code() { return m_result.get(); } + /// @returns latest compilation resul + CompilationResult const* code() const { return m_result.get(); } + + Q_PROPERTY(CompilationResult* code READ code NOTIFY codeChanged) signals: /// Emited on compilation status change @@ -116,6 +120,13 @@ signals: void compilationComplete(); /// Internal signal used to transfer compilation job to background thread void scheduleCompilationJob(int _jobId, QString const& _content); + /// Emitted if there are any changes in the code model + void codeChanged(); + /// Emitted on compilation complete. Internal + void compilationCompleteInternal(CompilationResult* _newResult); + +private slots: + void onCompilationComplete(CompilationResult*_newResult); public slots: /// Update code model on source code change @@ -125,7 +136,7 @@ private: void runCompilationJob(int _jobId, QString const& _content); void stop(); - std::shared_ptr m_result; + std::unique_ptr m_result; QThread m_backgroundThread; BackgroundWorker m_backgroundWorker; int m_backgroundJobId = 0; //protects from starting obsolete compilation job diff --git a/mix/ConstantCompilationControl.cpp b/mix/ConstantCompilationControl.cpp index 58f8df5f9..6fc684860 100644 --- a/mix/ConstantCompilationControl.cpp +++ b/mix/ConstantCompilationControl.cpp @@ -55,7 +55,7 @@ void ConstantCompilationControl::start() const void ConstantCompilationControl::update() { - auto result = m_ctx->codeModel()->lastCompilationResult(); + auto result = m_ctx->codeModel()->code(); QObject* status = m_view->findChild("status", Qt::FindChildrenRecursively); QObject* content = m_view->findChild("content", Qt::FindChildrenRecursively); diff --git a/mix/ProjectFile.cpp b/mix/ProjectFile.cpp new file mode 100644 index 000000000..0b847345b --- /dev/null +++ b/mix/ProjectFile.cpp @@ -0,0 +1,36 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file ProjectFile.cpp + * @author Arkadiy Paronyan arkadiy@ethdev.com + * @date 2014 + * Ethereum IDE client. + */ + +#include +#include "ProjectFile.h" + +namespace dev +{ +namespace mix +{ + +void ProjectFile::saveProject() +{ +} + +} +} diff --git a/mix/ProjectFile.h b/mix/ProjectFile.h new file mode 100644 index 000000000..7ae1fb84d --- /dev/null +++ b/mix/ProjectFile.h @@ -0,0 +1,57 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file ProjectFile.h + * @author Arkadiy Paronyan arkadiy@ethdev.com + * @date 2014 + * Ethereum IDE client. + */ + +#pragma once + +#include +#include "TransactionListModel.h" + +namespace dev +{ + +namespace mix +{ + +/// Background code compiler +class ProjectFile : public QObject +{ + Q_OBJECT + +public: + ProjectFile(); + + void loadProject(); + +signals: + void projectLoaded(); + +public slots: + void saveProject(); + +private: + QString defaultProjectPath() const; + TransactionListModel* transactionModel(); +}; + +} + +} diff --git a/mix/QContractDefinition.h b/mix/QContractDefinition.h index fcd07d7bc..fa85220ff 100644 --- a/mix/QContractDefinition.h +++ b/mix/QContractDefinition.h @@ -22,6 +22,7 @@ #pragma once #include +#include #include #include "QFunctionDefinition.h" #include "QBasicNodeDefinition.h" @@ -34,16 +35,17 @@ namespace mix class QContractDefinition: public QBasicNodeDefinition { Q_OBJECT - Q_PROPERTY(QList functions READ functions) + Q_PROPERTY(QQmlListProperty functions READ functions CONSTANT) public: QContractDefinition(solidity::ContractDefinition const* _contract); /// Get all the functions of the contract. - QList functions() const { return m_functions; } - + QQmlListProperty functions() const { return QQmlListProperty(const_cast(this), const_cast(this)->m_functions); } + QList const& functionsList() const { return m_functions; } private: QList m_functions; }; } } + diff --git a/mix/QFunctionDefinition.h b/mix/QFunctionDefinition.h index b4acca41f..b2d0cd0b7 100644 --- a/mix/QFunctionDefinition.h +++ b/mix/QFunctionDefinition.h @@ -22,8 +22,9 @@ #pragma once #include +#include #include -#include +#include "QVariableDeclaration.h" #include "QBasicNodeDefinition.h" namespace dev @@ -34,13 +35,16 @@ namespace mix class QFunctionDefinition: public QBasicNodeDefinition { Q_OBJECT - Q_PROPERTY(QList parameters READ parameters) + Q_PROPERTY(QQmlListProperty parameters READ parameters) Q_PROPERTY(int index READ index) public: + QFunctionDefinition() {} QFunctionDefinition(solidity::FunctionDefinition const* _f, int _index); /// Get all input parameters of this function. - QList parameters() const { return m_parameters; } + QList const& parametersList() const { return m_parameters; } + /// Get all input parameters of this function as QML property. + QQmlListProperty parameters() const { return QQmlListProperty(const_cast(this), const_cast(this)->m_parameters); } /// Get all return parameters of this function. QList returnParameters() const { return m_returnParameters; } /// Get the index of this function on the contract ABI. diff --git a/mix/QVariableDeclaration.h b/mix/QVariableDeclaration.h index d21d9358c..966ee0ff3 100644 --- a/mix/QVariableDeclaration.h +++ b/mix/QVariableDeclaration.h @@ -35,6 +35,7 @@ class QVariableDeclaration: public QBasicNodeDefinition Q_PROPERTY(QString type READ type CONSTANT) public: + QVariableDeclaration() {} QVariableDeclaration(solidity::VariableDeclaration const* _v): QBasicNodeDefinition(_v), m_type(QString::fromStdString(_v->getType()->toString())) {} QString type() const { return m_type; } private: @@ -43,5 +44,3 @@ private: } } - -Q_DECLARE_METATYPE(dev::mix::QVariableDeclaration*) diff --git a/mix/TransactionListModel.cpp b/mix/TransactionListModel.cpp index 943ffc9e0..f6ecc9846 100644 --- a/mix/TransactionListModel.cpp +++ b/mix/TransactionListModel.cpp @@ -96,14 +96,14 @@ QVariant TransactionListModel::data(QModelIndex const& _index, int _role) const QList buildParameters(CodeModel* _codeModel, TransactionSettings const& _transaction, QString const& _functionId) { QList params; - QContractDefinition const* contract = _codeModel->lastCompilationResult()->contract(); - auto functions = contract->functions(); + QContractDefinition const* contract = _codeModel->code()->contract(); + auto functions = contract->functionsList(); for (auto f : functions) { if (f->name() != _functionId) continue; - auto parameters = f->parameters(); + auto parameters = f->parametersList(); for (auto p : parameters) { QString paramValue; @@ -126,8 +126,8 @@ QList buildParameters(CodeModel* _codeModel, Transact QList TransactionListModel::getFunctions() { QList functionNames; - QContractDefinition const* contract = m_appContext->codeModel()->lastCompilationResult()->contract(); - auto functions = contract->functions(); + QContractDefinition const* contract = m_appContext->codeModel()->code()->contract(); + auto functions = contract->functionsList(); for (auto f : functions) { functionNames.append(f->name()); @@ -200,6 +200,19 @@ void TransactionListModel::runTransaction(int _index) emit transactionStarted(tr); } +QVariantMap TransactionListModel::save() +{ + +} + +/// Load transactions from a map +void TransactionListModel::load(QVariantMap const& _data) +{ + std::vector transactions; + + + m_transactions.swap(transactions); +} } } diff --git a/mix/TransactionListModel.h b/mix/TransactionListModel.h index 0af37a467..993767310 100644 --- a/mix/TransactionListModel.h +++ b/mix/TransactionListModel.h @@ -24,9 +24,11 @@ #include #include +#include #include #include #include +#include #include #include @@ -150,6 +152,10 @@ public: Q_INVOKABLE QVariantList getParameters(int _id, QString const& _functionId); /// Launch transaction execution UI handler Q_INVOKABLE void runTransaction(int _index); + /// Save transaction to a map for serialization into file + QVariantMap save(); + /// Load transactions from a map + void load(QVariantMap const& _data); signals: /// Transaction count has changed diff --git a/mix/TransactionListView.cpp b/mix/TransactionListView.cpp index 55df90b8a..9d20d173d 100644 --- a/mix/TransactionListView.cpp +++ b/mix/TransactionListView.cpp @@ -32,7 +32,7 @@ using namespace dev::mix; TransactionListView::TransactionListView(AppContext* _context): Extension(_context, ExtensionDisplayBehavior::RightTab) { m_model.reset(new TransactionListModel(this, _context)); - m_appEngine->rootContext()->setContextProperty("transactionListModel", m_model.get()); + //m_appEngine->rootContext()->setContextProperty("transactionListModel", m_model.get()); } TransactionListView::~TransactionListView() diff --git a/mix/qml.qrc b/mix/qml.qrc index 2384afa69..2ab2989b9 100644 --- a/mix/qml.qrc +++ b/mix/qml.qrc @@ -11,5 +11,8 @@ qml/TransactionList.qml qml/ModalDialog.qml qml/AlertMessageDialog.qml + qml/StateItem.qml + qml/StateList.qml + qml/TransactionItem.qml diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index 004d9be49..a6f22b0ca 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -32,9 +32,7 @@ Window { signal accepted; - function reset(index, m) { - model = m; - var item = model.getItem(index); + function reset(index, item) { transactionIndex = index; transactionTitle = item.title; gas = item.gas; @@ -43,10 +41,10 @@ Window { var functionId = item.functionId; functionsModel.clear(); var functionIndex = -1; - var functions = model.getFunctions(); + var functions = codeModel.code.contract.functions; for (var f = 0; f < functions.length; f++) { - functionsModel.append({ text: functions[f] }); - if (functions[f] === item.functionId) + functionsModel.append({ text: functions[f].name }); + if (functions[f].name === item.functionId) functionIndex = f; } functionComboBox.currentIndex = functionIndex; @@ -57,9 +55,13 @@ Window { return; paramsModel.clear(); if (functionComboBox.currentIndex >= 0 && functionComboBox.currentIndex < functionsModel.count) { - var parameters = model.getParameters(transactionIndex, functionsModel.get(functionComboBox.currentIndex).text); + console.log(codeModel.code.contract.functions[functionComboBox.currentIndex]); + var func = codeModel.code.contract.functions[functionComboBox.currentIndex]; + var parameters = func.parameters; + console.log(parameters); + console.log(parameters.length); for (var p = 0; p < parameters.length; p++) { - paramsModel.append({ name: parameters[p].name, type: parameters[p].type, value: parameters[p].value }); + paramsModel.append({ name: parameters[p].name, type: parameters[p].type, value: parameters[p].value !== undefined ? parameters[p].value : "" }); } } } @@ -195,7 +197,9 @@ Window { Connections { target: loaderEditor.item onTextChanged: { - paramsModel.setProperty(styleData.row, styleData.role, loaderEditor.item.text); + console.log(styleData.row + " : " + styleData.role + " = " + loaderEditor.item.text ); + if (styleData.role === "value" && styleData.row < paramsModel.count) + paramsModel.setProperty(styleData.row, styleData.role, loaderEditor.item.text); } } sourceComponent: (styleData.selected) ? editor : null diff --git a/mix/qml/TransactionItem.qml b/mix/qml/TransactionItem.qml new file mode 100644 index 000000000..70b26b202 --- /dev/null +++ b/mix/qml/TransactionItem.qml @@ -0,0 +1,11 @@ +import QtQuick 2.2 + + +Item { + property string title; + property string functionId; + property string value; + property string gas; + property string gasPrice; + property var paramValues; +} diff --git a/mix/qml/TransactionList.qml b/mix/qml/TransactionList.qml index 06ed2fa15..2d4de02b5 100644 --- a/mix/qml/TransactionList.qml +++ b/mix/qml/TransactionList.qml @@ -19,7 +19,14 @@ Rectangle { height: parent.height width: parent.width id: transactionList - model: transactionListModel + model: ListModel { + id: transactionListModel + + function runTransaction(index) { + console.log("runTransaction"); + } + } + delegate: renderDelegate } @@ -30,8 +37,16 @@ Rectangle { { // Set next id here to work around Qt bug // https://bugreports.qt-project.org/browse/QTBUG-41327 - // Second call to signal handle would just edit the item that was just created, no harm done - transactionDialog.reset(transactionListModel.count, transactionListModel); + // Second call to signal handler would just edit the item that was just created, no harm done + var item = { + title: "", + value: "", + functionId: "", + gas: "1000000000000", + gasPrice: "100000" + }; + + transactionDialog.reset(transactionListModel.count, item); transactionDialog.open(); transactionDialog.focus = true; } @@ -40,7 +55,18 @@ Rectangle { TransactionDialog { id: transactionDialog onAccepted: { - transactionListModel.edit(transactionDialog); + var item = { + title: transactionDialog.transactionTitle, + functionId: transactionDialog.functionId, + gas: transactionDialog.gas, + gasPrice: transactionDialog.gasPrice, + value: transactionDialog.transactionValue + } + console.log(item.title); + if (transactionDialog.transactionIndex < transactionListModel.count) + transactionListModel.set(transactionDialog.transactionIndex, item); + else + transactionListModel.append(item); } } @@ -65,7 +91,7 @@ Rectangle { text: qsTr("Edit"); Layout.fillHeight: true onClicked: { - transactionDialog.reset(index, transactionListModel); + transactionDialog.reset(index, transactionListModel.get(index)); transactionDialog.open(); transactionDialog.focus = true; } From 4ddaa9dd9483101aaef02055f0e6aeca310b4ff9 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 25 Dec 2014 13:39:44 +0100 Subject: [PATCH 05/17] project save/load --- mix/AppContext.cpp | 54 +++++++++++++++++++++------------ mix/AppContext.h | 14 ++++----- mix/AssemblyDebuggerControl.cpp | 34 ++++++++++----------- mix/AssemblyDebuggerControl.h | 5 +-- mix/KeyEventManager.cpp | 49 ------------------------------ mix/KeyEventManager.h | 53 -------------------------------- mix/MixApplication.cpp | 2 +- mix/qml.qrc | 3 +- mix/qml/TransactionDialog.qml | 4 --- mix/qml/TransactionItem.qml | 11 ------- mix/qml/TransactionList.qml | 21 +++++++++++-- mix/qml/main.qml | 21 ++++++++++++- 12 files changed, 100 insertions(+), 171 deletions(-) delete mode 100644 mix/KeyEventManager.cpp delete mode 100644 mix/KeyEventManager.h delete mode 100644 mix/qml/TransactionItem.qml diff --git a/mix/AppContext.cpp b/mix/AppContext.cpp index e70d3d0b1..b97b1b265 100644 --- a/mix/AppContext.cpp +++ b/mix/AppContext.cpp @@ -27,9 +27,11 @@ #include #include #include +#include +#include +#include #include #include -#include "KeyEventManager.h" #include "AppContext.h" #include "CodeModel.h" @@ -38,37 +40,39 @@ using namespace dev::eth; using namespace dev::solidity; using namespace dev::mix; +const QString c_projectFileName = "project.mix"; + AppContext::AppContext(QQmlApplicationEngine* _engine) { m_applicationEngine = _engine; - m_keyEventManager = std::unique_ptr(new KeyEventManager()); - m_webThree = std::unique_ptr(new WebThreeDirect(std::string("Mix/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir() + "/Mix", false, {"eth", "shh"})); + //m_webThree = std::unique_ptr(new WebThreeDirect(std::string("Mix/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir() + "/Mix", false, {"eth", "shh"})); m_codeModel = std::unique_ptr(new CodeModel(this)); m_applicationEngine->rootContext()->setContextProperty("codeModel", m_codeModel.get()); - + m_applicationEngine->rootContext()->setContextProperty("appContext", this); } AppContext::~AppContext() { } -QQmlApplicationEngine* AppContext::appEngine() +void AppContext::loadProject() { - return m_applicationEngine; + QString path = QStandardPaths::locate(QStandardPaths::DataLocation, c_projectFileName); + if (!path.isEmpty()) + { + QFile file(path); + if(file.open(QIODevice::ReadOnly | QIODevice::Text)) + { + QTextStream stream(&file); + QString json = stream.readAll(); + emit projectLoaded(json); + } + } } -void AppContext::initKeyEventManager(QObject* _res) -{ - QObject* mainContent = _res->findChild("mainContent", Qt::FindChildrenRecursively); - if (mainContent) - QObject::connect(mainContent, SIGNAL(keyPressed(QVariant)), m_keyEventManager.get(), SLOT(keyPressed(QVariant))); - else - qDebug() << "Unable to find QObject of mainContent.qml. KeyEvent will not be handled!"; -} - -KeyEventManager* AppContext::getKeyEventManager() +QQmlApplicationEngine* AppContext::appEngine() { - return m_keyEventManager.get(); + return m_applicationEngine; } void AppContext::displayMessageDialog(QString _title, QString _message) @@ -84,8 +88,18 @@ void AppContext::displayMessageDialog(QString _title, QString _message) QMetaObject::invokeMethod(dialogWin, "open"); } -void AppContext::resourceLoaded(QObject *_obj, QUrl _url) +void AppContext::saveProject(QString const& _json) { - Q_UNUSED(_url); - initKeyEventManager(_obj); + QDir dirPath(QStandardPaths::writableLocation(QStandardPaths::DataLocation)); + QString path = QDir(dirPath).filePath(c_projectFileName); + if (!path.isEmpty()) + { + dirPath.mkpath(dirPath.path()); + QFile file(path); + if(file.open(QIODevice::WriteOnly | QIODevice::Text)) + { + QTextStream stream(&file); + stream << _json; + } + } } diff --git a/mix/AppContext.h b/mix/AppContext.h index 432b1e976..d3aeb28c5 100644 --- a/mix/AppContext.h +++ b/mix/AppContext.h @@ -47,7 +47,6 @@ namespace mix { class CodeModel; -class KeyEventManager; /** * @brief Provides access to application scope variable. */ @@ -60,26 +59,25 @@ public: AppContext(QQmlApplicationEngine* _engine); ~AppContext(); QQmlApplicationEngine* appEngine(); - /// Initialize KeyEventManager (used to handle key pressed event). - void initKeyEventManager(QObject* _obj); - /// Get the current KeyEventManager instance. - KeyEventManager* getKeyEventManager(); /// Get code model CodeModel* codeModel() { return m_codeModel.get(); } /// Display an alert message. void displayMessageDialog(QString _title, QString _message); + /// Load project settings + void loadProject(); +signals: + void projectLoaded(QString const& _json); private: QQmlApplicationEngine* m_applicationEngine; //owned by app std::unique_ptr m_webThree; - std::unique_ptr m_keyEventManager; std::unique_ptr m_codeModel; public slots: /// Delete the current instance when application quit. void quitApplication() {} - /// Initialize components after the loading of the main QML view. - void resourceLoaded(QObject* _obj, QUrl _url); + + void saveProject(QString const& _json); }; } diff --git a/mix/AssemblyDebuggerControl.cpp b/mix/AssemblyDebuggerControl.cpp index b6d839e25..43a36287d 100644 --- a/mix/AssemblyDebuggerControl.cpp +++ b/mix/AssemblyDebuggerControl.cpp @@ -26,16 +26,13 @@ #include #include "AssemblyDebuggerModel.h" #include "AssemblyDebuggerControl.h" -#include "KeyEventManager.h" #include "AppContext.h" #include "DebuggingStateWrapper.h" #include "TransactionListModel.h" #include "QContractDefinition.h" #include "QVariableDeclaration.h" #include "ContractCallDataEncoder.h" -#include "KeyEventManager.h" #include "CodeModel.h" -#include "AssemblyDebuggerModel.h" using namespace dev::eth; using namespace dev::mix; @@ -53,6 +50,8 @@ AssemblyDebuggerControl::AssemblyDebuggerControl(AppContext* _context): Extensio connect(this, SIGNAL(dataAvailable(bool, DebuggingStatusResult, QList, QList, AssemblyDebuggerData)), this, SLOT(updateGUI(bool, DebuggingStatusResult, QList, QList, AssemblyDebuggerData)), Qt::QueuedConnection); + _context->appEngine()->rootContext()->setContextProperty("debugModel", this); + m_modelDebugger = std::unique_ptr(new AssemblyDebuggerModel); } @@ -68,24 +67,23 @@ QString AssemblyDebuggerControl::title() const void AssemblyDebuggerControl::start() const { - //start to listen on F5 - m_ctx->getKeyEventManager()->registerEvent(this, SLOT(keyPressed(int))); } -void AssemblyDebuggerControl::keyPressed(int _key) +void AssemblyDebuggerControl::debugDeployment() { - if (_key == Qt::Key_F5) - { - QtConcurrent::run([this]() - { - deployContract(); - }); - } - else if (_key == Qt::Key_F6) - { - m_modelDebugger->resetState(); - m_ctx->displayMessageDialog(QApplication::tr("State status"), QApplication::tr("State reseted ... need to redeploy contract")); - } + deployContract(); +} + +void AssemblyDebuggerControl::debugTransaction(QObject* _transaction) +{ + auto mo = _transaction->metaObject(); + auto p = mo->property(0); +} + +void AssemblyDebuggerControl::resetState() +{ + m_modelDebugger->resetState(); + m_ctx->displayMessageDialog(QApplication::tr("State status"), QApplication::tr("State reseted ... need to redeploy contract")); } void AssemblyDebuggerControl::callContract(TransactionSettings _tr, Address _contract) diff --git a/mix/AssemblyDebuggerControl.h b/mix/AssemblyDebuggerControl.h index 69239f827..8a906d9f4 100644 --- a/mix/AssemblyDebuggerControl.h +++ b/mix/AssemblyDebuggerControl.h @@ -65,8 +65,9 @@ private: DebuggingContent m_previousDebugResult; //TODO: to be replaced in a more consistent struct. Used for now to keep the contract address in case of future transaction call. public slots: - /// Handle key pressed. F5 deploy contract - F6 reset state. - void keyPressed(int); + void debugDeployment(); + void debugTransaction(QObject* _transaction); + void resetState(); /// Update UI with machine states result. Display a modal dialog. void updateGUI(bool _success, DebuggingStatusResult const& _reason, QList const& _returnParams = QList(), QList const& _wStates = QList(), AssemblyDebuggerData const& _code = AssemblyDebuggerData()); /// Run the given transaction. diff --git a/mix/KeyEventManager.cpp b/mix/KeyEventManager.cpp deleted file mode 100644 index f7af8270b..000000000 --- a/mix/KeyEventManager.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** @file KeyEventManager.cpp - * @author Yann yann@ethdev.com - * @date 2014 - * Used as an event handler for all classes which need keyboard interactions. - * Can be improve by adding the possibility to register to a specific key. - */ - -#include -#include -#include "KeyEventManager.h" - -namespace dev -{ -namespace mix -{ - -void KeyEventManager::registerEvent(const QObject* _receiver, const char* _slot) -{ - QObject::connect(this, SIGNAL(onKeyPressed(int)), _receiver, _slot); -} - -void KeyEventManager::unRegisterEvent(QObject* _receiver) -{ - QObject::disconnect(_receiver); -} - -void KeyEventManager::keyPressed(QVariant _event) -{ - emit onKeyPressed(_event.toInt()); -} - -} -} diff --git a/mix/KeyEventManager.h b/mix/KeyEventManager.h deleted file mode 100644 index 2b538ea24..000000000 --- a/mix/KeyEventManager.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** @file KeyEventManager.h - * @author Yann yann@ethdev.com - * @date 2014 - * Used as an event handler for all classes which need keyboard interactions - */ - -#pragma once - -#include - -namespace dev -{ -namespace mix -{ - -class KeyEventManager: public QObject -{ - Q_OBJECT - -public: - KeyEventManager() {} - /// Allows _receiver to handle key pressed event. - void registerEvent(const QObject* _receiver, const char* _slot); - /// Unregister _receiver. - void unRegisterEvent(QObject* _receiver); - -signals: - /// Emited when a key is pressed. - void onKeyPressed(int _event); - -public slots: - /// Called when a key is pressed. - void keyPressed(QVariant _event); -}; - -} -} diff --git a/mix/MixApplication.cpp b/mix/MixApplication.cpp index e37296547..c2e856d8e 100644 --- a/mix/MixApplication.cpp +++ b/mix/MixApplication.cpp @@ -32,8 +32,8 @@ MixApplication::MixApplication(int _argc, char* _argv[]): { qmlRegisterType("CodeEditorExtensionManager", 1, 0, "CodeEditorExtensionManager"); QObject::connect(this, SIGNAL(lastWindowClosed()), context(), SLOT(quitApplication())); //use to kill ApplicationContext and other stuff - QObject::connect(engine(), SIGNAL(objectCreated(QObject*, QUrl)), context(), SLOT(resourceLoaded(QObject*, QUrl))); m_engine->load(QUrl("qrc:/qml/main.qml")); + m_appContext->loadProject(); } MixApplication::~MixApplication() diff --git a/mix/qml.qrc b/mix/qml.qrc index 2ab2989b9..1e2fe9983 100644 --- a/mix/qml.qrc +++ b/mix/qml.qrc @@ -11,8 +11,7 @@ qml/TransactionList.qml qml/ModalDialog.qml qml/AlertMessageDialog.qml - qml/StateItem.qml + qml/StateDialog.qml qml/StateList.qml - qml/TransactionItem.qml diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index a6f22b0ca..14b41bde1 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -55,11 +55,8 @@ Window { return; paramsModel.clear(); if (functionComboBox.currentIndex >= 0 && functionComboBox.currentIndex < functionsModel.count) { - console.log(codeModel.code.contract.functions[functionComboBox.currentIndex]); var func = codeModel.code.contract.functions[functionComboBox.currentIndex]; var parameters = func.parameters; - console.log(parameters); - console.log(parameters.length); for (var p = 0; p < parameters.length; p++) { paramsModel.append({ name: parameters[p].name, type: parameters[p].type, value: parameters[p].value !== undefined ? parameters[p].value : "" }); } @@ -197,7 +194,6 @@ Window { Connections { target: loaderEditor.item onTextChanged: { - console.log(styleData.row + " : " + styleData.role + " = " + loaderEditor.item.text ); if (styleData.role === "value" && styleData.row < paramsModel.count) paramsModel.setProperty(styleData.row, styleData.role, loaderEditor.item.text); } diff --git a/mix/qml/TransactionItem.qml b/mix/qml/TransactionItem.qml deleted file mode 100644 index 70b26b202..000000000 --- a/mix/qml/TransactionItem.qml +++ /dev/null @@ -1,11 +0,0 @@ -import QtQuick 2.2 - - -Item { - property string title; - property string functionId; - property string value; - property string gas; - property string gasPrice; - property var paramValues; -} diff --git a/mix/qml/TransactionList.qml b/mix/qml/TransactionList.qml index 2d4de02b5..fd85f0d7b 100644 --- a/mix/qml/TransactionList.qml +++ b/mix/qml/TransactionList.qml @@ -4,7 +4,6 @@ import QtQuick.Controls 1.2 import QtQuick.Dialogs 1.2 import QtQuick.Layouts 1.1 - Rectangle { color: "transparent" id: transactionListContainer @@ -14,6 +13,16 @@ Rectangle { height: parent.height width: parent.width + Connections { + target: appContext + onProjectLoaded: { + var items = JSON.parse(_json); + for(var i = 0; i < items.length; i++) { + transactionListModel.append(items[i]); + } + } + } + ListView { anchors.top: parent.top height: parent.height @@ -23,7 +32,8 @@ Rectangle { id: transactionListModel function runTransaction(index) { - console.log("runTransaction"); + var item = transactionListModel.get(index); + debugModel.debugTransaction(item); } } @@ -67,6 +77,12 @@ Rectangle { transactionListModel.set(transactionDialog.transactionIndex, item); else transactionListModel.append(item); + + var items = []; + for (var i = 0; i < transactionListModel.count; i++) + items.push(transactionListModel.get(i)); + var json = JSON.stringify(items, function(key, value) { return key === "objectName" ? undefined : value; }); + appContext.saveProject(json); } } @@ -113,3 +129,4 @@ Rectangle { } } } + diff --git a/mix/qml/main.qml b/mix/qml/main.qml index 1e7542831..e44144f61 100644 --- a/mix/qml/main.qml +++ b/mix/qml/main.qml @@ -3,7 +3,7 @@ import QtQuick.Controls 1.1 import QtQuick.Controls.Styles 1.1 import QtQuick.Dialogs 1.1 import QtQuick.Layouts 1.1 -import QtQuick.Window 2.0 +import QtQuick.Window 2.1 import CodeEditorExtensionManager 1.0 ApplicationWindow { @@ -23,6 +23,11 @@ ApplicationWindow { onTriggered: Qt.quit(); } } + Menu { + title: qsTr("Debug") + MenuItem { action: debugRunAction } + MenuItem { action: debugResetStateAction } + } } Component.onCompleted: { setX(Screen.width / 2 - width / 2); @@ -41,4 +46,18 @@ ApplicationWindow { objectName: "alertMessageDialog" id: messageDialog } + + Action { + id: debugRunAction + text: "&Run" + shortcut: "F5" + onTriggered: debugModel.debugDeployment(); + } + + Action { + id: debugResetStateAction + text: "Reset &State" + shortcut: "F6" + onTriggered: debugModel.resetState(); + } } From c9a7a42e13f5877ecb4f6c6362228283b5bccf64 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 25 Dec 2014 15:57:46 +0100 Subject: [PATCH 06/17] removed obsolete transaction model --- mix/AssemblyDebuggerControl.cpp | 33 ++++- mix/AssemblyDebuggerControl.h | 1 - mix/AssemblyDebuggerModel.cpp | 1 - mix/AssemblyDebuggerModel.h | 25 +++- mix/CodeEditorExtensionManager.cpp | 1 - mix/ProjectFile.cpp | 36 ----- mix/ProjectFile.h | 57 -------- mix/TransactionListModel.cpp | 219 ----------------------------- mix/TransactionListModel.h | 174 ----------------------- mix/TransactionListView.cpp | 8 -- mix/TransactionListView.h | 8 -- mix/qml/TransactionDialog.qml | 6 +- mix/qml/TransactionList.qml | 8 +- 13 files changed, 61 insertions(+), 516 deletions(-) delete mode 100644 mix/ProjectFile.cpp delete mode 100644 mix/ProjectFile.h delete mode 100644 mix/TransactionListModel.cpp delete mode 100644 mix/TransactionListModel.h diff --git a/mix/AssemblyDebuggerControl.cpp b/mix/AssemblyDebuggerControl.cpp index 43a36287d..bf937a11f 100644 --- a/mix/AssemblyDebuggerControl.cpp +++ b/mix/AssemblyDebuggerControl.cpp @@ -17,6 +17,7 @@ * display opcode debugging. */ +#include #include #include #include @@ -28,7 +29,6 @@ #include "AssemblyDebuggerControl.h" #include "AppContext.h" #include "DebuggingStateWrapper.h" -#include "TransactionListModel.h" #include "QContractDefinition.h" #include "QVariableDeclaration.h" #include "ContractCallDataEncoder.h" @@ -37,6 +37,20 @@ using namespace dev::eth; using namespace dev::mix; +/// @todo Move this to QML +dev::u256 fromQString(QString const& _s) +{ + return dev::jsToU256(_s.toStdString()); +} + +/// @todo Move this to QML +QString toQString(dev::u256 _value) +{ + std::ostringstream s; + s << _value; + return QString::fromStdString(s.str()); +} + AssemblyDebuggerControl::AssemblyDebuggerControl(AppContext* _context): Extension(_context, ExtensionDisplayBehavior::ModalDialog) { qRegisterMetaType("QVariableDefinition*"); @@ -76,8 +90,16 @@ void AssemblyDebuggerControl::debugDeployment() void AssemblyDebuggerControl::debugTransaction(QObject* _transaction) { - auto mo = _transaction->metaObject(); - auto p = mo->property(0); + QString functionId = _transaction->property("functionId").toString(); + u256 value = fromQString(_transaction->property("value").toString()); + u256 gas = fromQString(_transaction->property("gas").toString()); + u256 gasPrice = fromQString(_transaction->property("gasPrice").toString()); + QVariantMap params = _transaction->property("parameters").toMap(); + TransactionSettings transaction("", functionId, value, gas, gasPrice); + + for (auto p = params.cbegin(); p != params.cend(); ++p) + transaction.parameterValues.insert(std::make_pair(p.key(), fromQString(p.value().toString()))); + runTransaction(transaction); } void AssemblyDebuggerControl::resetState() @@ -164,8 +186,5 @@ void AssemblyDebuggerControl::updateGUI(bool _success, DebuggingStatusResult con void AssemblyDebuggerControl::runTransaction(TransactionSettings const& _tr) { - QtConcurrent::run([this, _tr]() - { - callContract(_tr, m_previousDebugResult.contractAddress); - }); + callContract(_tr, m_previousDebugResult.contractAddress); } diff --git a/mix/AssemblyDebuggerControl.h b/mix/AssemblyDebuggerControl.h index 8a906d9f4..061a3d20a 100644 --- a/mix/AssemblyDebuggerControl.h +++ b/mix/AssemblyDebuggerControl.h @@ -21,7 +21,6 @@ #include #include "Extension.h" -#include "TransactionListModel.h" #include "AssemblyDebuggerModel.h" using AssemblyDebuggerData = std::tuple, dev::mix::QQMLMap*>; diff --git a/mix/AssemblyDebuggerModel.cpp b/mix/AssemblyDebuggerModel.cpp index ef75981bd..9deaba4d8 100644 --- a/mix/AssemblyDebuggerModel.cpp +++ b/mix/AssemblyDebuggerModel.cpp @@ -25,7 +25,6 @@ #include #include "AssemblyDebuggerModel.h" #include "AppContext.h" -#include "TransactionListModel.h" #include "DebuggingStateWrapper.h" using namespace std; diff --git a/mix/AssemblyDebuggerModel.h b/mix/AssemblyDebuggerModel.h index 1b1254464..fea132415 100644 --- a/mix/AssemblyDebuggerModel.h +++ b/mix/AssemblyDebuggerModel.h @@ -26,13 +26,36 @@ #include #include #include "DebuggingStateWrapper.h" -#include "TransactionListModel.h" namespace dev { namespace mix { +/// Backend transaction config class +struct TransactionSettings +{ + TransactionSettings(): + value(0), gas(10000), gasPrice(10 * dev::eth::szabo) {} + + TransactionSettings(QString const& _title, QString const& _functionId, u256 _value, u256 _gas, u256 _gasPrice): + title(_title), functionId(_functionId), value(_value), gas(_gas), gasPrice(_gasPrice) {} + + /// User specified transaction title + QString title; + /// Contract function name + QString functionId; + /// Transaction value + u256 value; + /// Gas + u256 gas; + /// Gas price + u256 gasPrice; + /// Mapping from contract function parameter name to value + std::map parameterValues; +}; + + /** * @brief Long-life object for managing all executions. */ diff --git a/mix/CodeEditorExtensionManager.cpp b/mix/CodeEditorExtensionManager.cpp index 4a93352b1..8001f0bdc 100644 --- a/mix/CodeEditorExtensionManager.cpp +++ b/mix/CodeEditorExtensionManager.cpp @@ -67,7 +67,6 @@ void CodeEditorExtensionManager::initExtensions() initExtension(std::make_shared(m_appContext)); std::shared_ptr debug = std::make_shared(m_appContext); std::shared_ptr tr = std::make_shared(m_appContext); - QObject::connect(tr->model(), &TransactionListModel::transactionStarted, debug.get(), &AssemblyDebuggerControl::runTransaction); QObject::connect(m_doc, &QTextDocument::contentsChanged, [=]() { m_appContext->codeModel()->registerCodeChange(m_doc->toPlainText()); }); initExtension(debug); diff --git a/mix/ProjectFile.cpp b/mix/ProjectFile.cpp deleted file mode 100644 index 0b847345b..000000000 --- a/mix/ProjectFile.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** @file ProjectFile.cpp - * @author Arkadiy Paronyan arkadiy@ethdev.com - * @date 2014 - * Ethereum IDE client. - */ - -#include -#include "ProjectFile.h" - -namespace dev -{ -namespace mix -{ - -void ProjectFile::saveProject() -{ -} - -} -} diff --git a/mix/ProjectFile.h b/mix/ProjectFile.h deleted file mode 100644 index 7ae1fb84d..000000000 --- a/mix/ProjectFile.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** @file ProjectFile.h - * @author Arkadiy Paronyan arkadiy@ethdev.com - * @date 2014 - * Ethereum IDE client. - */ - -#pragma once - -#include -#include "TransactionListModel.h" - -namespace dev -{ - -namespace mix -{ - -/// Background code compiler -class ProjectFile : public QObject -{ - Q_OBJECT - -public: - ProjectFile(); - - void loadProject(); - -signals: - void projectLoaded(); - -public slots: - void saveProject(); - -private: - QString defaultProjectPath() const; - TransactionListModel* transactionModel(); -}; - -} - -} diff --git a/mix/TransactionListModel.cpp b/mix/TransactionListModel.cpp deleted file mode 100644 index f6ecc9846..000000000 --- a/mix/TransactionListModel.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** @file TransactionListModel.cpp - * @author Arkadiy Paronyan arkadiy@ethdev.com - * @date 2014 - * Ethereum IDE client. - */ - -#include -#include -#include -#include -#include -#include "TransactionListModel.h" -#include "QContractDefinition.h" -#include "QFunctionDefinition.h" -#include "QVariableDeclaration.h" -#include "AppContext.h" -#include "CodeModel.h" - -namespace dev -{ -namespace mix -{ - -/// @todo Move this to QML -u256 fromQString(QString const& _s) -{ - return dev::jsToU256(_s.toStdString()); -} - -/// @todo Move this to QML -QString toQString(u256 _value) -{ - std::ostringstream s; - s << _value; - return QString::fromStdString(s.str()); -} - -TransactionListItem::TransactionListItem(int _index, TransactionSettings const& _t, QObject* _parent): - QObject(_parent), m_index(_index), m_title(_t.title), m_functionId(_t.functionId), m_value(toQString(_t.value)), - m_gas(toQString(_t.gas)), m_gasPrice(toQString(_t.gasPrice)) -{} - -TransactionListModel::TransactionListModel(QObject* _parent, AppContext* _appContext): - QAbstractListModel(_parent), m_appContext(_appContext) -{ - qRegisterMetaType("TransactionListItem*"); -} - -QHash TransactionListModel::roleNames() const -{ - QHash roles; - roles[TitleRole] = "title"; - roles[IdRole] = "transactionIndex"; - return roles; -} - -int TransactionListModel::rowCount(QModelIndex const& _parent) const -{ - Q_UNUSED(_parent); - return m_transactions.size(); -} - -QVariant TransactionListModel::data(QModelIndex const& _index, int _role) const -{ - if (_index.row() < 0 || _index.row() >= (int)m_transactions.size()) - return QVariant(); - auto const& transaction = m_transactions.at(_index.row()); - switch (_role) - { - case TitleRole: - return QVariant(transaction.title); - case IdRole: - return QVariant(_index.row()); - default: - return QVariant(); - } -} - -///@todo: get parameters from code model -QList buildParameters(CodeModel* _codeModel, TransactionSettings const& _transaction, QString const& _functionId) -{ - QList params; - QContractDefinition const* contract = _codeModel->code()->contract(); - auto functions = contract->functionsList(); - for (auto f : functions) - { - if (f->name() != _functionId) - continue; - - auto parameters = f->parametersList(); - for (auto p : parameters) - { - QString paramValue; - if (f->name() == _transaction.functionId) - { - auto paramValueIter = _transaction.parameterValues.find(p->name()); - if (paramValueIter != _transaction.parameterValues.cend()) - paramValue = toQString(paramValueIter->second); - } - - TransactionParameterItem* item = new TransactionParameterItem(p->name(), p->type(), paramValue); - QQmlEngine::setObjectOwnership(item, QQmlEngine::JavaScriptOwnership); - params.append(item); - } - } - return params; -} - -///@todo: get fnctions from code model -QList TransactionListModel::getFunctions() -{ - QList functionNames; - QContractDefinition const* contract = m_appContext->codeModel()->code()->contract(); - auto functions = contract->functionsList(); - for (auto f : functions) - { - functionNames.append(f->name()); - } - return functionNames; -} - -QVariantList TransactionListModel::getParameters(int _index, QString const& _functionId) -{ - TransactionSettings const& transaction = (_index >= 0 && _index < (int)m_transactions.size()) ? m_transactions[_index] : TransactionSettings(); - auto plist = buildParameters(m_appContext->codeModel(), transaction, _functionId); - QVariantList vl; - for (QObject* p : plist) - vl.append(QVariant::fromValue(p)); - return vl; -} - -TransactionListItem* TransactionListModel::getItem(int _index) -{ - TransactionSettings const& transaction = (_index >= 0 && _index < (int)m_transactions.size()) ? m_transactions[_index] : TransactionSettings(); - TransactionListItem* item = new TransactionListItem(_index, transaction, nullptr); - QQmlEngine::setObjectOwnership(item, QQmlEngine::JavaScriptOwnership); - return item; -} - -void TransactionListModel::edit(QObject* _data) -{ - //these properties come from TransactionDialog QML object - ///@todo change the model to a qml component - int index = _data->property("transactionIndex").toInt(); - QString title = _data->property("transactionTitle").toString(); - QString gas = _data->property("gas").toString(); - QString gasPrice = _data->property("gasPrice").toString(); - QString value = _data->property("transactionValue").toString(); - QString functionId = _data->property("functionId").toString(); - QAbstractListModel* paramsModel = qvariant_cast(_data->property("transactionParams")); - TransactionSettings transaction(title, functionId, fromQString(value), fromQString(gas), fromQString(gasPrice)); - int paramCount = paramsModel->rowCount(QModelIndex()); - for (int p = 0; p < paramCount; ++p) - { - QString paramName = paramsModel->data(paramsModel->index(p, 0), Qt::DisplayRole).toString(); - QString paramValue = paramsModel->data(paramsModel->index(p, 0), Qt::DisplayRole + 2).toString(); - if (!paramValue.isEmpty() && !paramName.isEmpty()) - transaction.parameterValues[paramName] = fromQString(paramValue); - } - - if (index >= 0 && index < (int)m_transactions.size()) - { - beginRemoveRows(QModelIndex(), index, index); - m_transactions.erase(m_transactions.begin() + index); - endRemoveRows(); - } - else - index = rowCount(QModelIndex()); - - beginInsertRows(QModelIndex(), index, index); - m_transactions.push_back(transaction); - emit countChanged(); - endInsertRows(); -} - -int TransactionListModel::getCount() const -{ - return rowCount(QModelIndex()); -} - -void TransactionListModel::runTransaction(int _index) -{ - TransactionSettings tr = m_transactions.at(_index); - emit transactionStarted(tr); -} - -QVariantMap TransactionListModel::save() -{ - -} - -/// Load transactions from a map -void TransactionListModel::load(QVariantMap const& _data) -{ - std::vector transactions; - - - m_transactions.swap(transactions); -} - -} -} - diff --git a/mix/TransactionListModel.h b/mix/TransactionListModel.h deleted file mode 100644 index 993767310..000000000 --- a/mix/TransactionListModel.h +++ /dev/null @@ -1,174 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** @file TransactionListView.h - * @author Arkadiy Paronyan arkadiy@ethdev.com - * @date 2014 - * Ethereum IDE client. - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace dev -{ -namespace mix -{ - -class AppContext; - -/// Backend transaction config class -struct TransactionSettings -{ - TransactionSettings(): - value(0), gas(10000), gasPrice(10 * dev::eth::szabo) {} - - TransactionSettings(QString const& _title, QString const& _functionId, u256 _value, u256 _gas, u256 _gasPrice): - title(_title), functionId(_functionId), value(_value), gas(_gas), gasPrice(_gasPrice) {} - - /// User specified transaction title - QString title; - /// Contract function name - QString functionId; - /// Transaction value - u256 value; - /// Gas - u256 gas; - /// Gas price - u256 gasPrice; - /// Mapping from contract function parameter name to value - std::map parameterValues; -}; - -/// QML transaction parameter class -class TransactionParameterItem: public QObject -{ - Q_OBJECT - Q_PROPERTY(QString name READ name CONSTANT) - Q_PROPERTY(QString type READ type CONSTANT) - Q_PROPERTY(QString value READ value CONSTANT) -public: - TransactionParameterItem(QString const& _name, QString const& _type, QString const& _value): - m_name(_name), m_type(_type), m_value(_value) {} - - /// Parameter name, set by contract definition - QString name() { return m_name; } - /// Parameter type, set by contract definition - QString type() { return m_type; } - /// Parameter value, set by user - QString value() { return m_value; } - -private: - QString m_name; - QString m_type; - QString m_value; -}; - -class TransactionListItem: public QObject -{ - Q_OBJECT - Q_PROPERTY(int index READ index CONSTANT) - Q_PROPERTY(QString title READ title CONSTANT) - Q_PROPERTY(QString functionId READ functionId CONSTANT) - Q_PROPERTY(QString gas READ gas CONSTANT) - Q_PROPERTY(QString gasPrice READ gasPrice CONSTANT) - Q_PROPERTY(QString value READ value CONSTANT) - -public: - TransactionListItem(int _index, TransactionSettings const& _t, QObject* _parent); - - /// User specified transaction title - QString title() { return m_title; } - /// Gas - QString gas() { return m_gas; } - /// Gas cost - QString gasPrice() { return m_gasPrice; } - /// Transaction value - QString value() { return m_value; } - /// Contract function name - QString functionId() { return m_functionId; } - /// Index of this transaction in the transactions list - int index() { return m_index; } - -private: - int m_index; - QString m_title; - QString m_functionId; - QString m_value; - QString m_gas; - QString m_gasPrice; -}; - -/// QML model for a list of transactions -class TransactionListModel: public QAbstractListModel -{ - Q_OBJECT - Q_PROPERTY(int count READ getCount() NOTIFY countChanged()) - - enum Roles - { - TitleRole = Qt::DisplayRole, - IdRole = Qt::UserRole + 1 - }; - -public: - TransactionListModel(QObject* _parent, AppContext* _appContext); - ~TransactionListModel() {} - - QHash roleNames() const override; - int rowCount(QModelIndex const& _parent) const override; - QVariant data(QModelIndex const& _index, int _role) const override; - int getCount() const; - /// Apply changes from transaction dialog. Argument is a dialog model as defined in TransactionDialog.qml - /// @todo Change that to transaction item - Q_INVOKABLE void edit(QObject* _data); - /// @returns transaction item for a give index - Q_INVOKABLE TransactionListItem* getItem(int _index); - /// @returns a list of functions for current contract - Q_INVOKABLE QList getFunctions(); - /// @returns function parameters along with parameter values if set. @see TransactionParameterItem - Q_INVOKABLE QVariantList getParameters(int _id, QString const& _functionId); - /// Launch transaction execution UI handler - Q_INVOKABLE void runTransaction(int _index); - /// Save transaction to a map for serialization into file - QVariantMap save(); - /// Load transactions from a map - void load(QVariantMap const& _data); - -signals: - /// Transaction count has changed - void countChanged(); - /// Transaction has been launched - void transactionStarted(dev::mix::TransactionSettings); - -private: - std::vector m_transactions; - AppContext* m_appContext; -}; - -} - -} - diff --git a/mix/TransactionListView.cpp b/mix/TransactionListView.cpp index 9d20d173d..a2b833209 100644 --- a/mix/TransactionListView.cpp +++ b/mix/TransactionListView.cpp @@ -26,18 +26,10 @@ #include #include #include "TransactionListView.h" -#include "TransactionListModel.h" using namespace dev::mix; TransactionListView::TransactionListView(AppContext* _context): Extension(_context, ExtensionDisplayBehavior::RightTab) { - m_model.reset(new TransactionListModel(this, _context)); - //m_appEngine->rootContext()->setContextProperty("transactionListModel", m_model.get()); -} - -TransactionListView::~TransactionListView() -{ - //implementation is in cpp file so that all types deleted are complete } QString TransactionListView::contentUrl() const diff --git a/mix/TransactionListView.h b/mix/TransactionListView.h index e21d7ecd8..04b6154d4 100644 --- a/mix/TransactionListView.h +++ b/mix/TransactionListView.h @@ -29,8 +29,6 @@ namespace dev namespace mix { -class TransactionListModel; - /// Transactions list control /// @todo This should be moved into state as a sequence class TransactionListView: public Extension @@ -39,15 +37,9 @@ class TransactionListView: public Extension public: TransactionListView(AppContext* _context); - ~TransactionListView(); void start() const override; QString title() const override; QString contentUrl() const override; - /// @returns the underlying model - TransactionListModel* model() const { return m_model.get(); } - -private: - std::unique_ptr m_model; }; } diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index 14b41bde1..f04e1a390 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -28,7 +28,7 @@ Window { property alias gasPrice : gasPriceField.text; property alias transactionValue : valueField.text; property alias functionId : functionComboBox.currentText; - property var model; + property var itemParams; signal accepted; @@ -39,6 +39,7 @@ Window { gasPrice = item.gasPrice; transactionValue = item.value; var functionId = item.functionId; + itemParams = item.parameters !== undefined ? item.parameters : {}; functionsModel.clear(); var functionIndex = -1; var functions = codeModel.code.contract.functions; @@ -58,7 +59,8 @@ Window { var func = codeModel.code.contract.functions[functionComboBox.currentIndex]; var parameters = func.parameters; for (var p = 0; p < parameters.length; p++) { - paramsModel.append({ name: parameters[p].name, type: parameters[p].type, value: parameters[p].value !== undefined ? parameters[p].value : "" }); + var pname = parameters[p].name; + paramsModel.append({ name: pname, type: parameters[p].type, value: itemParams[pname] !== undefined ? itemParams[pname] : "" }); } } } diff --git a/mix/qml/TransactionList.qml b/mix/qml/TransactionList.qml index fd85f0d7b..2ae3cecb4 100644 --- a/mix/qml/TransactionList.qml +++ b/mix/qml/TransactionList.qml @@ -70,8 +70,14 @@ Rectangle { functionId: transactionDialog.functionId, gas: transactionDialog.gas, gasPrice: transactionDialog.gasPrice, - value: transactionDialog.transactionValue + value: transactionDialog.transactionValue, + parameters: {} } + for (var p = 0; p < transactionDialog.transactionParams.count; p++) { + var parameter = transactionDialog.transactionParams.get(p); + item.parameters[parameter.name] = parameter.value; + } + console.log(item.title); if (transactionDialog.transactionIndex < transactionListModel.count) transactionListModel.set(transactionDialog.transactionIndex, item); From ab91e04767e3273e4d45b69d3ac0feb8cea55bc3 Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 26 Dec 2014 12:39:08 +0100 Subject: [PATCH 07/17] added missing qml files --- mix/qml/StateDialog.qml | 182 ++++++++++++++++++++++++++++++++++++++++ mix/qml/StateList.qml | 125 +++++++++++++++++++++++++++ 2 files changed, 307 insertions(+) create mode 100644 mix/qml/StateDialog.qml create mode 100644 mix/qml/StateList.qml diff --git a/mix/qml/StateDialog.qml b/mix/qml/StateDialog.qml new file mode 100644 index 000000000..eb0b68ac8 --- /dev/null +++ b/mix/qml/StateDialog.qml @@ -0,0 +1,182 @@ +import QtQuick 2.2 +import QtQuick.Controls 1.2 +import QtQuick.Layouts 1.1 +import QtQuick.Window 2.0 + +Window { + modality: Qt.WindowModal + + width:640 + height:480 + + visible: false + + property alias stateTitle : titleField.text + property alias stateBalance : balanceField.text + property int stateIndex + property var stateTransactions: [] + signal accepted + + function open(index, item) { + stateIndex = index; + stateTitle = item.title; + stateBalance = item.balance; + transactionsModel.clear(); + stateTransactions = []; + var transactions = item.transactions; + for (var t = 0; t < transactions.length; t++) { + transactionsModel.append(item.transactions[t]); + stateTransactions.push(item.transactions[t]); + } + visible = true; + titleField.focus = true; + } + + function close() { + visible = false; + } + + function getItem() { + var item = { + title: stateDialog.stateTitle, + balance: stateDialog.stateBalance, + transactions: [] + } + item.transactions = stateTransactions; + return item; + } + + GridLayout { + id: dialogContent + columns: 2 + anchors.fill: parent + anchors.margins: 10 + rowSpacing: 10 + columnSpacing: 10 + + Label { + text: qsTr("Title") + } + TextField { + id: titleField + focus: true + Layout.fillWidth: true + } + + Label { + text: qsTr("Balance") + } + TextField { + id: balanceField + Layout.fillWidth: true + } + + Label { + text: qsTr("Transactions") + } + ListView { + Layout.fillWidth: true + Layout.fillHeight: true + model: transactionsModel + delegate: transactionRenderDelegate + } + + Label { + + } + Button { + text: qsTr("Add") + onClicked: transactionsModel.addTransaction() + } + } + + RowLayout { + anchors.bottom: parent.bottom + anchors.right: parent.right; + + Button { + text: qsTr("Ok"); + onClicked: { + close(); + accepted(); + } + } + Button { + text: qsTr("Cancel"); + onClicked: close(); + } + } + + ListModel { + id: transactionsModel + + function editTransaction(index) { + transactionDialog.open(index, transactionsModel.get(index)); + } + + function addTransaction() { + + // Set next id here to work around Qt bug + // https://bugreports.qt-project.org/browse/QTBUG-41327 + // Second call to signal handler would just edit the item that was just created, no harm done + var item = { + value: "0", + functionId: "", + gas: "1000000000000", + gasPrice: "100000" + }; + + transactionDialog.open(transactionsModel.count, item); + } + + function deleteTransaction(index) { + stateTransactions.splice(index, 1); + transactionsModel.remove(index); + } + } + + Component { + id: transactionRenderDelegate + Item { + id: wrapperItem + height: 20 + width: parent.width + RowLayout { + anchors.fill: parent + Text { + Layout.fillWidth: true + Layout.fillHeight: true + text: functionId + font.pointSize: 12 + verticalAlignment: Text.AlignBottom + } + ToolButton { + text: qsTr("Edit"); + Layout.fillHeight: true + onClicked: transactionsModel.editTransaction(index) + } + ToolButton { + text: qsTr("Delete"); + Layout.fillHeight: true + onClicked: transactionsModel.deleteTransaction(index) + } + } + } + } + + TransactionDialog { + id: transactionDialog + onAccepted: { + var item = transactionDialog.getItem(); + + if (transactionDialog.transactionIndex < transactionsModel.count) { + transactionsModel.set(transactionDialog.transactionIndex, item); + stateTransactions[index] = item; + } else { + transactionsModel.append(item); + stateTransactions.push(item); + } + } + } + +} diff --git a/mix/qml/StateList.qml b/mix/qml/StateList.qml new file mode 100644 index 000000000..38f823941 --- /dev/null +++ b/mix/qml/StateList.qml @@ -0,0 +1,125 @@ +import QtQuick 2.2 +import QtQuick.Controls.Styles 1.2 +import QtQuick.Controls 1.2 +import QtQuick.Dialogs 1.2 +import QtQuick.Layouts 1.1 + +Rectangle { + color: "transparent" + id: stateListContainer + focus: true + anchors.topMargin: 10 + anchors.left: parent.left + height: parent.height + width: parent.width + property var stateList: [] + + Connections { + target: appContext + onProjectLoaded: { + var items = JSON.parse(_json); + for(var i = 0; i < items.length; i++) { + stateListModel.append(items[i]); + stateList.push(items[i]) + } + } + } + + ListView { + anchors.top: parent.top + height: parent.height + width: parent.width + model: stateListModel + delegate: renderDelegate + } + + Button { + anchors.bottom: parent.bottom + text: qsTr("Add") + onClicked: stateListModel.addState(); + } + + StateDialog { + id: stateDialog + onAccepted: { + var item = stateDialog.getItem(); + if (stateDialog.stateIndex < stateListModel.count) { + stateList[stateDialog.stateIndex] = item; + stateListModel.set(stateDialog.stateIndex, item); + } else { + stateList.push(item); + stateListModel.append(item); + } + + stateListModel.save(); + } + } + + ListModel { + id: stateListModel + + function addState() { + var item = { + title: "", + balance: "1000000000000", + transactions: [] + }; + stateDialog.open(stateListModel.count, item); + } + + function editState(index) { + stateDialog.open(index, stateList[index]); + } + + function runState(index) { + var item = stateListModel.get(index); + debugModel.debugState(item); + } + + function deleteState(index) { + stateListModel.remove(index); + stateList.splice(index, 1); + save(); + } + + function save() { + var json = JSON.stringify(stateList); + appContext.saveProject(json); + } + } + + Component { + id: renderDelegate + Item { + id: wrapperItem + height: 20 + width: parent.width + RowLayout { + anchors.fill: parent + Text { + Layout.fillWidth: true + Layout.fillHeight: true + text: title + font.pointSize: 12 + verticalAlignment: Text.AlignBottom + } + ToolButton { + text: qsTr("Edit"); + Layout.fillHeight: true + onClicked: stateListModel.editState(index); + } + ToolButton { + text: qsTr("Delete"); + Layout.fillHeight: true + onClicked: stateListModel.deleteState(index); + } + ToolButton { + text: qsTr("Run"); + Layout.fillHeight: true + onClicked: stateListModel.runState(index); + } + } + } + } +} + From 0ad33b5f9a659abe91555a26c8afa15d4f8c7d54 Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 26 Dec 2014 13:21:05 +0100 Subject: [PATCH 08/17] fixed start with empty contract, started implementing state debugging --- mix/AssemblyDebuggerControl.cpp | 36 +++++++++++++++++++++------------ mix/AssemblyDebuggerControl.h | 2 +- mix/CodeModel.cpp | 7 ++++++- mix/CodeModel.h | 2 ++ mix/QContractDefinition.h | 1 + mix/qml/StateList.qml | 2 +- 6 files changed, 34 insertions(+), 16 deletions(-) diff --git a/mix/AssemblyDebuggerControl.cpp b/mix/AssemblyDebuggerControl.cpp index 3d25694ab..528d965c3 100644 --- a/mix/AssemblyDebuggerControl.cpp +++ b/mix/AssemblyDebuggerControl.cpp @@ -92,20 +92,30 @@ void AssemblyDebuggerControl::debugDeployment() deployContract(); } -void AssemblyDebuggerControl::debugState(QObject* _state) +void AssemblyDebuggerControl::debugState(QVariantMap _state) { - /* - QString functionId = _transaction->property("functionId").toString(); - u256 value = fromQString(_transaction->property("value").toString()); - u256 gas = fromQString(_transaction->property("gas").toString()); - u256 gasPrice = fromQString(_transaction->property("gasPrice").toString()); - QVariantMap params = _transaction->property("parameters").toMap(); - TransactionSettings transaction(functionId, value, gas, gasPrice); - - for (auto p = params.cbegin(); p != params.cend(); ++p) - transaction.parameterValues.insert(std::make_pair(p.key(), fromQString(p.value().toString()))); - runTransaction(transaction); - */ + u256 balance = fromQString(_state.value("balance").toString()); + QVariantList transactions = _state.value("transactions").toList(); + + resetState(); + deployContract(); + + for (auto const& t : transactions) + { + QVariantMap transaction = t.toMap(); + + QString functionId = transaction.value("functionId").toString(); + u256 value = fromQString(transaction.value("value").toString()); + u256 gas = fromQString(transaction.value("gas").toString()); + u256 gasPrice = fromQString(transaction.value("gasPrice").toString()); + QVariantMap params = transaction.value("parameters").toMap(); + TransactionSettings transactionSettings(functionId, value, gas, gasPrice); + + for (auto p = params.cbegin(); p != params.cend(); ++p) + transactionSettings.parameterValues.insert(std::make_pair(p.key(), fromQString(p.value().toString()))); + + runTransaction(transactionSettings); + } } void AssemblyDebuggerControl::resetState() diff --git a/mix/AssemblyDebuggerControl.h b/mix/AssemblyDebuggerControl.h index 8c971f0ba..aaab913af 100644 --- a/mix/AssemblyDebuggerControl.h +++ b/mix/AssemblyDebuggerControl.h @@ -69,7 +69,7 @@ private: public slots: void debugDeployment(); - void debugState(QObject* _transaction); + void debugState(QVariantMap _state); void resetState(); /// Update UI with machine states result. Display a modal dialog. void updateGUI(bool _success, DebuggingStatusResult const& _reason, QList const& _returnParams = QList(), QList const& _wStates = QList(), AssemblyDebuggerData const& _code = AssemblyDebuggerData()); diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index 74d74fb6e..bafc42faa 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -42,6 +42,11 @@ void BackgroundWorker::queueCodeChange(int _jobId, QString const& _content) m_model->runCompilationJob(_jobId, _content); } +CompilationResult::CompilationResult(QObject *_parent): + QObject(_parent), m_successfull(false), + m_contract(new QContractDefinition()) +{} + CompilationResult::CompilationResult(const solidity::CompilerStack& _compiler, QObject *_parent): QObject(_parent), m_successfull(true), m_contract(new QContractDefinition(&_compiler.getContractDefinition(std::string()))), @@ -58,7 +63,7 @@ CompilationResult::CompilationResult(CompilationResult const& _prev, QString con {} CodeModel::CodeModel(QObject* _parent) : QObject(_parent), - m_backgroundWorker(this), m_backgroundJobId(0) + m_result(new CompilationResult(nullptr)), m_backgroundWorker(this), m_backgroundJobId(0) { m_backgroundWorker.moveToThread(&m_backgroundThread); connect(this, &CodeModel::scheduleCompilationJob, &m_backgroundWorker, &BackgroundWorker::queueCodeChange, Qt::QueuedConnection); diff --git a/mix/CodeModel.h b/mix/CodeModel.h index a70bdd500..c33110226 100644 --- a/mix/CodeModel.h +++ b/mix/CodeModel.h @@ -62,6 +62,8 @@ class CompilationResult : public QObject Q_PROPERTY(QContractDefinition* contract READ contract) public: + /// Empty compilation result constructor + CompilationResult(QObject* parent); /// Successfull compilation result constructor CompilationResult(solidity::CompilerStack const& _compiler, QObject* parent); /// Failed compilation result constructor diff --git a/mix/QContractDefinition.h b/mix/QContractDefinition.h index fa85220ff..e9c618804 100644 --- a/mix/QContractDefinition.h +++ b/mix/QContractDefinition.h @@ -38,6 +38,7 @@ class QContractDefinition: public QBasicNodeDefinition Q_PROPERTY(QQmlListProperty functions READ functions CONSTANT) public: + QContractDefinition() {} QContractDefinition(solidity::ContractDefinition const* _contract); /// Get all the functions of the contract. QQmlListProperty functions() const { return QQmlListProperty(const_cast(this), const_cast(this)->m_functions); } diff --git a/mix/qml/StateList.qml b/mix/qml/StateList.qml index 38f823941..f22df3d39 100644 --- a/mix/qml/StateList.qml +++ b/mix/qml/StateList.qml @@ -72,7 +72,7 @@ Rectangle { } function runState(index) { - var item = stateListModel.get(index); + var item = stateList[index]; debugModel.debugState(item); } From 50a1edb23bf75970fc6324250834b77d2e2f3d97 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sat, 27 Dec 2014 14:53:34 +0100 Subject: [PATCH 09/17] improved debugging model --- mix/AssemblyDebuggerControl.cpp | 172 +++++++++++++++-------------- mix/AssemblyDebuggerControl.h | 33 +++--- mix/AssemblyDebuggerModel.cpp | 27 ++--- mix/AssemblyDebuggerModel.h | 6 +- mix/CodeEditorExtensionManager.cpp | 4 +- mix/CodeModel.cpp | 12 +- mix/CodeModel.h | 22 ++-- mix/ConstantCompilationControl.cpp | 11 ++ mix/ConstantCompilationControl.h | 1 + mix/MixApplication.cpp | 2 + mix/qml/StateList.qml | 13 ++- mix/qml/main.qml | 7 +- 12 files changed, 179 insertions(+), 131 deletions(-) diff --git a/mix/AssemblyDebuggerControl.cpp b/mix/AssemblyDebuggerControl.cpp index 528d965c3..22e772409 100644 --- a/mix/AssemblyDebuggerControl.cpp +++ b/mix/AssemblyDebuggerControl.cpp @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #include #include @@ -55,7 +57,8 @@ QString toQString(dev::u256 _value) return QString::fromStdString(s.str()); } -AssemblyDebuggerControl::AssemblyDebuggerControl(AppContext* _context): Extension(_context, ExtensionDisplayBehavior::ModalDialog) +AssemblyDebuggerControl::AssemblyDebuggerControl(AppContext* _context): + Extension(_context, ExtensionDisplayBehavior::ModalDialog), m_running(false) { qRegisterMetaType("QVariableDefinition*"); qRegisterMetaType("QVariableDefinitionList*"); @@ -63,14 +66,11 @@ AssemblyDebuggerControl::AssemblyDebuggerControl(AppContext* _context): Extensio qRegisterMetaType>("QList"); qRegisterMetaType("QVariableDeclaration*"); qRegisterMetaType("AssemblyDebuggerData"); - qRegisterMetaType("DebuggingStatusResult"); - connect(this, SIGNAL(dataAvailable(bool, DebuggingStatusResult, QList, QList, AssemblyDebuggerData)), - this, SLOT(updateGUI(bool, DebuggingStatusResult, QList, QList, AssemblyDebuggerData)), Qt::QueuedConnection); + connect(this, &AssemblyDebuggerControl::dataAvailable, this, &AssemblyDebuggerControl::showDebugger, Qt::QueuedConnection); + m_modelDebugger = std::unique_ptr(new AssemblyDebuggerModel); _context->appEngine()->rootContext()->setContextProperty("debugModel", this); - - m_modelDebugger = std::unique_ptr(new AssemblyDebuggerModel); } QString AssemblyDebuggerControl::contentUrl() const @@ -80,7 +80,7 @@ QString AssemblyDebuggerControl::contentUrl() const QString AssemblyDebuggerControl::title() const { - return QApplication::tr("debugger"); + return QApplication::tr("Debugger"); } void AssemblyDebuggerControl::start() const @@ -89,7 +89,7 @@ void AssemblyDebuggerControl::start() const void AssemblyDebuggerControl::debugDeployment() { - deployContract(); + executeSequence(std::vector(), 0); } void AssemblyDebuggerControl::debugState(QVariantMap _state) @@ -97,8 +97,7 @@ void AssemblyDebuggerControl::debugState(QVariantMap _state) u256 balance = fromQString(_state.value("balance").toString()); QVariantList transactions = _state.value("transactions").toList(); - resetState(); - deployContract(); + std::vector transactionSequence; for (auto const& t : transactions) { @@ -114,93 +113,106 @@ void AssemblyDebuggerControl::debugState(QVariantMap _state) for (auto p = params.cbegin(); p != params.cend(); ++p) transactionSettings.parameterValues.insert(std::make_pair(p.key(), fromQString(p.value().toString()))); - runTransaction(transactionSettings); + transactionSequence.push_back(transactionSettings); } + executeSequence(transactionSequence, balance); } -void AssemblyDebuggerControl::resetState() -{ - m_modelDebugger->resetState(); - m_ctx->displayMessageDialog(QApplication::tr("State status"), QApplication::tr("State reseted ... need to redeploy contract")); -} - -void AssemblyDebuggerControl::callContract(TransactionSettings _tr, dev::Address _contract) +void AssemblyDebuggerControl::executeSequence(std::vector const& _sequence, u256 _balance) { + if (m_running) + throw (std::logic_error("debugging already running")); auto compilerRes = m_ctx->codeModel()->code(); - if (!compilerRes->successfull()) - m_ctx->displayMessageDialog("debugger","compilation failed"); - else + std::shared_ptr contractDef = compilerRes->sharedContract(); + m_running = true; + + emit runStarted(); + emit stateChanged(); + + //run sequence + QtConcurrent::run([=]() { - ContractCallDataEncoder c; - QContractDefinition const* contractDef = compilerRes->contract(); - QFunctionDefinition* f = nullptr; - for (int k = 0; k < contractDef->functionsList().size(); k++) + try { - if (contractDef->functionsList().at(k)->name() == _tr.functionId) + bytes contractCode = compilerRes->bytes(); + std::vector transactonData; + QFunctionDefinition* f; + ContractCallDataEncoder c; + //encode data for all transactions + for (auto const& t : _sequence) { - f = contractDef->functionsList().at(k); - break; + f = nullptr; + for (int k = 0; k < contractDef->functionsList().size(); k++) + { + if (contractDef->functionsList().at(k)->name() == t.functionId) + { + f = contractDef->functionsList().at(k); + break; + } + } + if (!f) + throw std::runtime_error("function " + t.functionId.toStdString() + " not found"); + + c.encode(f->index()); + for (int k = 0; k < f->parametersList().size(); k++) + { + QVariableDeclaration* var = (QVariableDeclaration*)f->parametersList().at(k); + u256 value = 0; + auto v = t.parameterValues.find(var->name()); + if (v != t.parameterValues.cend()) + value = v->second; + c.encode(var, value); + } + transactonData.emplace_back(c.encodedData()); } - } - if (!f) - m_ctx->displayMessageDialog(QApplication::tr("debugger"), QApplication::tr("function not found. Please redeploy this contract.")); - else - { - c.encode(f->index()); - for (int k = 0; k < f->parametersList().size(); k++) + + //run contract creation first + m_modelDebugger->resetState(_balance); + DebuggingContent debuggingContent = m_modelDebugger->deployContract(contractCode); + Address address = debuggingContent.contractAddress; + for (unsigned i = 0; i < _sequence.size(); ++i) + debuggingContent = m_modelDebugger->callContract(address, transactonData.at(i), _sequence.at(i)); + + if (f) + debuggingContent.returnParameters = c.decode(f->returnParameters(), debuggingContent.returnValue); + + //we need to wrap states in a QObject before sending to QML. + QList wStates; + for(int i = 0; i < debuggingContent.machineStates.size(); i++) { - QVariableDeclaration* var = (QVariableDeclaration*)f->parametersList().at(k); - c.encode(var, _tr.parameterValues[var->name()]); + QPointer s(new DebuggingStateWrapper(debuggingContent.executionCode, debuggingContent.executionData.toBytes())); + s->setState(debuggingContent.machineStates.at(i)); + wStates.append(s); } - DebuggingContent debuggingContent = m_modelDebugger->callContract(_contract, c.encodedData(), _tr); - debuggingContent.returnParameters = c.decode(f->returnParameters(), debuggingContent.returnValue); - finalizeExecution(debuggingContent); + //collect states for last transaction + AssemblyDebuggerData code = DebuggingStateWrapper::getHumanReadableCode(debuggingContent.executionCode); + emit dataAvailable(debuggingContent.returnParameters, wStates, code); + emit runComplete(); + } + catch(boost::exception const& e) + { + emit runFailed(QString::fromStdString(boost::current_exception_diagnostic_information())); } - } -} - -void AssemblyDebuggerControl::deployContract() -{ - auto compilerRes = m_ctx->codeModel()->code(); - if (!compilerRes->successfull()) - emit dataAvailable(false, DebuggingStatusResult::Compilationfailed); - else - { - m_previousDebugResult = m_modelDebugger->deployContract(compilerRes->bytes()); - finalizeExecution(m_previousDebugResult); - } -} -void AssemblyDebuggerControl::finalizeExecution(DebuggingContent _debuggingContent) -{ - //we need to wrap states in a QObject before sending to QML. - QList wStates; - for(int i = 0; i < _debuggingContent.machineStates.size(); i++) - { - QPointer s(new DebuggingStateWrapper(_debuggingContent.executionCode, _debuggingContent.executionData.toBytes())); - s->setState(_debuggingContent.machineStates.at(i)); - wStates.append(s); - } - AssemblyDebuggerData code = DebuggingStateWrapper::getHumanReadableCode(_debuggingContent.executionCode); - emit dataAvailable(true, DebuggingStatusResult::Ok, _debuggingContent.returnParameters, wStates, code); + catch(std::exception const& e) + { + emit runFailed(e.what()); + } + m_running = false; + emit stateChanged(); + }); } -void AssemblyDebuggerControl::updateGUI(bool _success, DebuggingStatusResult const& _reason, QList const& _returnParam, QList const& _wStates, AssemblyDebuggerData const& _code) +void AssemblyDebuggerControl::showDebugger(QList const& _returnParam, QList const& _wStates, AssemblyDebuggerData const& _code) { - Q_UNUSED(_reason); - if (_success) - { - m_appEngine->rootContext()->setContextProperty("debugStates", QVariant::fromValue(_wStates)); - m_appEngine->rootContext()->setContextProperty("humanReadableExecutionCode", QVariant::fromValue(std::get<0>(_code))); - m_appEngine->rootContext()->setContextProperty("bytesCodeMapping", QVariant::fromValue(std::get<1>(_code))); - m_appEngine->rootContext()->setContextProperty("contractCallReturnParameters", QVariant::fromValue(new QVariableDefinitionList(_returnParam))); - this->addContentOn(this); - } - else - m_ctx->displayMessageDialog(QApplication::tr("debugger"), QApplication::tr("compilation failed")); + m_appEngine->rootContext()->setContextProperty("debugStates", QVariant::fromValue(_wStates)); + m_appEngine->rootContext()->setContextProperty("humanReadableExecutionCode", QVariant::fromValue(std::get<0>(_code))); + m_appEngine->rootContext()->setContextProperty("bytesCodeMapping", QVariant::fromValue(std::get<1>(_code))); + m_appEngine->rootContext()->setContextProperty("contractCallReturnParameters", QVariant::fromValue(new QVariableDefinitionList(_returnParam))); + this->addContentOn(this); } -void AssemblyDebuggerControl::runTransaction(TransactionSettings const& _tr) +void AssemblyDebuggerControl::showDebugError(QString const& _error) { - callContract(_tr, m_previousDebugResult.contractAddress); + m_ctx->displayMessageDialog(QApplication::tr("Debugger"), _error); } diff --git a/mix/AssemblyDebuggerControl.h b/mix/AssemblyDebuggerControl.h index aaab913af..f56e85b3f 100644 --- a/mix/AssemblyDebuggerControl.h +++ b/mix/AssemblyDebuggerControl.h @@ -28,14 +28,8 @@ #include "AssemblyDebuggerModel.h" using AssemblyDebuggerData = std::tuple, dev::mix::QQMLMap*>; -enum DebuggingStatusResult -{ - Ok, - Compilationfailed -}; Q_DECLARE_METATYPE(AssemblyDebuggerData) -Q_DECLARE_METATYPE(DebuggingStatusResult) Q_DECLARE_METATYPE(dev::mix::DebuggingContent) class AppContext; @@ -59,26 +53,35 @@ public: QString title() const override; QString contentUrl() const override; + Q_PROPERTY(bool running MEMBER m_running NOTIFY stateChanged) + private: - void deployContract(); - void callContract(TransactionSettings _tr, Address _contract); - void finalizeExecution(DebuggingContent _content); + void executeSequence(std::vector const& _sequence, u256 _balance); std::unique_ptr m_modelDebugger; - DebuggingContent m_previousDebugResult; //TODO: to be replaced in a more consistent struct. Used for now to keep the contract address in case of future transaction call. + bool m_running; public slots: + /// Run the contract constructor and show debugger window. void debugDeployment(); + /// Setup state, run transaction sequence, show debugger for the last transaction + /// @param _state JS object with state configuration void debugState(QVariantMap _state); - void resetState(); + +private slots: /// Update UI with machine states result. Display a modal dialog. - void updateGUI(bool _success, DebuggingStatusResult const& _reason, QList const& _returnParams = QList(), QList const& _wStates = QList(), AssemblyDebuggerData const& _code = AssemblyDebuggerData()); - /// Run the given transaction. - void runTransaction(TransactionSettings const& _tr); + void showDebugger(QList const& _returnParams = QList(), QList const& _wStates = QList(), AssemblyDebuggerData const& _code = AssemblyDebuggerData()); + void showDebugError(QString const& _error); + signals: + void runStarted(); + void runComplete(); + void runFailed(QString const& _message); + void stateChanged(); + /// Emited when machine states are available. - void dataAvailable(bool _success, DebuggingStatusResult const& _reason, QList const& _returnParams = QList(), QList const& _wStates = QList(), AssemblyDebuggerData const& _code = AssemblyDebuggerData()); + void dataAvailable(QList const& _returnParams = QList(), QList const& _wStates = QList(), AssemblyDebuggerData const& _code = AssemblyDebuggerData()); }; } diff --git a/mix/AssemblyDebuggerModel.cpp b/mix/AssemblyDebuggerModel.cpp index 44789e8f9..8618b457f 100644 --- a/mix/AssemblyDebuggerModel.cpp +++ b/mix/AssemblyDebuggerModel.cpp @@ -41,20 +41,17 @@ namespace mix { AssemblyDebuggerModel::AssemblyDebuggerModel(): - m_userAccount(KeyPair::create()), - m_baseState(Address(), m_overlayDB, BaseState::Empty) + m_userAccount(KeyPair::create()) { - m_baseState.addBalance(m_userAccount.address(), 10000000 * ether); - m_executiveState = m_baseState; - m_currentExecution = std::unique_ptr(new Executive(m_executiveState, 0)); + resetState(10000000 * ether); } DebuggingContent AssemblyDebuggerModel::executeTransaction(bytesConstRef const& _rawTransaction) { QList machineStates; // Reset the state back to our clean premine. - m_currentExecution = std::unique_ptr(new Executive(m_executiveState, 0)); - m_currentExecution->setup(_rawTransaction); + eth::Executive execution(m_executiveState, 0); + execution.setup(_rawTransaction); std::vector levels; bytes code; bytesConstRef data; @@ -80,12 +77,12 @@ DebuggingContent AssemblyDebuggerModel::executeTransaction(bytesConstRef const& vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels})); }; - m_currentExecution->go(onOp); - m_currentExecution->finalize(onOp); + execution.go(onOp); + execution.finalize(onOp); m_executiveState.completeMine(); DebuggingContent d; - d.returnValue = m_currentExecution->out().toVector(); + d.returnValue = execution.out().toVector(); d.machineStates = machineStates; d.executionCode = code; d.executionData = data; @@ -99,7 +96,7 @@ DebuggingContent AssemblyDebuggerModel::deployContract(bytes const& _code) u256 gasPrice = 10000000000000; u256 gas = 1000000; u256 amount = 100; - Transaction _tr(amount, gasPrice, min(gas, m_baseState.gasLimitRemaining()), _code, m_executiveState.transactionsFrom(dev::toAddress(m_userAccount.secret())), m_userAccount.secret()); + Transaction _tr(amount, gasPrice, min(gas, m_executiveState.gasLimitRemaining()), _code, m_executiveState.transactionsFrom(dev::toAddress(m_userAccount.secret())), m_userAccount.secret()); bytes b = _tr.rlp(); dev::bytesConstRef bytesRef = &b; DebuggingContent d = executeTransaction(bytesRef); @@ -110,7 +107,7 @@ DebuggingContent AssemblyDebuggerModel::deployContract(bytes const& _code) DebuggingContent AssemblyDebuggerModel::callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr) { - Transaction tr = Transaction(_tr.value, _tr.gasPrice, min(_tr.gas, m_baseState.gasLimitRemaining()), _contract, _data, m_executiveState.transactionsFrom(dev::toAddress(m_userAccount.secret())), m_userAccount.secret()); + Transaction tr = Transaction(_tr.value, _tr.gasPrice, min(_tr.gas, m_executiveState.gasLimitRemaining()), _contract, _data, m_executiveState.transactionsFrom(dev::toAddress(m_userAccount.secret())), m_userAccount.secret()); bytes b = tr.rlp(); dev::bytesConstRef bytesRef = &b; DebuggingContent d = executeTransaction(bytesRef); @@ -118,10 +115,10 @@ DebuggingContent AssemblyDebuggerModel::callContract(Address const& _contract, b return d; } -void AssemblyDebuggerModel::resetState() +void AssemblyDebuggerModel::resetState(u256 _balance) { - // Reset the state back to our clean premine. - m_executiveState = m_baseState; + m_executiveState = eth::State(Address(), m_overlayDB, BaseState::Empty); + m_executiveState.addBalance(m_userAccount.address(), _balance); } } diff --git a/mix/AssemblyDebuggerModel.h b/mix/AssemblyDebuggerModel.h index 833c6fa6e..db4b87f8f 100644 --- a/mix/AssemblyDebuggerModel.h +++ b/mix/AssemblyDebuggerModel.h @@ -66,15 +66,13 @@ public: DebuggingContent callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr); /// Deploy the contract described by _code. DebuggingContent deployContract(bytes const& _code); - /// Reset state to the base state. - void resetState(); + /// Reset state to the empty state with given balance. + void resetState(u256 _balance); private: KeyPair m_userAccount; OverlayDB m_overlayDB; - eth::State m_baseState; eth::State m_executiveState; - std::unique_ptr m_currentExecution; DebuggingContent executeTransaction(dev::bytesConstRef const& _rawTransaction); }; diff --git a/mix/CodeEditorExtensionManager.cpp b/mix/CodeEditorExtensionManager.cpp index d2282655e..df43cac48 100644 --- a/mix/CodeEditorExtensionManager.cpp +++ b/mix/CodeEditorExtensionManager.cpp @@ -64,11 +64,13 @@ void CodeEditorExtensionManager::loadEditor(QQuickItem* _editor) void CodeEditorExtensionManager::initExtensions() { - initExtension(std::make_shared(m_appContext)); + std::shared_ptr output = std::make_shared(m_appContext); std::shared_ptr debug = std::make_shared(m_appContext); std::shared_ptr stateList = std::make_shared(m_appContext); QObject::connect(m_doc, &QTextDocument::contentsChanged, [=]() { m_appContext->codeModel()->registerCodeChange(m_doc->toPlainText()); }); + QObject::connect(debug.get(), &AssemblyDebuggerControl::runFailed, output.get(), &ConstantCompilationControl::displayError); + initExtension(output); initExtension(debug); initExtension(stateList); } diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index bafc42faa..b907c2e64 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -63,7 +63,7 @@ CompilationResult::CompilationResult(CompilationResult const& _prev, QString con {} CodeModel::CodeModel(QObject* _parent) : QObject(_parent), - m_result(new CompilationResult(nullptr)), m_backgroundWorker(this), m_backgroundJobId(0) + m_compiling(false), m_result(new CompilationResult(nullptr)), m_backgroundWorker(this), m_backgroundJobId(0) { m_backgroundWorker.moveToThread(&m_backgroundThread); connect(this, &CodeModel::scheduleCompilationJob, &m_backgroundWorker, &BackgroundWorker::queueCodeChange, Qt::QueuedConnection); @@ -94,10 +94,11 @@ void CodeModel::registerCodeChange(const QString &_code) { // launch the background thread m_backgroundJobId++; + m_compiling = true; + emit stateChanged(); emit scheduleCompilationJob(m_backgroundJobId, _code); } - void CodeModel::runCompilationJob(int _jobId, QString const& _code) { if (_jobId != m_backgroundJobId) @@ -124,11 +125,18 @@ void CodeModel::runCompilationJob(int _jobId, QString const& _code) void CodeModel::onCompilationComplete(CompilationResult*_newResult) { + m_compiling = false; m_result.reset(_newResult); emit compilationComplete(); + emit stateChanged(); if (m_result->successfull()) emit codeChanged(); } +bool CodeModel::hasContract() const +{ + return m_result->contract()->functionsList().size() > 0; +} + } } diff --git a/mix/CodeModel.h b/mix/CodeModel.h index c33110226..091c41843 100644 --- a/mix/CodeModel.h +++ b/mix/CodeModel.h @@ -69,8 +69,10 @@ public: /// Failed compilation result constructor CompilationResult(CompilationResult const& _prev, QString const& _compilerMessage, QObject* parent); - /// @returns contract definition + /// @returns contract definition for QML property QContractDefinition* contract() { return m_contract.get(); } + /// @returns contract definition + std::shared_ptr sharedContract() { return m_contract; } /// Indicates if the compilation was successfull bool successfull() const { return m_successfull; } @@ -96,12 +98,6 @@ private: /// Background code compiler class CodeModel : public QObject { - enum Status - { - Idle, ///< No compiation in progress - Compiling, ///< Compilation currently in progress - }; - Q_OBJECT public: @@ -114,10 +110,17 @@ public: CompilationResult const* code() const { return m_result.get(); } Q_PROPERTY(CompilationResult* code READ code NOTIFY codeChanged) + Q_PROPERTY(bool compiling READ isCompiling NOTIFY stateChanged) + Q_PROPERTY(bool hasContract READ hasContract NOTIFY codeChanged) + + /// @returns compilation status + bool isCompiling() const { return m_compiling; } + /// @returns true if contract has at least one function + bool hasContract() const; signals: - /// Emited on compilation status change - void statusChanged(Status _from, Status _to); + /// Emited on compilation state change + void stateChanged(); /// Emitted on compilation complete void compilationComplete(); /// Internal signal used to transfer compilation job to background thread @@ -138,6 +141,7 @@ private: void runCompilationJob(int _jobId, QString const& _content); void stop(); + bool m_compiling; std::unique_ptr m_result; QThread m_backgroundThread; BackgroundWorker m_backgroundWorker; diff --git a/mix/ConstantCompilationControl.cpp b/mix/ConstantCompilationControl.cpp index 6fc684860..e2d69bf62 100644 --- a/mix/ConstantCompilationControl.cpp +++ b/mix/ConstantCompilationControl.cpp @@ -37,6 +37,7 @@ using namespace dev::mix; ConstantCompilationControl::ConstantCompilationControl(AppContext* _context): Extension(_context, ExtensionDisplayBehavior::Tab) { connect(_context->codeModel(), &CodeModel::compilationComplete, this, &ConstantCompilationControl::update); + connect(_context->codeModel(), &CodeModel::compilationComplete, this, &ConstantCompilationControl::update); } QString ConstantCompilationControl::contentUrl() const @@ -80,3 +81,13 @@ void ConstantCompilationControl::resetOutPut() status->setProperty("text", ""); content->setProperty("text", ""); } + + +void ConstantCompilationControl::displayError(QString const& _error) +{ + QObject* status = m_view->findChild("status", Qt::FindChildrenRecursively); + QObject* content = m_view->findChild("content", Qt::FindChildrenRecursively); + status->setProperty("text", "failure"); + status->setProperty("color", "red"); + content->setProperty("text", _error); +} diff --git a/mix/ConstantCompilationControl.h b/mix/ConstantCompilationControl.h index fa056424e..227ad6080 100644 --- a/mix/ConstantCompilationControl.h +++ b/mix/ConstantCompilationControl.h @@ -45,6 +45,7 @@ private: public slots: void update(); + void displayError(QString const& _error); }; } diff --git a/mix/MixApplication.cpp b/mix/MixApplication.cpp index c2e856d8e..5cf71aa7d 100644 --- a/mix/MixApplication.cpp +++ b/mix/MixApplication.cpp @@ -25,6 +25,8 @@ #include "MixApplication.h" #include "AppContext.h" +#include + using namespace dev::mix; MixApplication::MixApplication(int _argc, char* _argv[]): diff --git a/mix/qml/StateList.qml b/mix/qml/StateList.qml index f22df3d39..152a35671 100644 --- a/mix/qml/StateList.qml +++ b/mix/qml/StateList.qml @@ -35,8 +35,7 @@ Rectangle { Button { anchors.bottom: parent.bottom - text: qsTr("Add") - onClicked: stateListModel.addState(); + action: addStateAction } StateDialog { @@ -61,7 +60,7 @@ Rectangle { function addState() { var item = { title: "", - balance: "1000000000000", + balance: "100000000000000000000000000", transactions: [] }; stateDialog.open(stateListModel.count, item); @@ -121,5 +120,13 @@ Rectangle { } } } + + Action { + id: addStateAction + text: "&Add State" + shortcut: "Ctrl+N" + enabled: codeModel.hasContract && !debugModel.running; + onTriggered: stateListModel.addState(); + } } diff --git a/mix/qml/main.qml b/mix/qml/main.qml index e44144f61..bba7c9088 100644 --- a/mix/qml/main.qml +++ b/mix/qml/main.qml @@ -1,6 +1,6 @@ import QtQuick 2.2 -import QtQuick.Controls 1.1 -import QtQuick.Controls.Styles 1.1 +import QtQuick.Controls 1.2 +import QtQuick.Controls.Styles 1.2 import QtQuick.Dialogs 1.1 import QtQuick.Layouts 1.1 import QtQuick.Window 2.1 @@ -51,6 +51,7 @@ ApplicationWindow { id: debugRunAction text: "&Run" shortcut: "F5" + enabled: codeModel.hasContract && !debugModel.running; onTriggered: debugModel.debugDeployment(); } @@ -60,4 +61,6 @@ ApplicationWindow { shortcut: "F6" onTriggered: debugModel.resetState(); } + + } From e70bf144c6f88e3dfbe48d7b506cd150b2ab175c Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 2 Jan 2015 18:11:50 +0100 Subject: [PATCH 10/17] basic syntax highlighting --- mix/CodeEditorExtensionManager.cpp | 15 +++- mix/CodeEditorExtensionManager.h | 4 + mix/CodeHighlighter.cpp | 139 +++++++++++++++++++++++++++++ mix/CodeHighlighter.h | 94 +++++++++++++++++++ mix/CodeModel.cpp | 66 ++++++++++---- mix/CodeModel.h | 24 +++-- mix/qml/MainContent.qml | 6 +- 7 files changed, 318 insertions(+), 30 deletions(-) create mode 100644 mix/CodeHighlighter.cpp create mode 100644 mix/CodeHighlighter.h diff --git a/mix/CodeEditorExtensionManager.cpp b/mix/CodeEditorExtensionManager.cpp index df43cac48..79bbe9a9e 100644 --- a/mix/CodeEditorExtensionManager.cpp +++ b/mix/CodeEditorExtensionManager.cpp @@ -25,13 +25,13 @@ #include #include #include -#include #include "ConstantCompilationControl.h" #include "AssemblyDebuggerControl.h" #include "StateListView.h" #include "AppContext.h" #include "MixApplication.h" #include "CodeModel.h" +#include "CodeHighlighter.h" #include "CodeEditorExtensionManager.h" using namespace dev::mix; @@ -67,8 +67,9 @@ void CodeEditorExtensionManager::initExtensions() std::shared_ptr output = std::make_shared(m_appContext); std::shared_ptr debug = std::make_shared(m_appContext); std::shared_ptr stateList = std::make_shared(m_appContext); - QObject::connect(m_doc, &QTextDocument::contentsChanged, [=]() { m_appContext->codeModel()->registerCodeChange(m_doc->toPlainText()); }); + QObject::connect(m_doc, &QTextDocument::contentsChange, this, &CodeEditorExtensionManager::onCodeChange); QObject::connect(debug.get(), &AssemblyDebuggerControl::runFailed, output.get(), &ConstantCompilationControl::displayError); + QObject::connect(m_appContext->codeModel(), &CodeModel::compilationComplete, this, &CodeEditorExtensionManager::applyCodeHighlight); initExtension(output); initExtension(debug); @@ -111,6 +112,16 @@ void CodeEditorExtensionManager::setEditor(QQuickItem* _editor) } } +void CodeEditorExtensionManager::onCodeChange() +{ + m_appContext->codeModel()->registerCodeChange(m_doc->toPlainText()); +} + +void CodeEditorExtensionManager::applyCodeHighlight() +{ + m_appContext->codeModel()->updateFormatting(m_doc); +} + void CodeEditorExtensionManager::setRightTabView(QQuickItem* _tabView) { m_rightTabView = _tabView; diff --git a/mix/CodeEditorExtensionManager.h b/mix/CodeEditorExtensionManager.h index 22ba1acef..46ee6569f 100644 --- a/mix/CodeEditorExtensionManager.h +++ b/mix/CodeEditorExtensionManager.h @@ -61,6 +61,10 @@ public: /// Set current right tab view. void setRightTabView(QQuickItem*); +private slots: + void onCodeChange(); + void applyCodeHighlight(); + private: QQuickItem* m_editor; QVector> m_features; diff --git a/mix/CodeHighlighter.cpp b/mix/CodeHighlighter.cpp new file mode 100644 index 000000000..f246e9b7b --- /dev/null +++ b/mix/CodeHighlighter.cpp @@ -0,0 +1,139 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file CodeHighlighter.cpp + * @author Arkadiy Paronyan arkadiy@ethdev.com + * @date 2015 + * Ethereum IDE client. + */ + +#include +#include +#include +#include +#include +#include "CodeHighlighter.h" +#include "libsolidity/ASTVisitor.h" +#include "libsolidity/AST.h" +#include "libsolidity/Scanner.h" + +namespace dev +{ +namespace mix +{ + +CodeHighlighterSettings::CodeHighlighterSettings() +{ + bg = QColor(0x00, 0x2b, 0x36); + fg = QColor (0xee, 0xe8, 0xd5); + formats[Keyword].setForeground(QColor(0x93, 0xa1, 0xa1)); + //formats[Type].setForeground(Qt::darkCyan); + formats[Comment].setForeground(QColor(0x85, 0x99, 0x00)); + formats[StringLiteral].setForeground(QColor(0xdc, 0x32, 0x2f)); + formats[NumLiteral].setForeground(fg); + formats[Import].setForeground(QColor(0x6c, 0x71, 0xc4)); +} + +namespace +{ + using namespace dev::solidity; + class HighlightVisitor : public solidity::ASTConstVisitor + { + public: + HighlightVisitor(CodeHighlighter::Formats* _formats) { m_formats = _formats; } + private: + CodeHighlighter::Formats* m_formats; + + virtual bool visit(ImportDirective const& _node) + { + m_formats->push_back(CodeHighlighter::FormatRange(CodeHighlighterSettings::Import, _node.getLocation())); + return true; + } + }; +} + + +CodeHighlighter::FormatRange::FormatRange(CodeHighlighterSettings::Token _t, solidity::Location const& _location): + token(_t), start(_location.start), length(_location.end - _location.start) +{} + +void CodeHighlighter::processSource(solidity::Scanner* _scanner) +{ + solidity::Token::Value token = _scanner->getCurrentToken(); + while (token != Token::EOS) + { + if ((token >= Token::BREAK && token < Token::TYPES_END) || + token == Token::IN || token == Token::DELETE || token == Token::NULL_LITERAL || token == Token::TRUE_LITERAL || token == Token::FALSE_LITERAL) + m_formats.push_back(FormatRange(CodeHighlighterSettings::Keyword, _scanner->getCurrentLocation())); + else if (token == Token::STRING_LITERAL) + m_formats.push_back(FormatRange(CodeHighlighterSettings::StringLiteral, _scanner->getCurrentLocation())); + else if (token == Token::COMMENT_LITERAL) + m_formats.push_back(FormatRange(CodeHighlighterSettings::Comment, _scanner->getCurrentLocation())); + else if (token == Token::NUMBER) + m_formats.push_back(FormatRange(CodeHighlighterSettings::NumLiteral, _scanner->getCurrentLocation())); + + token = _scanner->next(); + } + std::sort(m_formats.begin(), m_formats.end()); +} + +void CodeHighlighter::processAST(solidity::ASTNode const& _ast) +{ + HighlightVisitor visitor(&m_formats); + _ast.accept(visitor); + + std::sort(m_formats.begin(), m_formats.end()); +} + +void CodeHighlighter::updateFormatting(QTextDocument* _document, CodeHighlighterSettings const& _settings) +{ + QTextBlock block = _document->firstBlock(); + QList ranges; + + Formats::const_iterator format = m_formats.begin(); + while (true) + { + while ((format == m_formats.end() || (block.position() + block.length() <= format->start)) && block.isValid()) + { + auto layout = block.layout(); + layout->clearAdditionalFormats(); + layout->setAdditionalFormats(ranges); + _document->markContentsDirty(block.position(), block.length()); + block = block.next(); + ranges.clear(); + } + if (!block.isValid()) + break; + + int intersectionStart = std::max(format->start, block.position()); + int intersectionLength = std::min(format->start + format->length, block.position() + block.length()) - intersectionStart; + if (intersectionLength > 0) + { + QTextLayout::FormatRange range; + range.format = _settings.formats[format->token]; + range.start = format->start - block.position(); + range.length = format->length; + ranges.append(range); + } + ++format; + } +} + + + + +} +} diff --git a/mix/CodeHighlighter.h b/mix/CodeHighlighter.h new file mode 100644 index 000000000..baf39bc66 --- /dev/null +++ b/mix/CodeHighlighter.h @@ -0,0 +1,94 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file CodeHighlighter.h + * @author Arkadiy Paronyan arkadiy@ethdev.com + * @date 2015 + * Ethereum IDE client. + */ + +#pragma once + +#include +#include +#include + +class QTextDocument; + +namespace dev +{ + +namespace solidity +{ + class ASTNode; + class Scanner; + struct Location; +} + +namespace mix +{ + +class CodeHighlighterSettings +{ +public: + enum Token + { + Import, + Keyword, + Comment, + StringLiteral, + NumLiteral, + Size, //this must be kept last + }; + + CodeHighlighterSettings(); + ///Format for each token + QTextCharFormat formats[Size]; + ///Background color + QColor bg; + ///Foreground color + QColor fg; +}; + + +class CodeHighlighter +{ +public: + struct FormatRange + { + FormatRange(CodeHighlighterSettings::Token _t, int _start, int _length): token(_t), start(_start), length(_length) {} + FormatRange(CodeHighlighterSettings::Token _t, solidity::Location const& _location); + bool operator<(FormatRange const& _other) { return start < _other.start || (start == _other.start && length < _other.length); } + + CodeHighlighterSettings::Token token; + int start; + int length; + }; + typedef std::vector Formats; // Sorted by start position + +public: + /// Collect highligting information + void processSource(solidity::Scanner* _scanner); + void processAST(solidity::ASTNode const& _ast); + void updateFormatting(QTextDocument* _document, CodeHighlighterSettings const& _settings); + +private: + Formats m_formats; +}; + +} + +} diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index b907c2e64..60c961045 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -24,12 +24,14 @@ #include #include #include +#include #include #include #include #include "QContractDefinition.h" #include "QFunctionDefinition.h" #include "QVariableDeclaration.h" +#include "CodeHighlighter.h" #include "CodeModel.h" namespace dev @@ -42,28 +44,36 @@ void BackgroundWorker::queueCodeChange(int _jobId, QString const& _content) m_model->runCompilationJob(_jobId, _content); } -CompilationResult::CompilationResult(QObject *_parent): - QObject(_parent), m_successfull(false), - m_contract(new QContractDefinition()) +CompilationResult::CompilationResult(): + QObject(nullptr), m_successfull(false), + m_contract(new QContractDefinition()), + m_codeHighlighter(new CodeHighlighter()) {} -CompilationResult::CompilationResult(const solidity::CompilerStack& _compiler, QObject *_parent): - QObject(_parent), m_successfull(true), - m_contract(new QContractDefinition(&_compiler.getContractDefinition(std::string()))), - m_bytes(_compiler.getBytecode()), - m_assemblyCode(QString::fromStdString((dev::eth::disassemble(m_bytes)))) -{} +CompilationResult::CompilationResult(const solidity::CompilerStack& _compiler): + QObject(nullptr), m_successfull(true) +{ + if (!_compiler.getContractNames().empty()) + { + m_contract.reset(new QContractDefinition(&_compiler.getContractDefinition(std::string()))); + m_bytes = _compiler.getBytecode(); + m_assemblyCode = QString::fromStdString(dev::eth::disassemble(m_bytes)); + } + else + m_contract.reset(new QContractDefinition()); +} -CompilationResult::CompilationResult(CompilationResult const& _prev, QString const& _compilerMessage, QObject* _parent): - QObject(_parent), m_successfull(false), +CompilationResult::CompilationResult(CompilationResult const& _prev, QString const& _compilerMessage): + QObject(nullptr), m_successfull(false), m_contract(_prev.m_contract), m_compilerMessage(_compilerMessage), m_bytes(_prev.m_bytes), - m_assemblyCode(_prev.m_assemblyCode) + m_assemblyCode(_prev.m_assemblyCode), + m_codeHighlighter(_prev.m_codeHighlighter) {} CodeModel::CodeModel(QObject* _parent) : QObject(_parent), - m_compiling(false), m_result(new CompilationResult(nullptr)), m_backgroundWorker(this), m_backgroundJobId(0) + m_compiling(false), m_result(new CompilationResult()), m_codeHighlighterSettings(new CodeHighlighterSettings()), m_backgroundWorker(this), m_backgroundJobId(0) { m_backgroundWorker.moveToThread(&m_backgroundThread); connect(this, &CodeModel::scheduleCompilationJob, &m_backgroundWorker, &BackgroundWorker::queueCodeChange, Qt::QueuedConnection); @@ -105,22 +115,35 @@ void CodeModel::runCompilationJob(int _jobId, QString const& _code) return; //obsolete job solidity::CompilerStack cs; + std::unique_ptr result; + + std::string source = _code.toStdString(); + // run syntax highlighting first + // @todo combine this with compilation step + auto codeHighlighter = std::make_shared(); + solidity::CharStream stream(source); + solidity::Scanner scanner(stream); + codeHighlighter->processSource(&scanner); + + // run compilation try { - cs.setSource(_code.toStdString()); + cs.setSource(source); cs.compile(false); - std::unique_ptr result(new CompilationResult(cs, nullptr)); + codeHighlighter->processAST(cs.getAST()); + result.reset(new CompilationResult(cs)); qDebug() << QString(QApplication::tr("compilation succeeded")); - emit compilationCompleteInternal(result.release()); } catch (dev::Exception const& _exception) { std::ostringstream error; solidity::SourceReferenceFormatter::printExceptionInformation(error, _exception, "Error", cs); - std::unique_ptr result(new CompilationResult(*m_result, QString::fromStdString(error.str()), nullptr)); - qDebug() << QString(QApplication::tr("compilation failed") + " " + m_result->compilerMessage()); - emit compilationCompleteInternal(result.release()); + result.reset(new CompilationResult(*m_result, QString::fromStdString(error.str()))); + qDebug() << QString(QApplication::tr("compilation failed:") + " " + m_result->compilerMessage()); } + result->m_codeHighlighter = codeHighlighter; + + emit compilationCompleteInternal(result.release()); } void CodeModel::onCompilationComplete(CompilationResult*_newResult) @@ -138,5 +161,10 @@ bool CodeModel::hasContract() const return m_result->contract()->functionsList().size() > 0; } +void CodeModel::updateFormatting(QTextDocument* _document) +{ + m_result->codeHighlighter()->updateFormatting(_document, *m_codeHighlighterSettings); +} + } } diff --git a/mix/CodeModel.h b/mix/CodeModel.h index 091c41843..d148cad87 100644 --- a/mix/CodeModel.h +++ b/mix/CodeModel.h @@ -23,10 +23,13 @@ #pragma once #include +#include #include #include #include +class QTextDocument; + namespace dev { @@ -39,6 +42,8 @@ namespace mix { class CodeModel; +class CodeHighlighter; +class CodeHighlighterSettings; class QContractDefinition; //utility class to perform tasks in background thread @@ -63,28 +68,26 @@ class CompilationResult : public QObject public: /// Empty compilation result constructor - CompilationResult(QObject* parent); + CompilationResult(); /// Successfull compilation result constructor - CompilationResult(solidity::CompilerStack const& _compiler, QObject* parent); + CompilationResult(solidity::CompilerStack const& _compiler); /// Failed compilation result constructor - CompilationResult(CompilationResult const& _prev, QString const& _compilerMessage, QObject* parent); + CompilationResult(CompilationResult const& _prev, QString const& _compilerMessage); /// @returns contract definition for QML property QContractDefinition* contract() { return m_contract.get(); } /// @returns contract definition std::shared_ptr sharedContract() { return m_contract; } - /// Indicates if the compilation was successfull bool successfull() const { return m_successfull; } - /// @returns compiler error message in case of unsuccessfull compilation QString compilerMessage() const { return m_compilerMessage; } - /// @returns contract bytecode dev::bytes const& bytes() const { return m_bytes; } - /// @returns contract bytecode in human-readable form QString assemblyCode() const { return m_assemblyCode; } + /// Get code highlighter + std::shared_ptr codeHighlighter() { return m_codeHighlighter; } private: bool m_successfull; @@ -92,7 +95,9 @@ private: QString m_compilerMessage; ///< @todo: use some structure here dev::bytes m_bytes; QString m_assemblyCode; + std::shared_ptr m_codeHighlighter; ///@todo syntax highlighting, etc + friend class CodeModel; }; /// Background code compiler @@ -117,6 +122,8 @@ public: bool isCompiling() const { return m_compiling; } /// @returns true if contract has at least one function bool hasContract() const; + /// Apply text document formatting. @todo Move this to editor module + void updateFormatting(QTextDocument* _document); signals: /// Emited on compilation state change @@ -141,8 +148,9 @@ private: void runCompilationJob(int _jobId, QString const& _content); void stop(); - bool m_compiling; + std::atomic m_compiling; std::unique_ptr m_result; + std::unique_ptr m_codeHighlighterSettings; QThread m_backgroundThread; BackgroundWorker m_backgroundWorker; int m_backgroundJobId = 0; //protects from starting obsolete compilation job diff --git a/mix/qml/MainContent.qml b/mix/qml/MainContent.qml index 794e5746d..0b3303aa8 100644 --- a/mix/qml/MainContent.qml +++ b/mix/qml/MainContent.qml @@ -30,7 +30,11 @@ Rectangle { width: parent.width height: parent.height * 0.7 TextArea { - id: codeEditor + id: codeEditor + textColor: "#EEE8D5" + style: TextAreaStyle { + backgroundColor: "#002B36" + } height: parent.height font.family: "Monospace" font.pointSize: 12 From fcbd25a8be6e88e642da4550569bd06dbcbd25bc Mon Sep 17 00:00:00 2001 From: arkpar Date: Sat, 3 Jan 2015 14:59:36 +0100 Subject: [PATCH 11/17] comment highlighting --- mix/CodeEditorExtensionManager.cpp | 1 + mix/CodeHighlighter.cpp | 48 +++++++++++++++++++++++++----- mix/CodeHighlighter.h | 6 ++-- mix/CodeModel.cpp | 14 +++++---- mix/CodeModel.h | 1 + mix/qml/MainContent.qml | 10 +++---- 6 files changed, 60 insertions(+), 20 deletions(-) diff --git a/mix/CodeEditorExtensionManager.cpp b/mix/CodeEditorExtensionManager.cpp index 79bbe9a9e..48c928a1f 100644 --- a/mix/CodeEditorExtensionManager.cpp +++ b/mix/CodeEditorExtensionManager.cpp @@ -114,6 +114,7 @@ void CodeEditorExtensionManager::setEditor(QQuickItem* _editor) void CodeEditorExtensionManager::onCodeChange() { + m_appContext->codeModel()->updateFormatting(m_doc); //update old formatting m_appContext->codeModel()->registerCodeChange(m_doc->toPlainText()); } diff --git a/mix/CodeHighlighter.cpp b/mix/CodeHighlighter.cpp index f246e9b7b..6476b0995 100644 --- a/mix/CodeHighlighter.cpp +++ b/mix/CodeHighlighter.cpp @@ -70,22 +70,25 @@ CodeHighlighter::FormatRange::FormatRange(CodeHighlighterSettings::Token _t, sol token(_t), start(_location.start), length(_location.end - _location.start) {} -void CodeHighlighter::processSource(solidity::Scanner* _scanner) +void CodeHighlighter::processSource(std::string const& _source) { - solidity::Token::Value token = _scanner->getCurrentToken(); + processComments(_source); + solidity::CharStream stream(_source); + solidity::Scanner scanner(stream); + solidity::Token::Value token = scanner.getCurrentToken(); while (token != Token::EOS) { if ((token >= Token::BREAK && token < Token::TYPES_END) || token == Token::IN || token == Token::DELETE || token == Token::NULL_LITERAL || token == Token::TRUE_LITERAL || token == Token::FALSE_LITERAL) - m_formats.push_back(FormatRange(CodeHighlighterSettings::Keyword, _scanner->getCurrentLocation())); + m_formats.push_back(FormatRange(CodeHighlighterSettings::Keyword, scanner.getCurrentLocation())); else if (token == Token::STRING_LITERAL) - m_formats.push_back(FormatRange(CodeHighlighterSettings::StringLiteral, _scanner->getCurrentLocation())); + m_formats.push_back(FormatRange(CodeHighlighterSettings::StringLiteral, scanner.getCurrentLocation())); else if (token == Token::COMMENT_LITERAL) - m_formats.push_back(FormatRange(CodeHighlighterSettings::Comment, _scanner->getCurrentLocation())); + m_formats.push_back(FormatRange(CodeHighlighterSettings::Comment, scanner.getCurrentLocation())); else if (token == Token::NUMBER) - m_formats.push_back(FormatRange(CodeHighlighterSettings::NumLiteral, _scanner->getCurrentLocation())); + m_formats.push_back(FormatRange(CodeHighlighterSettings::NumLiteral, scanner.getCurrentLocation())); - token = _scanner->next(); + token = scanner.next(); } std::sort(m_formats.begin(), m_formats.end()); } @@ -98,6 +101,37 @@ void CodeHighlighter::processAST(solidity::ASTNode const& _ast) std::sort(m_formats.begin(), m_formats.end()); } + +void CodeHighlighter::processComments(std::string const& _source) +{ + unsigned i = 0; + unsigned size = _source.size(); + if (size == 0) + return; + while (i < size - 1) + { + if (_source[i] == '/' && _source[i + 1] == '/') + { + //add single line comment + int start = i; + i += 2; + while (_source[i] != '\n' && i < size) + ++i; + m_formats.push_back(FormatRange(CodeHighlighterSettings::Comment, start, i - start)); + } + else if (_source[i] == '/' && _source[i + 1] == '*') + { + //add multiline comment + int start = i; + i += 2; + while ((_source[i] != '/' || _source[i - 1] != '*') && i < size) + ++i; + m_formats.push_back(FormatRange(CodeHighlighterSettings::Comment, start, i - start + 1)); + } + ++i; + } +} + void CodeHighlighter::updateFormatting(QTextDocument* _document, CodeHighlighterSettings const& _settings) { QTextBlock block = _document->firstBlock(); diff --git a/mix/CodeHighlighter.h b/mix/CodeHighlighter.h index baf39bc66..8cc8b69e9 100644 --- a/mix/CodeHighlighter.h +++ b/mix/CodeHighlighter.h @@ -34,7 +34,6 @@ namespace dev namespace solidity { class ASTNode; - class Scanner; struct Location; } @@ -81,10 +80,13 @@ public: public: /// Collect highligting information - void processSource(solidity::Scanner* _scanner); + void processSource(std::string const& _source); void processAST(solidity::ASTNode const& _ast); void updateFormatting(QTextDocument* _document, CodeHighlighterSettings const& _settings); +private: + void processComments(std::string const& _source); + private: Formats m_formats; }; diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index 60c961045..deb58416c 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -47,7 +46,8 @@ void BackgroundWorker::queueCodeChange(int _jobId, QString const& _content) CompilationResult::CompilationResult(): QObject(nullptr), m_successfull(false), m_contract(new QContractDefinition()), - m_codeHighlighter(new CodeHighlighter()) + m_codeHighlighter(new CodeHighlighter()), + m_codeHash(qHash(QString())) {} CompilationResult::CompilationResult(const solidity::CompilerStack& _compiler): @@ -103,6 +103,9 @@ void CodeModel::stop() void CodeModel::registerCodeChange(const QString &_code) { // launch the background thread + uint hash = qHash(_code); + if (m_result->m_codeHash == hash) + return; m_backgroundJobId++; m_compiling = true; emit stateChanged(); @@ -121,9 +124,7 @@ void CodeModel::runCompilationJob(int _jobId, QString const& _code) // run syntax highlighting first // @todo combine this with compilation step auto codeHighlighter = std::make_shared(); - solidity::CharStream stream(source); - solidity::Scanner scanner(stream); - codeHighlighter->processSource(&scanner); + codeHighlighter->processSource(source); // run compilation try @@ -139,9 +140,10 @@ void CodeModel::runCompilationJob(int _jobId, QString const& _code) std::ostringstream error; solidity::SourceReferenceFormatter::printExceptionInformation(error, _exception, "Error", cs); result.reset(new CompilationResult(*m_result, QString::fromStdString(error.str()))); - qDebug() << QString(QApplication::tr("compilation failed:") + " " + m_result->compilerMessage()); + qDebug() << QString(QApplication::tr("compilation failed:") + " " + result->compilerMessage()); } result->m_codeHighlighter = codeHighlighter; + result->m_codeHash = qHash(_code); emit compilationCompleteInternal(result.release()); } diff --git a/mix/CodeModel.h b/mix/CodeModel.h index d148cad87..da093183d 100644 --- a/mix/CodeModel.h +++ b/mix/CodeModel.h @@ -98,6 +98,7 @@ private: std::shared_ptr m_codeHighlighter; ///@todo syntax highlighting, etc friend class CodeModel; + uint m_codeHash; }; /// Background code compiler diff --git a/mix/qml/MainContent.qml b/mix/qml/MainContent.qml index 0b3303aa8..99953344f 100644 --- a/mix/qml/MainContent.qml +++ b/mix/qml/MainContent.qml @@ -42,11 +42,11 @@ Rectangle { anchors.centerIn: parent tabChangesFocus: false Keys.onPressed: { - if (event.key === Qt.Key_Tab) { - codeEditor.insert(codeEditor.cursorPosition, "\t"); - event.accepted = true; - } - } + if (event.key === Qt.Key_Tab) { + codeEditor.insert(codeEditor.cursorPosition, "\t"); + event.accepted = true; + } + } } } Rectangle { From 1cddea44b5323376da2c49ce73597215a900cbff Mon Sep 17 00:00:00 2001 From: arkpar Date: Sat, 3 Jan 2015 18:18:22 +0100 Subject: [PATCH 12/17] line number indicator --- mix/qml/MainContent.qml | 73 +++++++++++++++++++++++++++++++---------- 1 file changed, 56 insertions(+), 17 deletions(-) diff --git a/mix/qml/MainContent.qml b/mix/qml/MainContent.qml index 99953344f..7f9a27d58 100644 --- a/mix/qml/MainContent.qml +++ b/mix/qml/MainContent.qml @@ -29,25 +29,64 @@ Rectangle { id: contentView width: parent.width height: parent.height * 0.7 - TextArea { - id: codeEditor - textColor: "#EEE8D5" - style: TextAreaStyle { - backgroundColor: "#002B36" - } - height: parent.height - font.family: "Monospace" - font.pointSize: 12 - width: parent.width - anchors.centerIn: parent - tabChangesFocus: false - Keys.onPressed: { - if (event.key === Qt.Key_Tab) { - codeEditor.insert(codeEditor.cursorPosition, "\t"); - event.accepted = true; + + Item { + anchors.fill: parent + Rectangle { + id: lineColumn + property int rowHeight: codeEditor.font.pixelSize + 3 + color: "#202020" + width: 50 + height: parent.height + Column { + y: -codeEditor.flickableItem.contentY + 4 + width: parent.width + Repeater { + model: Math.max(codeEditor.lineCount + 2, (lineColumn.height/lineColumn.rowHeight)) + delegate: Text { + id: text + color: codeEditor.textColor + font: codeEditor.font + width: lineColumn.width - 4 + horizontalAlignment: Text.AlignRight + verticalAlignment: Text.AlignVCenter + height: lineColumn.rowHeight + renderType: Text.NativeRendering + text: index + 1 + } + } + } + } + + TextArea { + id: codeEditor + textColor: "#EEE8D5" + style: TextAreaStyle { + backgroundColor: "#002B36" + } + + anchors.left: lineColumn.right + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + wrapMode: TextEdit.NoWrap + frameVisible: false + + height: parent.height + font.family: "Monospace" + font.pointSize: 12 + width: parent.width + //anchors.centerIn: parent + tabChangesFocus: false + Keys.onPressed: { + if (event.key === Qt.Key_Tab) { + codeEditor.insert(codeEditor.cursorPosition, "\t"); + event.accepted = true; + } } } - } + } + } Rectangle { anchors.bottom: parent.bottom From 8d129924e38da38f1c30e2f0fe0d159b80b0fe89 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sun, 4 Jan 2015 16:08:51 +0100 Subject: [PATCH 13/17] error highlighting --- mix/CodeHighlighter.cpp | 9 ++++++++- mix/CodeHighlighter.h | 6 +++++- mix/CodeModel.cpp | 1 + 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/mix/CodeHighlighter.cpp b/mix/CodeHighlighter.cpp index 6476b0995..5f6cf7489 100644 --- a/mix/CodeHighlighter.cpp +++ b/mix/CodeHighlighter.cpp @@ -29,6 +29,7 @@ #include "libsolidity/ASTVisitor.h" #include "libsolidity/AST.h" #include "libsolidity/Scanner.h" +#include "libsolidity/Exceptions.h" namespace dev { @@ -40,11 +41,12 @@ CodeHighlighterSettings::CodeHighlighterSettings() bg = QColor(0x00, 0x2b, 0x36); fg = QColor (0xee, 0xe8, 0xd5); formats[Keyword].setForeground(QColor(0x93, 0xa1, 0xa1)); - //formats[Type].setForeground(Qt::darkCyan); formats[Comment].setForeground(QColor(0x85, 0x99, 0x00)); formats[StringLiteral].setForeground(QColor(0xdc, 0x32, 0x2f)); formats[NumLiteral].setForeground(fg); formats[Import].setForeground(QColor(0x6c, 0x71, 0xc4)); + formats[CompilationError].setUnderlineColor(Qt::red); + formats[CompilationError].setUnderlineStyle(QTextCharFormat::SingleUnderline); } namespace @@ -101,6 +103,11 @@ void CodeHighlighter::processAST(solidity::ASTNode const& _ast) std::sort(m_formats.begin(), m_formats.end()); } +void CodeHighlighter::processError(dev::Exception const& _exception) +{ + Location const* location = boost::get_error_info(_exception); + m_formats.push_back(FormatRange(CodeHighlighterSettings::CompilationError, *location)); +} void CodeHighlighter::processComments(std::string const& _source) { diff --git a/mix/CodeHighlighter.h b/mix/CodeHighlighter.h index 8cc8b69e9..d0c92f3fc 100644 --- a/mix/CodeHighlighter.h +++ b/mix/CodeHighlighter.h @@ -31,6 +31,8 @@ class QTextDocument; namespace dev { +struct Exception; + namespace solidity { class ASTNode; @@ -50,6 +52,7 @@ public: Comment, StringLiteral, NumLiteral, + CompilationError, Size, //this must be kept last }; @@ -70,7 +73,7 @@ public: { FormatRange(CodeHighlighterSettings::Token _t, int _start, int _length): token(_t), start(_start), length(_length) {} FormatRange(CodeHighlighterSettings::Token _t, solidity::Location const& _location); - bool operator<(FormatRange const& _other) { return start < _other.start || (start == _other.start && length < _other.length); } + bool operator<(FormatRange const& _other) const { return start < _other.start || (start == _other.start && length < _other.length); } CodeHighlighterSettings::Token token; int start; @@ -82,6 +85,7 @@ public: /// Collect highligting information void processSource(std::string const& _source); void processAST(solidity::ASTNode const& _ast); + void processError(dev::Exception const& _exception); void updateFormatting(QTextDocument* _document, CodeHighlighterSettings const& _settings); private: diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index deb58416c..0c94173e9 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -140,6 +140,7 @@ void CodeModel::runCompilationJob(int _jobId, QString const& _code) std::ostringstream error; solidity::SourceReferenceFormatter::printExceptionInformation(error, _exception, "Error", cs); result.reset(new CompilationResult(*m_result, QString::fromStdString(error.str()))); + codeHighlighter->processError(_exception); qDebug() << QString(QApplication::tr("compilation failed:") + " " + result->compilerMessage()); } result->m_codeHighlighter = codeHighlighter; From 1626213af0aa35eba1f32d8350f09e1609045a26 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 5 Jan 2015 12:06:15 +0100 Subject: [PATCH 14/17] coding standards --- mix/AssemblyDebuggerControl.h | 10 ++++++++-- mix/CodeHighlighter.cpp | 28 +++++++++------------------- mix/CodeHighlighter.h | 17 +++++++++++++---- mix/CodeModel.cpp | 16 +++++----------- mix/CodeModel.h | 4 ++-- mix/StateListView.cpp | 1 + 6 files changed, 38 insertions(+), 38 deletions(-) diff --git a/mix/AssemblyDebuggerControl.h b/mix/AssemblyDebuggerControl.h index 4341b46e0..b4dff38f5 100644 --- a/mix/AssemblyDebuggerControl.h +++ b/mix/AssemblyDebuggerControl.h @@ -19,6 +19,7 @@ #pragma once +#include #include #include "Extension.h" #include "AssemblyDebuggerModel.h" @@ -55,7 +56,7 @@ private: void executeSequence(std::vector const& _sequence, u256 _balance); std::unique_ptr m_modelDebugger; - bool m_running; + std::atomic m_running; public slots: /// Run the contract constructor and show debugger window. @@ -67,13 +68,18 @@ public slots: private slots: /// Update UI with machine states result. Display a modal dialog. void showDebugger(QList const& _returnParams = QList(), QList const& _wStates = QList(), AssemblyDebuggerData const& _code = AssemblyDebuggerData()); + /// Update UI with transaction run error. void showDebugError(QString const& _error); - signals: + /// Transaction execution started void runStarted(); + /// Transaction execution completed successfully void runComplete(); + /// Transaction execution completed with error + /// @param _message Error message void runFailed(QString const& _message); + /// Execution state changed void stateChanged(); /// Emited when machine states are available. diff --git a/mix/CodeHighlighter.cpp b/mix/CodeHighlighter.cpp index 5f6cf7489..7cc07c9a5 100644 --- a/mix/CodeHighlighter.cpp +++ b/mix/CodeHighlighter.cpp @@ -25,25 +25,22 @@ #include #include #include +#include +#include +#include +#include #include "CodeHighlighter.h" -#include "libsolidity/ASTVisitor.h" -#include "libsolidity/AST.h" -#include "libsolidity/Scanner.h" -#include "libsolidity/Exceptions.h" -namespace dev -{ -namespace mix -{ +using namespace dev::mix; CodeHighlighterSettings::CodeHighlighterSettings() { - bg = QColor(0x00, 0x2b, 0x36); - fg = QColor (0xee, 0xe8, 0xd5); + backgroundColor = QColor(0x00, 0x2b, 0x36); + foregroundColor = QColor (0xee, 0xe8, 0xd5); formats[Keyword].setForeground(QColor(0x93, 0xa1, 0xa1)); formats[Comment].setForeground(QColor(0x85, 0x99, 0x00)); formats[StringLiteral].setForeground(QColor(0xdc, 0x32, 0x2f)); - formats[NumLiteral].setForeground(fg); + formats[NumLiteral].setForeground(foregroundColor); formats[Import].setForeground(QColor(0x6c, 0x71, 0xc4)); formats[CompilationError].setUnderlineColor(Qt::red); formats[CompilationError].setUnderlineStyle(QTextCharFormat::SingleUnderline); @@ -52,7 +49,7 @@ CodeHighlighterSettings::CodeHighlighterSettings() namespace { using namespace dev::solidity; - class HighlightVisitor : public solidity::ASTConstVisitor + class HighlightVisitor : public ASTConstVisitor { public: HighlightVisitor(CodeHighlighter::Formats* _formats) { m_formats = _formats; } @@ -67,7 +64,6 @@ namespace }; } - CodeHighlighter::FormatRange::FormatRange(CodeHighlighterSettings::Token _t, solidity::Location const& _location): token(_t), start(_location.start), length(_location.end - _location.start) {} @@ -172,9 +168,3 @@ void CodeHighlighter::updateFormatting(QTextDocument* _document, CodeHighlighter ++format; } } - - - - -} -} diff --git a/mix/CodeHighlighter.h b/mix/CodeHighlighter.h index d0c92f3fc..5083e6c82 100644 --- a/mix/CodeHighlighter.h +++ b/mix/CodeHighlighter.h @@ -42,6 +42,7 @@ namespace solidity namespace mix { +/// Code highligting settings class CodeHighlighterSettings { public: @@ -60,15 +61,16 @@ public: ///Format for each token QTextCharFormat formats[Size]; ///Background color - QColor bg; + QColor backgroundColor; ///Foreground color - QColor fg; + QColor foregroundColor; }; - +/// Code highlighting engine class class CodeHighlighter { public: + /// Formatting range struct FormatRange { FormatRange(CodeHighlighterSettings::Token _t, int _start, int _length): token(_t), start(_start), length(_length) {} @@ -82,13 +84,20 @@ public: typedef std::vector Formats; // Sorted by start position public: - /// Collect highligting information + /// Collect highligting information by lexing the source void processSource(std::string const& _source); + /// Collect additional highligting information from AST void processAST(solidity::ASTNode const& _ast); + /// Collect highlighting information from compilation exception void processError(dev::Exception const& _exception); + + /// Apply formatting for a text document + /// @todo Remove this once editor is reworked void updateFormatting(QTextDocument* _document, CodeHighlighterSettings const& _settings); private: + /// Collect highligting information by paring for comments + /// @todo Support this in solidity? void processComments(std::string const& _source); private: diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index 0c94173e9..8d2c24725 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -33,10 +33,7 @@ #include "CodeHighlighter.h" #include "CodeModel.h" -namespace dev -{ -namespace mix -{ +using namespace dev::mix; void BackgroundWorker::queueCodeChange(int _jobId, QString const& _content) { @@ -45,13 +42,13 @@ void BackgroundWorker::queueCodeChange(int _jobId, QString const& _content) CompilationResult::CompilationResult(): QObject(nullptr), m_successfull(false), + m_codeHash(qHash(QString())), m_contract(new QContractDefinition()), - m_codeHighlighter(new CodeHighlighter()), - m_codeHash(qHash(QString())) + m_codeHighlighter(new CodeHighlighter()) {} CompilationResult::CompilationResult(const solidity::CompilerStack& _compiler): - QObject(nullptr), m_successfull(true) + QObject(nullptr), m_successfull(true), m_codeHash(qHash(QString())) { if (!_compiler.getContractNames().empty()) { @@ -64,7 +61,7 @@ CompilationResult::CompilationResult(const solidity::CompilerStack& _compiler): } CompilationResult::CompilationResult(CompilationResult const& _prev, QString const& _compilerMessage): - QObject(nullptr), m_successfull(false), + QObject(nullptr), m_successfull(false), m_codeHash(qHash(QString())), m_contract(_prev.m_contract), m_compilerMessage(_compilerMessage), m_bytes(_prev.m_bytes), @@ -168,6 +165,3 @@ void CodeModel::updateFormatting(QTextDocument* _document) { m_result->codeHighlighter()->updateFormatting(_document, *m_codeHighlighterSettings); } - -} -} diff --git a/mix/CodeModel.h b/mix/CodeModel.h index da093183d..69c840aa5 100644 --- a/mix/CodeModel.h +++ b/mix/CodeModel.h @@ -91,14 +91,14 @@ public: private: bool m_successfull; + uint m_codeHash; std::shared_ptr m_contract; QString m_compilerMessage; ///< @todo: use some structure here dev::bytes m_bytes; QString m_assemblyCode; std::shared_ptr m_codeHighlighter; - ///@todo syntax highlighting, etc + friend class CodeModel; - uint m_codeHash; }; /// Background code compiler diff --git a/mix/StateListView.cpp b/mix/StateListView.cpp index 62df6530a..fef9ab8e9 100644 --- a/mix/StateListView.cpp +++ b/mix/StateListView.cpp @@ -26,6 +26,7 @@ #include #include #include "StateListView.h" + using namespace dev::mix; StateListView::StateListView(AppContext* _context): Extension(_context, ExtensionDisplayBehavior::RightTab) From 37b05992d106c712c4289b90e746f3fee40f2d6c Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 5 Jan 2015 12:28:22 +0100 Subject: [PATCH 15/17] style --- mix/StateListView.cpp | 2 +- mix/StateListView.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/mix/StateListView.cpp b/mix/StateListView.cpp index fef9ab8e9..79364fdfb 100644 --- a/mix/StateListView.cpp +++ b/mix/StateListView.cpp @@ -40,7 +40,7 @@ QString StateListView::contentUrl() const QString StateListView::title() const { - return QApplication::tr("State"); + return QApplication::tr("States"); } void StateListView::start() const diff --git a/mix/StateListView.h b/mix/StateListView.h index 12b5bac6a..18d1ae879 100644 --- a/mix/StateListView.h +++ b/mix/StateListView.h @@ -28,8 +28,7 @@ namespace dev namespace mix { -/// Transactions list control -/// @todo This should be moved into state as a sequence +/// State list control class StateListView: public Extension { Q_OBJECT From 525ac762dd7128de7d2aec6560af495d8f3eb709 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 5 Jan 2015 22:25:41 +0100 Subject: [PATCH 16/17] fixed code style --- mix/AppContext.cpp | 4 ++-- mix/AppContext.h | 2 +- mix/AssemblyDebuggerControl.cpp | 18 +++++++++--------- mix/CodeHighlighter.cpp | 4 ++-- mix/CodeModel.cpp | 22 ++++++++++++++++------ mix/CodeModel.h | 10 +++++----- mix/MixApplication.h | 3 ++- mix/main.cpp | 2 +- 8 files changed, 38 insertions(+), 27 deletions(-) diff --git a/mix/AppContext.cpp b/mix/AppContext.cpp index 8eae2b230..ff2d10d01 100644 --- a/mix/AppContext.cpp +++ b/mix/AppContext.cpp @@ -60,7 +60,7 @@ void AppContext::loadProject() if (!path.isEmpty()) { QFile file(path); - if(file.open(QIODevice::ReadOnly | QIODevice::Text)) + if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { QTextStream stream(&file); QString json = stream.readAll(); @@ -95,7 +95,7 @@ void AppContext::saveProject(QString const& _json) { dirPath.mkpath(dirPath.path()); QFile file(path); - if(file.open(QIODevice::WriteOnly | QIODevice::Text)) + if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { QTextStream stream(&file); stream << _json; diff --git a/mix/AppContext.h b/mix/AppContext.h index a7fa8a017..7435c7777 100644 --- a/mix/AppContext.h +++ b/mix/AppContext.h @@ -51,7 +51,7 @@ class CodeModel; * @brief Provides access to application scope variable. */ -class AppContext : public QObject +class AppContext: public QObject { Q_OBJECT diff --git a/mix/AssemblyDebuggerControl.cpp b/mix/AssemblyDebuggerControl.cpp index c230d9b6f..136353dc6 100644 --- a/mix/AssemblyDebuggerControl.cpp +++ b/mix/AssemblyDebuggerControl.cpp @@ -92,7 +92,7 @@ void AssemblyDebuggerControl::debugState(QVariantMap _state) std::vector transactionSequence; - for (auto const& t : transactions) + for (auto const& t: transactions) { QVariantMap transaction = t.toMap(); @@ -132,14 +132,14 @@ void AssemblyDebuggerControl::executeSequence(std::vector c QFunctionDefinition* f; ContractCallDataEncoder c; //encode data for all transactions - for (auto const& t : _sequence) + for (auto const& t: _sequence) { f = nullptr; - for (int k = 0; k < contractDef->functionsList().size(); k++) + for (int tf = 0; tf < contractDef->functionsList().size(); tf++) { - if (contractDef->functionsList().at(k)->name() == t.functionId) + if (contractDef->functionsList().at(tf)->name() == t.functionId) { - f = contractDef->functionsList().at(k); + f = contractDef->functionsList().at(tf); break; } } @@ -147,9 +147,9 @@ void AssemblyDebuggerControl::executeSequence(std::vector c throw std::runtime_error("function " + t.functionId.toStdString() + " not found"); c.encode(f->index()); - for (int k = 0; k < f->parametersList().size(); k++) + for (int p = 0; p < f->parametersList().size(); p++) { - QVariableDeclaration* var = (QVariableDeclaration*)f->parametersList().at(k); + QVariableDeclaration* var = (QVariableDeclaration*)f->parametersList().at(p); u256 value = 0; auto v = t.parameterValues.find(var->name()); if (v != t.parameterValues.cend()) @@ -171,7 +171,7 @@ void AssemblyDebuggerControl::executeSequence(std::vector c //we need to wrap states in a QObject before sending to QML. QList wStates; - for(int i = 0; i < debuggingContent.machineStates.size(); i++) + for (int i = 0; i < debuggingContent.machineStates.size(); i++) { QPointer s(new DebuggingStateWrapper(debuggingContent.executionCode, debuggingContent.executionData.toBytes())); s->setState(debuggingContent.machineStates.at(i)); @@ -182,7 +182,7 @@ void AssemblyDebuggerControl::executeSequence(std::vector c emit dataAvailable(debuggingContent.returnParameters, wStates, code); emit runComplete(); } - catch(boost::exception const& e) + catch(boost::exception const&) { emit runFailed(QString::fromStdString(boost::current_exception_diagnostic_information())); } diff --git a/mix/CodeHighlighter.cpp b/mix/CodeHighlighter.cpp index 7cc07c9a5..5c126d8e2 100644 --- a/mix/CodeHighlighter.cpp +++ b/mix/CodeHighlighter.cpp @@ -36,7 +36,7 @@ using namespace dev::mix; CodeHighlighterSettings::CodeHighlighterSettings() { backgroundColor = QColor(0x00, 0x2b, 0x36); - foregroundColor = QColor (0xee, 0xe8, 0xd5); + foregroundColor = QColor(0xee, 0xe8, 0xd5); formats[Keyword].setForeground(QColor(0x93, 0xa1, 0xa1)); formats[Comment].setForeground(QColor(0x85, 0x99, 0x00)); formats[StringLiteral].setForeground(QColor(0xdc, 0x32, 0x2f)); @@ -49,7 +49,7 @@ CodeHighlighterSettings::CodeHighlighterSettings() namespace { using namespace dev::solidity; - class HighlightVisitor : public ASTConstVisitor + class HighlightVisitor: public ASTConstVisitor { public: HighlightVisitor(CodeHighlighter::Formats* _formats) { m_formats = _formats; } diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index 8d2c24725..7d8b0442a 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -41,14 +41,17 @@ void BackgroundWorker::queueCodeChange(int _jobId, QString const& _content) } CompilationResult::CompilationResult(): - QObject(nullptr), m_successfull(false), + QObject(nullptr), + m_successful(false), m_codeHash(qHash(QString())), m_contract(new QContractDefinition()), m_codeHighlighter(new CodeHighlighter()) {} CompilationResult::CompilationResult(const solidity::CompilerStack& _compiler): - QObject(nullptr), m_successfull(true), m_codeHash(qHash(QString())) + QObject(nullptr), + m_successful(true), + m_codeHash(qHash(QString())) { if (!_compiler.getContractNames().empty()) { @@ -61,7 +64,9 @@ CompilationResult::CompilationResult(const solidity::CompilerStack& _compiler): } CompilationResult::CompilationResult(CompilationResult const& _prev, QString const& _compilerMessage): - QObject(nullptr), m_successfull(false), m_codeHash(qHash(QString())), + QObject(nullptr), + m_successful(false), + m_codeHash(qHash(QString())), m_contract(_prev.m_contract), m_compilerMessage(_compilerMessage), m_bytes(_prev.m_bytes), @@ -69,8 +74,13 @@ CompilationResult::CompilationResult(CompilationResult const& _prev, QString con m_codeHighlighter(_prev.m_codeHighlighter) {} -CodeModel::CodeModel(QObject* _parent) : QObject(_parent), - m_compiling(false), m_result(new CompilationResult()), m_codeHighlighterSettings(new CodeHighlighterSettings()), m_backgroundWorker(this), m_backgroundJobId(0) +CodeModel::CodeModel(QObject* _parent): + QObject(_parent), + m_compiling(false), + m_result(new CompilationResult()), + m_codeHighlighterSettings(new CodeHighlighterSettings()), + m_backgroundWorker(this), + m_backgroundJobId(0) { m_backgroundWorker.moveToThread(&m_backgroundThread); connect(this, &CodeModel::scheduleCompilationJob, &m_backgroundWorker, &BackgroundWorker::queueCodeChange, Qt::QueuedConnection); @@ -97,7 +107,7 @@ void CodeModel::stop() m_backgroundThread.wait(); } -void CodeModel::registerCodeChange(const QString &_code) +void CodeModel::registerCodeChange(QString const& _code) { // launch the background thread uint hash = qHash(_code); diff --git a/mix/CodeModel.h b/mix/CodeModel.h index 69c840aa5..c66703b22 100644 --- a/mix/CodeModel.h +++ b/mix/CodeModel.h @@ -61,7 +61,7 @@ private: }; ///Compilation result model. Contains all the compiled contract data required by UI -class CompilationResult : public QObject +class CompilationResult: public QObject { Q_OBJECT Q_PROPERTY(QContractDefinition* contract READ contract) @@ -79,7 +79,7 @@ public: /// @returns contract definition std::shared_ptr sharedContract() { return m_contract; } /// Indicates if the compilation was successfull - bool successfull() const { return m_successfull; } + bool successfull() const { return m_successful; } /// @returns compiler error message in case of unsuccessfull compilation QString compilerMessage() const { return m_compilerMessage; } /// @returns contract bytecode @@ -90,7 +90,7 @@ public: std::shared_ptr codeHighlighter() { return m_codeHighlighter; } private: - bool m_successfull; + bool m_successful; uint m_codeHash; std::shared_ptr m_contract; QString m_compilerMessage; ///< @todo: use some structure here @@ -102,7 +102,7 @@ private: }; /// Background code compiler -class CodeModel : public QObject +class CodeModel: public QObject { Q_OBJECT @@ -139,7 +139,7 @@ signals: void compilationCompleteInternal(CompilationResult* _newResult); private slots: - void onCompilationComplete(CompilationResult*_newResult); + void onCompilationComplete(CompilationResult* _newResult); public slots: /// Update code model on source code change diff --git a/mix/MixApplication.h b/mix/MixApplication.h index e1cb1e5cf..86c1126fc 100644 --- a/mix/MixApplication.h +++ b/mix/MixApplication.h @@ -43,7 +43,8 @@ public: MixApplication(int _argc, char* _argv[]); virtual ~MixApplication(); AppContext* context() { return m_appContext.get(); } - QQmlApplicationEngine* engine( ) { return m_engine.get(); } + QQmlApplicationEngine* engine() { return m_engine.get(); } + private: std::unique_ptr m_engine; std::unique_ptr m_appContext; diff --git a/mix/main.cpp b/mix/main.cpp index e10903c80..90099555f 100644 --- a/mix/main.cpp +++ b/mix/main.cpp @@ -23,7 +23,7 @@ #include "MixApplication.h" using namespace dev::mix; -int main(int _argc, char *_argv[]) +int main(int _argc, char* _argv[]) { MixApplication app(_argc, _argv); return app.exec(); From 8491e5f2f797fdbb82e68acc1a7208b5a0f754c7 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 6 Jan 2015 16:42:58 +0100 Subject: [PATCH 17/17] Various fixes. Initial portion of NatSpec integration. --- alethzero/MainWin.cpp | 2 +- alethzero/MainWin.h | 2 ++ alethzero/OurWebThreeStubServer.cpp | 40 ++++++++++++++++++++++++++- alethzero/OurWebThreeStubServer.h | 4 +++ eth/main.cpp | 2 +- libdevcrypto/CryptoPP.cpp | 4 +-- libethereum/EthereumPeer.cpp | 8 ------ libethereum/Executive.cpp | 2 +- libethereum/Executive.h | 2 +- libethereum/State.cpp | 7 +++++ libethereum/State.h | 4 +++ libweb3jsonrpc/WebThreeStubServer.cpp | 22 ++++++++++----- libweb3jsonrpc/WebThreeStubServer.h | 6 +++- mix/AssemblyDebuggerModel.cpp | 2 +- 14 files changed, 83 insertions(+), 24 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index dbcd0f493..b73a2cd0d 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1475,7 +1475,7 @@ void Main::populateDebugger(dev::bytesConstRef _r) m_history.append(WorldState({steps, ext.myAddress, vm.curPC(), inst, newMemSize, vm.gas(), lastHash, lastDataHash, vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels})); }; m_currentExecution->go(onOp); - m_currentExecution->finalize(onOp); + m_currentExecution->finalize(); initDebugger(); updateDebugger(); } diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index 5c196792d..ed5d275eb 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -78,6 +78,8 @@ public: dev::eth::Client* ethereum() const { return m_webThree->ethereum(); } std::shared_ptr whisper() const { return m_webThree->whisper(); } + std::string lookupNatSpec(dev::h256 const& _contractCode) const { (void)_contractCode; return ""; } // TODO: actually implement with leveldb & a UI. + QList owned() const { return m_myIdentities + m_myKeys; } public slots: diff --git a/alethzero/OurWebThreeStubServer.cpp b/alethzero/OurWebThreeStubServer.cpp index 0c6f42b5a..0d840e8d4 100644 --- a/alethzero/OurWebThreeStubServer.cpp +++ b/alethzero/OurWebThreeStubServer.cpp @@ -20,12 +20,16 @@ */ #include "OurWebThreeStubServer.h" + +#include +#include +#include "MainWin.h" using namespace std; using namespace dev; using namespace dev::eth; OurWebThreeStubServer::OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3, std::vector const& _accounts): - WebThreeStubServer(_conn, _web3, _accounts) + WebThreeStubServer(_conn, _web3, _accounts), m_web3(&_web3) {} std::string OurWebThreeStubServer::shh_newIdentity() @@ -34,3 +38,37 @@ std::string OurWebThreeStubServer::shh_newIdentity() emit onNewId(QString::fromStdString(toJS(kp.sec()))); return toJS(kp.pub()); } + +bool OurWebThreeStubServer::authenticate(dev::TransactionSkeleton const& _t) const +{ + return true; + + // To get the balance of the sender + cnote << "Sender has ETH: " << m_web3->ethereum()->postState().balance(_t.from); + + Main* main; // don't know this yet, should be a member and set at construction time by Main, who will construct us. + + h256 contractCodeHash = m_web3->ethereum()->postState().codeHash(_t.to); + + if (contractCodeHash == EmptySHA3) + { + // recipient has no code - nothing special about this transaction. + // TODO: show basic message for value transfer. + return true; // or whatever. + } + + std::string natspecJson = main->lookupNatSpec(contractCodeHash); + + if (natspecJson.empty()) + { + // TODO: HUGE warning - we don't know what this will do! + return false; // or whatever. + } + + // otherwise it's a transaction to contract for which we have the natspec: + // determine the actual message (embellish with real data) and ask user. + +// QMessageBox::question(); + + return true; +} diff --git a/alethzero/OurWebThreeStubServer.h b/alethzero/OurWebThreeStubServer.h index fb026d07e..9ff973371 100644 --- a/alethzero/OurWebThreeStubServer.h +++ b/alethzero/OurWebThreeStubServer.h @@ -32,7 +32,11 @@ public: OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3, std::vector const& _accounts); virtual std::string shh_newIdentity() override; + virtual bool authenticate(dev::TransactionSkeleton const& _t) const; signals: void onNewId(QString _s); + +private: + dev::WebThreeDirect* m_web3; }; diff --git a/eth/main.cpp b/eth/main.cpp index d55766cfd..c6435235e 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -672,7 +672,7 @@ int main(int argc, char** argv) f << ext->myAddress << " " << hex << toHex(dev::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)vm->gas(), 1)) << endl; }; e.go(oof); - e.finalize(oof); + e.finalize(); } catch(Exception const& _e) { diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp index 766ca485d..d73e3fa43 100644 --- a/libdevcrypto/CryptoPP.cpp +++ b/libdevcrypto/CryptoPP.cpp @@ -108,7 +108,7 @@ Signature Secp256k1::sign(Secret const& _key, h256 const& _hash) Integer kInv = k.InverseMod(m_q); Integer z(_hash.asBytes().data(), 32); - Integer s = (kInv * (Integer(_key.asBytes().data(), 32)*r + z)) % m_q; + Integer s = (kInv * (Integer(_key.asBytes().data(), 32) * r + z)) % m_q; if (r == 0 || s == 0) BOOST_THROW_EXCEPTION(InvalidState()); @@ -144,7 +144,7 @@ Public Secp256k1::recover(Signature _signature, bytesConstRef _message) Integer s(_signature.data()+32, 32); // cryptopp encodes sign of y as 0x02/0x03 instead of 0/1 or 27/28 byte encodedpoint[33]; - encodedpoint[0] = _signature[64]|2; + encodedpoint[0] = _signature[64] | 2; memcpy(&encodedpoint[1], _signature.data(), 32); ECP::Element x; diff --git a/libethereum/EthereumPeer.cpp b/libethereum/EthereumPeer.cpp index b204546d4..0901766bf 100644 --- a/libethereum/EthereumPeer.cpp +++ b/libethereum/EthereumPeer.cpp @@ -317,14 +317,6 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) disable("Blacklisted client version."); else if (host()->isBanned(session()->id())) disable("Peer banned for previous bad behaviour."); - else - { - // Grab transactions off them. - RLPStream s; - prep(s, GetTransactionsPacket); - sealAndSend(s); - transition(Asking::Nothing); - } break; } case GetTransactionsPacket: break; // DEPRECATED. diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index 965d6f0af..f79bb4a3b 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -220,7 +220,7 @@ bool Executive::go(OnOpFunc const& _onOp) return true; } -void Executive::finalize(OnOpFunc const&) +void Executive::finalize() { // SSTORE refunds... // must be done before the miner gets the fees. diff --git a/libethereum/Executive.h b/libethereum/Executive.h index 5a97e5f87..d743e3746 100644 --- a/libethereum/Executive.h +++ b/libethereum/Executive.h @@ -64,7 +64,7 @@ public: bool setup(bytesConstRef _transaction); /// Finalise a transaction previously set up with setup(). /// @warning Only valid after setup(), and possibly go(). - void finalize(OnOpFunc const& _onOp = OnOpFunc()); + void finalize(); /// @returns the transaction from setup(). /// @warning Only valid after setup(). Transaction const& t() const { return m_t; } diff --git a/libethereum/State.cpp b/libethereum/State.cpp index dfd65c713..c6a6ce125 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -958,6 +958,13 @@ bytes const& State::code(Address _contract) const return m_cache[_contract].code(); } +h256 State::codeHash(Address _contract) const +{ + if (!addressHasCode(_contract)) + return EmptySHA3; + return m_cache[_contract].codeHash(); +} + bool State::isTrieGood(bool _enforceRefs, bool _requireNoLeftOvers) const { for (int e = 0; e < (_enforceRefs ? 2 : 1); ++e) diff --git a/libethereum/State.h b/libethereum/State.h index 0473893c4..921c82bb9 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -201,6 +201,10 @@ public: /// @returns bytes() if no account exists at that address. bytes const& code(Address _contract) const; + /// Get the code hash of an account. + /// @returns EmptySHA3 if no account exists at that address or if there is no code associated with the address. + h256 codeHash(Address _contract) const; + /// Note that the given address is sending a transaction and thus increment the associated ticker. void noteSending(Address _id); diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index d88aa0a5f..8dc95b8c2 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -677,16 +677,24 @@ std::string WebThreeStubServer::eth_transact(Json::Value const& _json) t.gasPrice = 10 * dev::eth::szabo; if (!t.gas) t.gas = min(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice); - cwarn << "Silently signing transaction from address" << t.from.abridged() << ": User validation hook goes here."; - if (t.to) - // TODO: from qethereum, insert validification hook here. - client()->transact(m_accounts[t.from].secret(), t.value, t.to, t.data, t.gas, t.gasPrice); - else - ret = toJS(client()->transact(m_accounts[t.from].secret(), t.value, t.data, t.gas, t.gasPrice)); - client()->flushTransactions(); + if (authenticate(t)) + { + if (t.to) + // TODO: from qethereum, insert validification hook here. + client()->transact(m_accounts[t.from].secret(), t.value, t.to, t.data, t.gas, t.gasPrice); + else + ret = toJS(client()->transact(m_accounts[t.from].secret(), t.value, t.data, t.gas, t.gasPrice)); + client()->flushTransactions(); + } return ret; } +bool WebThreeStubServer::authenticate(TransactionSkeleton const& _t) const +{ + cwarn << "Silently signing transaction from address" << _t.from.abridged() << ": User validation hook goes here."; + return true; +} + Json::Value WebThreeStubServer::eth_transactionByHash(std::string const& _hash, int const& _i) { if (!client()) diff --git a/libweb3jsonrpc/WebThreeStubServer.h b/libweb3jsonrpc/WebThreeStubServer.h index 6d54c59ef..0f81fce9d 100644 --- a/libweb3jsonrpc/WebThreeStubServer.h +++ b/libweb3jsonrpc/WebThreeStubServer.h @@ -42,6 +42,7 @@ namespace dev { class WebThreeDirect; class KeyPair; +class TransactionSkeleton; namespace eth { class Interface; @@ -119,12 +120,15 @@ public: void setIdentities(std::vector const& _ids); std::map const& ids() const { return m_ids; } +protected: + virtual bool authenticate(dev::TransactionSkeleton const& _t) const; + private: dev::eth::Interface* client() const; std::shared_ptr face() const; dev::WebThreeDirect& m_web3; std::map m_accounts; - + ldb::ReadOptions m_readOptions; ldb::WriteOptions m_writeOptions; ldb::DB* m_db; diff --git a/mix/AssemblyDebuggerModel.cpp b/mix/AssemblyDebuggerModel.cpp index 354d0bd1e..3967b09af 100644 --- a/mix/AssemblyDebuggerModel.cpp +++ b/mix/AssemblyDebuggerModel.cpp @@ -73,7 +73,7 @@ DebuggingContent AssemblyDebuggerModel::executeTransaction(bytesConstRef const& }; m_currentExecution->go(onOp); - m_currentExecution->finalize(onOp); + m_currentExecution->finalize(); m_executiveState.completeMine(); DebuggingContent d;