Browse Source

Merge pull request #2359 from yann300/event_watcher

Mix - events and watchers panel
cl-refactor
Arkadiy Paronyan 10 years ago
parent
commit
d9d073be5a
  1. 42
      mix/ClientModel.cpp
  2. 14
      mix/ClientModel.h
  3. 2
      mix/CodeModel.cpp
  4. 2
      mix/qml.qrc
  5. 244
      mix/qml/Block.qml
  6. 84
      mix/qml/BlockChain.qml
  7. 134
      mix/qml/KeyValuePanel.qml
  8. 2
      mix/qml/MainContent.qml
  9. 124
      mix/qml/ScenarioExecution.qml
  10. 9
      mix/qml/ScenarioLoader.qml
  11. 3
      mix/qml/StateListModel.qml
  12. 7
      mix/qml/TransactionDialog.qml
  13. 203
      mix/qml/Watchers.qml
  14. 5
      mix/res.qrc

42
mix/ClientModel.cpp

@ -206,6 +206,21 @@ QVariantList ClientModel::gasCosts() const
return res;
}
void ClientModel::addAccount(QString const& _secret)
{
KeyPair key(Secret(_secret.toStdString()));
m_accountsSecret.push_back(key);
Address address = key.address();
m_accounts[address] = Account(u256(0), Account::NormalCreation);
m_ethAccounts->setAccounts(m_accountsSecret);
}
QString ClientModel::resolveAddress(QString const& _secret)
{
KeyPair key(Secret(_secret.toStdString()));
return "0x" + QString::fromStdString(key.address().hex());
}
void ClientModel::setupScenario(QVariantMap _scenario)
{
onStateReset();
@ -336,6 +351,7 @@ void ClientModel::executeSequence(vector<TransactionSettings> const& _sequence)
if (!transaction.isFunctionCall)
{
callAddress(Address(address.toStdString()), bytes(), transaction);
onNewTransaction();
continue;
}
@ -674,7 +690,7 @@ RecordLogEntry* ClientModel::lastBlock() const
strGas << blockInfo.gasUsed;
stringstream strNumber;
strNumber << blockInfo.number;
RecordLogEntry* record = new RecordLogEntry(0, QString::fromStdString(strNumber.str()), tr(" - Block - "), tr("Hash: ") + QString(QString::fromStdString(dev::toHex(blockInfo.hash().ref()))), QString(), QString(), QString(), false, RecordLogEntry::RecordType::Block, QString::fromStdString(strGas.str()), QString(), tr("Block"), QVariantMap(), QVariantList());
RecordLogEntry* record = new RecordLogEntry(0, QString::fromStdString(strNumber.str()), tr(" - Block - "), tr("Hash: ") + QString(QString::fromStdString(dev::toHex(blockInfo.hash().ref()))), QString(), QString(), QString(), false, RecordLogEntry::RecordType::Block, QString::fromStdString(strGas.str()), QString(), tr("Block"), QVariantMap(), QVariantMap(), QVariantList());
QQmlEngine::setObjectOwnership(record, QQmlEngine::JavaScriptOwnership);
return record;
}
@ -735,6 +751,7 @@ void ClientModel::onNewTransaction()
Address contractAddress = (bool)tr.address ? tr.address : tr.contractAddress;
auto contractAddressIter = m_contractNames.find(contractAddress);
QVariantMap inputParameters;
QVariantMap returnParameters;
QVariantList logs;
if (contractAddressIter != m_contractNames.end())
{
@ -754,6 +771,11 @@ void ClientModel::onNewTransaction()
returned += "(";
returned += returnValues.join(", ");
returned += ")";
QStringList returnParams = encoder.decode(funcDef->returnParameters(), tr.result.output);
for (int k = 0; k < returnParams.length(); ++k)
returnParameters.insert(funcDef->returnParameters().at(k)->name(), returnParams.at(k));
bytes data = tr.inputParameters;
data.erase(data.begin(), data.begin() + 4);
QStringList parameters = encoder.decode(funcDef->parametersList(), data);
@ -837,9 +859,25 @@ void ClientModel::onNewTransaction()
}
RecordLogEntry* log = new RecordLogEntry(recordIndex, transactionIndex, contract, function, value, address, returned, tr.isCall(), RecordLogEntry::RecordType::Transaction,
gasUsed, sender, label, inputParameters, logs);
gasUsed, sender, label, inputParameters, returnParameters, logs);
QQmlEngine::setObjectOwnership(log, QQmlEngine::JavaScriptOwnership);
emit newRecord(log);
// retrieving all accounts balance
QVariantMap state;
QVariantMap accountBalances;
for (auto const& ctr : m_contractAddresses)
{
u256 wei = m_client->balanceAt(ctr.second, PendingBlock);
accountBalances.insert("0x" + QString::fromStdString(ctr.second.hex()), QEther(wei, QEther::Wei).format());
}
for (auto const& account : m_accounts)
{
u256 wei = m_client->balanceAt(account.first, PendingBlock);
accountBalances.insert("0x" + QString::fromStdString(account.first.hex()), QEther(wei, QEther::Wei).format());
}
state.insert("accounts", accountBalances);
emit newState(recordIndex, state);
}
}

14
mix/ClientModel.h

@ -32,6 +32,7 @@
#include <QVariableDeclaration.h>
#include <libethereum/Account.h>
#include "MachineStates.h"
#include "QEther.h"
namespace dev
{
@ -115,6 +116,8 @@ class RecordLogEntry: public QObject
Q_PROPERTY(QString label MEMBER m_label CONSTANT)
/// input parameters
Q_PROPERTY(QVariantMap parameters MEMBER m_inputParameters CONSTANT)
/// return parameters
Q_PROPERTY(QVariantMap returnParameters MEMBER m_returnParameters CONSTANT)
/// logs
Q_PROPERTY(QVariantList logs MEMBER m_logs CONSTANT)
@ -128,9 +131,9 @@ public:
RecordLogEntry():
m_recordIndex(0), m_call(false), m_type(RecordType::Transaction) {}
RecordLogEntry(unsigned _recordIndex, QString _transactionIndex, QString _contract, QString _function, QString _value, QString _address, QString _returned, bool _call, RecordType _type, QString _gasUsed,
QString _sender, QString _label, QVariantMap _inputParameters, QVariantList _logs):
QString _sender, QString _label, QVariantMap _inputParameters, QVariantMap _returnParameters, QVariantList _logs):
m_recordIndex(_recordIndex), m_transactionIndex(_transactionIndex), m_contract(_contract), m_function(_function), m_value(_value), m_address(_address), m_returned(_returned), m_call(_call), m_type(_type), m_gasUsed(_gasUsed),
m_sender(_sender), m_label(_label), m_inputParameters(_inputParameters), m_logs(_logs) {}
m_sender(_sender), m_label(_label), m_inputParameters(_inputParameters), m_returnParameters(_returnParameters), m_logs(_logs) {}
private:
unsigned m_recordIndex;
@ -146,6 +149,7 @@ private:
QString m_sender;
QString m_label;
QVariantMap m_inputParameters;
QVariantMap m_returnParameters;
QVariantList m_logs;
};
@ -183,6 +187,10 @@ public:
Q_INVOKABLE QString encodeStringParam(QString const& _param);
/// To Hex number
Q_INVOKABLE QString toHex(QString const& _int);
/// Add new account to the model
Q_INVOKABLE void addAccount(QString const& _secret);
/// Return the address associated with the current secret
Q_INVOKABLE QString resolveAddress(QString const& _secret);
public slots:
/// Setup scenario, run transaction sequence, show debugger for the last transaction
@ -236,6 +244,8 @@ signals:
void newRecord(RecordLogEntry* _r);
/// State (transaction log) cleared
void stateCleared();
/// new state has been processed
void newState(unsigned _record, QVariantMap _accounts);
private:
RecordLogEntry* lastBlock() const;

2
mix/CodeModel.cpp

@ -543,7 +543,7 @@ void CodeModel::retrieveSubType(SolidityType& _wrapperType, dev::solidity::Type
SolidityType CodeModel::nodeType(dev::solidity::Type const* _type)
{
SolidityType r { SolidityType::Type::UnsignedInteger, 32, 1, false, false, QString::fromStdString(_type->toString()), std::vector<SolidityDeclaration>(), std::vector<QString>(), nullptr };
SolidityType r { SolidityType::Type::UnsignedInteger, 32, 1, false, false, QString::fromStdString(_type->toString(true)), std::vector<SolidityDeclaration>(), std::vector<QString>(), nullptr };
if (!_type)
return r;
switch (_type->getCategory())

2
mix/qml.qrc

@ -69,5 +69,7 @@
<file>qml/ScenarioExecution.qml</file>
<file>qml/ScenarioLoader.qml</file>
<file>qml/ScenarioButton.qml</file>
<file>qml/Watchers.qml</file>
<file>qml/KeyValuePanel.qml</file>
</qresource>
</RCC>

244
mix/qml/Block.qml

@ -22,6 +22,7 @@ ColumnLayout
property int blockIndex
property variant scenario
property string labelColor: "#414141"
signal txSelected(var txIndex)
function calculateHeight()
{
@ -36,6 +37,14 @@ ColumnLayout
return trHeight
}
function editTx(txIndex)
{
transactionDialog.stateAccounts = scenario.accounts
transactionDialog.execute = false
transactionDialog.editMode = true
transactionDialog.open(txIndex, blockIndex, transactions.get(txIndex))
}
onOpenedTrChanged:
{
Layout.preferredHeight = calculateHeight()
@ -156,11 +165,11 @@ ColumnLayout
Image {
anchors.top: parent.top
anchors.left: parent.left
anchors.leftMargin: -9
anchors.topMargin: -9
anchors.leftMargin: -4
anchors.topMargin: 0
id: saveStatusImage
source: "qrc:/qml/img/recyclediscard@2x.png"
width: statusWidth + 20
width: statusWidth + 10
fillMode: Image.PreserveAspectFit
}
@ -194,185 +203,125 @@ ColumnLayout
Rectangle
{
Layout.preferredWidth: blockWidth
Layout.preferredHeight: parent.height
Layout.preferredHeight: trHeight
height: trHeight
color: "#DEDCDC"
id: rowContentTr
anchors.top: parent.top
property bool selected: false
Connections
{
target: blockChainPanel
onTxSelected: {
if (root.blockIndex !== blockIndex || index !== txIndex)
rowContentTr.deselect()
}
}
function deselect()
{
rowContentTr.selected = false
rowContentTr.color = "#DEDCDC"
hash.color = labelColor
func.color = labelColor
}
MouseArea
{
anchors.fill: parent
onClicked: {
if (!rowContentTr.selected)
{
rowContentTr.selected = true
rowContentTr.color = "#4F4F4F"
hash.color = "#EAB920"
func.color = "#EAB920"
txSelected(index)
}
else
rowContentTr.deselect()
}
onDoubleClicked:
{
transactionDialog.stateAccounts = scenario.accounts
transactionDialog.execute = false
transactionDialog.open(index, blockIndex, transactions.get(index))
root.editTx(index)
}
}
ColumnLayout
RowLayout
{
anchors.top: parent.top
width: parent.width
spacing: 20
RowLayout
Layout.fillWidth: true
Layout.preferredHeight: trHeight - 10
anchors.verticalCenter: parent.verticalCenter
Rectangle
{
anchors.top: parent.top
Layout.fillWidth: true
Rectangle
Layout.preferredWidth: fromWidth
anchors.left: parent.left
anchors.leftMargin: horizontalMargin
Text
{
Layout.preferredWidth: fromWidth
anchors.left: parent.left
anchors.leftMargin: horizontalMargin
Text
{
id: hash
width: parent.width - 30
elide: Text.ElideRight
anchors.verticalCenter: parent.verticalCenter
maximumLineCount: 1
color: labelColor
font.pointSize: dbgStyle.absoluteSize(1)
font.bold: true
text: {
if (index >= 0)
return transactions.get(index).sender
else
return ""
}
}
}
Rectangle
{
Layout.preferredWidth: toWidth
Text
{
id: func
text: {
if (index >= 0)
parent.parent.userFrienldyToken(transactions.get(index).label)
else
return ""
}
elide: Text.ElideRight
anchors.verticalCenter: parent.verticalCenter
color: labelColor
font.pointSize: dbgStyle.absoluteSize(1)
font.bold: true
maximumLineCount: 1
width: parent.width
}
}
function userFrienldyToken(value)
{
if (value && value.indexOf("<") === 0)
{
if (value.split("> ")[1] === " - ")
return value.split(" - ")[0].replace("<", "")
id: hash
width: parent.width - 30
elide: Text.ElideRight
anchors.verticalCenter: parent.verticalCenter
maximumLineCount: 1
color: labelColor
font.pointSize: dbgStyle.absoluteSize(1)
font.bold: true
text: {
if (index >= 0)
return clientModel.resolveAddress(transactions.get(index).sender)
else
return value.split(" - ")[0].replace("<", "") + "." + value.split("> ")[1] + "()";
}
else
return value
}
Rectangle
{
Layout.preferredWidth: valueWidth
Text
{
id: returnValue
elide: Text.ElideRight
anchors.verticalCenter: parent.verticalCenter
maximumLineCount: 1
color: labelColor
font.bold: true
font.pointSize: dbgStyle.absoluteSize(1)
width: parent.width - 30
text: {
if (index >= 0 && transactions.get(index).returned)
return transactions.get(index).returned
else
return ""
}
return ""
}
}
}
Rectangle
Rectangle
{
Layout.preferredWidth: toWidth
Text
{
Layout.preferredWidth: logsWidth
Layout.preferredHeight: trHeight - 10
width: logsWidth
color: "transparent"
Text
{
id: logs
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: 10
color: labelColor
font.bold: true
font.pointSize: dbgStyle.absoluteSize(1)
text: {
if (index >= 0 && transactions.get(index).logs && transactions.get(index).logs.count)
return transactions.get(index).logs.count
else
return ""
}
}
MouseArea {
anchors.fill: parent
onClicked: {
rowTransaction.displayContent();
}
id: func
text: {
if (index >= 0)
parent.parent.userFrienldyToken(transactions.get(index).label)
else
return ""
}
elide: Text.ElideRight
anchors.verticalCenter: parent.verticalCenter
color: labelColor
font.pointSize: dbgStyle.absoluteSize(1)
font.bold: true
maximumLineCount: 1
width: parent.width
}
}
RowLayout
function userFrienldyToken(value)
{
id: rowDetailedContent
visible: false
Layout.preferredHeight:{
if (index >= 0 && transactions.get(index).logs)
return 100 * transactions.get(index).logs.count
else
return 100
}
onVisibleChanged:
if (value && value.indexOf("<") === 0)
{
var lognb = transactions.get(index).logs.count
if (visible)
{
rowContentTr.Layout.preferredHeight = trHeight + 100 * lognb
openedTr += 100 * lognb
}
if (value.split("> ")[1] === " - ")
return value.split(" - ")[0].replace("<", "")
else
{
rowContentTr.Layout.preferredHeight = trHeight
openedTr -= 100 * lognb
}
return value.split(" - ")[0].replace("<", "") + "." + value.split("> ")[1] + "()";
}
Text {
anchors.left: parent.left
anchors.leftMargin: horizontalMargin
id: logsText
}
}
else
return value
}
}
}
Rectangle
{
width: debugActionWidth
height: trHeight
anchors.left: rowContentTr.right
anchors.topMargin: -6
height: trHeight - 10
anchors.right: rowContentTr.right
anchors.top: rowContentTr.top
anchors.leftMargin: -50
anchors.rightMargin: 10
color: "transparent"
Image {
@ -380,7 +329,6 @@ ColumnLayout
source: "qrc:/qml/img/rightarrow@2x.png"
width: debugActionWidth
fillMode: Image.PreserveAspectFit
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
visible: transactions.get(index).recordIndex !== undefined
}

84
mix/qml/BlockChain.qml

@ -13,12 +13,18 @@ import "."
ColumnLayout {
id: blockChainPanel
property alias trDialog: transactionDialog
property alias blockChainRepeater: blockChainRepeater
property variant model
property var states: ({})
spacing: 0
property int previousWidth
property variant debugTrRequested: []
signal chainChanged
signal chainReloaded
signal txSelected(var blockIndex, var txIndex)
signal rebuilding
signal accountAdded(string address, string amount)
Connections
{
@ -40,20 +46,23 @@ ColumnLayout {
var minWidth = scenarioMinWidth - 20 // margin
if (width <= minWidth || previousWidth <= minWidth)
{
fromWidth = 100
toWidth = 100
valueWidth = 200
fromWidth = 250
toWidth = 240
}
else
{
var diff = (width - previousWidth) / 3;
fromWidth = fromWidth + diff < 100 ? 100 : fromWidth + diff
toWidth = toWidth + diff < 100 ? 100 : toWidth + diff
valueWidth = valueWidth + diff < 200 ? 200 : valueWidth + diff
fromWidth = fromWidth + diff < 250 ? 250 : fromWidth + diff
toWidth = toWidth + diff < 240 ? 240 : toWidth + diff
}
previousWidth = width
}
function getState(record)
{
return states[record]
}
function load(scenario)
{
if (!scenario)
@ -61,6 +70,7 @@ ColumnLayout {
if (model)
rebuild.startBlinking()
model = scenario
states = []
blockModel.clear()
for (var b in model.blocks)
blockModel.append(model.blocks[b])
@ -68,10 +78,8 @@ ColumnLayout {
}
property int statusWidth: 30
property int fromWidth: 150
property int toWidth: 100
property int valueWidth: 200
property int logsWidth: 40
property int fromWidth: 250
property int toWidth: 240
property int debugActionWidth: 40
property int horizontalMargin: 10
property int cellSpacing: 10
@ -80,7 +88,7 @@ ColumnLayout {
{
id: header
spacing: 0
Layout.preferredHeight: 30
Layout.preferredHeight: 24
Rectangle
{
Layout.preferredWidth: statusWidth
@ -91,12 +99,13 @@ ColumnLayout {
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
source: "qrc:/qml/img/recycleicon@2x.png"
width: statusWidth + 20
width: statusWidth + 10
fillMode: Image.PreserveAspectFit
}
}
Rectangle
{
anchors.verticalCenter: parent.verticalCenter
Layout.preferredWidth: fromWidth
Label
{
@ -109,21 +118,13 @@ ColumnLayout {
Label
{
text: "To"
anchors.verticalCenter: parent.verticalCenter
Layout.preferredWidth: toWidth + cellSpacing
}
Label
{
text: "Value"
Layout.preferredWidth: valueWidth + cellSpacing
}
Label
{
text: "Logs"
Layout.preferredWidth: logsWidth + cellSpacing
}
Label
{
text: ""
anchors.verticalCenter: parent.verticalCenter
Layout.preferredWidth: debugActionWidth
}
}
@ -162,8 +163,22 @@ ColumnLayout {
{
id: blockChainRepeater
model: blockModel
function editTx(blockIndex, txIndex)
{
itemAt(blockIndex).editTx(txIndex)
}
Block
{
Connections
{
target: block
onTxSelected: {
blockChainPanel.txSelected(index, txIndex)
}
}
id: block
scenario: blockChainPanel.model
Layout.preferredWidth: blockChainScrollView.width
Layout.preferredHeight:
@ -248,6 +263,8 @@ ColumnLayout {
Rectangle
{
Layout.preferredWidth: parent.width
Layout.preferredHeight: 70
color: "transparent"
RowLayout
{
anchors.horizontalCenter: parent.horizontalCenter
@ -270,7 +287,9 @@ ColumnLayout {
{
if (ensureNotFuturetime.running)
return;
rebuilding()
stopBlinking()
states = []
var retBlocks = [];
var bAdded = 0;
for (var j = 0; j < model.blocks.length; j++)
@ -316,7 +335,7 @@ ColumnLayout {
blockModel.append(model.blocks[j])
ensureNotFuturetime.start()
clientModel.setupScenario(model);
clientModel.setupScenario(model);
}
buttonShortcut: ""
sourceImg: "qrc:/qml/img/recycleicon@2x.png"
@ -346,6 +365,7 @@ ColumnLayout {
var item = TransactionHelper.defaultTransaction()
transactionDialog.stateAccounts = model.accounts
transactionDialog.execute = true
transactionDialog.editMode = false
transactionDialog.open(model.blocks[model.blocks.length - 1].transactions.length, model.blocks.length - 1, item)
}
width: 100
@ -397,7 +417,6 @@ ColumnLayout {
}
else
addNewBlock()
}
function addNewBlock()
@ -410,7 +429,7 @@ ColumnLayout {
height: 30
buttonShortcut: ""
sourceImg: "qrc:/qml/img/addblock@2x.png"
sourceImg: "qrc:/qml/img/newblock@2x.png"
}
}
@ -448,11 +467,13 @@ ColumnLayout {
tr.recordIndex = _r.recordIndex
tr.logs = _r.logs
tr.sender = _r.sender
tr.returnParameters = _r.returnParameters
var trModel = blockModel.getTransaction(blockIndex, trIndex)
trModel.returned = _r.returned
trModel.recordIndex = _r.recordIndex
trModel.logs = _r.logs
trModel.sender = _r.sender
trModel.returnParameters = _r.returnParameters
blockModel.setTransaction(blockIndex, trIndex, trModel)
return;
}
@ -472,9 +493,15 @@ ColumnLayout {
itemTr.sender = _r.sender
itemTr.recordIndex = _r.recordIndex
itemTr.logs = _r.logs
itemTr.returnParameters = _r.returnParameters
model.blocks[model.blocks.length - 1].transactions.push(itemTr)
blockModel.appendTransaction(itemTr)
}
onNewState: {
states[_record] = _accounts
}
onMiningComplete:
{
}
@ -484,7 +511,12 @@ ColumnLayout {
id: newAccount
text: qsTr("New Account..")
onClicked: {
model.accounts.push(projectModel.stateListModel.newAccount("1000000", QEther.Ether))
var ac = projectModel.stateListModel.newAccount("O", QEther.Wei)
model.accounts.push(ac)
clientModel.addAccount(ac.secret);
for (var k in Object.keys(blockChainPanel.states))
blockChainPanel.states[k].accounts["0x" + ac.address] = "0 wei" // add the account in all the previous state (balance at O)
accountAdded(ac.address, "0")
}
Layout.preferredWidth: 100
Layout.preferredHeight: 30

134
mix/qml/KeyValuePanel.qml

@ -0,0 +1,134 @@
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
import QtQuick.Dialogs 1.1
import QtQuick.Layouts 1.1
import Qt.labs.settings 1.0
import org.ethereum.qml.QEther 1.0
import "js/Debugger.js" as Debugger
import "js/ErrorLocationFormater.js" as ErrorLocationFormater
import "js/TransactionHelper.js" as TransactionHelper
import "js/QEtherHelper.js" as QEtherHelper
import "."
ColumnLayout {
id: root
property alias title: titleLabel.text
property variant _data
property string role
property alias model: modelKeyValue
function add(key, value)
{
modelKeyValue.append({ "key": key, "value": value })
}
function clear()
{
modelKeyValue.clear()
}
function init()
{
modelKeyValue.clear()
if (typeof(computeData) !== "undefined" && computeData instanceof Function)
computeData()
else
{
if (_data !== undefined && _data[role] !== undefined)
{
var keys = Object.keys(_data[role])
for (var k in keys)
{
modelKeyValue.append({ "key": keys[k] === "" ? "undefined" : keys[k], "value": _data[role][keys[k]] })
}
}
}
}
RowLayout
{
Layout.preferredHeight: 20
Layout.fillWidth: true
Label
{
id: titleLabel
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
color: "white"
}
}
RowLayout
{
Layout.fillWidth: true
Layout.preferredHeight: 100
ListModel
{
id: modelKeyValue
}
Rectangle
{
Layout.fillWidth: true
Layout.fillHeight: true
color: "white"
radius: 2
ScrollView
{
id: columnValues
horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff
anchors.fill: parent
clip: true
ColumnLayout
{
anchors.margins: 10
Repeater
{
id: repeaterKeyValue
model: modelKeyValue
RowLayout
{
Layout.fillWidth: true
Layout.preferredHeight: 30
spacing: 0
Rectangle
{
Layout.preferredWidth: columnValues.width / 2
Label
{
anchors.left: parent.left
anchors.leftMargin: 10
text: {
if (index >= 0 && repeaterKeyValue.model.get(index).key !== undefined)
return repeaterKeyValue.model.get(index).key
else
return ""
}
}
}
Rectangle
{
Layout.preferredWidth: columnValues.width / 2 - 10
Label
{
anchors.right: parent.right
anchors.rightMargin: 10
text: {
if (index >= 0 && repeaterKeyValue.model.get(index).value !== undefined)
return repeaterKeyValue.model.get(index).value
else
return ""
}
}
}
}
}
}
}
}
}
}

2
mix/qml/MainContent.qml

@ -31,7 +31,7 @@ Rectangle {
property alias codeEditor: codeEditor
property bool webViewHorizontal: codeWebSplitter.orientation === Qt.Vertical //vertical splitter positions elements vertically, splits screen horizontally
property bool firstCompile: true
property int scenarioMinWidth: 590
property int scenarioMinWidth: 620
Connections {
target: codeModel

124
mix/qml/ScenarioExecution.qml

@ -8,6 +8,7 @@ import "js/Debugger.js" as Debugger
import "js/ErrorLocationFormater.js" as ErrorLocationFormater
import "."
Rectangle {
color: "#ededed"
property alias bc: blockChain
@ -18,50 +19,109 @@ Rectangle {
onProjectLoaded: {
loader.init()
}
}
Column
ScrollView
{
anchors.margins: 10
anchors.fill: parent
spacing: 10
ScenarioLoader
{
height: 100
width: parent.width
id: loader
onWidthChanged: {
columnExe.width = width - 40
}
Connections
ColumnLayout
{
target: blockChain
onChainChanged:
{
loader.needSaveOrReload()
}
}
id: columnExe
Layout.preferredWidth: parent.width
width: parent.width - 40
anchors.left: parent.left
anchors.leftMargin: 15
ColumnLayout
{
id: scenarioColumn
width: parent.width
spacing: 10
ScenarioLoader
{
anchors.horizontalCenter: parent.horizontalCenter
height: 100
Layout.preferredWidth: 400
width: 400
id: loader
}
Rectangle
{
width: parent.parent.width
height: 1
color: "#cccccc"
}
Connections
{
target: blockChain
onChainChanged:
{
loader.needSaveOrReload()
}
}
Connections
{
target: loader
onLoaded:
Rectangle
{
Layout.preferredWidth: parent.width
height: 1
color: "#cccccc"
}
Connections
{
target: loader
onLoaded:
{
watchers.clear()
blockChain.load(scenario)
}
}
BlockChain
{
id: blockChain
width: parent.width
}
Connections
{
target: blockChain
property var currentSelectedBlock
property var currentSelectedTx
onTxSelected: {
currentSelectedBlock = blockIndex
currentSelectedTx = txIndex
updateWatchers(blockIndex, txIndex)
}
function updateWatchers(blockIndex, txIndex){
var tx = blockChain.model.blocks[blockIndex].transactions[txIndex]
var state = blockChain.getState(tx.recordIndex)
watchers.updateWidthTx(tx, state, blockIndex, txIndex)
}
onRebuilding: {
watchers.clear()
}
onAccountAdded: {
watchers.addAccount(address, "0 wei")
}
}
}
Watchers
{
blockChain.load(scenario)
id: watchers
bc: blockChain
Layout.fillWidth: true
Layout.preferredHeight: 740
}
}
BlockChain
{
id: blockChain
width: parent.width
Rectangle
{
color: "transparent"
Layout.preferredHeight: 50
Layout.fillWidth: true
}
}
}
}

9
mix/qml/ScenarioLoader.qml

@ -107,11 +107,13 @@ ColumnLayout
Rectangle
{
id: editIconRect
anchors.top: scenarioName.top
anchors.topMargin: 6
anchors.left: scenarioName.right
anchors.leftMargin: 15
anchors.leftMargin: 20
Image {
source: "qrc:/qml/img/edit.png"
width: 10
source: "qrc:/qml/img/edittransaction.png"
width: 30
fillMode: Image.PreserveAspectFit
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
@ -126,7 +128,6 @@ ColumnLayout
scenarioNameEdit.save()
else
scenarioNameEdit.edit()
}
}
}

3
mix/qml/StateListModel.qml

@ -257,7 +257,8 @@ Item {
_secret = clientModel.newSecret();
var address = clientModel.address(_secret);
var name = qsTr("Account") + "-" + address.substring(0, 4);
return { name: name, secret: _secret, balance: QEtherHelper.createEther(_balance, _unit), address: address };
var amount = QEtherHelper.createEther(_balance, _unit)
return { name: name, secret: _secret, balance: amount, address: address };
}
function duplicateState(index)

7
mix/qml/TransactionDialog.qml

@ -16,7 +16,8 @@ Dialog {
width: 580
height: 500
visible: false
title: qsTr("Edit Transaction")
title: editMode ? qsTr("Edit Transaction") : qsTr("Add Transaction")
property bool editMode
property int transactionIndex
property int blockIndex
property alias gas: gasValueEdit.gasValue;
@ -390,7 +391,7 @@ Dialog {
objectName: "trTypeExecute"
exclusiveGroup: rbbuttonList
height: 30
text: qsTr("Execute Contract")
text: qsTr("Transact with Contract")
}
}
}
@ -687,7 +688,7 @@ Dialog {
}
Button {
text: qsTr("Update");
text: editMode ? qsTr("Update") : qsTr("Ok")
onClicked: {
var invalid = InputValidator.validate(paramsModel, paramValues);
if (invalid.length === 0)

203
mix/qml/Watchers.qml

@ -0,0 +1,203 @@
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
import QtQuick.Dialogs 1.1
import QtQuick.Layouts 1.1
import Qt.labs.settings 1.0
import org.ethereum.qml.QEther 1.0
import "js/Debugger.js" as Debugger
import "js/ErrorLocationFormater.js" as ErrorLocationFormater
import "js/TransactionHelper.js" as TransactionHelper
import "js/QEtherHelper.js" as QEtherHelper
import "."
Rectangle {
color: "#4F4F4F"
radius: 4
property variant tx
property variant currentState
property variant bc
property var blockIndex
property var txIndex
function clear()
{
from.text = ""
to.text = ""
value.text = ""
inputParams.clear()
returnParams.clear()
accounts.clear()
events.clear()
}
function addAccount(address, amount)
{
accounts.add(address, amount)
}
function updateWidthTx(_tx, _state, _blockIndex, _txIndex)
{
from.text = clientModel.resolveAddress(_tx.sender)
to.text = _tx.label
value.text = _tx.value.format()
tx = _tx
blockIndex = _blockIndex
txIndex = _txIndex
currentState = _state
inputParams.init()
if (_tx.isContractCreation)
{
returnParams.role = "creationAddr"
returnParams._data = {
creationAddr : {
}
}
returnParams._data.creationAddr[qsTr("contract address")] = _tx.returned
}
else
{
returnParams.role = "returnParameters"
returnParams._data = tx
}
returnParams.init()
accounts.init()
events.init()
}
Column {
anchors.fill: parent
spacing: 15
Rectangle
{
height: 15
width: parent.width - 30
color: "transparent"
Row
{
id: rowHeader
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: rowHeader.parent.top
anchors.topMargin: 6
spacing: 5
Label {
id: fromLabel
text: qsTr("from")
visible: from.text !== ""
color: "#EAB920"
}
Label {
id: from
color: "#EAB920"
elide: Text.ElideRight
maximumLineCount: 1
clip: true
width: 200
}
Label {
id: toLabel
text: qsTr("to")
visible: from.text !== ""
color: "#EAB920"
}
Label {
id: to
color: "#EAB920"
elide: Text.ElideRight
maximumLineCount: 1
clip: true
width: 100
}
Label {
id: value
color: "#EAB920"
font.italic: true
clip: true
}
}
Image {
anchors.right: rowHeader.parent.right
anchors.top: rowHeader.parent.top
anchors.topMargin: -3
source: "qrc:/qml/img/edittransaction2.png"
height: 30
fillMode: Image.PreserveAspectFit
visible: from.text !== ""
MouseArea
{
anchors.fill: parent
onClicked:
{
bc.blockChainRepeater.editTx(blockIndex, txIndex)
}
}
}
}
Rectangle {
height: 1
width: parent.width - 30
anchors.horizontalCenter: parent.horizontalCenter
border.color: "#cccccc"
border.width: 1
}
KeyValuePanel
{
height: 150
width: parent.width - 30
anchors.horizontalCenter: parent.horizontalCenter
id: inputParams
title: qsTr("INPUT PARAMETERS")
role: "parameters"
_data: tx
}
KeyValuePanel
{
height: 150
width: parent.width - 30
anchors.horizontalCenter: parent.horizontalCenter
id: returnParams
title: qsTr("RETURN PARAMETERS")
role: "returnParameters"
_data: tx
}
KeyValuePanel
{
height: 150
width: parent.width - 30
anchors.horizontalCenter: parent.horizontalCenter
id: accounts
title: qsTr("ACCOUNTS")
role: "accounts"
_data: currentState
}
KeyValuePanel
{
height: 150
width: parent.width - 30
anchors.horizontalCenter: parent.horizontalCenter
id: events
title: qsTr("EVENTS")
function computeData()
{
model.clear()
var ret = []
for (var k in tx.logs)
{
var param = ""
for (var p in tx.logs[k].param)
{
param += " " + tx.logs[k].param[p].value + " "
}
param = "(" + param + ")"
model.append({ "key": tx.logs[k].name, "value": param })
}
}
}
}
}

5
mix/res.qrc

@ -90,5 +90,10 @@
<file>qml/img/saveicon@2x.png</file>
<file>qml/img/sendtransactionicon.png</file>
<file>qml/img/sendtransactionicon@2x.png</file>
<file>qml/img/edittransaction@2x.png</file>
<file>qml/img/newblock@2x.png</file>
<file>qml/img/edittransaction2@2x.png</file>
<file>qml/img/edittransaction.png</file>
<file>qml/img/edittransaction2.png</file>
</qresource>
</RCC>

Loading…
Cancel
Save