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.
 
 
 
 
 

440 lines
11 KiB

import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
import QtQuick.Dialogs 1.1
import QtQuick.Window 2.2
import QtQuick.Layouts 1.1
import org.ethereum.qml.QEther 1.0
import "js/QEtherHelper.js" as QEtherHelper
import "js/TransactionHelper.js" as TransactionHelper
Item {
property alias model: stateListModel
property var stateList: []
property alias stateDialog: stateDialog
property string defaultAccount: "cb73d9408c4720e230387d956eb0f829d8a4dd2c1055f96257167e14e7169074" //support for old project
function fromPlainStateItem(s) {
if (!s.accounts)
s.accounts = [stateListModel.newAccount("1000000", QEther.Ether, defaultAccount)]; //support for old project
if (!s.contracts)
s.contracts = [];
var ret = {};
ret.title = s.title;
ret.transactions = s.transactions.filter(function(t) { return !t.stdContract; }).map(fromPlainTransactionItem); //support old projects by filtering std contracts
if (s.blocks)
ret.blocks = s.blocks.map(fromPlainBlockItem);
ret.accounts = s.accounts.map(fromPlainAccountItem);
ret.contracts = s.contracts.map(fromPlainAccountItem);
ret.miner = s.miner;
// support old projects
if (!ret.blocks)
{
ret.blocks = [{
hash: "",
number: -1,
transactions: [],
status: "pending"
}]
for (var j in ret.transactions)
ret.blocks[0].transactions.push(fromPlainTransactionItem(toPlainTransactionItem(ret.transactions[j])))
}
return ret;
}
function fromPlainAccountItem(t)
{
return {
name: t.name,
address: t.address,
secret: t.secret,
balance: QEtherHelper.createEther(t.balance.value, t.balance.unit),
storage: t.storage,
code: t.code,
};
}
function fromPlainTransactionItem(t) {
if (!t.sender)
t.sender = defaultAccount; //support for old project
var r = {
type: t.type,
contractId: t.contractId,
functionId: t.functionId,
url: t.url,
value: QEtherHelper.createEther(t.value.value, t.value.unit),
gas: QEtherHelper.createBigInt(t.gas.value),
gasPrice: QEtherHelper.createEther(t.gasPrice.value, t.gasPrice.unit),
gasAuto: t.gasAuto,
parameters: {},
sender: t.sender,
isContractCreation: t.isContractCreation,
label: t.label,
isFunctionCall: t.isFunctionCall,
saveStatus: t.saveStatus
};
if (r.saveStatus === undefined)
r.saveStatus = true
if (r.isFunctionCall === undefined)
r.isFunctionCall = true;
if (!r.label)
r.label = r.contractId + " - " + r.functionId;
if (r.isContractCreation === undefined)
r.isContractCreation = r.functionId === r.contractId;
for (var key in t.parameters)
r.parameters[key] = t.parameters[key];
return r;
}
function fromPlainBlockItem(b)
{
var r = {
hash: b.hash,
number: b.number,
transactions: b.transactions.filter(function(t) { return !t.stdContract; }).map(fromPlainTransactionItem), //support old projects by filtering std contracts
status: b.status
}
return r;
}
function toPlainStateItem(s) {
return {
title: s.title,
blocks: s.blocks.map(toPlainBlockItem),
transactions: s.transactions.map(toPlainTransactionItem),
accounts: s.accounts.map(toPlainAccountItem),
contracts: s.contracts.map(toPlainAccountItem),
miner: s.miner
};
}
function getParamType(param, params)
{
for (var k in params)
{
if (params[k].declaration.name === param)
return params[k].declaration.type;
}
return '';
}
function toPlainBlockItem(b)
{
var r = {
hash: b.hash,
number: b.number,
transactions: b.transactions.map(toPlainTransactionItem),
status: b.status
}
return r;
}
function toPlainAccountItem(t)
{
return {
name: t.name,
secret: t.secret,
balance: {
value: t.balance.value,
unit: t.balance.unit
},
address: t.address,
storage: t.storage,
code: t.code,
};
}
function toPlainTransactionItem(t) {
var r = {
type: t.type,
contractId: t.contractId,
functionId: t.functionId,
url: t.url,
value: { value: t.value.value, unit: t.value.unit },
gas: { value: t.gas.value() },
gasAuto: t.gasAuto,
gasPrice: { value: t.gasPrice.value, unit: t.gasPrice.unit },
sender: t.sender,
parameters: {},
isContractCreation: t.isContractCreation,
label: t.label,
isFunctionCall: t.isFunctionCall,
saveStatus: t.saveStatus
};
for (var key in t.parameters)
r.parameters[key] = t.parameters[key];
return r;
}
Connections {
target: projectModel
onProjectClosed: {
stateListModel.clear();
stateList = [];
codeModel.reset();
}
onProjectLoading: stateListModel.loadStatesFromProject(projectData);
onProjectFileSaving: {
projectData.states = []
for(var i = 0; i < stateListModel.count; i++) {
projectData.states.push(toPlainStateItem(stateList[i]));
}
projectData.defaultStateIndex = stateListModel.defaultStateIndex;
stateListModel.data = projectData
}
onNewProject: {
var state = toPlainStateItem(stateListModel.createDefaultState());
state.title = qsTr("Default");
projectData.states = [ state ];
projectData.defaultStateIndex = 0;
stateListModel.loadStatesFromProject(projectData);
}
}
Connections {
target: codeModel
onNewContractCompiled: {
stateListModel.addNewContracts();
}
onContractRenamed: {
stateListModel.renameContracts(_oldName, _newName);
}
}
StateDialog {
id: stateDialog
onAccepted: {
var item = stateDialog.getItem();
saveState(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);
}
if (stateDialog.isDefault)
stateListModel.defaultStateChanged();
stateListModel.save();
}
}
ListModel {
id: stateListModel
property int defaultStateIndex: 0
property variant data
signal defaultStateChanged;
signal stateListModelReady;
signal stateRun(int index)
signal stateDeleted(int index)
function defaultTransactionItem() {
return TransactionHelper.defaultTransaction();
}
function newAccount(_balance, _unit, _secret)
{
if (!_secret)
_secret = clientModel.newSecret();
var address = clientModel.address(_secret);
var name = qsTr("Account") + "-" + address.substring(0, 4);
var amount = QEtherHelper.createEther(_balance, _unit)
return { name: name, secret: _secret, balance: amount, address: address };
}
function duplicateState(index)
{
var state = stateList[index]
var item = fromPlainStateItem(toPlainStateItem(state))
item.title = qsTr("Copy of") + " " + state.title
appendState(item)
save()
}
function createEmptyBlock()
{
return {
hash: "",
number: -1,
transactions: [],
status: "pending"
}
}
function createDefaultState() {
var item = {
title: "",
transactions: [],
accounts: [],
contracts: [],
blocks: [{ status: "pending", number: -1, hash: "", transactions: []}]
};
var account = newAccount("1000000", QEther.Ether, defaultAccount)
item.accounts.push(account);
item.miner = account;
//add constructors, //TODO: order by dependencies
for(var c in codeModel.contracts) {
var ctorTr = defaultTransactionItem();
ctorTr.functionId = c;
ctorTr.contractId = c;
ctorTr.label = qsTr("Deploy") + " " + ctorTr.contractId;
ctorTr.sender = item.accounts[0].secret;
item.transactions.push(ctorTr);
item.blocks[0].transactions.push(ctorTr)
}
return item;
}
function renameContracts(oldName, newName) {
var changed = false;
for(var c in codeModel.contracts) {
for (var s = 0; s < stateListModel.count; s++) {
var state = stateList[s];
for (var t = 0; t < state.transactions.length; t++) {
var transaction = state.transactions[t];
if (transaction.contractId === oldName) {
transaction.contractId = newName;
if (transaction.functionId === oldName)
transaction.functionId = newName;
changed = true;
state.transactions[t] = transaction;
}
}
stateListModel.set(s, state);
stateList[s] = state;
}
}
if (changed)
save();
}
function addNewContracts() {
//add new contracts to empty states
var changed = false;
for (var c in codeModel.contracts) {
for (var s = 0; s < stateListModel.count; s++) {
var state = stateList[s];
if (state.transactions.length === 0) {
//append this contract
var ctorTr = defaultTransactionItem();
ctorTr.functionId = c;
ctorTr.contractId = c;
ctorTr.label = qsTr("Deploy") + " " + ctorTr.contractId;
ctorTr.sender = state.accounts[0].secret;
state.transactions.push(ctorTr);
changed = true;
stateListModel.set(s, state);
stateList[s] = state;
}
}
}
if (changed)
save();
}
function addState() {
var item = createDefaultState();
stateDialog.open(stateListModel.count, item, false);
}
function appendState(item)
{
stateListModel.append(item);
stateList.push(item);
}
function editState(index) {
stateDialog.open(index, stateList[index], defaultStateIndex === index);
}
function getState(index) {
return stateList[index];
}
function debugDefaultState() {
if (defaultStateIndex >= 0 && defaultStateIndex < stateList.length)
runState(defaultStateIndex);
}
function runState(index) {
var item = stateList[index];
clientModel.setupScenario(item);
stateRun(index);
}
function deleteState(index) {
stateListModel.remove(index);
stateList.splice(index, 1);
if (index === defaultStateIndex)
{
defaultStateIndex = 0;
defaultStateChanged();
}
else if (defaultStateIndex > index)
defaultStateIndex--;
save();
stateDeleted(index);
}
function save() {
projectModel.saveProject();
}
function defaultStateName()
{
return stateList[defaultStateIndex].title;
}
function reloadStateFromFromProject(index)
{
if (data)
{
var item = fromPlainStateItem(data.states[index])
stateListModel.set(index, item)
stateList[index] = item
return item
}
}
function loadStatesFromProject(projectData)
{
data = projectData
if (!projectData.states)
projectData.states = [];
if (projectData.defaultStateIndex !== undefined)
defaultStateIndex = projectData.defaultStateIndex;
else
defaultStateIndex = 0;
var items = projectData.states;
stateListModel.clear();
stateList = [];
for(var i = 0; i < items.length; i++) {
var item = fromPlainStateItem(items[i]);
stateListModel.append(item);
stateList.push(item);
}
stateListModelReady();
}
}
}