|
|
|
import QtQuick 2.2
|
|
|
|
import QtQuick.Controls 1.1
|
|
|
|
import QtQuick.Layouts 1.1
|
|
|
|
import QtQuick.Window 2.0
|
|
|
|
import QtQuick.Controls.Styles 1.3
|
|
|
|
import org.ethereum.qml.QEther 1.0
|
|
|
|
import "js/TransactionHelper.js" as TransactionHelper
|
|
|
|
import "."
|
|
|
|
|
|
|
|
Window {
|
|
|
|
id: modalTransactionDialog
|
|
|
|
modality: Qt.ApplicationModal
|
|
|
|
width: 520
|
|
|
|
height: (paramsModel.count > 0 ? 500 : 300)
|
|
|
|
visible: false
|
|
|
|
color: StateDialogStyle.generic.backgroundColor
|
|
|
|
title: qsTr("Edit Transaction")
|
|
|
|
property int transactionIndex
|
|
|
|
property alias transactionParams: paramsModel;
|
|
|
|
property alias gas: gasValueEdit.gasValue;
|
|
|
|
property alias gasPrice: gasPriceField.value;
|
|
|
|
property alias transactionValue: valueField.value;
|
|
|
|
property string contractId: contractComboBox.currentValue();
|
|
|
|
property alias functionId: functionComboBox.currentText;
|
|
|
|
property var itemParams;
|
|
|
|
property bool useTransactionDefaultValue: false
|
|
|
|
property var qType;
|
|
|
|
|
|
|
|
signal accepted;
|
|
|
|
|
|
|
|
function open(index, item) {
|
|
|
|
qType = [];
|
|
|
|
rowFunction.visible = !useTransactionDefaultValue;
|
|
|
|
rowValue.visible = !useTransactionDefaultValue;
|
|
|
|
rowGas.visible = !useTransactionDefaultValue;
|
|
|
|
rowGasPrice.visible = !useTransactionDefaultValue;
|
|
|
|
|
|
|
|
transactionIndex = index;
|
|
|
|
gasValueEdit.gasValue = item.gas;
|
|
|
|
gasPriceField.value = item.gasPrice;
|
|
|
|
valueField.value = item.value;
|
|
|
|
var contractId = item.contractId;
|
|
|
|
var functionId = item.functionId;
|
|
|
|
rowFunction.visible = true;
|
|
|
|
|
|
|
|
itemParams = item.parameters !== undefined ? item.parameters : {};
|
|
|
|
|
|
|
|
contractsModel.clear();
|
|
|
|
var contractIndex = -1;
|
|
|
|
var contracts = codeModel.contracts;
|
|
|
|
for (var c in contracts) {
|
|
|
|
contractsModel.append({ cid: c, text: contracts[c].contract.name });
|
|
|
|
if (contracts[c].contract.name === contractId)
|
|
|
|
contractIndex = contractsModel.count - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (contractIndex == -1 && contractsModel.count > 0)
|
|
|
|
contractIndex = 0; //@todo suggest unused contract
|
|
|
|
contractComboBox.currentIndex = contractIndex;
|
|
|
|
|
|
|
|
loadFunctions(contractComboBox.currentValue());
|
|
|
|
|
|
|
|
var functionIndex = -1;
|
|
|
|
for (var f = 0; f < functionsModel.count; f++)
|
|
|
|
if (functionsModel.get(f).text === item.functionId)
|
|
|
|
functionIndex = f;
|
|
|
|
|
|
|
|
if (functionIndex == -1 && functionsModel.count > 0)
|
|
|
|
functionIndex = 0; //@todo suggest unused function
|
|
|
|
|
|
|
|
functionComboBox.currentIndex = functionIndex;
|
|
|
|
|
|
|
|
paramsModel.clear();
|
|
|
|
if (functionId !== contractComboBox.currentValue())
|
|
|
|
loadParameters();
|
|
|
|
else {
|
|
|
|
var contract = codeModel.contracts[contractId];
|
|
|
|
if (contract) {
|
|
|
|
var parameters = contract.contract.constructor.parameters;
|
|
|
|
for (var p = 0; p < parameters.length; p++)
|
|
|
|
loadParameter(parameters[p]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
modalTransactionDialog.setX((Screen.width - width) / 2);
|
|
|
|
modalTransactionDialog.setY((Screen.height - height) / 2);
|
|
|
|
|
|
|
|
visible = true;
|
|
|
|
valueField.focus = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
function loadFunctions(contractId)
|
|
|
|
{
|
|
|
|
functionsModel.clear();
|
|
|
|
var contract = codeModel.contracts[contractId];
|
|
|
|
if (contract) {
|
|
|
|
var functions = codeModel.contracts[contractId].contract.functions;
|
|
|
|
for (var f = 0; f < functions.length; f++) {
|
|
|
|
functionsModel.append({ text: functions[f].name });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//append constructor
|
|
|
|
functionsModel.append({ text: contractId });
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
function loadParameter(parameter)
|
|
|
|
{
|
|
|
|
var type = parameter.type;
|
|
|
|
var pname = parameter.name;
|
|
|
|
var varComponent;
|
|
|
|
|
|
|
|
if (type.indexOf("int") !== -1)
|
|
|
|
varComponent = Qt.createComponent("qrc:/qml/QIntType.qml");
|
|
|
|
else if (type.indexOf("real") !== -1)
|
|
|
|
varComponent = Qt.createComponent("qrc:/qml/QRealType.qml");
|
|
|
|
else if (type.indexOf("string") !== -1 || type.indexOf("text") !== -1)
|
|
|
|
varComponent = Qt.createComponent("qrc:/qml/QStringType.qml");
|
|
|
|
else if (type.indexOf("hash") !== -1 || type.indexOf("address") !== -1)
|
|
|
|
varComponent = Qt.createComponent("qrc:/qml/QHashType.qml");
|
|
|
|
else if (type.indexOf("bool") !== -1)
|
|
|
|
varComponent = Qt.createComponent("qrc:/qml/QBoolType.qml");
|
|
|
|
|
|
|
|
var param = varComponent.createObject(modalTransactionDialog);
|
|
|
|
var value = itemParams[pname] !== undefined ? itemParams[pname] : "";
|
|
|
|
|
|
|
|
param.setValue(value);
|
|
|
|
param.setDeclaration(parameter);
|
|
|
|
qType.push({ name: pname, value: param });
|
|
|
|
paramsModel.append({ name: pname, type: type, value: value });
|
|
|
|
}
|
|
|
|
|
|
|
|
function loadParameters() {
|
|
|
|
paramsModel.clear();
|
|
|
|
if (!paramsModel)
|
|
|
|
return;
|
|
|
|
if (functionComboBox.currentIndex >= 0 && functionComboBox.currentIndex < functionsModel.count) {
|
|
|
|
var contract = codeModel.contracts[contractComboBox.currentValue()];
|
|
|
|
if (contract) {
|
|
|
|
var func = contract.contract.functions[functionComboBox.currentIndex];
|
|
|
|
if (func) {
|
|
|
|
var parameters = func.parameters;
|
|
|
|
for (var p = 0; p < parameters.length; p++)
|
|
|
|
loadParameter(parameters[p]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function param(name)
|
|
|
|
{
|
|
|
|
for (var k = 0; k < paramsModel.count; k++)
|
|
|
|
{
|
|
|
|
if (paramsModel.get(k).name === name)
|
|
|
|
return paramsModel.get(k);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function close()
|
|
|
|
{
|
|
|
|
visible = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
function qTypeParam(name)
|
|
|
|
{
|
|
|
|
for (var k in qType)
|
|
|
|
{
|
|
|
|
if (qType[k].name === name)
|
|
|
|
return qType[k].value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function getItem()
|
|
|
|
{
|
|
|
|
var item;
|
|
|
|
if (!useTransactionDefaultValue)
|
|
|
|
{
|
|
|
|
item = {
|
|
|
|
contractId: transactionDialog.contractId,
|
|
|
|
functionId: transactionDialog.functionId,
|
|
|
|
gas: transactionDialog.gas,
|
|
|
|
gasPrice: transactionDialog.gasPrice,
|
|
|
|
value: transactionDialog.transactionValue,
|
|
|
|
parameters: {},
|
|
|
|
};
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
item = TransactionHelper.defaultTransaction();
|
|
|
|
item.contractId = transactionDialog.contractId;
|
|
|
|
item.functionId = transactionDialog.functionId;
|
|
|
|
}
|
|
|
|
|
|
|
|
var orderedQType = [];
|
|
|
|
for (var p = 0; p < transactionDialog.transactionParams.count; p++) {
|
|
|
|
var parameter = transactionDialog.transactionParams.get(p);
|
|
|
|
var qtypeParam = qTypeParam(parameter.name);
|
|
|
|
qtypeParam.setValue(parameter.value);
|
|
|
|
orderedQType.push(qtypeParam);
|
|
|
|
item.parameters[parameter.name] = parameter.value;
|
|
|
|
}
|
|
|
|
item.qType = orderedQType;
|
|
|
|
return item;
|
|
|
|
}
|
|
|
|
|
|
|
|
ColumnLayout {
|
|
|
|
anchors.fill: parent
|
|
|
|
anchors.margins: 10
|
|
|
|
|
|
|
|
ColumnLayout {
|
|
|
|
id: dialogContent
|
|
|
|
anchors.top: parent.top
|
|
|
|
spacing: 10
|
|
|
|
RowLayout
|
|
|
|
{
|
|
|
|
id: rowContract
|
|
|
|
Layout.fillWidth: true
|
|
|
|
height: 150
|
|
|
|
DefaultLabel {
|
|
|
|
Layout.preferredWidth: 75
|
|
|
|
text: qsTr("Contract")
|
|
|
|
}
|
|
|
|
ComboBox {
|
|
|
|
id: contractComboBox
|
|
|
|
function currentValue() {
|
|
|
|
return (currentIndex >=0 && currentIndex < contractsModel.count) ? contractsModel.get(currentIndex).cid : "";
|
|
|
|
}
|
|
|
|
Layout.preferredWidth: 350
|
|
|
|
currentIndex: -1
|
|
|
|
textRole: "text"
|
|
|
|
editable: false
|
|
|
|
model: ListModel {
|
|
|
|
id: contractsModel
|
|
|
|
}
|
|
|
|
onCurrentIndexChanged: {
|
|
|
|
loadFunctions(currentValue());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RowLayout
|
|
|
|
{
|
|
|
|
id: rowFunction
|
|
|
|
Layout.fillWidth: true
|
|
|
|
height: 150
|
|
|
|
DefaultLabel {
|
|
|
|
Layout.preferredWidth: 75
|
|
|
|
text: qsTr("Function")
|
|
|
|
}
|
|
|
|
ComboBox {
|
|
|
|
id: functionComboBox
|
|
|
|
Layout.preferredWidth: 350
|
|
|
|
currentIndex: -1
|
|
|
|
textRole: "text"
|
|
|
|
editable: false
|
|
|
|
model: ListModel {
|
|
|
|
id: functionsModel
|
|
|
|
}
|
|
|
|
onCurrentIndexChanged: {
|
|
|
|
loadParameters();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CommonSeparator
|
|
|
|
{
|
|
|
|
Layout.fillWidth: true
|
|
|
|
}
|
|
|
|
|
|
|
|
RowLayout
|
|
|
|
{
|
|
|
|
id: rowValue
|
|
|
|
Layout.fillWidth: true
|
|
|
|
height: 150
|
|
|
|
DefaultLabel {
|
|
|
|
Layout.preferredWidth: 75
|
|
|
|
text: qsTr("Value")
|
|
|
|
}
|
|
|
|
Ether {
|
|
|
|
id: valueField
|
|
|
|
edit: true
|
|
|
|
displayFormattedValue: true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CommonSeparator
|
|
|
|
{
|
|
|
|
Layout.fillWidth: true
|
|
|
|
}
|
|
|
|
|
|
|
|
RowLayout
|
|
|
|
{
|
|
|
|
id: rowGas
|
|
|
|
Layout.fillWidth: true
|
|
|
|
height: 150
|
|
|
|
DefaultLabel {
|
|
|
|
Layout.preferredWidth: 75
|
|
|
|
text: qsTr("Gas")
|
|
|
|
}
|
|
|
|
|
|
|
|
DefaultTextField
|
|
|
|
{
|
|
|
|
property variant gasValue
|
|
|
|
onGasValueChanged: text = gasValue.value();
|
|
|
|
onTextChanged: gasValue.setValue(text);
|
|
|
|
implicitWidth: 200
|
|
|
|
id: gasValueEdit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CommonSeparator
|
|
|
|
{
|
|
|
|
Layout.fillWidth: true
|
|
|
|
}
|
|
|
|
|
|
|
|
RowLayout
|
|
|
|
{
|
|
|
|
id: rowGasPrice
|
|
|
|
Layout.fillWidth: true
|
|
|
|
height: 150
|
|
|
|
DefaultLabel {
|
|
|
|
Layout.preferredWidth: 75
|
|
|
|
text: qsTr("Gas Price")
|
|
|
|
}
|
|
|
|
Ether {
|
|
|
|
id: gasPriceField
|
|
|
|
edit: true
|
|
|
|
displayFormattedValue: true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CommonSeparator
|
|
|
|
{
|
|
|
|
Layout.fillWidth: true
|
|
|
|
}
|
|
|
|
|
|
|
|
DefaultLabel {
|
|
|
|
id: paramLabel
|
|
|
|
text: qsTr("Parameters:")
|
|
|
|
Layout.preferredWidth: 75
|
|
|
|
visible: paramsModel.count > 0
|
|
|
|
}
|
|
|
|
|
|
|
|
ScrollView
|
|
|
|
{
|
|
|
|
anchors.top: paramLabel.bottom
|
|
|
|
anchors.topMargin: 10
|
|
|
|
Layout.preferredWidth: 350
|
|
|
|
Layout.fillHeight: true
|
|
|
|
visible: paramsModel.count > 0
|
|
|
|
Column
|
|
|
|
{
|
|
|
|
id: paramRepeater
|
|
|
|
Layout.fillWidth: true
|
|
|
|
Layout.fillHeight: true
|
|
|
|
spacing: 3
|
|
|
|
Repeater
|
|
|
|
{
|
|
|
|
height: 20 * paramsModel.count
|
|
|
|
model: paramsModel
|
|
|
|
visible: paramsModel.count > 0
|
|
|
|
RowLayout
|
|
|
|
{
|
|
|
|
id: row
|
|
|
|
Layout.fillWidth: true
|
|
|
|
height: 20
|
|
|
|
DefaultLabel {
|
|
|
|
id: typeLabel
|
|
|
|
text: type
|
|
|
|
Layout.preferredWidth: 50
|
|
|
|
}
|
|
|
|
|
|
|
|
DefaultLabel {
|
|
|
|
id: nameLabel
|
|
|
|
text: name
|
|
|
|
Layout.preferredWidth: 80
|
|
|
|
}
|
|
|
|
|
|
|
|
DefaultLabel {
|
|
|
|
id: equalLabel
|
|
|
|
text: "="
|
|
|
|
Layout.preferredWidth: 15
|
|
|
|
}
|
|
|
|
|
|
|
|
Loader
|
|
|
|
{
|
|
|
|
id: typeLoader
|
|
|
|
Layout.preferredWidth: 150
|
|
|
|
function getCurrent()
|
|
|
|
{
|
|
|
|
return modalTransactionDialog.param(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
Connections {
|
|
|
|
target: typeLoader.item
|
|
|
|
onTextChanged: {
|
|
|
|
typeLoader.getCurrent().value = typeLoader.item.text;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sourceComponent:
|
|
|
|
{
|
|
|
|
if (type.indexOf("int") !== -1)
|
|
|
|
return intViewComp;
|
|
|
|
else if (type.indexOf("bool") !== -1)
|
|
|
|
return boolViewComp;
|
|
|
|
else if (type.indexOf("string") !== -1)
|
|
|
|
return stringViewComp;
|
|
|
|
else if (type.indexOf("hash") !== -1 || type.indexOf("address") !== -1)
|
|
|
|
return hashViewComp;
|
|
|
|
else
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
Component
|
|
|
|
{
|
|
|
|
id: intViewComp
|
|
|
|
QIntTypeView
|
|
|
|
{
|
|
|
|
height: 20
|
|
|
|
width: 150
|
|
|
|
id: intView
|
|
|
|
text: typeLoader.getCurrent().value
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Component
|
|
|
|
{
|
|
|
|
id: boolViewComp
|
|
|
|
QBoolTypeView
|
|
|
|
{
|
|
|
|
height: 20
|
|
|
|
width: 150
|
|
|
|
id: boolView
|
|
|
|
defaultValue: "1"
|
|
|
|
Component.onCompleted:
|
|
|
|
{
|
|
|
|
var current = typeLoader.getCurrent().value;
|
|
|
|
(current === "" ? text = defaultValue : text = current);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Component
|
|
|
|
{
|
|
|
|
id: stringViewComp
|
|
|
|
QStringTypeView
|
|
|
|
{
|
|
|
|
height: 20
|
|
|
|
width: 150
|
|
|
|
id: stringView
|
|
|
|
text:
|
|
|
|
{
|
|
|
|
return typeLoader.getCurrent().value
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Component
|
|
|
|
{
|
|
|
|
id: hashViewComp
|
|
|
|
QHashTypeView
|
|
|
|
{
|
|
|
|
height: 20
|
|
|
|
width: 150
|
|
|
|
id: hashView
|
|
|
|
text: typeLoader.getCurrent().value
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CommonSeparator
|
|
|
|
{
|
|
|
|
Layout.fillWidth: true
|
|
|
|
visible: paramsModel.count > 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RowLayout
|
|
|
|
{
|
|
|
|
anchors.bottom: parent.bottom
|
|
|
|
anchors.right: parent.right;
|
|
|
|
|
|
|
|
Button {
|
|
|
|
text: qsTr("OK");
|
|
|
|
onClicked: {
|
|
|
|
close();
|
|
|
|
accepted();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Button {
|
|
|
|
text: qsTr("Cancel");
|
|
|
|
onClicked: close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ListModel {
|
|
|
|
id: paramsModel
|
|
|
|
}
|
|
|
|
}
|