Browse Source

mix IDE M1 first commit

cl-refactor
yann300 10 years ago
committed by yann300
parent
commit
f990a1ac63
  1. 62
      mix/ApplicationCtx.cpp
  2. 19
      mix/ApplicationCtx.h
  3. 84
      mix/AssemblyDebuggerCtrl.cpp
  4. 55
      mix/AssemblyDebuggerCtrl.h
  5. 111
      mix/AssemblyDebuggerModel.cpp
  6. 49
      mix/AssemblyDebuggerModel.h
  7. 22
      mix/CodeEditorExtensionManager.cpp
  8. 3
      mix/CodeEditorExtensionManager.h
  9. 4
      mix/ConstantCompilationCtrl.cpp
  10. 1
      mix/ConstantCompilationModel.cpp
  11. 2
      mix/ConstantCompilationModel.h
  12. 189
      mix/DebuggingStateWrapper.cpp
  13. 133
      mix/DebuggingStateWrapper.h
  14. 23
      mix/Extension.cpp
  15. 14
      mix/Extension.h
  16. 43
      mix/KeyEventManager.cpp
  17. 42
      mix/KeyEventManager.h
  18. 92
      mix/TransactionBuilder.cpp
  19. 48
      mix/TransactionBuilder.h
  20. 3
      mix/main.cpp
  21. 3
      mix/qml.qrc
  22. 20
      mix/qml/BasicMessage.qml
  23. 231
      mix/qml/Debugger.qml
  24. 14
      mix/qml/MainContent.qml
  25. 63
      mix/qml/js/Debugger.js
  26. 38
      mix/qml/main.qml

62
mix/ApplicationCtx.cpp

@ -14,23 +14,83 @@
/** @file ApplicationCtx.cpp
* @author Yann yann@ethdev.com
* @date 2014
* Provide an access to the current QQmlApplicationEngine which is used to add QML file on the fly.
* Provides an access to the current QQmlApplicationEngine which is used to add QML file on the fly.
* In the future this class can be extended to add more variable related to the context of the application.
* For now ApplicationCtx provides reference to:
* - QQmlApplicationEngine
* - dev::WebThreeDirect (and dev::eth::Client)
* - KeyEventManager
*/
#include <QDebug>
#include <QMessageBox>
#include <QQmlComponent>
#include <QQmlApplicationEngine>
#include "libdevcrypto/FileSystem.h"
#include "KeyEventManager.h"
#include "ApplicationCtx.h"
using namespace dev;
using namespace dev::mix;
using namespace dev::eth;
ApplicationCtx* ApplicationCtx::Instance = nullptr;
ApplicationCtx::ApplicationCtx(QQmlApplicationEngine* _engine)
{
m_applicationEngine = _engine;
m_keyEventManager = std::unique_ptr<KeyEventManager>();
m_webThree = std::unique_ptr<dev::WebThreeDirect>();
m_webThree.reset(new WebThreeDirect(std::string("Mix/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir() + "/Mix", false, {"eth", "shh"}));
m_keyEventManager.reset(new KeyEventManager());
}
ApplicationCtx::~ApplicationCtx()
{
delete m_applicationEngine;
}
QQmlApplicationEngine* ApplicationCtx::appEngine()
{
return m_applicationEngine;
}
dev::eth::Client* ApplicationCtx::getEthereumClient()
{
return m_webThree.get()->ethereum();
}
void ApplicationCtx::initKeyEventManager()
{
QObject* mainContent = m_applicationEngine->rootObjects().at(0)->findChild<QObject*>("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* ApplicationCtx::getKeyEventManager()
{
return m_keyEventManager.get();
}
void ApplicationCtx::setApplicationContext(QQmlApplicationEngine* _engine)
{
if (Instance == nullptr)
Instance = new ApplicationCtx(_engine);
}
void ApplicationCtx::displayMessageDialog(QString _title, QString _message)
{
QQmlComponent component(m_applicationEngine, QUrl("qrc:/qml/BasicMessage.qml"));
QObject* dialog = component.create();
dialog->findChild<QObject*>("messageContent", Qt::FindChildrenRecursively)->setProperty("text", _message);
QObject* dialogWin = ApplicationCtx::getInstance()->appEngine()->rootObjects().at(0)->findChild<QObject*>("messageDialog", Qt::FindChildrenRecursively);
QMetaObject::invokeMethod(dialogWin, "close");
dialogWin->setProperty("contentItem", QVariant::fromValue(dialog));
dialogWin->setProperty("title", _title);
dialogWin->setProperty("width", "250");
dialogWin->setProperty("height", "100");
QMetaObject::invokeMethod(dialogWin, "open");
}

19
mix/ApplicationCtx.h

@ -16,14 +16,19 @@
*/
/** @file ApplicationCtx.h
* @author Yann yann@ethdev.com
* @date 2014
* Provide an access to the current QQmlApplicationEngine which is used to add QML file on the fly.
* Provides an access to the current QQmlApplicationEngine which is used to add QML file on the fly.
* In the future this class can be extended to add more variable related to the context of the application.
* For now ApplicationCtx provides reference to:
* - QQmlApplicationEngine
* - dev::WebThreeDirect (and dev::eth::Client)
* - KeyEventManager
*/
#pragma once
#include <QQmlApplicationEngine>
#include "libwebthree/WebThree.h"
#include "KeyEventManager.h"
namespace dev
{
@ -36,15 +41,21 @@ class ApplicationCtx: public QObject
Q_OBJECT
public:
ApplicationCtx(QQmlApplicationEngine* _engine) { m_applicationEngine = _engine; }
~ApplicationCtx() { delete m_applicationEngine; }
ApplicationCtx(QQmlApplicationEngine* _engine);
~ApplicationCtx();
static ApplicationCtx* getInstance() { return Instance; }
static void setApplicationContext(QQmlApplicationEngine* _engine);
QQmlApplicationEngine* appEngine();
dev::eth::Client* getEthereumClient();
void initKeyEventManager();
KeyEventManager* getKeyEventManager();
void displayMessageDialog(QString _title, QString _message);
private:
static ApplicationCtx* Instance;
QQmlApplicationEngine* m_applicationEngine;
std::unique_ptr<dev::WebThreeDirect> m_webThree;
std::unique_ptr<KeyEventManager> m_keyEventManager;
public slots:
void quitApplication() { delete Instance; }

84
mix/AssemblyDebuggerCtrl.cpp

@ -0,0 +1,84 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
/** @file AssemblyDebuggerCtrl.h
* @author Yann yann@ethdev.com
* @date 2014
* display opcode debugging.
*/
#include <QDebug>
#include <QQmlContext>
#include <QModelIndex>
#include "libethereum/Transaction.h"
#include "AssemblyDebuggerModel.h"
#include "AssemblyDebuggerCtrl.h"
#include "TransactionBuilder.h"
#include "KeyEventManager.h"
#include "ApplicationCtx.h"
#include "DebuggingStateWrapper.h"
using namespace dev::mix;
AssemblyDebuggerCtrl::AssemblyDebuggerCtrl(QTextDocument* _doc): Extension(ExtensionDisplayBehavior::ModalDialog)
{
m_modelDebugger = std::unique_ptr<AssemblyDebuggerModel>(new AssemblyDebuggerModel);
m_doc = _doc;
}
QString AssemblyDebuggerCtrl::contentUrl() const
{
return QStringLiteral("qrc:/qml/Debugger.qml");
}
QString AssemblyDebuggerCtrl::title() const
{
return "debugger";
}
void AssemblyDebuggerCtrl::start() const
{
//start to listen on F5
ApplicationCtx::getInstance()->getKeyEventManager()->registerEvent(this, SLOT(keyPressed(int)));
}
void AssemblyDebuggerCtrl::keyPressed(int _key)
{
if (_key == Qt::Key_F5)
{
if (!m_modelDebugger->compile(m_doc->toPlainText()))
{
ApplicationCtx::getInstance()->displayMessageDialog("debugger","compilation failed");
return;
}
KeyPair ad = KeyPair::create();
u256 gasPrice = 10000000000000;
u256 gas = 1000000;
u256 amount = 100;
DebuggingContent debuggingContent = m_modelDebugger->getContractInitiationDebugStates(amount, gasPrice, gas, m_doc->toPlainText(), ad);
//we need to wrap states in a QObject before sending to QML.
QList<QObject*> wStates;
for(int i = 0; i < debuggingContent.states.size(); i++)
{
DebuggingStateWrapper* s = new DebuggingStateWrapper(debuggingContent.executionCode, debuggingContent.executionData.toBytes());
s->setState(debuggingContent.states.at(i));
wStates.append(s);
}
std::tuple<QList<QObject*>, QQMLMap*> code = DebuggingStateWrapper::getHumanReadableCode(debuggingContent.executionCode);
ApplicationCtx::getInstance()->appEngine()->rootContext()->setContextProperty("debugStates", QVariant::fromValue(wStates));
ApplicationCtx::getInstance()->appEngine()->rootContext()->setContextProperty("humanReadableExecutionCode", QVariant::fromValue(std::get<0>(code)));
ApplicationCtx::getInstance()->appEngine()->rootContext()->setContextProperty("bytesCodeMapping", QVariant::fromValue(std::get<1>(code)));
this->addContentOn(this);
};
}

55
mix/AssemblyDebuggerCtrl.h

@ -0,0 +1,55 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
/** @file AssemblyDebuggerCtrl.h
* @author Yann yann@ethdev.com
* @date 2014
* Ethereum IDE client.
*/
#pragma once
#include <QKeySequence>
#include "QTextDocument"
#include "Extension.h"
#include "ConstantCompilationModel.h"
#include "AssemblyDebuggerModel.h"
namespace dev
{
namespace mix
{
class AssemblyDebuggerCtrl: public Extension
{
Q_OBJECT
public:
AssemblyDebuggerCtrl(QTextDocument*);
~AssemblyDebuggerCtrl() {}
void start() const override;
QString title() const override;
QString contentUrl() const override;
private:
std::unique_ptr<AssemblyDebuggerModel> m_modelDebugger;
QTextDocument* m_doc;
public Q_SLOTS:
void keyPressed(int);
};
}
}

111
mix/AssemblyDebuggerModel.cpp

@ -0,0 +1,111 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
/** @file AssemblyDebuggerModel.h
* @author Yann yann@ethdev.com
* @date 2014
* used as a model to debug contract assembly code.
*/
#include "libethereum/Executive.h"
#include "libethereum/Transaction.h"
#include "libethereum/ExtVM.h"
#include "libevm/VM.h"
#include "libdevcore/Common.h"
#include "ApplicationCtx.h"
#include "TransactionBuilder.h"
#include "AssemblyDebuggerModel.h"
#include "ConstantCompilationModel.h"
#include "DebuggingStateWrapper.h"
using namespace dev;
using namespace dev::eth;
using namespace dev::mix;
AssemblyDebuggerModel::AssemblyDebuggerModel()
{
m_currentExecution = std::unique_ptr<Executive>(new Executive(m_executiveState));
}
DebuggingContent AssemblyDebuggerModel::getContractInitiationDebugStates(dev::bytesConstRef _rawTransaction)
{
QList<DebuggingState> states;
Transaction tr(_rawTransaction);
m_currentExecution.get()->create(tr.sender(), tr.value(), tr.gasPrice(), tr.gas(), &tr.data(), tr.sender());
std::vector<DebuggingState const*> levels;
bytes code;
bytesConstRef data;
bool firstIteration = true;
auto onOp = [&](uint64_t steps, Instruction inst, dev::bigint newMemSize, dev::bigint gasCost, void* voidVM, void const* voidExt)
{
VM& vm = *(VM*)voidVM;
ExtVM const& ext = *(ExtVM const*)voidExt;
if (firstIteration)
{
code = ext.code;
data = ext.data;
firstIteration = false;
}
if (levels.size() < ext.depth)
levels.push_back(&states.back());
else
levels.resize(ext.depth);
states.append(DebuggingState({steps, ext.myAddress, vm.curPC(), inst, newMemSize, vm.gas(),
vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels}));
};
m_currentExecution.get()->go(onOp);
m_currentExecution.get()->finalize(onOp);
DebuggingContent d;
d.states = states;
d.executionCode = code;
d.executionData = data;
d.contentAvailable = true;
d.message = "ok";
return d;
}
DebuggingContent AssemblyDebuggerModel::getContractInitiationDebugStates(dev::u256 _value,
dev::u256 _gasPrice,
dev::u256 _gas,
QString code,
KeyPair _key)
{
ConstantCompilationModel compiler;
CompilerResult res = compiler.compile(code);
if (!res.success)
{
DebuggingContent r;
r.contentAvailable = false;
r.message = "compile failed";
return r;
}
TransactionBuilder trBuild;
Transaction tr = trBuild.getCreationTransaction(_value, _gasPrice, _gas, res.bytes,
m_executiveState.transactionsFrom(dev::toAddress(_key.secret())), _key.secret());
bytes b = tr.rlp();
dev::bytesConstRef bytesRef = &b;
return getContractInitiationDebugStates(bytesRef);
}
bool AssemblyDebuggerModel::compile(QString code)
{
ConstantCompilationModel compiler;
CompilerResult res = compiler.compile(code);
return res.success;
}

49
mix/AssemblyDebuggerModel.h

@ -0,0 +1,49 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
/** @file AssemblyDebuggerModel.h
* @author Yann yann@ethdev.com
* @date 2014
* serves as a model to debug contract assembly code.
*/
#pragma once
#include <QObject>
#include <QList>
#include "libethereum/State.h"
#include "libethereum/Executive.h"
#include "libdevcore/Common.h"
#include "DebuggingStateWrapper.h"
namespace dev
{
namespace mix
{
class AssemblyDebuggerModel
{
public:
AssemblyDebuggerModel();
DebuggingContent getContractInitiationDebugStates(dev::u256, dev::u256, dev::u256, QString, KeyPair);
DebuggingContent getContractInitiationDebugStates(dev::bytesConstRef);
bool compile(QString code);
private:
std::unique_ptr<dev::eth::Executive> m_currentExecution;
dev::eth::State m_executiveState;
};
}
}

22
mix/CodeEditorExtensionManager.cpp

@ -27,6 +27,7 @@
#include <QQuickTextDocument>
#include <libevm/VM.h>
#include "ConstantCompilationCtrl.h"
#include "AssemblyDebuggerCtrl.h"
#include "features.h"
#include "ApplicationCtx.h"
#include "CodeEditorExtensionManager.h"
@ -59,22 +60,29 @@ void CodeEditorExtensionManager::loadEditor(QQuickItem* _editor)
void CodeEditorExtensionManager::initExtensions()
{
//only one for now
std::shared_ptr<ConstantCompilationCtrl> constantCompilation = std::make_shared<ConstantCompilationCtrl>(m_doc);
if (constantCompilation.get()->contentUrl() != "")
initExtension(std::make_shared<ConstantCompilationCtrl>(m_doc));
initExtension(std::make_shared<AssemblyDebuggerCtrl>(m_doc));
}
void CodeEditorExtensionManager::initExtension(std::shared_ptr<Extension> ext)
{
if (!ext.get()->contentUrl().isEmpty())
{
try
{
constantCompilation.get()->addContentOn(m_tabView);
if (ext.get()->getDisplayBehavior() == ExtensionDisplayBehavior::Tab)
{
ext.get()->addTabOn(m_tabView);
}
}
catch (...)
{
qDebug() << "Exception when adding content into view.";
qDebug() << "Exception when adding tab into view.";
return;
}
}
constantCompilation.get()->start();
m_features.append(constantCompilation);
ext.get()->start();
m_features.append(ext);
}
void CodeEditorExtensionManager::setEditor(QQuickItem* _editor)

3
mix/CodeEditorExtensionManager.h

@ -45,12 +45,13 @@ public:
CodeEditorExtensionManager() {}
~CodeEditorExtensionManager();
void initExtensions();
void initExtension(std::shared_ptr<Extension>);
void setEditor(QQuickItem*);
void setTabView(QQuickItem*);
private:
QQuickItem* m_editor;
QVector<std::shared_ptr<ConstantCompilationCtrl>> m_features;
QVector<std::shared_ptr<Extension>> m_features;
QQuickItem* m_tabView;
QTextDocument* m_doc;
void loadEditor(QQuickItem*);

4
mix/ConstantCompilationCtrl.cpp

@ -30,7 +30,7 @@
#include "ConstantCompilationModel.h"
using namespace dev::mix;
ConstantCompilationCtrl::ConstantCompilationCtrl(QTextDocument* _doc)
ConstantCompilationCtrl::ConstantCompilationCtrl(QTextDocument* _doc): Extension(ExtensionDisplayBehavior::Tab)
{
m_editor = _doc;
m_compilationModel = new ConstantCompilationModel();
@ -64,7 +64,7 @@ void ConstantCompilationCtrl::compile()
resetOutPut();
return;
}
CompilerResult res = m_compilationModel->compile(m_editor->toPlainText());
CompilerResult res = m_compilationModel->compile(m_editor->toPlainText().replace("\t", " "));
writeOutPut(res);
}

1
mix/ConstantCompilationModel.cpp

@ -42,6 +42,7 @@ CompilerResult ConstantCompilationModel::compile(QString _code)
res.success = true;
res.comment = "ok";
res.hexCode = QString::fromStdString(dev::eth::disassemble(m_data));
res.bytes = m_data;
}
catch (dev::Exception const& _exception)
{

2
mix/ConstantCompilationModel.h

@ -22,6 +22,7 @@
#pragma once
#include <libevm/VM.h>
#include <QObject>
namespace dev
@ -34,6 +35,7 @@ struct CompilerResult
{
QString hexCode;
QString comment;
dev::bytes bytes;
bool success;
};

189
mix/DebuggingStateWrapper.cpp

@ -0,0 +1,189 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
/** @file DebuggingState.h
* @author Yann yann@ethdev.com
* @date 2014
* Used to translate c++ type (u256, bytes, ...) into friendly value (to be used by QML).
*/
#include <QDebug>
#include <QString>
#include <QTextStream>
#include "libdevcrypto/Common.h"
#include "libevmcore/Instruction.h"
#include "libdevcore/Common.h"
#include "DebuggingStateWrapper.h"
using namespace dev;
using namespace dev::eth;
using namespace dev::mix;
std::tuple<QList<QObject*>, QQMLMap*> DebuggingStateWrapper::getHumanReadableCode(const bytes& code)
{
QList<QObject*> codeStr;
QMap<int, int> codeMapping;
for (unsigned i = 0; i <= code.size(); ++i)
{
byte b = i < code.size() ? code[i] : 0;
try
{
QString s = QString::fromStdString(instructionInfo((Instruction)b).name);
std::ostringstream out;
out << hex << std::setw(4) << std::setfill('0') << i;
codeMapping[i] = codeStr.size();
int line = i;
if (b >= (byte)Instruction::PUSH1 && b <= (byte)Instruction::PUSH32)
{
unsigned bc = b - (byte)Instruction::PUSH1 + 1;
s = "PUSH 0x" + QString::fromStdString(toHex(bytesConstRef(&code[i + 1], bc)));
i += bc;
}
HumanReadableCode* humanCode = new HumanReadableCode(QString::fromStdString(out.str()) + " " + s, line);
codeStr.append(humanCode);
}
catch (...)
{
qDebug() << QString("Unhandled exception!") << endl <<
QString::fromStdString(boost::current_exception_diagnostic_information());
break; // probably hit data segment
}
}
return std::make_tuple(codeStr, new QQMLMap(codeMapping));
}
QString DebuggingStateWrapper::debugStack()
{
QString stack;
for (auto i: m_state.stack)
stack.prepend(prettyU256(i) + "\n");
return stack;
}
QString DebuggingStateWrapper::debugStorage()
{
std::stringstream s;
for (auto const& i: m_state.storage)
s << "@" << prettyU256(i.first).toStdString() << "&nbsp;&nbsp;&nbsp;&nbsp;" << prettyU256(i.second).toStdString();
return QString::fromStdString(s.str());
}
QString DebuggingStateWrapper::debugMemory()
{
return QString::fromStdString(memDump(m_state.memory, 16, false));
}
QString DebuggingStateWrapper::debugCallData()
{
return QString::fromStdString(memDump(m_data, 16, false));
}
QStringList DebuggingStateWrapper::levels()
{
QStringList levelsStr;
for (unsigned i = 0; i <= m_state.levels.size(); ++i)
{
DebuggingState const& s = i ? *m_state.levels[m_state.levels.size() - i] : m_state;
std::ostringstream out;
out << m_state.cur.abridged();
if (i)
out << " " << instructionInfo(m_state.inst).name << " @0x" << hex << m_state.curPC;
levelsStr.append(QString::fromStdString(out.str()));
}
return levelsStr;
}
QString DebuggingStateWrapper::headerInfo()
{
std::ostringstream ss;
ss << dec << " STEP: " << m_state.steps << " | PC: 0x" << hex << m_state.curPC << " : " << dev::eth::instructionInfo(m_state.inst).name << " | ADDMEM: " << dec << m_state.newMemSize << " words | COST: " << dec << m_state.gasCost << " | GAS: " << dec << m_state.gas;
return QString::fromStdString(ss.str());
}
QString DebuggingStateWrapper::endOfDebug()
{
if (m_state.gasCost > m_state.gas)
return "OUT-OF-GAS";
else if (m_state.inst == Instruction::RETURN && m_state.stack.size() >= 2)
{
unsigned from = (unsigned)m_state.stack.back();
unsigned size = (unsigned)m_state.stack[m_state.stack.size() - 2];
unsigned o = 0;
bytes out(size, 0);
for (; o < size && from + o < m_state.memory.size(); ++o)
out[o] = m_state.memory[from + o];
return "RETURN " + QString::fromStdString(dev::memDump(out, 16, false));
}
else if (m_state.inst == Instruction::STOP)
return "STOP";
else if (m_state.inst == Instruction::SUICIDE && m_state.stack.size() >= 1)
return "SUICIDE 0x" + QString::fromStdString(toString(right160(m_state.stack.back())));
else
return "EXCEPTION";
}
QString DebuggingStateWrapper::prettyU256(u256 _n)
{
unsigned inc = 0;
QString raw;
std::ostringstream s;
if (!(_n >> 64))
s << " " << (uint64_t)_n << " (0x" << hex << (uint64_t)_n << ")";
else if (!~(_n >> 64))
s << " " << (int64_t)_n << " (0x" << hex << (int64_t)_n << ")";
else if ((_n >> 160) == 0)
{
Address a = right160(_n);
QString n = QString::fromStdString(a.abridged());//pretty(a);
if (n.isNull())
s << "0x" << a;
else
s << n.toHtmlEscaped().toStdString() << "(0x" << a.abridged() << ")";
}
else if ((raw = fromRaw((h256)_n, &inc)).size())
return "\"" + raw.toHtmlEscaped() + "\"" + (inc ? " + " + QString::number(inc) : "");
else
s << "" << (h256)_n;
return QString::fromStdString(s.str());
}
QString DebuggingStateWrapper::fromRaw(h256 _n, unsigned* _inc)
{
if (_n)
{
std::string s((char const*)_n.data(), 32);
auto l = s.find_first_of('\0');
if (!l)
return QString();
if (l != std::string::npos)
{
auto p = s.find_first_not_of('\0', l);
if (!(p == std::string::npos || (_inc && p == 31)))
return QString();
if (_inc)
*_inc = (byte)s[31];
s.resize(l);
}
for (auto i: s)
if (i < 32)
return QString();
return QString::fromStdString(s);
}
return QString();
}

133
mix/DebuggingStateWrapper.h

@ -0,0 +1,133 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
/** @file DebuggingState.h
* @author Yann yann@ethdev.com
* @date 2014
* Ethereum IDE client.
*/
#pragma once
#include <QStringList>
#include "libethereum/State.h"
#include "libethereum/Executive.h"
#include "libdevcore/Common.h"
namespace dev
{
namespace mix
{
struct DebuggingState
{
uint64_t steps;
dev::Address cur;
dev::u256 curPC;
dev::eth::Instruction inst;
dev::bigint newMemSize;
dev::u256 gas;
dev::u256s stack;
dev::bytes memory;
dev::bigint gasCost;
std::map<dev::u256, dev::u256> storage;
std::vector<DebuggingState const*> levels;
};
struct DebuggingContent
{
QList<DebuggingState> states;
bytes executionCode;
bytesConstRef executionData;
bool contentAvailable;
QString message;
};
/* contains the line nb of the assembly code and the corresponding index in the code bytes array */
class HumanReadableCode: public QObject
{
Q_OBJECT
Q_PROPERTY(QString line READ line)
Q_PROPERTY(int processIndex READ processIndex)
public:
HumanReadableCode(QString _line, int _processIndex) : m_line(_line), m_processIndex(_processIndex) {}
QString line() { return m_line; }
int processIndex() { return m_processIndex; }
private:
QString m_line;
int m_processIndex;
};
/* used to publish QMap type to QML */
class QQMLMap : public QObject
{
Q_OBJECT
public:
QQMLMap(QMap<int, int> _map) : m_map(_map) { }
Q_INVOKABLE int getValue(int _key) { return m_map.value(_key); }
private:
QMap<int, int> m_map;
};
/* used to publish DebuggingState struct to QML */
class DebuggingStateWrapper : public QObject
{
Q_OBJECT
Q_PROPERTY(int step READ step)
Q_PROPERTY(int curPC READ curPC)
Q_PROPERTY(int gasCost READ gasCost)
Q_PROPERTY(int gas READ gas)
Q_PROPERTY(QString debugStack READ debugStack)
Q_PROPERTY(QString debugStorage READ debugStorage)
Q_PROPERTY(QString debugMemory READ debugMemory)
Q_PROPERTY(QString debugCallData READ debugCallData)
Q_PROPERTY(QString headerInfo READ headerInfo)
Q_PROPERTY(QString endOfDebug READ endOfDebug)
Q_PROPERTY(QStringList levels READ levels)
public:
DebuggingStateWrapper(bytes _code, bytes _data) : m_code(_code), m_data(_data) {}
int step() { return (int)m_state.steps; }
int curPC() { return (int)m_state.curPC; }
int gasCost() { return (int)m_state.gasCost; }
int gas() { return (int)m_state.gas; }
QString debugStack();
QString debugStorage();
QString debugMemory();
QString debugCallData();
QString headerInfo();
QString endOfDebug();
QStringList levels();
DebuggingState state() { return m_state; }
void setState(DebuggingState _state) { m_state = _state; }
static std::tuple<QList<QObject*>, QQMLMap*> getHumanReadableCode(bytes const& code);
private:
DebuggingState m_state;
bytes m_code;
bytes m_data;
QString prettyU256(u256 _n);
QString fromRaw(h256 _n, unsigned* _inc = nullptr);
};
}
}

23
mix/Extension.cpp

@ -25,7 +25,7 @@
using namespace dev;
using namespace dev::mix;
void Extension::addContentOn(QObject* _tabView)
void Extension::addTabOn(QObject* _view)
{
if (contentUrl() == "")
return;
@ -33,12 +33,29 @@ void Extension::addContentOn(QObject* _tabView)
QVariant returnValue;
QQmlComponent* component = new QQmlComponent(
ApplicationCtx::getInstance()->appEngine(),
QUrl(this->contentUrl()), _tabView);
QUrl(contentUrl()), _view);
QMetaObject::invokeMethod(_tabView, "addTab",
QMetaObject::invokeMethod(_view, "addTab",
Q_RETURN_ARG(QVariant, returnValue),
Q_ARG(QVariant, this->title()),
Q_ARG(QVariant, QVariant::fromValue(component)));
m_view = qvariant_cast<QObject*>(returnValue);
}
void Extension::addContentOn(QObject* _view)
{
Q_UNUSED(_view);
if (m_displayBehavior == ExtensionDisplayBehavior::ModalDialog)
{
QQmlComponent component(ApplicationCtx::getInstance()->appEngine(), QUrl(contentUrl()));
QObject* dialog = component.create();
QObject* dialogWin = ApplicationCtx::getInstance()->appEngine()->rootObjects().at(0)->findChild<QObject*>("dialog", Qt::FindChildrenRecursively);
QMetaObject::invokeMethod(dialogWin, "close");
dialogWin->setProperty("contentItem", QVariant::fromValue(dialog));
dialogWin->setProperty("title", title());
QMetaObject::invokeMethod(dialogWin, "open");
}
//TODO add more view type.
}

14
mix/Extension.h

@ -28,19 +28,31 @@ namespace dev
namespace mix
{
enum ExtensionDisplayBehavior
{
Tab,
ModalDialog
};
class Extension: public QObject
{
Q_OBJECT
public:
Extension() {}
Extension(ExtensionDisplayBehavior _displayBehavior) { m_displayBehavior = _displayBehavior; }
virtual QString contentUrl() const { return ""; }
virtual QString title() const { return ""; }
virtual void start() const {}
void addContentOn(QObject* tabView);
void addContentOn(QObject* _tabView);
void addTabOn(QObject* _view);
void setDisplayBehavior(ExtensionDisplayBehavior _displayBehavior) { m_displayBehavior = _displayBehavior; }
ExtensionDisplayBehavior getDisplayBehavior() { return m_displayBehavior; }
protected:
QObject* m_view;
ExtensionDisplayBehavior m_displayBehavior;
};
}

43
mix/KeyEventManager.cpp

@ -0,0 +1,43 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
/** @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 <QDebug>
#include <QKeySequence>
#include "KeyEventManager.h"
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());
}

42
mix/KeyEventManager.h

@ -0,0 +1,42 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
/** @file KeyEventManager.h
* @author Yann yann@ethdev.com
* @date 2014
* use as an event handler for all classes which need keyboard interactions
*/
#pragma once
#include <QObject>
class KeyEventManager: public QObject
{
Q_OBJECT
public:
KeyEventManager() {}
void registerEvent(const QObject* receiver, const char* slot);
void unRegisterEvent(QObject* receiver);
signals:
void onKeyPressed(int);
public Q_SLOTS:
void keyPressed(QVariant event);
};

92
mix/TransactionBuilder.cpp

@ -0,0 +1,92 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
/** @file TransactionBuilder.cpp
* @author Yann yann@ethdev.com
* @date 2014
* Ethereum IDE client.
*/
#include "libethereum/Executive.h"
#include "libdevcore/Common.h"
#include "ApplicationCtx.h"
#include "TransactionBuilder.h"
using namespace dev::mix;
using namespace dev::eth;
using namespace dev;
Transaction TransactionBuilder::getCreationTransaction(u256 _value, u256 _gasPrice, u256 _gas,
bytes _data, u256 _nonce, Secret _secret) const
{
return Transaction(_value, _gasPrice, _gas, _data, _nonce, _secret);
}
Transaction TransactionBuilder::getBasicTransaction(u256 _value, u256 _gasPrice, u256 _gas,
QString address, bytes _data, u256 _nonce, Secret _secret) const
{
return Transaction(_value, _gasPrice, _gas, fromString(address), _data, _nonce, _secret);
}
int TransactionBuilder::fromHex(char _i) const
{
if (_i >= '0' && _i <= '9')
return _i - '0';
if (_i >= 'a' && _i <= 'f')
return _i - 'a' + 10;
if (_i >= 'A' && _i <= 'F')
return _i - 'A' + 10;
BOOST_THROW_EXCEPTION(BadHexCharacter() << errinfo_invalidSymbol(_i));
}
bytes TransactionBuilder::fromHex(std::string const& _s) const
{
unsigned s = (_s[0] == '0' && _s[1] == 'x') ? 2 : 0;
std::vector<uint8_t> ret;
ret.reserve((_s.size() - s + 1) / 2);
if (_s.size() % 2)
try
{
ret.push_back(fromHex(_s[s++]));
}
catch (...){ ret.push_back(0); cwarn << boost::current_exception_diagnostic_information(); }
for (unsigned i = s; i < _s.size(); i += 2)
try
{
ret.push_back((byte)(fromHex(_s[i]) * 16 + fromHex(_s[i + 1])));
}
catch (...){ ret.push_back(0); cwarn << boost::current_exception_diagnostic_information(); }
return ret;
}
Address TransactionBuilder::fromString(QString const& _a) const
{
Client* ethClient = ApplicationCtx::getInstance()->getEthereumClient();
std::string sn = _a.toStdString();
if (sn.size() > 32)
sn.resize(32);
h256 n;
memcpy(n.data(), sn.data(), sn.size());
memset(n.data() + sn.size(), 0, 32 - sn.size());
if (_a.size() == 40)
return Address(fromHex(_a.toStdString()));
else
{
//we try to resolve the recipient adress using nameReg contract state
const Address c_config = Address("661005d2720d855f1d9976f88bb10c1a3398c77f"); //NameReg contract
if (h160 nameReg = (u160)ethClient->stateAt(c_config, 0))
if (h256 a = ethClient->stateAt(nameReg, n))
return right160(a);
}
return Address(); // should maybe throws exception instead of returning blank address.
}

48
mix/TransactionBuilder.h

@ -0,0 +1,48 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
/** @file TransactionBuilder.h
* @author Yann yann@ethdev.com
* @date 2014
* Ethereum IDE client.
*/
#pragma once
#include <QString>
#include "libdevcore/Common.h"
#include "libethereum/Transaction.h"
namespace dev
{
namespace mix
{
class TransactionBuilder
{
public:
TransactionBuilder() {}
dev::eth::Transaction getBasicTransaction(dev::u256 _value, dev::u256 _gasPrice, dev::u256 _gas,
QString address, bytes _data, dev::u256 _nonce, Secret _secret) const;
dev::eth::Transaction getCreationTransaction(dev::u256 _value, dev::u256 _gasPrice, dev::u256 _gas,
dev::bytes _data, dev::u256 _nonce, Secret _secret) const;
private:
bytes fromHex(std::string const& _s) const;
int fromHex(char _i) const;
Address fromString(QString const& _a) const;
};
}
}

3
mix/main.cpp

@ -35,6 +35,9 @@ int main(int _argc, char *_argv[])
QQmlApplicationEngine* engine = new QQmlApplicationEngine();
ApplicationCtx::setApplicationContext(engine);
QObject::connect(&app, SIGNAL(lastWindowClosed()), ApplicationCtx::getInstance(), SLOT(quitApplication())); //use to kill ApplicationContext and other stuff
engine->load(QUrl(QStringLiteral("qrc:/qml/main.qml")));
ApplicationCtx::getInstance()->initKeyEventManager(); //has to be called after the loading of the main view.
return app.exec();
}

3
mix/qml.qrc

@ -4,5 +4,8 @@
<file>qml/main.qml</file>
<file>qml/MainContent.qml</file>
<file>qml/TabStyle.qml</file>
<file>qml/Debugger.qml</file>
<file>qml/js/Debugger.js</file>
<file>qml/BasicMessage.qml</file>
</qresource>
</RCC>

20
mix/qml/BasicMessage.qml

@ -0,0 +1,20 @@
import QtQuick 2.3
import QtQuick.Controls.Styles 1.2
import QtQuick.Controls 1.2
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.1
Rectangle {
anchors.fill: parent
color: "lightgrey"
Label
{
width: parent.width
height: parent.height
horizontalAlignment: "AlignHCenter"
verticalAlignment: "AlignVCenter"
objectName: "messageContent"
id: messageTxt
text: ""
}
}

231
mix/qml/Debugger.qml

@ -0,0 +1,231 @@
import QtQuick 2.3
import QtQuick.Controls.Styles 1.2
import QtQuick.Controls 1.2
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.1
import "js/Debugger.js" as Debugger
Rectangle {
anchors.fill: parent;
Rectangle {
id: headerInfo
width: parent.width
height: 30
anchors.top: parent.top
Label {
anchors.centerIn: parent
font.family: "Verdana"
font.pointSize: 9
font.italic: true
id: headerInfoLabel
}
}
Keys.onPressed: {
if (event.key === Qt.Key_F10)
Debugger.moveSelection(1);
else if (event.key === Qt.Key_F9)
Debugger.moveSelection(-1);
}
Rectangle {
id: stateListContainer
focus: true
anchors.top: headerInfo.bottom
anchors.left: parent.left
height: parent.height - 30
width: parent.width * 0.5
ListView {
anchors.top: parent.top
height: parent.height * 0.55
width: 200
anchors.horizontalCenter: parent.horizontalCenter
id: statesList
Component.onCompleted: Debugger.init();
model: humanReadableExecutionCode
delegate: renderDelegate
highlight: highlightBar
highlightFollowsCurrentItem: true
}
Component {
id: highlightBar
Rectangle {
height: statesList.currentItem.height
width: statesList.currentItem.width
border.color: "orange"
border.width: 1
Behavior on y { SpringAnimation { spring: 2; damping: 0.1 } }
}
}
Component {
id: renderDelegate
Item {
id: wrapperItem
height:20
width: parent.width
Text {
anchors.centerIn: parent
text: line
font.pointSize: 9
}
}
}
Rectangle {
anchors.top: statesList.bottom
height: parent.height * 0.30
width: parent.width
Label {
id: callStackLabel
anchors.top: statesList.bottom
anchors.bottomMargin: 10
horizontalAlignment: "AlignHCenter"
font.family: "Verdana"
font.pointSize: 8
font.letterSpacing: 2
width: parent.width
height: 15
text: "callstack"
}
ListView {
height: parent.height - 15
width: 200
anchors.top: callStackLabel.bottom
anchors.horizontalCenter: parent.horizontalCenter
id: levelList
delegate: Component {
Item {
Text {
font.family: "Verdana"
font.pointSize: 8
text: modelData
}
}
}
}
}
}
Rectangle {
anchors.topMargin: 5
anchors.bottomMargin: 10
anchors.rightMargin: 10
height: parent.height - 30
width: parent.width * 0.5
anchors.right: parent.right
anchors.top: headerInfo.bottom
anchors.bottom: parent.bottom
Rectangle {
id: debugStack
anchors.top: parent.top
width: parent.width
height: parent.height * 0.25
Label {
horizontalAlignment: "AlignHCenter"
font.family: "Verdana"
font.pointSize: 8
font.letterSpacing: 2
width: parent.width
height: 15
anchors.top : parent.top
text: "debug stack"
}
TextArea {
anchors.bottom: parent.bottom
width: parent.width
font.family: "Verdana"
font.pointSize: 8
font.letterSpacing: 2
height: parent.height - 15
id:debugStackTxt
readOnly: true;
}
}
Rectangle {
id: debugMemory
anchors.top: debugStack.bottom
width: parent.width
height: parent.height * 0.25
Label {
horizontalAlignment: "AlignHCenter"
font.family: "Verdana"
font.pointSize: 8
font.letterSpacing: 2
width: parent.width
height: 15
anchors.top : parent.top
text: "debug memory"
}
TextArea {
anchors.bottom: parent.bottom
width: parent.width
font.family: "Verdana"
font.pointSize: 8
font.letterSpacing: 2
height: parent.height - 15
id: debugMemoryTxt
readOnly: true;
}
}
Rectangle {
id: debugStorage
anchors.top: debugMemory.bottom
width: parent.width
height: parent.height * 0.25
Label {
horizontalAlignment: "AlignHCenter"
font.family: "Verdana"
font.pointSize: 8
font.letterSpacing: 2
width: parent.width
height: 15
anchors.top : parent.top
text: "debug storage"
}
TextArea {
anchors.bottom: parent.bottom
width: parent.width
font.family: "Verdana"
font.pointSize: 8
font.letterSpacing: 2
height: parent.height - 15
id:debugStorageTxt
readOnly: true;
}
}
Rectangle {
id: debugCallData
anchors.top: debugStorage.bottom
width: parent.width
height: parent.height * 0.25
Label {
horizontalAlignment: "AlignHCenter"
font.family: "Verdana"
font.pointSize: 8
font.letterSpacing: 2
width: parent.width
height: 15
anchors.top : parent.top
text: "debug calldata"
}
TextArea {
anchors.bottom: parent.bottom
width: parent.width
height: parent.height - 15
id: debugCallDataTxt
readOnly: true;
}
}
}
}

14
mix/qml/MainContent.qml

@ -1,10 +1,18 @@
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.0
import QtQuick.Controls.Styles 1.1
import QtQuick.Controls.Styles 1.2
import CodeEditorExtensionManager 1.0
Rectangle {
objectName: "mainContent"
signal keyPressed(variant event)
focus: true
Keys.enabled: true
Keys.onPressed:
{
root.keyPressed(event.key);
}
anchors.fill: parent
height: parent.height
width: parent.width;

63
mix/qml/js/Debugger.js

@ -0,0 +1,63 @@
//humanReadableExecutionCode => contain human readable code.
//debugStates => contain all debug states.
//bytesCodeMapping => mapping between humanReadableExecutionCode and bytesCode.
//statesList => ListView
var currentSelectedState = null;
function init()
{
currentSelectedState = 0;
select(currentSelectedState);
}
function moveSelection(incr)
{
if (currentSelectedState + incr >= 0)
{
if (currentSelectedState + incr < debugStates.length)
{
select(currentSelectedState + incr);
}
else
{
endOfDebug();
}
}
}
function select(stateIndex)
{
var state = debugStates[stateIndex];
var codeStr = bytesCodeMapping.getValue(state.curPC);
highlightSelection(codeStr);
currentSelectedState = codeStr;
completeCtxInformation(state);
levelList.model = state.levels;
levelList.update();
}
function highlightSelection(index)
{
console.log(index);
statesList.currentIndex = index;
}
function completeCtxInformation(state)
{
debugStackTxt.text = state.debugStack;
debugStorageTxt.text = state.debugStorage;
debugMemoryTxt.text = state.debugMemory;
debugCallDataTxt.text = state.debugCallData;
headerInfoLabel.text = state.headerInfo
}
function endOfDebug()
{
var state = debugStates[debugStates.length - 1];
debugStorageTxt.text = "";
debugCallDataTxt.text = "";
debugStackTxt.text = "";
debugMemoryTxt.text = state.endOfDebug
var gascost = state.gas - state.gasCost;
headerInfoLabel.text = "EXIT | GAS: " + gascost;
}

38
mix/qml/main.qml

@ -1,15 +1,22 @@
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.1
import QtQuick.Window 2.0
import CodeEditorExtensionManager 1.0
ApplicationWindow {
id: mainApplication
visible: true
width: 1000
height: 480
x: Screen.width / 2 - width / 2
y: Screen.height / 2 - height / 2
width: 1200
height: 600
minimumWidth: 400
minimumHeight: 300
title: qsTr("mix")
menuBar: MenuBar {
Menu {
title: qsTr("File")
@ -19,6 +26,33 @@ ApplicationWindow {
}
}
}
MainContent {
}
Dialog {
x: mainApplication.x + (mainApplication.width - width) / 2
y: mainApplication.y + (mainApplication.height - height) / 2
objectName: "dialog"
id: dialog
height: 400
width: 700
modality: Qt.WindowModal
contentItem: Rectangle {
objectName: "dialogContent"
}
}
Dialog {
x: mainApplication.x + (mainApplication.width - width) / 2
y: mainApplication.y + (mainApplication.height - height) / 2
objectName: "messageDialog"
id: messageDialog
height: 150
width: 200
modality: Qt.WindowModal
contentItem: Rectangle {
objectName: "messageContent"
}
}
}

Loading…
Cancel
Save