diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index dad1ced62..c0ce36ab5 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -237,6 +237,7 @@ void ClientModel::executeSequence(vector const& _sequence, { try { + vector
deployedContracts; onStateReset(); for (TransactionSettings const& transaction: _sequence) { @@ -248,6 +249,7 @@ void ClientModel::executeSequence(vector const& _sequence, TransactionSettings stdTransaction = transaction; stdTransaction.gasAuto = true; Address address = deployContract(stdContractCode, stdTransaction); + deployedContracts.push_back(address); m_stdContractAddresses[stdTransaction.contractId] = address; m_stdContractNames[address] = stdTransaction.contractId; } @@ -280,6 +282,11 @@ void ClientModel::executeSequence(vector const& _sequence, { QSolidityType const* type = p->type(); QVariant value = transaction.parameterValues.value(p->name()); + if (type->type().type == SolidityType::Type::Address && value.toString().startsWith("<") && value.toString().endsWith(">")) + { + QStringList nb = value.toString().remove("<").remove(">").split(" - "); + value = QVariant(QString::fromStdString("0x" + toHex(deployedContracts.at(nb.back().toInt()).ref()))); + } encoder.encode(value, type->type()); } @@ -288,6 +295,7 @@ void ClientModel::executeSequence(vector const& _sequence, bytes param = encoder.encodedData(); contractCode.insert(contractCode.end(), param.begin(), param.end()); Address newAddress = deployContract(contractCode, transaction); + deployedContracts.push_back(newAddress); auto contractAddressIter = m_contractAddresses.find(transaction.contractId); if (contractAddressIter == m_contractAddresses.end() || newAddress != contractAddressIter->second) { diff --git a/mix/qml/Debugger.qml b/mix/qml/Debugger.qml index 87a27cf79..c6283b60e 100644 --- a/mix/qml/Debugger.qml +++ b/mix/qml/Debugger.qml @@ -211,8 +211,8 @@ Rectangle { anchors.top: parent.top anchors.topMargin: 15 anchors.left: parent.left; - anchors.leftMargin: machineStates.sideMargin - width: debugScrollArea.width - machineStates.sideMargin * 2 - 20 ; + anchors.leftMargin: machineStates.sideMargin + width: debugScrollArea.width - machineStates.sideMargin * 2 - 20 spacing: machineStates.sideMargin Rectangle { @@ -641,9 +641,6 @@ Rectangle { } } - - - Rectangle { id: storageRect diff --git a/mix/qml/QAddressView.qml b/mix/qml/QAddressView.qml new file mode 100644 index 000000000..2c1d43276 --- /dev/null +++ b/mix/qml/QAddressView.qml @@ -0,0 +1,96 @@ +import QtQuick 2.0 +import QtQuick.Controls 1.3 +import QtQuick.Controls.Styles 1.3 + +Item +{ + property alias value: textinput.text + property alias contractCreationTr: ctrModel + id: editRoot + height: 20 + width: 200 + + SourceSansProBold + { + id: boldFont + } + + function init() + { + trCombobox.visible = ctrModel.count > 1; //index 0 is a blank value. + if (value.indexOf("<") === 0) + { + for (var k = 0; k < ctrModel.count; k++) + { + if ("<" + ctrModel.get(k).functionId + ">" === value) + { + trCombobox.currentIndex = k; + return; + } + } + trCombobox.currentIndex = 0; + value = ""; + } + } + + Rectangle { + anchors.fill: parent + radius: 4 + anchors.verticalCenter: parent.verticalCenter + height: 20 + TextInput { + id: textinput + text: value + width: parent.width + height: parent.width + wrapMode: Text.WrapAnywhere + clip: true + font.family: boldFont.name + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + onClicked: textinput.forceActiveFocus() + } + onTextChanged: + { + if (trCombobox.selected) + { + trCombobox.currentIndex = 0; + trCombobox.selected = false; + } + } + } + } + + ListModel + { + id: ctrModel + } + + ComboBox + { + property bool selected: false + id: trCombobox + model: ctrModel + textRole: "functionId" + height: 20 + anchors.verticalCenter: parent.verticalCenter + anchors.left: textinput.parent.right + anchors.leftMargin: 3 + onCurrentIndexChanged: { + trCombobox.selected = false; + if (currentText === "") + return; + else if (currentText !== " - ") + { + textinput.text = "<" + currentText + ">"; + trCombobox.selected = true; + } + else if (textinput.text.indexOf("<") === 0) + { + textinput.text = ""; + } + } + } +} diff --git a/mix/qml/StateDialog.qml b/mix/qml/StateDialog.qml index a2f9a09b7..b85996b29 100644 --- a/mix/qml/StateDialog.qml +++ b/mix/qml/StateDialog.qml @@ -366,7 +366,12 @@ Dialog { DefaultLabel { Layout.preferredWidth: 150 - text: styleData.row >= 0 ? transactionsModel.get(styleData.row).functionId : "" + text: { + if (styleData.row >= 0) + return transactionsModel.get(styleData.row).functionId; + else + return ""; + } } } } @@ -378,7 +383,6 @@ Dialog { } } } - } RowLayout @@ -456,7 +460,6 @@ Dialog { onAccepted: { var item = transactionDialog.getItem(); - if (transactionDialog.transactionIndex < transactionsModel.count) { transactionsModel.set(transactionDialog.transactionIndex, item); stateTransactions[transactionDialog.transactionIndex] = item; diff --git a/mix/qml/StructView.qml b/mix/qml/StructView.qml index 2a0c5c68a..32ce3d618 100644 --- a/mix/qml/StructView.qml +++ b/mix/qml/StructView.qml @@ -8,17 +8,19 @@ Column id: root property alias members: repeater.model //js array property var value: ({}) + property int transactionIndex Layout.fillWidth: true - + spacing: 10 Repeater { id: repeater visible: model.length > 0 Layout.fillWidth: true + RowLayout { id: row - height: 20 + (members[index].type.category === QSolidityType.Struct ? (20 * members[index].type.members.length) : 0) + height: 30 + (members[index].type.category === QSolidityType.Struct ? (20 * members[index].type.members.length) : 0) Layout.fillWidth: true DefaultLabel { height: 20 @@ -51,10 +53,12 @@ Column return Qt.createComponent("qrc:/qml/QBoolTypeView.qml"); else if (t === QSolidityType.Bytes) return Qt.createComponent("qrc:/qml/QStringTypeView.qml"); - else if (t === QSolidityType.Hash || t === QSolidityType.Address) + else if (t === QSolidityType.Hash) return Qt.createComponent("qrc:/qml/QHashTypeView.qml"); else if (t === QSolidityType.Struct) return Qt.createComponent("qrc:/qml/StructView.qml"); + else if (t === QSolidityType.Address) + return Qt.createComponent("qrc:/qml/QAddressView.qml"); else return undefined; } @@ -63,7 +67,26 @@ Column var ptype = members[index].type; var pname = members[index].name; var vals = value; - if (ptype.category === QSolidityType.Struct && !item.members) + if (ptype.category === QSolidityType.Address) + { + item.contractCreationTr.append({"functionId": " - "}); + var trCr = -1; + for (var k = 0; k < transactionsModel.count; k++) + { + if (k >= transactionIndex) + break; + var tr = transactionsModel.get(k); + if (tr.functionId === tr.contractId) + { + trCr++; + if (modelData.type.name === qsTr("contract") + " " + tr.contractId) + item.contractCreationTr.append({ "functionId": tr.contractId + " - " + trCr }); + } + } + item.value = getValue(); + item.init(); + } + else if (ptype.category === QSolidityType.Struct && !item.members) { item.value = getValue(); item.members = ptype.members; diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index ed76d48eb..0668bfca2 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -39,6 +39,8 @@ Dialog { rowGasPrice.visible = !useTransactionDefaultValue; transactionIndex = index; + typeLoader.transactionIndex = index; + gasValueEdit.gasValue = item.gas; gasAutoCheck.checked = item.gasAuto ? true : false; gasPriceField.value = item.gasPrice; @@ -99,6 +101,18 @@ Dialog { } + function selectContract(contractName) + { + for (var k = 0; k < contractsModel.count; k++) + { + if (contractsModel.get(k).cid === contractName) + { + contractComboBox.currentIndex = k; + break; + } + } + } + function selectFunction(functionId) { var functionIndex = -1; diff --git a/mix/res.qrc b/mix/res.qrc index f175fab1f..ac0af57ac 100644 --- a/mix/res.qrc +++ b/mix/res.qrc @@ -67,5 +67,6 @@ qml/img/stop_button2x.png qml/img/warningicon.png qml/img/warningicon@2x.png + qml/QAddressView.qml diff --git a/mix/test/qml/TestMain.qml b/mix/test/qml/TestMain.qml index 778e4dc20..c0d179707 100644 --- a/mix/test/qml/TestMain.qml +++ b/mix/test/qml/TestMain.qml @@ -96,6 +96,7 @@ TestCase function test_dbg_arrayParametersAndStorage() { TestDebugger.test_arrayParametersAndStorage(); } function test_dbg_solidity() { TestDebugger.test_solidityDebugging(); } function test_dbg_vm() { TestDebugger.test_vmDebugging(); } + function test_dbg_ctrTypeAsParam() { TestDebugger.test_ctrTypeAsParam(); } function test_miner_getDefaultiner() { TestMiner.test_getDefaultMiner(); } function test_miner_selectMiner() { TestMiner.test_selectMiner(); } function test_miner_mine() { TestMiner.test_mine(); } diff --git a/mix/test/qml/js/TestDebugger.js b/mix/test/qml/js/TestDebugger.js index f8453df78..2300dd390 100644 --- a/mix/test/qml/js/TestDebugger.js +++ b/mix/test/qml/js/TestDebugger.js @@ -203,3 +203,47 @@ function test_vmDebugging() tryCompare(mainApplication.mainContent.rightPane.vmMemory.listModel, "length", 0); } +function test_ctrTypeAsParam() +{ + newProject(); + editContract( + "contract C1 {\r " + + " function get() returns (uint256)\r " + + " {\r " + + " return 159;\r " + + " }\r " + + "}\r" + + "contract C2 {\r " + + " C1 c1;\r " + + " function getFromC1() returns (uint256)\r " + + " {\r " + + " return c1.get();\r " + + " }\r " + + " function C2(C1 _c1)\r" + + " {\r " + + " c1 = _c1;\r" + + " }\r " + + "}"); + mainApplication.projectModel.stateListModel.editState(0); //C1 ctor already added + mainApplication.projectModel.stateDialog.model.addTransaction(); + var transactionDialog = mainApplication.projectModel.stateDialog.transactionDialog; + ts.waitForRendering(transactionDialog, 3000); + transactionDialog.selectContract("C2"); + transactionDialog.selectFunction("C2"); + transactionDialog.acceptAndClose(); + mainApplication.projectModel.stateDialog.model.addTransaction(); + transactionDialog = mainApplication.projectModel.stateDialog.transactionDialog; + ts.waitForRendering(transactionDialog, 3000); + transactionDialog.selectContract("C2"); + transactionDialog.selectFunction("getFromC1"); + clickElement(transactionDialog, 406, 340); + clickElement(transactionDialog, 406, 366); + transactionDialog.acceptAndClose(); + mainApplication.projectModel.stateDialog.acceptAndClose(); + mainApplication.mainContent.startQuickDebugging(); + if (!ts.waitForSignal(mainApplication.clientModel, "debugDataReady(QObject*)", 5000)) + fail("Error running transaction"); + + tryCompare(mainApplication.mainContent.rightPane.transactionLog.transactionModel.get(4), "returned", "(159)"); +} + diff --git a/mix/test/qml/js/TestTutorial.js b/mix/test/qml/js/TestTutorial.js index 895b5c9c1..7f366f23b 100644 --- a/mix/test/qml/js/TestTutorial.js +++ b/mix/test/qml/js/TestTutorial.js @@ -52,7 +52,7 @@ function test_tutorial() transactionDialog.selectFunction("setRating"); clickElement(transactionDialog, 200, 310); ts.typeString("Titanic", transactionDialog); - clickElement(transactionDialog, 200, 330); + clickElement(transactionDialog, 200, 350); ts.typeString("2", transactionDialog); transactionDialog.acceptAndClose(); mainApplication.projectModel.stateDialog.acceptAndClose();