Browse Source

Merge branch 'mix' of https://github.com/arkpar/cpp-ethereum into

ide_m25

Conflicts:
	libdevcore/CommonJS.cpp
	libdevcore/CommonJS.h
	mix/AssemblyDebuggerCtrl.cpp
	mix/AssemblyDebuggerCtrl.h
	mix/AssemblyDebuggerModel.cpp
	mix/DebuggingStateWrapper.cpp
	mix/QBasicNodeDefinition.h
	mix/QFunctionDefinition.h
	mix/QVariableDeclaration.h
	mix/TransactionBuilder.cpp
	mix/TransactionBuilder.h
cl-refactor
yann300 10 years ago
parent
commit
c3d38d54f8
  1. 16
      alethzero/MainWin.cpp
  2. 8
      alethzero/MainWin.h
  3. 64
      libdevcore/CommonJS.cpp
  4. 3
      libdevcore/CommonJS.h
  5. 18
      libevmcore/Instruction.h
  6. 43
      mix/AppContext.cpp
  7. 20
      mix/AppContext.h
  8. 93
      mix/AssemblyDebuggerCtrl.cpp
  9. 23
      mix/AssemblyDebuggerCtrl.h
  10. 29
      mix/AssemblyDebuggerModel.cpp
  11. 6
      mix/AssemblyDebuggerModel.h
  12. 36
      mix/CodeEditorExtensionManager.cpp
  13. 4
      mix/CodeEditorExtensionManager.h
  14. 10
      mix/ConstantCompilationCtrl.cpp
  15. 7
      mix/ConstantCompilationCtrl.h
  16. 4
      mix/ConstantCompilationModel.cpp
  17. 5
      mix/ConstantCompilationModel.h
  18. 9
      mix/ContractCallDataEncoder.cpp
  19. 1
      mix/ContractCallDataEncoder.h
  20. 72
      mix/DebuggingStateWrapper.cpp
  21. 28
      mix/DebuggingStateWrapper.h
  22. 25
      mix/Extension.cpp
  23. 12
      mix/Extension.h
  24. 8
      mix/KeyEventManager.h
  25. 1
      mix/MixApplication.h
  26. 2
      mix/QBasicNodeDefinition.h
  27. 6
      mix/QContractDefinition.h
  28. 6
      mix/QFunctionDefinition.h
  29. 2
      mix/QVariableDeclaration.h
  30. 4
      mix/QVariableDefinition.h
  31. 63
      mix/TransactionBuilder.cpp
  32. 7
      mix/TransactionBuilder.h
  33. 217
      mix/TransactionListModel.cpp
  34. 165
      mix/TransactionListModel.h
  35. 56
      mix/TransactionListView.cpp
  36. 56
      mix/TransactionListView.h
  37. 8
      mix/main.cpp
  38. 2
      mix/qml.qrc
  39. 8
      mix/qml/BasicContent.qml
  40. 2
      mix/qml/BasicMessage.qml
  41. 2
      mix/qml/Debugger.qml
  42. 107
      mix/qml/MainContent.qml
  43. 187
      mix/qml/TransactionDialog.qml
  44. 89
      mix/qml/TransactionList.qml
  45. 10
      mix/qml/main.qml

16
alethzero/MainWin.cpp

@ -64,7 +64,7 @@ static void initUnits(QComboBox* _b)
_b->addItem(QString::fromStdString(units()[n].second), n);
}
static QString fromRaw(dev::h256 _n, unsigned* _inc = nullptr)
QString Main::fromRaw(dev::h256 _n, unsigned* _inc)
{
if (_n)
{
@ -148,7 +148,7 @@ Main::Main(QWidget *parent) :
statusBar()->addPermanentWidget(ui->peerCount);
statusBar()->addPermanentWidget(ui->mineStatus);
statusBar()->addPermanentWidget(ui->blockCount);
connect(ui->ourAccounts->model(), SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), SLOT(ourAccountsRowsMoved()));
m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir() + "/AlethZero", false, {"eth", "shh"}));
@ -173,17 +173,17 @@ Main::Main(QWidget *parent) :
connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, this, qweb));
connect(m_qweb, SIGNAL(onNewId(QString)), this, SLOT(addNewId(QString)));
});
connect(ui->webView, &QWebView::loadFinished, [=]()
{
m_qweb->poll();
});
connect(ui->webView, &QWebView::titleChanged, [=]()
{
ui->tabWidget->setTabText(0, ui->webView->title());
});
readSettings();
installWatches();
startTimer(100);
@ -1067,7 +1067,7 @@ void Main::timerEvent(QTimerEvent*)
// 7/18, Alex: aggregating timers, prelude to better threading?
// Runs much faster on slower dual-core processors
static int interval = 100;
// refresh mining every 200ms
if (interval / 100 % 2 == 0)
refreshMining();
@ -1093,7 +1093,7 @@ void Main::timerEvent(QTimerEvent*)
}
else
interval += 100;
if (m_qweb)
m_qweb->poll();
@ -1759,7 +1759,7 @@ void Main::on_net_triggered()
{
ui->port->setEnabled(!ui->net->isChecked());
ui->clientName->setEnabled(!ui->net->isChecked());
string n = string("AlethZero/v") + dev::Version;
string n = string("AlethZero/v") + dev::Version;
if (ui->clientName->text().size())
n += "/" + ui->clientName->text().toStdString();
n += "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM);

8
alethzero/MainWin.h

@ -69,7 +69,7 @@ struct WorldState
class Main : public QMainWindow
{
Q_OBJECT
public:
explicit Main(QWidget *parent = 0);
~Main();
@ -79,7 +79,7 @@ public:
std::shared_ptr<dev::shh::WhisperHost> whisper() const { return m_webThree->whisper(); }
QList<dev::KeyPair> owned() const { return m_myIdentities + m_myKeys; }
public slots:
void load(QString _file);
void note(QString _entry);
@ -146,7 +146,7 @@ private slots:
void on_debugDumpState_triggered(int _add = 1);
void on_debugDumpStatePre_triggered();
void on_refresh_triggered();
void on_usePrivate_triggered();
void on_usePrivate_triggered();
void on_enableOptimizer_triggered();
void on_turboMining_triggered();
void on_go_triggered();
@ -259,4 +259,6 @@ private:
QWebThreeConnector* m_qwebConnector;
std::unique_ptr<OurWebThreeStubServer> m_server;
QWebThree* m_qweb = nullptr;
static QString fromRaw(dev::h256 _n, unsigned* _inc = nullptr);
};

64
libdevcore/CommonJS.cpp

@ -61,4 +61,68 @@ std::string unpadded(std::string _b)
return _b;
}
std::string prettyU256(u256 _n)
{
unsigned inc = 0;
std::string raw;
std::ostringstream s;
if (!(_n >> 64))
s << " " << (uint64_t)_n << " (0x" << (uint64_t)_n << ")";
else if (!~(_n >> 64))
s << " " << (int64_t)_n << " (0x" << (int64_t)_n << ")";
else if ((_n >> 160) == 0)
{
Address a = right160(_n);
std::string n = a.abridged();
if (n.empty())
s << "0x" << a;
else
s << n << "(0x" << a.abridged() << ")";
}
else if ((raw = fromRaw((h256)_n, &inc)).size())
return "\"" + raw + "\"" + (inc ? " + " + std::to_string(inc) : "");
else
s << "" << (h256)_n;
return s.str();
}
std::string 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 "";
if (l != std::string::npos)
{
auto p = s.find_first_not_of('\0', l);
if (!(p == std::string::npos || (_inc && p == 31)))
return "";
if (_inc)
*_inc = (byte)s[31];
s.resize(l);
}
for (auto i: s)
if (i < 32)
return "";
return s;
}
return "";
}
Address fromString(std::string _sn)
{
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 (_sn.size() == 40)
return Address(fromHex(_sn));
else
return Address();
}
}

3
libdevcore/CommonJS.h

@ -50,6 +50,9 @@ bytes jsToBytes(std::string const& _s);
bytes padded(bytes _b, unsigned _l);
bytes unpadded(bytes _s);
std::string unpadded(std::string _s);
std::string prettyU256(u256 _n);
std::string fromRaw(h256 _n, unsigned* _inc = nullptr);
Address fromString(std::string _a);
template <unsigned N> FixedHash<N> jsToFixed(std::string const& _s)
{

18
libevmcore/Instruction.h

@ -173,6 +173,24 @@ enum class Instruction: uint8_t
SUICIDE = 0xff ///< halt execution and register account for later deletion
};
/// @returns the number of PUSH Instruction _inst
inline unsigned getPushNumber(Instruction _inst)
{
return (byte)_inst - unsigned(Instruction::PUSH1) + 1;
}
/// @returns the number of DUP Instruction _inst
inline unsigned getDupNumber(Instruction _inst)
{
return (byte)_inst - unsigned(Instruction::DUP1) + 1;
}
/// @returns the number of SWAP Instruction _inst
inline unsigned getSwapNumber(Instruction _inst)
{
return (byte)_inst - unsigned(Instruction::SWAP1) + 1;
}
/// @returns the PUSH<_number> instruction
inline Instruction pushInstruction(unsigned _number)
{

43
mix/ApplicationCtx.cpp → mix/AppContext.cpp

@ -11,12 +11,12 @@
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 ApplicationCtx.cpp
/** @file AppContext.cpp
* @author Yann yann@ethdev.com
* @date 2014
* Provides an access to the current QQmlApplicationEngine which is used to add QML file on the fly.
* Provides 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:
* For now AppContext provides reference to:
* - QQmlApplicationEngine
* - dev::WebThreeDirect (and dev::eth::Client)
* - KeyEventManager
@ -28,63 +28,56 @@
#include <QQmlApplicationEngine>
#include "libdevcrypto/FileSystem.h"
#include "KeyEventManager.h"
#include "ApplicationCtx.h"
#include "AppContext.h"
using namespace dev;
using namespace dev::mix;
using namespace dev::eth;
ApplicationCtx* ApplicationCtx::Instance = nullptr;
AppContext* AppContext::Instance = nullptr;
ApplicationCtx::ApplicationCtx(QQmlApplicationEngine* _engine)
AppContext::AppContext(QQmlApplicationEngine* _engine)
{
m_applicationEngine = _engine;
m_applicationEngine = std::unique_ptr<QQmlApplicationEngine>(_engine);
m_keyEventManager = std::unique_ptr<KeyEventManager>(new KeyEventManager());
m_webThree = std::unique_ptr<dev::WebThreeDirect>(new WebThreeDirect(std::string("Mix/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir() + "/Mix", false, {"eth", "shh"}));
}
ApplicationCtx::~ApplicationCtx()
QQmlApplicationEngine* AppContext::appEngine()
{
delete m_applicationEngine;
return m_applicationEngine.get();
}
QQmlApplicationEngine* ApplicationCtx::appEngine()
dev::eth::Client* AppContext::getEthereumClient()
{
return m_applicationEngine;
return m_webThree->ethereum();
}
dev::eth::Client* ApplicationCtx::getEthereumClient()
{
return m_webThree.get()->ethereum();
}
void ApplicationCtx::initKeyEventManager()
void AppContext::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()
KeyEventManager* AppContext::getKeyEventManager()
{
return m_keyEventManager.get();
}
void ApplicationCtx::setApplicationContext(QQmlApplicationEngine* _engine)
void AppContext::setApplicationContext(QQmlApplicationEngine* _engine)
{
if (Instance == nullptr)
Instance = new ApplicationCtx(_engine);
Instance = new AppContext(_engine);
}
void ApplicationCtx::displayMessageDialog(QString _title, QString _message)
void AppContext::displayMessageDialog(QString _title, QString _message)
{
QQmlComponent component(m_applicationEngine, QUrl("qrc:/qml/BasicMessage.qml"));
QQmlComponent component(m_applicationEngine.get(), 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);
QObject* dialogWin = AppContext::getInstance()->appEngine()->rootObjects().at(0)->findChild<QObject*>("messageDialog", Qt::FindChildrenRecursively);
QMetaObject::invokeMethod(dialogWin, "close");
dialogWin->setProperty("contentItem", QVariant::fromValue(dialog));
dialogWin->setProperty("title", _title);

20
mix/ApplicationCtx.h → mix/AppContext.h

@ -14,11 +14,12 @@
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 ApplicationCtx.h
/** @file AppContext.h
* @author Yann yann@ethdev.com
* Provides an access to the current QQmlApplicationEngine which is used to add QML file on the fly.
* @date 2014
* Provides 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:
* For now AppContext provides reference to:
* - QQmlApplicationEngine
* - dev::WebThreeDirect (and dev::eth::Client)
* - KeyEventManager
@ -32,18 +33,17 @@
namespace dev
{
namespace mix
{
class ApplicationCtx: public QObject
class AppContext: public QObject
{
Q_OBJECT
public:
ApplicationCtx(QQmlApplicationEngine* _engine);
~ApplicationCtx();
static ApplicationCtx* getInstance() { return Instance; }
AppContext(QQmlApplicationEngine* _engine);
~AppContext() {}
static AppContext* getInstance() { return Instance; }
static void setApplicationContext(QQmlApplicationEngine* _engine);
QQmlApplicationEngine* appEngine();
dev::eth::Client* getEthereumClient();
@ -52,8 +52,8 @@ public:
void displayMessageDialog(QString _title, QString _message);
private:
static ApplicationCtx* Instance;
QQmlApplicationEngine* m_applicationEngine;
static AppContext* Instance;
std::unique_ptr<QQmlApplicationEngine> m_applicationEngine;
std::unique_ptr<dev::WebThreeDirect> m_webThree;
std::unique_ptr<KeyEventManager> m_keyEventManager;

93
mix/AssemblyDebuggerCtrl.cpp

@ -17,6 +17,7 @@
* display opcode debugging.
*/
#include <QtConcurrent/QtConcurrent>
#include <QDebug>
#include <QVariableDefinition.h>
#include <QQmlContext>
@ -27,8 +28,9 @@
#include "AssemblyDebuggerCtrl.h"
#include "TransactionBuilder.h"
#include "KeyEventManager.h"
#include "ApplicationCtx.h"
#include "AppContext.h"
#include "DebuggingStateWrapper.h"
#include "TransactionListModel.h"
#include "QContractDefinition.h"
#include "QVariableDeclaration.h"
#include "ContractCallDataEncoder.h"
@ -42,6 +44,11 @@ AssemblyDebuggerCtrl::AssemblyDebuggerCtrl(QTextDocument* _doc): Extension(Exten
qRegisterMetaType<QList<QVariableDefinition*>>("QList<QVariableDefinition*>");
qRegisterMetaType<QVariableDeclaration*>("QVariableDeclaration*");
qRegisterMetaType<AssemblyDebuggerData>();
qRegisterMetaType<DebuggingStatusResult>();
connect(this, SIGNAL(dataAvailable(bool, DebuggingStatusResult, QList<QObject*>, AssemblyDebuggerData)),
this, SLOT(updateGUI(bool, DebuggingStatusResult, QList<QObject*>, AssemblyDebuggerData)), Qt::QueuedConnection);
m_modelDebugger = std::unique_ptr<AssemblyDebuggerModel>(new AssemblyDebuggerModel);
m_compilation = std::unique_ptr<ConstantCompilationModel>(new ConstantCompilationModel);
m_senderAddress = KeyPair::create(); //this address will be used as the sender address.
@ -62,7 +69,7 @@ QString AssemblyDebuggerCtrl::title() const
void AssemblyDebuggerCtrl::start() const
{
//start to listen on F5
ApplicationCtx::getInstance()->getKeyEventManager()->registerEvent(this, SLOT(keyPressed(int)));
m_ctx->getKeyEventManager()->registerEvent(this, SLOT(keyPressed(int)));
}
void AssemblyDebuggerCtrl::keyPressed(int _key)
@ -71,43 +78,53 @@ void AssemblyDebuggerCtrl::keyPressed(int _key)
{
m_previousDebugResult = deployContract();
}
else if(_key == Qt::Key_F4)
/*else if(_key == Qt::Key_F4)
callContract(m_previousDebugResult.contractAddress);
else if(_key == Qt::Key_F3)
{
//Reset state;
m_modelDebugger.get()->resetState();
}
}*/
}
void AssemblyDebuggerCtrl::callContract(Address contractAddress)
void AssemblyDebuggerCtrl::callContract(dev::mix::TransactionSettings _tr)
{
CompilerResult compilerRes = m_compilation.get()->compile(m_doc->toPlainText());
if (!compilerRes.success)
{
ApplicationCtx::getInstance()->displayMessageDialog("debugger","compilation failed");
AppContext::getInstance()->displayMessageDialog("debugger","compilation failed");
return;
}
ContractCallDataEncoder c;
std::shared_ptr<QContractDefinition> contractDef = QContractDefinition::Contract(m_doc->toPlainText());
QFunctionDefinition* fo = nullptr;
for (int i = 0; i < contractDef->functions().size(); i++)
QFunctionDefinition* f = nullptr;
for (int k = 0; k < contractDef.get()->functions().size(); k++)
{
QFunctionDefinition* f = (QFunctionDefinition*)contractDef->functions().at(i);
if (f->name() == "test2")
if (contractDef.get()->functions().at(k)->name() == _tr.functionId)
{
fo = f;
c.encode(i);
for (int k = 0; k < f->parameters().size(); k++)
{
c.encode((QVariableDeclaration*)f->parameters().at(k), QString("3"));
}
f = (QFunctionDefinition*)contractDef->functions().at(k);
}
}
if (!f)
{
AppContext::getInstance()->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);
c.encode(var, _tr.parameterValues[var->name()]);
}
Transaction tr = m_trBuilder.getDefaultBasicTransaction(contractAddress, c.encodedData(), m_senderAddress);
DebuggingContent debuggingContent = m_modelDebugger->getContractCallDebugStates(tr);
debuggingContent.returnParameters = c.decode(fo->returnParameters(), debuggingContent.returnValue);
DebuggingContent debuggingContent = m_modelDebugger->getContractCallDebugStates(m_previousDebugResult.contractAddress,
c.encodedData(),
m_senderAddress,
_tr);
debuggingContent.returnParameters = c.decode(f->returnParameters(), debuggingContent.returnValue);
finalizeExecution(debuggingContent);
}
@ -116,14 +133,13 @@ DebuggingContent AssemblyDebuggerCtrl::deployContract()
CompilerResult compilerRes = m_compilation.get()->compile(m_doc->toPlainText());
if (!compilerRes.success)
{
ApplicationCtx::getInstance()->displayMessageDialog("debugger","compilation failed");
AppContext::getInstance()->displayMessageDialog("debugger","compilation failed");
DebuggingContent res;
res.contentAvailable = false;
return res;
}
Transaction tr = m_trBuilder.getDefaultCreationTransaction(compilerRes.bytes, m_senderAddress);
DebuggingContent debuggingContent = m_modelDebugger->getContractInitiationDebugStates(tr);
DebuggingContent debuggingContent = m_modelDebugger->getContractInitiationDebugStates(compilerRes.bytes, m_senderAddress);
finalizeExecution(debuggingContent);
return debuggingContent;
}
@ -132,17 +148,36 @@ void AssemblyDebuggerCtrl::finalizeExecution(DebuggingContent debuggingContent)
{
//we need to wrap states in a QObject before sending to QML.
QList<QObject*> wStates;
for(int i = 0; i < debuggingContent.states.size(); i++)
for(int i = 0; i < debuggingContent.machineStates.size(); i++)
{
DebuggingStateWrapper* s = new DebuggingStateWrapper(debuggingContent.executionCode, debuggingContent.executionData.toBytes());
s->setState(debuggingContent.states.at(i));
DebuggingStateWrapper* s = new DebuggingStateWrapper(debuggingContent.executionCode, debuggingContent.executionData.toBytes(), this);
s->setState(debuggingContent.machineStates.at(i));
wStates.append(s);
}
std::tuple<QList<QObject*>, QQMLMap*> code = DebuggingStateWrapper::getHumanReadableCode(debuggingContent.executionCode, this);
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)));
ApplicationCtx::getInstance()->appEngine()->rootContext()->setContextProperty("contractCallReturnParameters",
AppContext::getInstance()->appEngine()->rootContext()->setContextProperty("debugStates", QVariant::fromValue(wStates));
AppContext::getInstance()->appEngine()->rootContext()->setContextProperty("humanReadableExecutionCode", QVariant::fromValue(std::get<0>(code)));
AppContext::getInstance()->appEngine()->rootContext()->setContextProperty("bytesCodeMapping", QVariant::fromValue(std::get<1>(code)));
AppContext::getInstance()->appEngine()->rootContext()->setContextProperty("contractCallReturnParameters",
QVariant::fromValue(new QVariableDefinitionList(debuggingContent.returnParameters)));
this->addContentOn(this);
}
void AssemblyDebuggerCtrl::updateGUI(bool success, DebuggingStatusResult reason, QList<QObject*> _wStates, AssemblyDebuggerData _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)));
this->addContentOn(this);
}
else
m_ctx->displayMessageDialog("debugger","compilation failed");
}
void AssemblyDebuggerCtrl::runTransaction(TransactionSettings _tr)
{
callContract(_tr);
}

23
mix/AssemblyDebuggerCtrl.h

@ -23,12 +23,23 @@
#include "QTextDocument"
#include "Extension.h"
#include "ConstantCompilationModel.h"
#include "TransactionListModel.h"
#include "AssemblyDebuggerModel.h"
#include "TransactionBuilder.h"
#include "AppContext.h"
namespace dev
using AssemblyDebuggerData = std::tuple<QList<QObject*>, dev::mix::QQMLMap*>;
enum DebuggingStatusResult
{
Ok,
Compilationfailed
};
Q_DECLARE_METATYPE(AssemblyDebuggerData)
Q_DECLARE_METATYPE(DebuggingStatusResult)
namespace dev
{
namespace mix
{
@ -50,13 +61,19 @@ private:
TransactionBuilder m_trBuilder;
KeyPair m_senderAddress;
DebuggingContent deployContract();
void callContract(Address contractAddress);
void callContract(dev::mix::TransactionSettings contractAddress);
void finalizeExecution(DebuggingContent content);
DebuggingContent m_previousDebugResult;
public Q_SLOTS:
public slots:
void keyPressed(int);
void updateGUI(bool success, DebuggingStatusResult reason, QList<QObject*> _wStates = QList<QObject*>(), AssemblyDebuggerData _code = AssemblyDebuggerData());
void runTransaction(dev::mix::TransactionSettings _tr);
signals:
void dataAvailable(bool success, DebuggingStatusResult reason, QList<QObject*> _wStates = QList<QObject*>(), AssemblyDebuggerData _code = AssemblyDebuggerData());
};
}

29
mix/AssemblyDebuggerModel.cpp

@ -22,9 +22,9 @@
#include "libethereum/ExtVM.h"
#include "libevm/VM.h"
#include "libdevcore/Common.h"
#include "libdevcore/CommonJS.h"
#include "ApplicationCtx.h"
#include "AppContext.h"
#include "TransactionBuilder.h"
#include "TransactionListModel.h"
#include "AssemblyDebuggerModel.h"
#include "ConstantCompilationModel.h"
#include "DebuggingStateWrapper.h"
@ -46,7 +46,7 @@ void AssemblyDebuggerModel::addBalance(KeyPair address, u256 amount)
DebuggingContent AssemblyDebuggerModel::executeTransaction()
{
QList<DebuggingState> states;
QList<DebuggingState> machineStates;
std::vector<DebuggingState const*> levels;
bytes code;
bytesConstRef data;
@ -64,11 +64,11 @@ DebuggingContent AssemblyDebuggerModel::executeTransaction()
}
if (levels.size() < ext.depth)
levels.push_back(&states.back());
levels.push_back(&machineStates.back());
else
levels.resize(ext.depth);
states.append(DebuggingState({steps, ext.myAddress, vm.curPC(), inst, newMemSize, vm.gas(),
machineStates.append(DebuggingState({steps, ext.myAddress, vm.curPC(), inst, newMemSize, vm.gas(),
vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels}));
};
@ -78,7 +78,7 @@ DebuggingContent AssemblyDebuggerModel::executeTransaction()
DebuggingContent d;
d.returnValue = m_currentExecution.get()->out().toVector();
d.states = states;
d.machineStates = machineStates;
d.executionCode = code;
d.executionData = data;
d.contentAvailable = true;
@ -86,8 +86,11 @@ DebuggingContent AssemblyDebuggerModel::executeTransaction()
return d;
}
DebuggingContent AssemblyDebuggerModel::getContractInitiationDebugStates(Transaction _tr)
DebuggingContent AssemblyDebuggerModel::getContractInitiationDebugStates(bytes _code, KeyPair _sender)
{
TransactionBuilder trBuilder;
dev::eth::Transaction _tr = trBuilder.getDefaultCreationTransaction(_code, _sender,
m_executiveState.transactionsFrom(dev::toAddress(_sender.secret())));
bytes b = _tr.rlp();
dev::bytesConstRef bytesRef = &b;
m_currentExecution.get()->forceSetup(bytesRef);
@ -99,15 +102,21 @@ DebuggingContent AssemblyDebuggerModel::getContractInitiationDebugStates(Transac
return d;
}
DebuggingContent AssemblyDebuggerModel::getContractCallDebugStates(Transaction _tr)
DebuggingContent AssemblyDebuggerModel::getContractCallDebugStates(Address _contract, bytes _data,
KeyPair _sender, dev::mix::TransactionSettings _tr)
{
TransactionBuilder trBuilder;
dev::eth::Transaction tr = trBuilder.getBasicTransaction(_tr.value,_tr.gasPrice,_tr.gas, _contract, _data,
m_executiveState.transactionsFrom(dev::toAddress(_sender.secret())), _sender.secret());
m_currentExecution = std::unique_ptr<Executive>(new Executive(m_executiveState));
bytes b = _tr.rlp();
bytes b = tr.rlp();
dev::bytesConstRef bytesRef = &b;
m_currentExecution.get()->forceSetup(bytesRef);
DebuggingContent d = executeTransaction();
d.contractAddress = _tr.receiveAddress();
d.contractAddress = tr.receiveAddress();
m_currentExecution.reset();
return d;
}

6
mix/AssemblyDebuggerModel.h

@ -26,10 +26,10 @@
#include "libethereum/Executive.h"
#include "libdevcore/Common.h"
#include "DebuggingStateWrapper.h"
#include "TransactionListModel.h"
namespace dev
{
namespace mix
{
@ -37,8 +37,8 @@ class AssemblyDebuggerModel
{
public:
AssemblyDebuggerModel();
DebuggingContent getContractInitiationDebugStates(dev::eth::Transaction);
DebuggingContent getContractCallDebugStates(dev::eth::Transaction);
DebuggingContent getContractInitiationDebugStates(bytes code, KeyPair _sender);
DebuggingContent getContractCallDebugStates(Address _contract, bytes _data, KeyPair _sender, dev::mix::TransactionSettings _tr);
void addBalance(KeyPair address, u256 amount);
void resetState();

36
mix/CodeEditorExtensionManager.cpp

@ -28,7 +28,8 @@
#include <libevm/VM.h>
#include "ConstantCompilationCtrl.h"
#include "AssemblyDebuggerCtrl.h"
#include "ApplicationCtx.h"
#include "TransactionListView.h"
#include "AppContext.h"
#include "CodeEditorExtensionManager.h"
using namespace dev::mix;
@ -48,7 +49,17 @@ void CodeEditorExtensionManager::loadEditor(QQuickItem* _editor)
{
QQuickTextDocument* qqdoc = doc.value<QQuickTextDocument*>();
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());
}
}
}
}
catch (...)
@ -60,19 +71,23 @@ void CodeEditorExtensionManager::loadEditor(QQuickItem* _editor)
void CodeEditorExtensionManager::initExtensions()
{
initExtension(std::make_shared<ConstantCompilationCtrl>(m_doc));
initExtension(std::make_shared<AssemblyDebuggerCtrl>(m_doc));
std::shared_ptr<AssemblyDebuggerCtrl> debug = std::make_shared<AssemblyDebuggerCtrl>(m_doc);
std::shared_ptr<TransactionListView> tr = std::make_shared<TransactionListView>(m_doc);
QObject::connect(tr->model(), &TransactionListModel::transactionRan, debug.get(), &AssemblyDebuggerCtrl::runTransaction);
initExtension(debug);
initExtension(tr);
}
void CodeEditorExtensionManager::initExtension(std::shared_ptr<Extension> _ext)
{
if (!_ext.get()->contentUrl().isEmpty())
if (!_ext->contentUrl().isEmpty())
{
try
{
if (_ext.get()->getDisplayBehavior() == ExtensionDisplayBehavior::Tab)
{
_ext.get()->addTabOn(m_tabView);
}
if (_ext->getDisplayBehavior() == ExtensionDisplayBehavior::Tab)
_ext->addTabOn(m_tabView);
else if (_ext->getDisplayBehavior() == ExtensionDisplayBehavior::RightTab)
_ext->addTabOn(m_rightTabView);
}
catch (...)
{
@ -80,7 +95,7 @@ void CodeEditorExtensionManager::initExtension(std::shared_ptr<Extension> _ext)
return;
}
}
_ext.get()->start();
_ext->start();
m_features.append(_ext);
}
@ -90,6 +105,11 @@ void CodeEditorExtensionManager::setEditor(QQuickItem* _editor)
this->initExtensions();
}
void CodeEditorExtensionManager::setRightTabView(QQuickItem* _tabView)
{
m_rightTabView = _tabView;
}
void CodeEditorExtensionManager::setTabView(QQuickItem* _tabView)
{
m_tabView = _tabView;

4
mix/CodeEditorExtensionManager.h

@ -30,7 +30,6 @@
namespace dev
{
namespace mix
{
@ -40,6 +39,7 @@ class CodeEditorExtensionManager: public QObject
Q_PROPERTY(QQuickItem* editor MEMBER m_editor WRITE setEditor)
Q_PROPERTY(QQuickItem* tabView MEMBER m_tabView WRITE setTabView)
Q_PROPERTY(QQuickItem* rightTabView MEMBER m_rightTabView WRITE setRightTabView)
public:
CodeEditorExtensionManager() {}
@ -48,11 +48,13 @@ public:
void initExtension(std::shared_ptr<Extension>);
void setEditor(QQuickItem*);
void setTabView(QQuickItem*);
void setRightTabView(QQuickItem*);
private:
QQuickItem* m_editor;
QVector<std::shared_ptr<Extension>> m_features;
QQuickItem* m_tabView;
QQuickItem* m_rightTabView;
QTextDocument* m_doc;
void loadEditor(QQuickItem*);
};

10
mix/ConstantCompilationCtrl.cpp

@ -27,7 +27,6 @@
#include <QQmlApplicationEngine>
#include <QtCore/QtCore>
#include <QDebug>
#include "ApplicationCtx.h"
#include "ConstantCompilationCtrl.h"
#include "ConstantCompilationModel.h"
#include "QContractDefinition.h"
@ -36,12 +35,7 @@ using namespace dev::mix;
ConstantCompilationCtrl::ConstantCompilationCtrl(QTextDocument* _doc): Extension(ExtensionDisplayBehavior::Tab)
{
m_editor = _doc;
m_compilationModel = new ConstantCompilationModel();
}
ConstantCompilationCtrl::~ConstantCompilationCtrl()
{
delete m_compilationModel;
m_compilationModel = std::unique_ptr<ConstantCompilationModel>(new ConstantCompilationModel());
}
QString ConstantCompilationCtrl::contentUrl() const
@ -67,7 +61,7 @@ void ConstantCompilationCtrl::compile()
resetOutPut();
return;
}
CompilerResult res = m_compilationModel->compile(m_editor->toPlainText().replace("\t", " "));
CompilerResult res = m_compilationModel->compile(m_editor->toPlainText().replace("\t", " "));
writeOutPut(res);
}

7
mix/ConstantCompilationCtrl.h

@ -25,7 +25,6 @@
namespace dev
{
namespace mix
{
@ -35,18 +34,18 @@ class ConstantCompilationCtrl: public Extension
public:
ConstantCompilationCtrl(QTextDocument*);
~ConstantCompilationCtrl();
~ConstantCompilationCtrl() {}
void start() const override;
QString title() const override;
QString contentUrl() const override;
private:
QTextDocument* m_editor;
ConstantCompilationModel* m_compilationModel;
std::unique_ptr<ConstantCompilationModel> m_compilationModel;
void writeOutPut(CompilerResult const&);
void resetOutPut();
public Q_SLOTS:
public slots:
void compile();
};

4
mix/ConstantCompilationModel.cpp

@ -14,7 +14,7 @@
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 ApplicationCtx.h
/** @file ConstantCompilationModel.h
* @author Yann yann@ethdev.com
* @date 2014
* Ethereum IDE client.
@ -52,7 +52,7 @@ CompilerResult ConstantCompilationModel::compile(QString _code)
ostringstream error;
solidity::SourceReferenceFormatter::printExceptionInformation(error, _exception, "Error", compiler.getScanner());
res.success = false;
res.comment = QString::fromStdString(error.str()).toHtmlEscaped();
res.comment = QString::fromStdString(error.str());
res.hexCode = "";
}
catch (...)

5
mix/ConstantCompilationModel.h

@ -14,7 +14,7 @@
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 ApplicationCtx.h
/** @file ConstantCompilationModel.h
* @author Yann yann@ethdev.com
* @date 2014
* Ethereum IDE client.
@ -28,7 +28,6 @@
namespace dev
{
namespace mix
{
@ -46,7 +45,7 @@ class ConstantCompilationModel
public:
ConstantCompilationModel() {}
~ConstantCompilationModel() {}
CompilerResult compile(QString);
CompilerResult compile(QString _code);
};
}

9
mix/ContractCallDataEncoder.cpp

@ -58,6 +58,15 @@ void ContractCallDataEncoder::encode(QVariableDeclaration* _dec, QString _value)
m_encodedData.insert(m_encodedData.end(), data.begin(), data.end());
}
void ContractCallDataEncoder::encode(QVariableDeclaration* _dec, u256 _value)
{
int padding = this->padding(_dec->type());
std::ostringstream s;
s << _value;
bytes data = padded(jsToBytes(s.str()), padding);
m_encodedData.insert(m_encodedData.end(), data.begin(), data.end());
}
QList<QVariableDefinition*> ContractCallDataEncoder::decode(QList<QObject*> _returnParameters, bytes _value)
{
QList<QVariableDefinition*> r;

1
mix/ContractCallDataEncoder.h

@ -35,6 +35,7 @@ class ContractCallDataEncoder
public:
ContractCallDataEncoder();
void encode(QVariableDeclaration* _dec, QString _value);
void encode(QVariableDeclaration* _dec, u256 _value);
QList<QVariableDefinition*> decode(QList<QObject*> _dec, bytes _value);
void encode(QVariableDeclaration* _dec, bool _value);
void encode(int _functionIndex);

72
mix/DebuggingStateWrapper.cpp

@ -14,7 +14,7 @@
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
/** @file DebuggingStateWrapper.cpp
* @author Yann yann@ethdev.com
* @date 2014
* Used to translate c++ type (u256, bytes, ...) into friendly value (to be used by QML).
@ -23,6 +23,8 @@
#include <QDebug>
#include <QString>
#include <QTextStream>
#include "libevmcore/Instruction.h"
#include "libdevcore/CommonJS.h"
#include "libdevcrypto/Common.h"
#include "libevmcore/Instruction.h"
#include "libdevcore/Common.h"
@ -42,12 +44,12 @@ std::tuple<QList<QObject*>, QQMLMap*> DebuggingStateWrapper::getHumanReadableCod
{
QString s = QString::fromStdString(instructionInfo((Instruction)b).name);
std::ostringstream out;
out << std::setw(4) << std::setfill('0') << i;
out << std::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;
unsigned bc = getPushNumber((Instruction)b);
s = "PUSH 0x" + QString::fromStdString(toHex(bytesConstRef(&_code[i + 1], bc)));
i += bc;
}
@ -68,7 +70,7 @@ QString DebuggingStateWrapper::debugStack()
{
QString stack;
for (auto i: m_state.stack)
stack.prepend(prettyU256(i) + "\n");
stack.prepend(QString::fromStdString(prettyU256(i)) + "\n");
return stack;
}
@ -77,7 +79,7 @@ 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();
s << "@" << prettyU256(i.first) << "&nbsp;&nbsp;&nbsp;&nbsp;" << prettyU256(i.second);
return QString::fromStdString(s.str());
}
@ -89,7 +91,6 @@ QString DebuggingStateWrapper::debugMemory()
QString DebuggingStateWrapper::debugCallData()
{
return QString::fromStdString(memDump(m_data, 16, false));
}
@ -102,7 +103,7 @@ QStringList DebuggingStateWrapper::levels()
std::ostringstream out;
out << m_state.cur.abridged();
if (i)
out << " " << instructionInfo(m_state.inst).name << " @0x" << m_state.curPC;
out << " " << instructionInfo(m_state.inst).name << " @0x" << std::hex << m_state.curPC;
levelsStr.append(QString::fromStdString(out.str()));
}
return levelsStr;
@ -111,7 +112,7 @@ QStringList DebuggingStateWrapper::levels()
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;
ss << std::dec << " STEP: " << m_state.steps << " | PC: 0x" << std::hex << m_state.curPC << " : " << dev::eth::instructionInfo(m_state.inst).name << " | ADDMEM: " << std::dec << m_state.newMemSize << " words | COST: " << std::dec << m_state.gasCost << " | GAS: " << std::dec << m_state.gas;
return QString::fromStdString(ss.str());
}
@ -130,60 +131,9 @@ QString DebuggingStateWrapper::endOfDebug()
return "RETURN " + QString::fromStdString(dev::memDump(out, 16, false));
}
else if (m_state.inst == Instruction::STOP)
return "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())));
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" << (uint64_t)_n << ")";
else if (!~(_n >> 64))
s << " " << (int64_t)_n << " (0x" << (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();
}

28
mix/DebuggingStateWrapper.h

@ -14,7 +14,7 @@
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
/** @file DebuggingStateWrapper.h
* @author Yann yann@ethdev.com
* @date 2014
* Ethereum IDE client.
@ -30,7 +30,6 @@
namespace dev
{
namespace mix
{
@ -51,7 +50,7 @@ struct DebuggingState
struct DebuggingContent
{
QList<DebuggingState> states;
QList<DebuggingState> machineStates;
bytes executionCode;
bytesConstRef executionData;
Address contractAddress;
@ -61,7 +60,9 @@ struct DebuggingContent
QList<QVariableDefinition*> returnParameters;
};
/* contains the line nb of the assembly code and the corresponding index in the code bytes array */
/**
* @brief Contains the line nb of the assembly code and the corresponding index in the code bytes array.
*/
class HumanReadableCode: public QObject
{
Q_OBJECT
@ -78,20 +79,25 @@ private:
int m_processIndex;
};
/* used to publish QMap type to QML */
/**
* @brief Publish QMap type to QML.
*/
class QQMLMap: public QObject
{
Q_OBJECT
public:
QQMLMap(QMap<int, int> _map, QObject* _parent): QObject(_parent), m_map(_map) { }
Q_INVOKABLE int getValue(int _key) { return m_map.value(_key); }
QQMLMap(QMap<int, int> _map, QObject* _parent): QObject(_parent), 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 */
/**
* @brief Wrap DebuggingState in QObject
*/
class DebuggingStateWrapper: public QObject
{
Q_OBJECT
@ -108,7 +114,7 @@ class DebuggingStateWrapper: public QObject
Q_PROPERTY(QStringList levels READ levels)
public:
DebuggingStateWrapper(bytes _code, bytes _data) : m_code(_code), m_data(_data) {}
DebuggingStateWrapper(bytes _code, bytes _data, QObject* _parent): QObject(_parent), 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; }
@ -122,14 +128,12 @@ public:
QStringList levels();
DebuggingState state() { return m_state; }
void setState(DebuggingState _state) { m_state = _state; }
static std::tuple<QList<QObject*>, QQMLMap*> getHumanReadableCode(bytes const& code, QObject* _objUsedAsParent);
static std::tuple<QList<QObject*>, QQMLMap*> getHumanReadableCode(bytes const& _code, QObject* _objUsedAsParent);
private:
DebuggingState m_state;
bytes m_code;
bytes m_data;
QString prettyU256(u256 _n);
QString fromRaw(h256 _n, unsigned* _inc = nullptr);
};
}

25
mix/Extension.cpp

@ -21,10 +21,27 @@
#include <QDebug>
#include <libevm/VM.h>
#include "Extension.h"
#include "ApplicationCtx.h"
#include "AppContext.h"
using namespace dev;
using namespace dev::mix;
Extension::Extension()
{
init();
}
Extension::Extension(ExtensionDisplayBehavior _displayBehavior)
{
init();
m_displayBehavior = _displayBehavior;
}
void Extension::init()
{
m_ctx = AppContext::getInstance();
m_appEngine = m_ctx->appEngine();
}
void Extension::addTabOn(QObject* _view)
{
if (contentUrl() == "")
@ -32,7 +49,7 @@ void Extension::addTabOn(QObject* _view)
QVariant returnValue;
QQmlComponent* component = new QQmlComponent(
ApplicationCtx::getInstance()->appEngine(),
AppContext::getInstance()->appEngine(),
QUrl(contentUrl()), _view);
QMetaObject::invokeMethod(_view, "addTab",
@ -48,9 +65,9 @@ void Extension::addContentOn(QObject* _view)
Q_UNUSED(_view);
if (m_displayBehavior == ExtensionDisplayBehavior::ModalDialog)
{
QQmlComponent component(ApplicationCtx::getInstance()->appEngine(), QUrl(contentUrl()));
QQmlComponent component(AppContext::getInstance()->appEngine(), QUrl(contentUrl()));
QObject* dialog = component.create();
QObject* dialogWin = ApplicationCtx::getInstance()->appEngine()->rootObjects().at(0)->findChild<QObject*>("dialog", Qt::FindChildrenRecursively);
QObject* dialogWin = AppContext::getInstance()->appEngine()->rootObjects().at(0)->findChild<QObject*>("dialog", Qt::FindChildrenRecursively);
QMetaObject::invokeMethod(dialogWin, "close");
dialogWin->setProperty("contentItem", QVariant::fromValue(dialog));
dialogWin->setProperty("title", title());

12
mix/Extension.h

@ -21,16 +21,17 @@
#include <QApplication>
#include <QQmlComponent>
#include "AppContext.h"
namespace dev
{
namespace mix
{
enum ExtensionDisplayBehavior
{
Tab,
RightTab,
ModalDialog
};
@ -40,8 +41,8 @@ class Extension: public QObject
Q_OBJECT
public:
Extension() {}
Extension(ExtensionDisplayBehavior _displayBehavior) { m_displayBehavior = _displayBehavior; }
Extension();
Extension(ExtensionDisplayBehavior _displayBehavior);
virtual QString contentUrl() const { return ""; }
virtual QString title() const { return ""; }
virtual void start() const {}
@ -53,6 +54,11 @@ public:
protected:
QObject* m_view;
ExtensionDisplayBehavior m_displayBehavior;
AppContext* m_ctx;
QQmlApplicationEngine* m_appEngine;
private:
void init();
};
}

8
mix/KeyEventManager.h

@ -30,13 +30,13 @@ class KeyEventManager: public QObject
public:
KeyEventManager() {}
void registerEvent(const QObject* receiver, const char* slot);
void unRegisterEvent(QObject* receiver);
void registerEvent(const QObject* _receiver, const char* _slot);
void unRegisterEvent(QObject* _receiver);
signals:
void onKeyPressed(int);
public Q_SLOTS:
void keyPressed(QVariant event);
public slots:
void keyPressed(QVariant _event);
};

1
mix/MixApplication.h

@ -27,7 +27,6 @@
namespace dev
{
namespace mix
{

2
mix/QBasicNodeDefinition.h

@ -39,7 +39,7 @@ public:
~QBasicNodeDefinition() {
}
QBasicNodeDefinition(std::shared_ptr<dev::solidity::Declaration> _d): QObject(), m_dec(_d) {}
QString name() { return QString::fromStdString(m_dec.get()->getName()); }
QString name() const { return QString::fromStdString(m_dec.get()->getName()); }
protected:
std::shared_ptr<dev::solidity::Declaration> m_dec;

6
mix/QContractDefinition.h

@ -34,15 +34,15 @@ namespace mix
class QContractDefinition: public QBasicNodeDefinition
{
Q_OBJECT
Q_PROPERTY(QList<QObject*> functions READ functions)
Q_PROPERTY(QList<QFunctionDefinition*> functions READ functions)
public:
QContractDefinition(std::shared_ptr<dev::solidity::ContractDefinition> _contract);
QList<QObject*> functions() { return m_functions; }
QList<QFunctionDefinition*> functions() const { return m_functions; }
static std::shared_ptr<QContractDefinition> Contract(QString _code);
private:
QList<QObject*> m_functions;
QList<QFunctionDefinition*> m_functions;
void initQFunctions();
};

6
mix/QFunctionDefinition.h

@ -38,9 +38,9 @@ class QFunctionDefinition: public QBasicNodeDefinition
public:
QFunctionDefinition(std::shared_ptr<dev::solidity::FunctionDefinition> _f, int _index): QBasicNodeDefinition(_f), m_index(_index) { initQParameters(); }
QList<QObject*> parameters() { return m_parameters; }
QList<QObject*> returnParameters() { return m_returnParameters; }
int index() { return m_index; }
QList<QObject*> parameters() const { return m_parameters; }
QList<QObject*> returnParameters() const { return m_returnParameters; }
int index() const { return m_index; }
private:
QList<QObject*> m_parameters;

2
mix/QVariableDeclaration.h

@ -36,7 +36,7 @@ class QVariableDeclaration: public QBasicNodeDefinition
public:
QVariableDeclaration(std::shared_ptr<dev::solidity::VariableDeclaration> _v): QBasicNodeDefinition(_v), m_var(_v) {}
QString type() { return QString::fromStdString(m_var.get()->getType()->toString()); }
QString type() const { return QString::fromStdString(m_var.get()->getType()->toString()); }
private:
std::shared_ptr<dev::solidity::VariableDeclaration> m_var;

4
mix/QVariableDefinition.h

@ -38,8 +38,8 @@ class QVariableDefinition: public QObject
public:
QVariableDefinition(QVariableDeclaration* _def, QString _value): QObject(_def->parent()), m_value(_value), m_dec(_def) {}
QVariableDeclaration* declaration() { return m_dec; }
QString value() { return m_value; }
QVariableDeclaration* declaration() const { return m_dec; }
QString value() const { return m_value; }
private:
QVariableDeclaration* m_dec;

63
mix/TransactionBuilder.cpp

@ -18,8 +18,10 @@
*/
#include "libethereum/Executive.h"
#include "libdevcore/CommonJS.h"
#include "libdevcore/Common.h"
#include "ApplicationCtx.h"
#include "AppContext.h"
#include "TransactionListModel.h"
#include "TransactionBuilder.h"
using namespace dev::mix;
using namespace dev::eth;
@ -37,72 +39,25 @@ Transaction TransactionBuilder::getBasicTransaction(u256 _value, u256 _gasPrice,
return Transaction(_value, _gasPrice, _gas, address, _data, _nonce, _secret);
}
Transaction TransactionBuilder::getDefaultCreationTransaction(dev::bytes code, KeyPair sender) const
Transaction TransactionBuilder::getDefaultCreationTransaction(dev::bytes _code, KeyPair _sender, u256 _nonce) const
{
u256 gasPrice = 10000000000000;
u256 gas = 1000000;
u256 amount = 100;
return getCreationTransaction(amount, gasPrice, gas, code, 0, sender.secret());
return getCreationTransaction(amount, gasPrice, gas, _code, _nonce, _sender.secret());
}
Transaction TransactionBuilder::getDefaultBasicTransaction(Address contractAddress, dev::bytes data, KeyPair sender) const
Transaction TransactionBuilder::getDefaultBasicTransaction(Address _contractAddress, dev::bytes _data, KeyPair _sender, u256 _nonce) const
{
u256 gasPrice = 10000000000000;
u256 gas = 1000000;
u256 amount = 100;
return getBasicTransaction(amount, gasPrice, gas, contractAddress, data, 0, sender.secret());
return getBasicTransaction(amount, gasPrice, gas, _contractAddress, _data, _nonce, _sender.secret());
}
int TransactionBuilder::fromHex(char _i) const
Transaction TransactionBuilder::getTransaction(Address _contractAddress, dev::bytes _data, KeyPair _sender, u256 _nonce, dev::mix::TransactionSettings _tr)
{
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));
return getBasicTransaction(_tr.value, _tr.gasPrice, _tr.gas, _contractAddress, _data, _nonce, _sender.secret());
}
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.
}

7
mix/TransactionBuilder.h

@ -22,10 +22,10 @@
#include <QString>
#include "libdevcore/Common.h"
#include "libethereum/Transaction.h"
#include "TransactionListModel.h"
namespace dev
{
namespace mix
{
@ -37,8 +37,9 @@ public:
dev::Address 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;
dev::eth::Transaction getDefaultCreationTransaction(dev::bytes code, KeyPair sender) const;
dev::eth::Transaction getDefaultBasicTransaction(dev::Address contractAddress, dev::bytes data, KeyPair sender) const;
dev::eth::Transaction getDefaultCreationTransaction(dev::bytes code, KeyPair sender, dev::u256 _nonce) const;
dev::eth::Transaction getDefaultBasicTransaction(dev::Address contractAddress, dev::bytes data, KeyPair sender, dev::u256 _nonce) const;
dev::eth::Transaction getTransaction(Address _contractAddress, dev::bytes _data, KeyPair _sender, u256 _nonce, dev::mix::TransactionSettings _tr);
private:
bytes fromHex(std::string const& _s) const;

217
mix/TransactionListModel.cpp

@ -0,0 +1,217 @@
/*
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 TransactionListModel.cpp
* @author Arkadiy Paronyan arkadiy@ethdev.com
* @date 2014
* Ethereum IDE client.
*/
#include <QObject>
#include <QQmlEngine>
#include <QTextDocument>
#include <QAbstractListModel>
#include "TransactionListModel.h"
#include "QContractDefinition.h"
#include "QFunctionDefinition.h"
#include "QVariableDeclaration.h"
#include "libdevcore/CommonJS.h"
namespace dev
{
namespace mix
{
u256 fromQString(QString const& _s)
{
return dev::jsToU256(_s.toStdString());
}
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, QTextDocument* _document):
QAbstractListModel(_parent), m_document(_document)
{}
QHash<int, QByteArray> TransactionListModel::roleNames() const
{
QHash<int, QByteArray> 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<TransactionParameterItem*> buildParameters(QTextDocument* _document, TransactionSettings const& _transaction, QString const& _functionId)
{
QList<TransactionParameterItem*> params;
try
{
QString code = _document->toPlainText().replace("\n", ""); //TODO: is this required?
std::shared_ptr<QContractDefinition> contract = QContractDefinition::Contract(code);
auto functions = contract->functions();
for(auto qf : functions)
{
QFunctionDefinition const& f = (QFunctionDefinition const&) *qf;
if (f.name() != _functionId)
continue;
auto parameters = f.parameters();
for(auto qp : parameters)
{
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);
}
}
}
catch (boost::exception const&)
{
//TODO:
}
return params;
}
//TODO: get fnctions from code model
QList<QString> TransactionListModel::getFunctions()
{
QList<QString> functionNames;
try
{
QString code = m_document->toPlainText().replace("\n", ""); //TODO: is this required?
std::shared_ptr<QContractDefinition> 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&)
{
}
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_document, transaction, _functionId);
QVariantList vl;
for(QObject* p : plist)
vl.append(QVariant::fromValue(p));
return vl;
}
QObject* 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
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<QAbstractListModel*>(_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 transactionAdded();
emit countChanged();
endInsertRows();
}
int TransactionListModel::getCount() const
{
return rowCount(QModelIndex());
}
void TransactionListModel::runTransaction(int _index)
{
TransactionSettings tr = m_transactions.at(_index);
emit transactionRan(tr);
}
}
}

165
mix/TransactionListModel.h

@ -0,0 +1,165 @@
/*
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 TransactionListView.h
* @author Arkadiy Paronyan arkadiy@ethdev.com
* @date 2014
* Ethereum IDE client.
*/
#pragma once
#include <QObject>
#include <QVariant>
#include <QAbstractListModel>
#include <QHash>
#include <QByteArray>
#include <libdevcore/Common.h>
class QTextDocument;
namespace dev
{
namespace mix
{
/// Backend transaction config class
struct TransactionSettings
{
TransactionSettings():
value(0), gas(10000), gasPrice(10) {}
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<QString, u256> 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, QTextDocument* _document);
~TransactionListModel() {}
QHash<int, QByteArray> 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 QObject* getItem(int _index);
/// @returns a list of functions for current contract
Q_INVOKABLE QList<QString> getFunctions();
/// @returns function parameters along with parameter values if set. @see TransactionParameterItem
Q_INVOKABLE QVariantList getParameters(int _id, QString const& _functionId);
Q_INVOKABLE void runTransaction(int _index);
signals:
void transactionAdded();
void countChanged();
void transactionRan(dev::mix::TransactionSettings);
private:
std::vector<TransactionSettings> m_transactions;
QTextDocument* m_document;
};
}
}

56
mix/TransactionListView.cpp

@ -0,0 +1,56 @@
/*
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 TransactionListView.cpp
* @author Arkadiy Paronyan arkadiy@ethdev.com
* @date 2014
* Ethereum IDE client.
*/
#include <QQuickItem>
#include <QApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QDebug>
#include "TransactionListView.h"
#include "TransactionListModel.h"
using namespace dev::mix;
TransactionListView::TransactionListView(QTextDocument* _doc): Extension(ExtensionDisplayBehavior::RightTab)
{
m_editor = _doc;
m_model.reset(new TransactionListModel(this, _doc));
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
{
return QStringLiteral("qrc:/qml/TransactionList.qml");
}
QString TransactionListView::title() const
{
return QApplication::tr("Transactions");
}
void TransactionListView::start() const
{
}

56
mix/TransactionListView.h

@ -0,0 +1,56 @@
/*
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 TransactionListView.h
* @author Arkadiy Paronyan arkadiy@ethdev.com
* @date 2014
* Ethereum IDE client.
*/
#pragma once
#include <QTextDocument>
#include "TransactionListView.h"
#include "Extension.h"
namespace dev
{
namespace mix
{
class TransactionListModel;
/// Transactions list control
/// @todo This should be moved into state as a sequence
class TransactionListView: public Extension
{
Q_OBJECT
public:
TransactionListView(QTextDocument*);
~TransactionListView();
void start() const override;
QString title() const override;
QString contentUrl() const override;
TransactionListModel* model() const { return m_model.get(); }
private:
QTextDocument* m_editor;
std::unique_ptr<TransactionListModel> m_model;
public slots:
};
}
}

8
mix/main.cpp

@ -24,7 +24,7 @@
#include <QQmlApplicationEngine>
#include <QQuickItem>
#include "CodeEditorExtensionManager.h"
#include "ApplicationCtx.h"
#include "AppContext.h"
#include "MixApplication.h"
using namespace dev::mix;
@ -33,11 +33,11 @@ int main(int _argc, char *_argv[])
QApplication app(_argc, _argv);
qmlRegisterType<CodeEditorExtensionManager>("CodeEditorExtensionManager", 1, 0, "CodeEditorExtensionManager");
QQmlApplicationEngine* engine = new QQmlApplicationEngine();
ApplicationCtx::setApplicationContext(engine);
QObject::connect(&app, SIGNAL(lastWindowClosed()), ApplicationCtx::getInstance(), SLOT(quitApplication())); //use to kill ApplicationContext and other stuff
AppContext::setApplicationContext(engine);
QObject::connect(&app, SIGNAL(lastWindowClosed()), AppContext::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.
AppContext::getInstance()->initKeyEventManager(); //has to be called after the loading of the main view.
return app.exec();
}

2
mix/qml.qrc

@ -7,5 +7,7 @@
<file>qml/Debugger.qml</file>
<file>qml/js/Debugger.js</file>
<file>qml/BasicMessage.qml</file>
<file>qml/TransactionDialog.qml</file>
<file>qml/TransactionList.qml</file>
</qresource>
</RCC>

8
mix/qml/BasicContent.qml

@ -7,13 +7,13 @@ Rectangle {
height: parent.height
color: "lightgray"
Text {
font.pointSize: 7
font.pointSize: 9
anchors.left: parent.left
anchors.top: parent.top
anchors.topMargin: 3
anchors.leftMargin: 3
height: 9
font.family: "Sego UI light"
font.family: "Monospace"
objectName: "status"
id: status
}
@ -23,8 +23,8 @@ Rectangle {
anchors.leftMargin: 10
anchors.top: status.bottom
anchors.topMargin: 3
font.pointSize: 7
font.family: "Sego UI light"
font.pointSize: 9
font.family: "Monospace"
height: parent.height * 0.8
width: parent.width - 20
wrapMode: Text.Wrap

2
mix/qml/BasicMessage.qml

@ -1,4 +1,4 @@
import QtQuick 2.3
import QtQuick 2.2
import QtQuick.Controls.Styles 1.2
import QtQuick.Controls 1.2
import QtQuick.Dialogs 1.2

2
mix/qml/Debugger.qml

@ -1,4 +1,4 @@
import QtQuick 2.3
import QtQuick 2.2
import QtQuick.Controls.Styles 1.2
import QtQuick.Controls 1.2
import QtQuick.Dialogs 1.2

107
mix/qml/MainContent.qml

@ -1,4 +1,4 @@
import QtQuick 2.3
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.0
import QtQuick.Controls.Styles 1.2
@ -16,47 +16,66 @@ Rectangle {
anchors.fill: parent
height: parent.height
width: parent.width;
id:root
SplitView {
anchors.fill: parent
orientation: Qt.Vertical
Rectangle {
anchors.top: parent.top
id: contentView
width: parent.width
height: parent.height * 0.7
TextArea {
id: codeEditor
height: parent.height
font.family: "Verdana"
font.pointSize: 9
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
id: contextualView
width: parent.width
Layout.minimumHeight: 20
height: parent.height * 0.3
TabView {
id: contextualTabs
antialiasing: true
anchors.fill: parent
style: TabStyle {}
}
}
CodeEditorExtensionManager {
tabView: contextualTabs
editor: codeEditor
}
}
id:root
SplitView {
orientation: Qt.Horizontal
anchors.fill: parent
SplitView {
//anchors.fill: parent
width: parent.width * 0.8
orientation: Qt.Vertical
Rectangle {
anchors.top: parent.top
id: contentView
width: parent.width
height: parent.height * 0.7
TextArea {
id: codeEditor
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
id: contextualView
width: parent.width
Layout.minimumHeight: 20
height: parent.height * 0.3
TabView {
id: contextualTabs
antialiasing: true
anchors.fill: parent
style: TabStyle {}
}
}
}
Rectangle {
anchors.right: parent.right
id: rightPaneView
width: parent.width * 0.2
height: parent.height
Layout.minimumWidth: 20
TabView {
id: rightPaneTabs
antialiasing: true
anchors.fill: parent
//style: TabStyle {}
}
}
CodeEditorExtensionManager {
tabView: contextualTabs
rightTabView: rightPaneTabs
editor: codeEditor
}
}
}

187
mix/qml/TransactionDialog.qml

@ -0,0 +1,187 @@
import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.1
import QtQuick.Window 2.0
Dialog {
modality: Qt.WindowModal
standardButtons: StandardButton.Ok | StandardButton.Cancel
width:640
height:480
property alias focus : titleField.focus
property alias transactionTitle : titleField.text
property int transactionIndex
property alias transactionParams : paramsModel;
property alias gas : gasField.text;
property alias gasPrice : gasPriceField.text;
property alias transactionValue : valueField.text;
property alias functionId : functionComboBox.currentText;
property var model;
function reset(index, m) {
model = m;
var item = model.getItem(index);
transactionIndex = index;
transactionTitle = item.title;
gas = item.gas;
gasPrice = item.gasPrice;
transactionValue = item.value;
var functionId = item.functionId;
functionsModel.clear();
var functionIndex = -1;
var functions = model.getFunctions();
for (var f = 0; f < functions.length; f++) {
functionsModel.append({ text: functions[f] });
if (functions[f] === item.functionId)
functionIndex = f;
}
functionComboBox.currentIndex = functionIndex;
}
function loadParameters() {
if (!paramsModel)
return;
paramsModel.clear();
if (functionComboBox.currentIndex >= 0 && functionComboBox.currentIndex < functionsModel.count) {
var parameters = model.getParameters(transactionIndex, functionsModel.get(functionComboBox.currentIndex).text);
for (var p = 0; p < parameters.length; p++) {
paramsModel.append({ name: parameters[p].name, type: parameters[p].type, value: parameters[p].value });
}
}
}
GridLayout {
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("Function")
}
ComboBox {
id: functionComboBox
Layout.fillWidth: true
currentIndex: -1
textRole: "text"
editable: false
model: ListModel {
id: functionsModel
}
onCurrentIndexChanged: {
loadParameters();
}
}
Label {
text: qsTr("Value")
}
TextField {
id: valueField
Layout.fillWidth: true
}
Label {
text: qsTr("Gas")
}
TextField {
id: gasField
Layout.fillWidth: true
}
Label {
text: qsTr("Gas price")
}
TextField {
id: gasPriceField
Layout.fillWidth: true
}
Label {
text: qsTr("Parameters")
}
TableView {
model: paramsModel
Layout.fillWidth: true
TableViewColumn {
role: "name"
title: "Name"
width: 120
}
TableViewColumn {
role: "type"
title: "Type"
width: 120
}
TableViewColumn {
role: "value"
title: "Value"
width: 120
}
itemDelegate: {
return editableDelegate;
}
}
}
ListModel {
id: paramsModel
}
Component {
id: editableDelegate
Item {
Text {
width: parent.width
anchors.margins: 4
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
elide: styleData.elideMode
text: styleData.value !== undefined ? styleData.value : ""
color: styleData.textColor
visible: !styleData.selected
}
Loader {
id: loaderEditor
anchors.fill: parent
anchors.margins: 4
Connections {
target: loaderEditor.item
onTextChanged: {
paramsModel.setProperty(styleData.row, styleData.role, loaderEditor.item.text);
}
}
sourceComponent: (styleData.selected /*&& styleData.role === "value"*/) ? editor : null
Component {
id: editor
TextInput {
id: textinput
color: styleData.textColor
text: styleData.value
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: textinput.forceActiveFocus()
}
}
}
}
}
}
}

89
mix/qml/TransactionList.qml

@ -0,0 +1,89 @@
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: transactionListContainer
focus: true
anchors.topMargin: 10
anchors.left: parent.left
height: parent.height
width: parent.width
ListView {
anchors.top: parent.top
height: parent.height
width: parent.width
id: transactionList
model: transactionListModel
delegate: renderDelegate
}
Button {
anchors.bottom: parent.bottom
text: qsTr("Add")
onClicked:
{
// 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);
transactionDialog.open();
transactionDialog.focus = true;
}
}
TransactionDialog {
id: transactionDialog
onAccepted: {
transactionListModel.edit(transactionDialog);
}
}
Component {
id: renderDelegate
Item {
id: wrapperItem
height: 20
width: parent.width
RowLayout
{
anchors.fill: parent
Text {
//anchors.fill: parent
Layout.fillWidth: true
Layout.fillHeight: true
text: title
font.pointSize: 12
verticalAlignment: Text.AlignBottom
}
ToolButton {
text: qsTr("Edit");
Layout.fillHeight: true
onClicked: {
transactionDialog.reset(index, transactionListModel);
transactionDialog.open();
transactionDialog.focus = true;
}
}
ToolButton {
text: qsTr("Delete");
Layout.fillHeight: true
onClicked: {
}
}
ToolButton {
text: qsTr("Run");
Layout.fillHeight: true
onClicked: {
transactionListModel.runTransaction(index);
}
}
}
}
}
}

10
mix/qml/main.qml

@ -9,8 +9,6 @@ import CodeEditorExtensionManager 1.0
ApplicationWindow {
id: mainApplication
visible: true
x: Screen.width / 2 - width / 2
y: Screen.height / 2 - height / 2
width: 1200
height: 600
minimumWidth: 400
@ -26,13 +24,15 @@ ApplicationWindow {
}
}
}
Component.onCompleted: {
setX(Screen.width / 2 - width / 2);
setY(Screen.height / 2 - height / 2);
}
MainContent {
}
Dialog {
x: mainApplication.x + (mainApplication.width - width) / 2
y: mainApplication.y + (mainApplication.height - height) / 2
objectName: "dialog"
id: dialog
height: 400
@ -44,8 +44,6 @@ ApplicationWindow {
}
Dialog {
x: mainApplication.x + (mainApplication.width - width) / 2
y: mainApplication.y + (mainApplication.height - height) / 2
objectName: "messageDialog"
id: messageDialog
height: 150

Loading…
Cancel
Save