Browse Source

Merge pull request #2594 from yann300/bugFix

Mix - bugFix
cl-refactor
Gav Wood 10 years ago
parent
commit
9ca31a937e
  1. 18
      mix/ClientModel.cpp
  2. 52
      mix/ContractCallDataEncoder.cpp
  3. 8
      mix/qml/Application.qml
  4. 34
      mix/qml/Block.qml
  5. 84
      mix/qml/BlockChain.qml
  6. 25
      mix/qml/DeployContractStep.qml
  7. 2
      mix/qml/DeploymentDialog.qml
  8. 19
      mix/qml/DeploymentWorker.qml
  9. 8
      mix/qml/RegisteringStep.qml
  10. 8
      mix/qml/ScenarioExecution.qml
  11. 51
      mix/qml/ScenarioLoader.qml
  12. 241
      mix/qml/StateDialog.qml
  13. 19
      mix/qml/StateList.qml
  14. 37
      mix/qml/StateListModel.qml
  15. 4
      mix/qml/TransactionDialog.qml

18
mix/ClientModel.cpp

@ -81,7 +81,7 @@ ClientModel::ClientModel():
qRegisterMetaType<QInstruction*>("QInstruction");
qRegisterMetaType<QCode*>("QCode");
qRegisterMetaType<QCallData*>("QCallData");
qRegisterMetaType<RecordLogEntry*>("RecordLogEntry*");
qRegisterMetaType<RecordLogEntry*>("RecordLogEntry*");
}
ClientModel::~ClientModel()
@ -236,6 +236,7 @@ void ClientModel::setupScenario(QVariantMap _scenario)
QVariantList blocks = _scenario.value("blocks").toList();
QVariantList stateAccounts = _scenario.value("accounts").toList();
QVariantList stateContracts = _scenario.value("contracts").toList();
m_accounts.clear();
m_accountsSecret.clear();
@ -258,6 +259,19 @@ void ClientModel::setupScenario(QVariantMap _scenario)
}
m_ethAccounts->setAccounts(m_accountsSecret);
for (auto const& c: stateContracts)
{
QVariantMap contract = c.toMap();
Address address = Address(fromHex(contract.value("address").toString().toStdString()));
Account account(qvariant_cast<QEther*>(contract.value("balance"))->toU256Wei(), Account::ContractConception);
bytes code = fromHex(contract.value("code").toString().toStdString());
account.setCode(std::move(code));
QVariantMap storageMap = contract.value("storage").toMap();
for(auto s = storageMap.cbegin(); s != storageMap.cend(); ++s)
account.setStorage(fromBigEndian<u256>(fromHex(s.key().toStdString())), fromBigEndian<u256>(fromHex(s.value().toString().toStdString())));
m_accounts[address] = account;
}
bool trToExecute = false;
for (auto const& b: blocks)
{
@ -891,7 +905,7 @@ void ClientModel::onNewTransaction()
QVariantMap accountBalances;
for (auto const& ctr : m_contractAddresses)
{
u256 wei = m_client->balanceAt(ctr.second, PendingBlock);
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)

52
mix/ContractCallDataEncoder.cpp

@ -21,6 +21,7 @@
*/
#include <vector>
#include <QtCore/qmath.h>
#include <QMap>
#include <QStringList>
#include <QJsonArray>
@ -101,9 +102,9 @@ void ContractCallDataEncoder::encode(QVariant const& _data, SolidityType const&
bytes empty(32);
size_t sizePos = m_dynamicData.size();
m_dynamicData += empty; //reserve space for count
u256 count = encodeSingleItem(_data.toString(), _type, m_dynamicData);
encodeSingleItem(_data.toString(), _type, m_dynamicData);
vector_ref<byte> sizeRef(m_dynamicData.data() + sizePos, 32);
toBigEndian(count, sizeRef);
toBigEndian(_data.toString().size(), sizeRef);
m_staticOffsetMap.push_back(std::make_pair(m_encodedData.size(), sizePos));
m_encodedData += empty; //reserve space for offset
}
@ -223,11 +224,7 @@ dev::bytes ContractCallDataEncoder::decodeBytes(dev::bytes const& _rawValue)
QString ContractCallDataEncoder::toString(dev::bytes const& _b)
{
QString str;
if (asString(_b, str))
return "\"" + str + "\" " + QString::fromStdString(dev::toJS(_b));
else
return QString::fromStdString(dev::toJS(_b));
return QString::fromStdString(dev::toJS(_b));
}
QString ContractCallDataEncoder::toChar(dev::bytes const& _b)
@ -242,8 +239,6 @@ QJsonValue ContractCallDataEncoder::decodeArrayContent(SolidityType const& _type
if (_type.baseType->array)
{
QJsonArray sub = decodeArray(*_type.baseType, _value, pos);
if (_type.baseType->dynamicSize)
pos = pos + 32;
return sub;
}
else
@ -262,6 +257,8 @@ QJsonArray ContractCallDataEncoder::decodeArray(SolidityType const& _type, bytes
QJsonArray array;
bytesConstRef value(&_value);
int count = 0;
bigint offset = pos;
int valuePosition = pos;
if (!_type.dynamicSize)
count = _type.count;
else
@ -269,14 +266,33 @@ QJsonArray ContractCallDataEncoder::decodeArray(SolidityType const& _type, bytes
bytesConstRef value(_value.data() + pos, 32); // offset
bytes rawParam(32);
value.populate(&rawParam);
bigint offset = decodeInt(rawParam);
pos = static_cast<int>(offset) + 32;
value = bytesConstRef(_value.data() + static_cast<int>(offset), 32); // offset
offset = decodeInt(rawParam);
valuePosition = static_cast<int>(offset) + 32;
pos += 32;
value = bytesConstRef(_value.data() + static_cast<int>(offset), 32); // count
value.populate(&rawParam);
count = static_cast<int>(decodeInt(rawParam));
}
for (int k = 0; k < count; ++k)
array.append(decodeArrayContent(_type, _value, pos));
if (_type.type == QSolidityType::Type::Bytes || _type.type == QSolidityType::Type::String)
{
bytesConstRef value(_value.data() + (static_cast<int>(offset) + 32), 32);
bytes rawParam(count);
value.populate(&rawParam);
if (_type.type == QSolidityType::Type::Bytes)
array.append(toString(decodeBytes(rawParam)));
else
array.append(toChar(decodeBytes(rawParam)));
}
else
{
for (int k = 0; k < count; ++k)
{
if (_type.dynamicSize)
array.append(decodeArrayContent(_type, _value, valuePosition));
else
array.append(decodeArrayContent(_type, _value, pos));
}
}
return array;
}
@ -329,18 +345,14 @@ QStringList ContractCallDataEncoder::decode(QList<QVariableDeclaration*> const&
QJsonArray array = decodeArray(type, _v, readPosition);
QJsonDocument jsonDoc = QJsonDocument::fromVariant(array.toVariantList());
r.append(jsonDoc.toJson(QJsonDocument::Compact));
if (type.dynamicSize)
readPosition++;
else
readPosition = type.count;
}
else
{
bytesConstRef value(_value.data() + (readPosition * 32), 32);
bytesConstRef value(_value.data() + readPosition, 32);
bytes rawParam(32);
value.populate(&rawParam);
r.append(decode(type, rawParam).toString());
readPosition++;
readPosition += 32;
}
}
return r;

8
mix/qml/Application.qml

@ -108,12 +108,14 @@ ApplicationWindow {
title: qsTr("Deploy")
MenuItem { action: mineAction }
MenuSeparator {}
MenuItem { action: editStatesAction }
MenuSeparator {}
MenuItem { action: deployViaRpcAction }
MenuSeparator {}
MenuItem { action: toggleRunOnLoadAction }
}
Menu {
title: qsTr("Scenario")
MenuItem { action: editStatesAction }
}
Menu {
title: qsTr("Debug")
MenuItem { action: debugRunAction }
@ -184,7 +186,7 @@ ApplicationWindow {
Action {
id: editStatesAction
text: qsTr("Edit States")
text: qsTr("Edit Scenarii")
shortcut: "Ctrl+Alt+E"
onTriggered: stateList.open();
}

34
mix/qml/Block.qml

@ -22,6 +22,7 @@ ColumnLayout
property int blockIndex
property variant scenario
property string labelColor: "#414141"
property int scenarioIndex
signal txSelected(var txIndex)
function calculateHeight()
@ -45,6 +46,11 @@ ColumnLayout
transactionDialog.open(txIndex, blockIndex, transactions.get(txIndex))
}
function select(txIndex)
{
transactionRepeater.itemAt(txIndex).select()
}
onOpenedTrChanged:
{
Layout.preferredHeight = calculateHeight()
@ -90,7 +96,7 @@ ColumnLayout
text:
{
if (number === -2)
return qsTr("STARTING PARAMETERS")
return qsTr("GENESIS PARAMETERS")
else if (status === "mined")
return qsTr("BLOCK") + " " + number
else
@ -105,13 +111,14 @@ ColumnLayout
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: 14
visible: false
visible: number === -2
MouseArea
{
anchors.fill: parent
onClicked:
{
// load edit block panel
projectModel.stateListModel.editState(scenarioIndex)
}
}
}
@ -127,6 +134,12 @@ ColumnLayout
id: rowTransaction
Layout.preferredHeight: trHeight
spacing: 0
function select()
{
rowContentTr.select()
}
function displayContent()
{
logsText.text = ""
@ -220,6 +233,15 @@ ColumnLayout
}
}
function select()
{
rowContentTr.selected = true
rowContentTr.color = "#4F4F4F"
hash.color = "#EAB920"
func.color = "#EAB920"
txSelected(index)
}
function deselect()
{
rowContentTr.selected = false
@ -233,13 +255,7 @@ ColumnLayout
anchors.fill: parent
onClicked: {
if (!rowContentTr.selected)
{
rowContentTr.selected = true
rowContentTr.color = "#4F4F4F"
hash.color = "#EAB920"
func.color = "#EAB920"
txSelected(index)
}
rowContentTr.select()
else
rowContentTr.deselect()

84
mix/qml/BlockChain.qml

@ -16,6 +16,7 @@ ColumnLayout {
property alias trDialog: transactionDialog
property alias blockChainRepeater: blockChainRepeater
property variant model
property int scenarioIndex
property var states: ({})
spacing: 0
property int previousWidth
@ -26,6 +27,25 @@ ColumnLayout {
signal rebuilding
signal accountAdded(string address, string amount)
Connections
{
target: projectModel.stateListModel
onAccountsValidated:
{
if (rebuild.accountsSha3 !== codeModel.sha3(JSON.stringify(_accounts)))
rebuild.needRebuild("AccountsChanged")
else
rebuild.notNeedRebuild("AccountsChanged")
}
onContractsValidated:
{
if (rebuild.contractsSha3 !== codeModel.sha3(JSON.stringify(_contracts)))
rebuild.needRebuild("ContractsChanged")
else
rebuild.notNeedRebuild("ContractsChanged")
}
}
Connections
{
target: codeModel
@ -94,13 +114,15 @@ ColumnLayout {
return states[record]
}
function load(scenario)
function load(scenario, index)
{
if (!scenario)
return;
if (model)
rebuild.startBlinking()
model = scenario
scenarioIndex = index
genesis.scenarioIndex = index
states = []
blockModel.clear()
for (var b in model.blocks)
@ -138,6 +160,20 @@ ColumnLayout {
width: parent.width
spacing: 20
Block
{
id: genesis
scenario: blockChainPanel.model
scenarioIndex: scenarioIndex
Layout.preferredWidth: blockChainScrollView.width
Layout.preferredHeight: 60
blockIndex: -1
transactions: []
status: ""
number: -2
trHeight: 60
}
Repeater // List of blocks
{
id: blockChainRepeater
@ -148,6 +184,11 @@ ColumnLayout {
itemAt(blockIndex).editTx(txIndex)
}
function select(blockIndex, txIndex)
{
itemAt(blockIndex).select(txIndex)
}
Block
{
Connections
@ -264,6 +305,8 @@ ColumnLayout {
roundRight: true
property variant contractsHex: ({})
property variant txSha3: ({})
property variant accountsSha3
property variant contractsSha3
property variant txChanged: []
property var blinkReasons: []
@ -352,10 +395,22 @@ ColumnLayout {
ensureNotFuturetime.start()
takeCodeSnapshot()
takeTxSnaphot()
takeAccountsSnapshot()
takeContractsSnapShot()
blinkReasons = []
clientModel.setupScenario(model);
}
function takeContractsSnapShot()
{
contractsSha3 = codeModel.sha3(JSON.stringify(model.contracts))
}
function takeAccountsSnapshot()
{
accountsSha3 = codeModel.sha3(JSON.stringify(model.accounts))
}
function takeCodeSnapshot()
{
contractsHex = {}
@ -395,19 +450,22 @@ ColumnLayout {
text: qsTr("Add Tx")
onClicked:
{
var lastBlock = model.blocks[model.blocks.length - 1];
if (lastBlock.status === "mined")
if (model && model.blocks)
{
var newblock = projectModel.stateListModel.createEmptyBlock()
blockModel.appendBlock(newblock)
model.blocks.push(newblock);
}
var lastBlock = model.blocks[model.blocks.length - 1];
if (lastBlock.status === "mined")
{
var newblock = projectModel.stateListModel.createEmptyBlock()
blockModel.appendBlock(newblock)
model.blocks.push(newblock);
}
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)
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
height: 30
@ -516,6 +574,7 @@ ColumnLayout {
trModel.sender = _r.sender
trModel.returnParameters = _r.returnParameters
blockModel.setTransaction(blockIndex, trIndex, trModel)
blockChainRepeater.select(blockIndex, trIndex)
return;
}
}
@ -537,6 +596,7 @@ ColumnLayout {
itemTr.returnParameters = _r.returnParameters
model.blocks[model.blocks.length - 1].transactions.push(itemTr)
blockModel.appendTransaction(itemTr)
blockChainRepeater.select(blockIndex, trIndex)
}
onNewState: {

25
mix/qml/DeployContractStep.qml

@ -36,6 +36,19 @@ Rectangle {
accountsList.currentIndex = 0
}
verifyDeployedContract()
deployedAddresses.refresh()
worker.renewCtx()
worker.pooler.onTriggered.connect(function() {
if (root.visible)
verifyDeployedContract();
})
}
function verifyDeployedContract()
{
if (projectModel.deployBlockNumber !== -1)
{
worker.verifyHashes(projectModel.deploymentTrHashes, function (bn, trLost)
@ -43,8 +56,6 @@ Rectangle {
root.updateVerification(bn, trLost)
});
}
deployedAddresses.refresh()
worker.renewCtx()
}
function updateVerification(blockNumber, trLost)
@ -112,14 +123,10 @@ Rectangle {
for (var k = 0; k < projectModel.stateListModel.get(currentIndex).blocks.count; k++)
{
for (var j = 0; j < projectModel.stateListModel.get(currentIndex).blocks.get(k).transactions.count; j++)
{
trListModel.append(projectModel.stateListModel.get(currentIndex).blocks.get(k).transactions.get(j));
}
}
for (var k = 0; k < trListModel.count; k++)
{
trList.itemAt(k).init()
}
ctrDeployCtrLabel.calculateContractDeployGas();
}
}
@ -166,9 +173,7 @@ Rectangle {
if (trListModel.get(index).parameters)
{
for (var k in trListModel.get(index).parameters)
{
paramList.append({ "name": k, "value": trListModel.get(index).parameters[k] })
}
}
}
@ -220,7 +225,6 @@ Rectangle {
}
}
ColumnLayout
{
anchors.top: parent.top
@ -486,7 +490,8 @@ Rectangle {
id: clearDeployAction
onTriggered: {
worker.forceStopPooling()
fileIo.deleteDir(projectModel.deploymentDir)
if (projectModel.deploymentDir && projectModel.deploymentDir !== "")
fileIo.deleteDir(projectModel.deploymentDir)
projectModel.cleanDeploymentStatus()
deploymentDialog.steps.reset()
}

2
mix/qml/DeploymentDialog.qml

@ -27,6 +27,7 @@ Dialog {
function close()
{
visible = false;
worker.pooler.running = false
}
function open()
@ -36,6 +37,7 @@ Dialog {
registerStep.visible = false
steps.init()
worker.renewCtx()
worker.pooler.running = true
visible = true;
}

19
mix/qml/DeploymentWorker.qml

@ -19,6 +19,7 @@ Item
property alias gasPriceInt: gasPriceInt
property variant balances: ({})
property variant accounts: []
property alias pooler: pooler
signal gasPriceLoaded()
function renewCtx()
@ -169,10 +170,11 @@ Item
{
if (!clientModelGasEstimation.running)
{
var ctr = projectModel.codeEditor.getContracts()
for (var k in ctr)
for (var si = 0; si < projectModel.listModel.count; si++)
{
codeModelGasEstimation.registerCodeChange(ctr[k].document.documentId, ctr[k].getText());
var document = projectModel.listModel.get(si);
if (document.isContract)
codeModelGasEstimation.registerCodeChange(document.documentId, fileIo.readFile(document.path));
}
gasEstimationConnect.callback = callback
clientModelGasEstimation.setupScenario(scenario)
@ -193,7 +195,8 @@ Item
id: codeModelGasEstimation
}
ClientModel {
ClientModel
{
id: clientModelGasEstimation
codeModel: codeModelGasEstimation
Component.onCompleted:
@ -202,6 +205,14 @@ Item
}
}
Timer
{
id: pooler
interval: 5000
repeat: true
running: false
}
Timer
{
id: poolLog

8
mix/qml/RegisteringStep.qml

@ -32,6 +32,14 @@ Rectangle {
visible = true
worker.pooler.onTriggered.connect(function() {
if (root.visible)
verifyRegistering();
})
}
function verifyRegistering()
{
verificationEthUrl.text = ""
if (projectModel.registerContentHashTrHash !== "" && projectModel.registerContentHashBlockNumber !== -1)
{

8
mix/qml/ScenarioExecution.qml

@ -70,7 +70,7 @@ Rectangle {
onLoaded:
{
watchers.clear()
blockChain.load(scenario)
blockChain.load(scenario, loader.selectedScenarioIndex)
}
}
@ -85,13 +85,15 @@ Rectangle {
target: blockChain
property var currentSelectedBlock
property var currentSelectedTx
onTxSelected: {
onTxSelected:
{
currentSelectedBlock = blockIndex
currentSelectedTx = txIndex
updateWatchers(blockIndex, txIndex)
}
function 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)

51
mix/qml/ScenarioLoader.qml

@ -20,6 +20,7 @@ ColumnLayout
signal loaded(variant scenario)
signal renamed(variant scenario)
signal deleted()
property alias selectedScenarioIndex: scenarioList.currentIndex
spacing: 0
function init()
{
@ -80,15 +81,14 @@ ColumnLayout
}
}
Label
{
anchors.left: editImg.right
text: "X"
height: parent.height
color: "#cccccc"
Image {
source: "qrc:/qml/img/delete_sign.png"
height: parent.height - 16
fillMode: Image.PreserveAspectFit
id: deleteImg
anchors.left: editImg.right
anchors.top: parent.top
anchors.topMargin: 7
anchors.topMargin: 8
visible: projectModel.stateListModel.count > 1
MouseArea
{
@ -98,13 +98,37 @@ ColumnLayout
if (projectModel.stateListModel.count > 1)
{
projectModel.stateListModel.deleteState(scenarioList.currentIndex)
scenarioList.currentIndex = 0
deleted()
scenarioList.init()
}
}
}
}
Label
{
MouseArea
{
anchors.fill: parent
onClicked:
{
if (projectModel.stateListModel.count > 1)
{
projectModel.stateListModel.deleteState(scenarioList.currentIndex)
scenarioList.init()
}
}
}
}
Connections
{
target: projectModel.stateListModel
onStateDeleted: {
scenarioList.init()
}
}
ComboBox
{
id: scenarioList
@ -122,6 +146,12 @@ ColumnLayout
restoreScenario.restore()
}
function init()
{
scenarioList.currentIndex = 0
deleted()
}
function load()
{
var state = projectModel.stateListModel.getState(currentIndex)
@ -291,7 +321,7 @@ ColumnLayout
text: qsTr("Restore")
function restore()
{
var state = projectModel.stateListModel.reloadStateFromFromProject(scenarioList.currentIndex)
var state = projectModel.stateListModel.reloadStateFromProject(scenarioList.currentIndex)
if (state)
{
restored(state)
@ -302,7 +332,6 @@ ColumnLayout
roundLeft: true
}
Rectangle
{
width: 1

241
mix/qml/StateDialog.qml

@ -18,12 +18,8 @@ Dialog {
title: qsTr("Edit State")
visible: false
property alias stateTitle: titleField.text
property alias isDefault: defaultCheckBox.checked
property alias model: transactionsModel
property alias transactionDialog: transactionDialog
property alias minerComboBox: comboMiner
property alias newAccAction: newAccountAction
property int stateIndex
property var stateTransactions: []
property var stateAccounts: []
@ -36,16 +32,6 @@ Dialog {
function open(index, item, setDefault) {
stateIndex = index
stateTitle = item.title
transactionsModel.clear()
stateTransactions = []
var transactions = item.transactions
for (var t = 0; t < transactions.length; t++) {
transactionsModel.append(item.transactions[t])
stateTransactions.push(item.transactions[t])
}
accountsModel.clear()
stateAccounts = []
var miner = 0
@ -66,8 +52,8 @@ Dialog {
visible = true
isDefault = setDefault
titleField.focus = true
defaultCheckBox.enabled = !isDefault
console.log(isDefault)
defaultCheckBox.checked = isDefault
comboMiner.model = stateAccounts
comboMiner.currentIndex = miner
forceActiveFocus()
@ -84,8 +70,6 @@ Dialog {
function getItem() {
var item = {
title: stateDialog.stateTitle,
transactions: stateTransactions,
accounts: stateAccounts,
contracts: stateContracts
}
@ -95,6 +79,7 @@ Dialog {
break
}
}
item.defaultState = defaultCheckBox.checked
return item
}
@ -111,21 +96,6 @@ Dialog {
ColumnLayout {
id: dialogContent
anchors.top: parent.top
RowLayout {
Layout.fillWidth: true
DefaultLabel {
Layout.preferredWidth: 85
text: qsTr("Title")
}
DefaultTextField {
id: titleField
Layout.fillWidth: true
}
}
CommonSeparator {
Layout.fillWidth: true
}
RowLayout {
Layout.fillWidth: true
@ -258,30 +228,6 @@ Dialog {
Layout.preferredWidth: 85
text: qsTr("Accounts")
}
Button {
id: newAccountButton
anchors.top: accountsLabel.bottom
anchors.topMargin: 10
iconSource: "qrc:/qml/img/plus.png"
action: newAccountAction
}
Action {
id: newAccountAction
tooltip: qsTr("Add new Account")
onTriggered: {
add()
}
function add() {
var account = stateListModel.newAccount(
"1000000", QEther.Ether)
stateAccounts.push(account)
accountsModel.append(account)
return account
}
}
}
MessageDialog {
@ -313,21 +259,8 @@ Dialog {
id: deleteAccountAction
tooltip: qsTr("Delete Account")
onTriggered: {
if (transactionsModel.isUsed(
stateAccounts[styleData.row].secret))
alertAlreadyUsed.open()
else {
if (stateAccounts[styleData.row].name
=== comboMiner.currentText)
comboMiner.currentIndex = 0
stateAccounts.splice(
styleData.row,
1)
accountsModel.remove(
styleData.row)
comboMiner.model = stateAccounts //TODO: filter accounts wo private keys
comboMiner.update()
}
stateAccounts.splice(styleData.row, 1)
accountsView.model.remove(styleData.row)
}
}
@ -405,115 +338,17 @@ Dialog {
Layout.fillWidth: true
}
RowLayout {
Layout.fillWidth: true
Rectangle {
Layout.preferredWidth: 85
DefaultLabel {
id: transactionsLabel
Layout.preferredWidth: 85
text: qsTr("Transactions")
}
Button {
anchors.top: transactionsLabel.bottom
anchors.topMargin: 10
iconSource: "qrc:/qml/img/plus.png"
action: newTrAction
}
Action {
id: newTrAction
tooltip: qsTr("Create a new transaction")
onTriggered: transactionsModel.addTransaction()
}
}
TableView {
id: transactionsView
Layout.fillWidth: true
model: transactionsModel
headerVisible: false
TableViewColumn {
role: "label"
title: qsTr("Name")
width: 150
delegate: Item {
RowLayout {
height: 30
width: parent.width
Button {
iconSource: "qrc:/qml/img/delete_sign.png"
action: deleteTransactionAction
}
Action {
id: deleteTransactionAction
tooltip: qsTr("Delete")
onTriggered: transactionsModel.deleteTransaction(
styleData.row)
}
Button {
iconSource: "qrc:/qml/img/edit.png"
action: editAction
visible: styleData.row
>= 0 ? !transactionsModel.get(
styleData.row).stdContract : false
width: 10
height: 10
Action {
id: editAction
tooltip: qsTr("Edit")
onTriggered: transactionsModel.editTransaction(
styleData.row)
}
}
DefaultLabel {
Layout.preferredWidth: 150
text: {
if (styleData.row >= 0)
return transactionsModel.get(
styleData.row).label
else
return ""
}
}
}
}
}
rowDelegate: Rectangle {
color: styleData.alternate ? "transparent" : "#f0f0f0"
height: 30
}
}
}
}
RowLayout {
anchors.bottom: parent.bottom
anchors.right: parent.right
Button {
text: qsTr("Delete")
enabled: !modalStateDialog.isDefault
onClicked: {
projectModel.stateListModel.deleteState(stateIndex)
close()
}
}
Button {
text: qsTr("OK")
onClicked: {
if (titleField.text === "")
alertDialog.open()
else
{
close()
accepted()
}
close()
accepted()
}
}
Button {
@ -522,21 +357,6 @@ Dialog {
}
}
MessageDialog
{
id: alertDialog
text: qsTr("Please provide a name.")
}
ListModel {
id: accountsModel
function removeAccount(_i) {
accountsModel.remove(_i)
stateAccounts.splice(_i, 1)
}
}
ListModel {
id: contractsModel
@ -547,50 +367,11 @@ Dialog {
}
ListModel {
id: transactionsModel
function editTransaction(index) {
transactionDialog.stateAccounts = stateAccounts
transactionDialog.open(index,
transactionsModel.get(index))
}
function addTransaction() {
// Set next id here to work around Qt bug
// https://bugreports.qt-project.org/browse/QTBUG-41327
// Second call to signal handler would just edit the item that was just created, no harm done
var item = TransactionHelper.defaultTransaction()
transactionDialog.stateAccounts = stateAccounts
transactionDialog.open(transactionsModel.count, item)
}
function deleteTransaction(index) {
stateTransactions.splice(index, 1)
transactionsModel.remove(index)
}
function isUsed(secret) {
for (var i in stateTransactions) {
if (stateTransactions[i].sender === secret)
return true
}
return false
}
}
id: accountsModel
TransactionDialog {
id: transactionDialog
onAccepted: {
var item = transactionDialog.getItem()
if (transactionDialog.transactionIndex < transactionsModel.count) {
transactionsModel.set(
transactionDialog.transactionIndex,
item)
stateTransactions[transactionDialog.transactionIndex] = item
} else {
transactionsModel.append(item)
stateTransactions.push(item)
}
function removeAccount(_i) {
accountsModel.remove(_i)
stateAccounts.splice(_i, 1)
}
}
}

19
mix/qml/StateList.qml

@ -27,7 +27,7 @@ Dialog {
frameVisible: false
TableViewColumn {
role: "title"
title: qsTr("State")
title: qsTr("Scenario")
width: list.width
}
}
@ -37,10 +37,6 @@ Dialog {
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.rightMargin: 10
Button {
action: addStateAction
}
Button {
action: closeAction
}
@ -71,25 +67,12 @@ Dialog {
Layout.fillHeight: true
onClicked: list.model.deleteState(styleData.row);
}
ToolButton {
text: qsTr("Run");
Layout.fillHeight: true
onClicked: list.model.runState(styleData.row);
}
}
}
}
Row
{
Action {
id: addStateAction
text: qsTr("Add State")
shortcut: "Ctrl+T"
enabled: codeModel.hasContract && !clientModel.running;
onTriggered: list.model.addState();
}
Action {
id: closeAction
text: qsTr("Close")

37
mix/qml/StateListModel.qml

@ -186,12 +186,13 @@ Item {
onProjectLoading: stateListModel.loadStatesFromProject(projectData);
onProjectFileSaving: {
projectData.states = []
for(var i = 0; i < stateListModel.count; i++) {
for(var i = 0; i < stateListModel.count; i++)
{
projectData.states.push(toPlainStateItem(stateList[i]));
stateListModel.set(i, stateList[i]);
}
projectData.defaultStateIndex = stateListModel.defaultStateIndex;
stateListModel.data = projectData
}
onNewProject: {
var state = toPlainStateItem(stateListModel.createDefaultState());
@ -221,20 +222,19 @@ Item {
function saveState(item)
{
if (stateDialog.stateIndex < stateListModel.count) {
if (stateDialog.isDefault)
stateListModel.defaultStateIndex = stateIndex;
stateList[stateDialog.stateIndex] = item;
stateListModel.set(stateDialog.stateIndex, item);
} else {
if (stateDialog.isDefault)
stateListModel.defaultStateIndex = 0;
stateList.push(item);
stateListModel.append(item);
stateList[stateDialog.stateIndex].accounts = item.accounts
stateList[stateDialog.stateIndex].contracts = item.contracts
stateListModel.get(stateDialog.stateIndex).accounts = item.accounts
stateListModel.get(stateDialog.stateIndex).contracts = item.contracts
stateListModel.accountsValidated(item.accounts)
stateListModel.contractsValidated(item.contracts)
stateListModel.get(stateDialog.stateIndex).miner = item.miner
stateList[stateDialog.stateIndex].miner = item.miner
if (item.defaultState)
{
stateListModel.defaultStateIndex = stateDialog.stateIndex
stateListModel.defaultStateChanged()
}
if (stateDialog.isDefault)
stateListModel.defaultStateChanged();
stateListModel.save();
}
}
@ -242,12 +242,15 @@ Item {
id: stateListModel
property int defaultStateIndex: 0
property variant data
signal accountsValidated(var _accounts)
signal contractsValidated(var _contracts)
signal defaultStateChanged;
signal stateListModelReady;
signal stateRun(int index)
signal stateDeleted(int index)
function defaultTransactionItem() {
function defaultTransactionItem()
{
return TransactionHelper.defaultTransaction();
}
@ -409,7 +412,7 @@ Item {
return ""
}
function reloadStateFromFromProject(index)
function reloadStateFromProject(index)
{
if (data)
{

4
mix/qml/TransactionDialog.qml

@ -125,7 +125,7 @@ Dialog {
function loadParameters() {
paramsModel = []
if (functionComboBox.currentIndex >= 0 && functionComboBox.currentIndex < functionsModel.count) {
var contract = codeModel.contracts[TransactionHelper.contractFromToken(contractCreationComboBox.currentValue())];
var contract = codeModel.contracts[TransactionHelper.contractFromToken(recipientsAccount.currentValue())];
if (contract) {
var func = getFunction(functionComboBox.currentText, contract);
if (func) {
@ -498,9 +498,7 @@ Dialog {
paramScroll.visible = paramsModel.length > 0
paramScroll.Layout.preferredHeight = paramsModel.length < 6 ? paramsModel.length * 30 : 205
if (paramsModel.length === 0)
{
paramScroll.height = 0
}
}
}

Loading…
Cancel
Save