You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
516 lines
10 KiB
516 lines
10 KiB
import QtQuick 2.2
|
|
import QtQuick.Controls 1.1
|
|
import QtQuick.Layouts 1.1
|
|
import QtQuick.Window 2.0
|
|
import QtQuick.Dialogs 1.2
|
|
import QtQuick.Controls.Styles 1.3
|
|
import org.ethereum.qml.QEther 1.0
|
|
import "js/TransactionHelper.js" as TransactionHelper
|
|
import "js/ProjectModel.js" as ProjectModelCode
|
|
import "js/QEtherHelper.js" as QEtherHelper
|
|
import "."
|
|
|
|
|
|
Dialog {
|
|
id: modalDeploymentDialog
|
|
modality: Qt.ApplicationModal
|
|
width: 735
|
|
height: 400
|
|
visible: false
|
|
property alias applicationUrlEth: applicationUrlEth.text
|
|
property alias applicationUrlHttp: applicationUrlHttp.text
|
|
property alias urlHintContract: urlHintAddr.text
|
|
property alias localPackageUrl: localPackageUrl.text
|
|
property string packageHash
|
|
property string packageBase64
|
|
property string eth: registrarAddr.text
|
|
property string currentAccount
|
|
property alias gasToUse: gasToUseInput.text
|
|
|
|
function close()
|
|
{
|
|
visible = false;
|
|
}
|
|
|
|
function open()
|
|
{
|
|
visible = true;
|
|
var requests = [{
|
|
//accounts
|
|
jsonrpc: "2.0",
|
|
method: "eth_accounts",
|
|
params: null,
|
|
id: 0
|
|
}];
|
|
|
|
TransactionHelper.rpcCall(requests, function(arg1, arg2)
|
|
{
|
|
modelAccounts.clear();
|
|
var ids = JSON.parse(arg2)[0].result;
|
|
requests = [];
|
|
for (var k in ids)
|
|
{
|
|
modelAccounts.append({ "id": ids[k] })
|
|
requests.push({
|
|
//accounts
|
|
jsonrpc: "2.0",
|
|
method: "eth_balanceAt",
|
|
params: [ids[k]],
|
|
id: k
|
|
});
|
|
}
|
|
|
|
if (ids.length > 0)
|
|
currentAccount = modelAccounts.get(0).id;
|
|
|
|
TransactionHelper.rpcCall(requests, function (request, response){
|
|
var balanceRet = JSON.parse(response);
|
|
for (var k in balanceRet)
|
|
{
|
|
var ether = QEtherHelper.createEther(balanceRet[k].result, QEther.Wei);
|
|
comboAccounts.balances.push(ether.format());
|
|
}
|
|
balance.text = comboAccounts.balances[0];
|
|
});
|
|
});
|
|
|
|
var gas = 0;
|
|
var gasCosts = clientModel.gasCosts;
|
|
for (var g in gasCosts)
|
|
gas += gasCosts[g];
|
|
gasToUse = gas;
|
|
}
|
|
|
|
function stopForInputError(inError)
|
|
{
|
|
errorDialog.text = "";
|
|
if (inError.length > 0)
|
|
{
|
|
errorDialog.text = qsTr("The length of a string cannot exceed 32 characters.\nPlease verify the following value(s):\n\n")
|
|
for (var k in inError)
|
|
errorDialog.text += inError[k] + "\n";
|
|
errorDialog.open();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function pad(h)
|
|
{
|
|
// TODO move this to QHashType class
|
|
while (h.length < 64)
|
|
{
|
|
h = '0' + h;
|
|
}
|
|
return h;
|
|
}
|
|
|
|
function waitForTrCountToIncrement(callBack)
|
|
{
|
|
poolLog.callBack = callBack;
|
|
poolLog.k = -1;
|
|
poolLog.elapsed = 0;
|
|
poolLog.start();
|
|
}
|
|
|
|
Timer
|
|
{
|
|
id: poolLog
|
|
property var callBack
|
|
property int k: -1
|
|
property int elapsed
|
|
interval: 500
|
|
running: false
|
|
repeat: true
|
|
onTriggered: {
|
|
elapsed += interval;
|
|
var requests = [];
|
|
var jsonRpcRequestId = 0;
|
|
requests.push({
|
|
jsonrpc: "2.0",
|
|
method: "eth_getTransactionCount",
|
|
params: [ currentAccount, "pending" ],
|
|
id: jsonRpcRequestId++
|
|
});
|
|
TransactionHelper.rpcCall(requests, function (httpRequest, response){
|
|
response = response.replace(/,0+/, ''); // ==> result:27,00000000
|
|
var count = JSON.parse(response)[0].result
|
|
if (k < parseInt(count) && k > 0)
|
|
{
|
|
stop();
|
|
callBack(1);
|
|
}
|
|
else if (elapsed > 25000)
|
|
{
|
|
stop();
|
|
callBack(-1);
|
|
}
|
|
else
|
|
k = parseInt(JSON.parse(response)[0].result);
|
|
})
|
|
}
|
|
}
|
|
|
|
SourceSansProRegular
|
|
{
|
|
id: lightFont
|
|
}
|
|
|
|
contentItem: Rectangle {
|
|
color: appStyle.generic.layout.backgroundColor
|
|
anchors.fill: parent
|
|
Column
|
|
{
|
|
spacing: 5
|
|
anchors.fill: parent
|
|
anchors.margins: 10
|
|
ColumnLayout
|
|
{
|
|
id: containerDeploy
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 500
|
|
RowLayout
|
|
{
|
|
Rectangle
|
|
{
|
|
Layout.preferredWidth: 357
|
|
DefaultLabel
|
|
{
|
|
text: qsTr("Deployment")
|
|
font.family: lightFont.name
|
|
font.underline: true
|
|
anchors.centerIn: parent
|
|
}
|
|
}
|
|
|
|
Button
|
|
{
|
|
action: displayHelpAction
|
|
iconSource: "qrc:/qml/img/help.png"
|
|
}
|
|
|
|
Action {
|
|
id: displayHelpAction
|
|
tooltip: qsTr("Help")
|
|
onTriggered: {
|
|
Qt.openUrlExternally("https://github.com/ethereum/wiki/wiki/Mix:-The-DApp-IDE#deployment-to-network")
|
|
}
|
|
}
|
|
|
|
Button
|
|
{
|
|
action: openFolderAction
|
|
iconSource: "qrc:/qml/img/openedfolder.png"
|
|
}
|
|
|
|
Action {
|
|
id: openFolderAction
|
|
enabled: deploymentDialog.packageBase64 !== ""
|
|
tooltip: qsTr("Open Package Folder")
|
|
onTriggered: {
|
|
fileIo.openFileBrowser(projectModel.deploymentDir);
|
|
}
|
|
}
|
|
|
|
Button
|
|
{
|
|
action: b64Action
|
|
iconSource: "qrc:/qml/img/b64.png"
|
|
}
|
|
|
|
Action {
|
|
id: b64Action
|
|
enabled: deploymentDialog.packageBase64 !== ""
|
|
tooltip: qsTr("Copy Base64 conversion to ClipBoard")
|
|
onTriggered: {
|
|
clipboard.text = deploymentDialog.packageBase64;
|
|
}
|
|
}
|
|
|
|
Button
|
|
{
|
|
action: exitAction
|
|
iconSource: "qrc:/qml/img/exit.png"
|
|
}
|
|
|
|
Action {
|
|
id: exitAction
|
|
tooltip: qsTr("Exit")
|
|
onTriggered: {
|
|
close()
|
|
}
|
|
}
|
|
}
|
|
|
|
GridLayout
|
|
{
|
|
columns: 2
|
|
width: parent.width
|
|
|
|
DefaultLabel
|
|
{
|
|
text: qsTr("Root Registrar address:")
|
|
}
|
|
|
|
DefaultTextField
|
|
{
|
|
Layout.preferredWidth: 350
|
|
id: registrarAddr
|
|
}
|
|
|
|
DefaultLabel
|
|
{
|
|
text: qsTr("Account used to deploy:")
|
|
}
|
|
|
|
Rectangle
|
|
{
|
|
width: 300
|
|
height: 25
|
|
color: "transparent"
|
|
ComboBox {
|
|
id: comboAccounts
|
|
property var balances: []
|
|
onCurrentIndexChanged : {
|
|
if (modelAccounts.count > 0)
|
|
{
|
|
currentAccount = modelAccounts.get(currentIndex).id;
|
|
balance.text = balances[currentIndex];
|
|
}
|
|
}
|
|
model: ListModel {
|
|
id: modelAccounts
|
|
}
|
|
}
|
|
|
|
DefaultLabel
|
|
{
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.left: comboAccounts.right
|
|
anchors.leftMargin: 20
|
|
id: balance;
|
|
}
|
|
}
|
|
}
|
|
|
|
DefaultLabel
|
|
{
|
|
text: qsTr("Amount of gas to use for each contract deployment: ")
|
|
}
|
|
|
|
DefaultTextField
|
|
{
|
|
text: "1000000"
|
|
Layout.preferredWidth: 350
|
|
id: gasToUseInput
|
|
}
|
|
|
|
DefaultLabel
|
|
{
|
|
text: qsTr("Ethereum Application URL: ")
|
|
}
|
|
|
|
Rectangle
|
|
{
|
|
Layout.fillWidth: true
|
|
height: 25
|
|
color: "transparent"
|
|
DefaultTextField
|
|
{
|
|
width: 200
|
|
id: applicationUrlEth
|
|
onTextChanged: {
|
|
appUrlFormatted.text = ProjectModelCode.formatAppUrl(text).join('/');
|
|
}
|
|
}
|
|
|
|
DefaultLabel
|
|
{
|
|
id: appUrlFormatted
|
|
anchors.verticalCenter: parent.verticalCenter;
|
|
anchors.left: applicationUrlEth.right
|
|
font.italic: true
|
|
font.pointSize: appStyle.absoluteSize(-1)
|
|
}
|
|
}
|
|
}
|
|
|
|
RowLayout
|
|
{
|
|
Layout.fillWidth: true
|
|
Rectangle
|
|
{
|
|
Layout.preferredWidth: 357
|
|
color: "transparent"
|
|
}
|
|
|
|
Button
|
|
{
|
|
id: deployButton
|
|
action: runAction
|
|
iconSource: "qrc:/qml/img/run.png"
|
|
}
|
|
|
|
Action {
|
|
id: runAction
|
|
tooltip: qsTr("Deploy contract(s) and Package resources files.")
|
|
onTriggered: {
|
|
var inError = [];
|
|
var ethUrl = ProjectModelCode.formatAppUrl(applicationUrlEth.text);
|
|
for (var k in ethUrl)
|
|
{
|
|
if (ethUrl[k].length > 32)
|
|
inError.push(qsTr("Member too long: " + ethUrl[k]) + "\n");
|
|
}
|
|
if (!stopForInputError(inError))
|
|
{
|
|
if (contractRedeploy.checked)
|
|
deployWarningDialog.open();
|
|
else
|
|
ProjectModelCode.startDeployProject(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
CheckBox
|
|
{
|
|
anchors.left: deployButton.right
|
|
id: contractRedeploy
|
|
enabled: Object.keys(projectModel.deploymentAddresses).length > 0
|
|
checked: Object.keys(projectModel.deploymentAddresses).length == 0
|
|
text: qsTr("Deploy Contract(s)")
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
}
|
|
}
|
|
|
|
Rectangle
|
|
{
|
|
width: parent.width
|
|
height: 1
|
|
color: "#5891d3"
|
|
}
|
|
|
|
ColumnLayout
|
|
{
|
|
id: containerRegister
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 500
|
|
RowLayout
|
|
{
|
|
Layout.preferredHeight: 25
|
|
Rectangle
|
|
{
|
|
Layout.preferredWidth: 356
|
|
DefaultLabel
|
|
{
|
|
text: qsTr("Registration")
|
|
font.family: lightFont.name
|
|
font.underline: true
|
|
anchors.centerIn: parent
|
|
}
|
|
}
|
|
}
|
|
|
|
GridLayout
|
|
{
|
|
columns: 2
|
|
Layout.fillWidth: true
|
|
|
|
DefaultLabel
|
|
{
|
|
Layout.preferredWidth: 355
|
|
text: qsTr("Local package URL")
|
|
}
|
|
|
|
DefaultTextField
|
|
{
|
|
Layout.preferredWidth: 350
|
|
id: localPackageUrl
|
|
readOnly: true
|
|
|
|
}
|
|
|
|
DefaultLabel
|
|
{
|
|
Layout.preferredWidth: 355
|
|
text: qsTr("URL Hint contract address:")
|
|
}
|
|
|
|
DefaultTextField
|
|
{
|
|
Layout.preferredWidth: 350
|
|
id: urlHintAddr
|
|
enabled: rowRegister.isOkToRegister()
|
|
}
|
|
|
|
DefaultLabel
|
|
{
|
|
Layout.preferredWidth: 355
|
|
text: qsTr("Web Application Resources URL: ")
|
|
}
|
|
|
|
DefaultTextField
|
|
{
|
|
Layout.preferredWidth: 350
|
|
id: applicationUrlHttp
|
|
enabled: rowRegister.isOkToRegister()
|
|
}
|
|
}
|
|
|
|
RowLayout
|
|
{
|
|
id: rowRegister
|
|
Layout.fillWidth: true
|
|
|
|
Rectangle
|
|
{
|
|
Layout.preferredWidth: 357
|
|
color: "transparent"
|
|
}
|
|
|
|
function isOkToRegister()
|
|
{
|
|
return Object.keys(projectModel.deploymentAddresses).length > 0 && deploymentDialog.packageHash !== "";
|
|
}
|
|
|
|
Button {
|
|
action: registerAction
|
|
iconSource: "qrc:/qml/img/note.png"
|
|
}
|
|
|
|
Action {
|
|
id: registerAction
|
|
enabled: rowRegister.isOkToRegister()
|
|
tooltip: qsTr("Register hosted Web Application.")
|
|
onTriggered: {
|
|
if (applicationUrlHttp.text === "" || deploymentDialog.packageHash === "")
|
|
{
|
|
deployDialog.title = text;
|
|
deployDialog.text = qsTr("Please provide the link where the resources are stored and ensure the package is aleary built using the deployment step.")
|
|
deployDialog.open();
|
|
return;
|
|
}
|
|
var inError = [];
|
|
if (applicationUrlHttp.text.length > 32)
|
|
inError.push(qsTr(applicationUrlHttp.text));
|
|
if (!stopForInputError(inError))
|
|
ProjectModelCode.registerToUrlHint();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
MessageDialog {
|
|
id: deployDialog
|
|
standardButtons: StandardButton.Ok
|
|
icon: StandardIcon.Warning
|
|
}
|
|
|
|
MessageDialog {
|
|
id: errorDialog
|
|
standardButtons: StandardButton.Ok
|
|
icon: StandardIcon.Critical
|
|
}
|
|
}
|
|
|