From 50a1edb23bf75970fc6324250834b77d2e2f3d97 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sat, 27 Dec 2014 14:53:34 +0100 Subject: [PATCH] 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(); } + + }