Browse Source

ScenarioExecution.qml ux design

cl-refactor
yann300 10 years ago
parent
commit
6e6ebc6037
  1. 1
      mix/qml.qrc
  2. 169
      mix/qml/Block.qml
  3. 334
      mix/qml/BlockChain.qml
  4. 62
      mix/qml/ScenarioButton.qml
  5. 7
      mix/qml/ScenarioExecution.qml
  6. 27
      mix/qml/ScenarioLoader.qml
  7. 5
      mix/qml/StateListModel.qml
  8. BIN
      mix/qml/img/duplicateIcon.png
  9. BIN
      mix/qml/img/duplicateIcon@2x.png
  10. BIN
      mix/qml/img/newIcon.png
  11. BIN
      mix/qml/img/newIcon@2x.png
  12. BIN
      mix/qml/img/recycle-discard.png
  13. BIN
      mix/qml/img/recycle-discard@2x.png
  14. BIN
      mix/qml/img/recycle-icon.png
  15. BIN
      mix/qml/img/recycle-icon@2x.png
  16. BIN
      mix/qml/img/recycle-keep.png
  17. BIN
      mix/qml/img/recycle-keep@2x.png
  18. BIN
      mix/qml/img/restoreIcon.png
  19. BIN
      mix/qml/img/restoreIcon@2x.png
  20. BIN
      mix/qml/img/saveIcon.png
  21. BIN
      mix/qml/img/saveIcon@2x.png
  22. 12
      mix/res.qrc

1
mix/qml.qrc

@ -68,5 +68,6 @@
<file>qml/BlockChain.qml</file>
<file>qml/ScenarioExecution.qml</file>
<file>qml/ScenarioLoader.qml</file>
<file>qml/ScenarioButton.qml</file>
</qresource>
</RCC>

169
mix/qml/Block.qml

@ -10,25 +10,40 @@ import "."
ColumnLayout
{
id: root
property variant transactions
property string status
property int number
Rectangle
{
width: parent.width
height: 50
anchors.left: parent.left
anchors.leftMargin: statusWidth
Label {
text:
{
if (status === "mined")
return qsTr("BLOCK") + " " + number
else
return qsTr("BLOCK") + " pending"
}
property int blockWidth: Layout.preferredWidth - statusWidth - horizontalMargin
property int horizontalMargin: 10
property int trHeight: 30
spacing: 0
RowLayout
{
Layout.preferredHeight: trHeight
Layout.preferredWidth: blockWidth
id: rowHeader
Rectangle
{
color: "#DEDCDC"
Layout.preferredWidth: blockWidth
Layout.preferredHeight: trHeight
radius: 4
anchors.left: parent.left
anchors.leftMargin: statusWidth + 5
Label {
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: horizontalMargin
text:
{
if (status === "mined")
return qsTr("BLOCK") + " " + number
else
return qsTr("BLOCK") + " pending"
}
}
}
}
@ -36,57 +51,80 @@ ColumnLayout
{
id: transactionRepeater
model: transactions
Row
RowLayout
{
height: 50
Layout.preferredHeight: trHeight
Rectangle
{
id: trSaveStatus
Layout.preferredWidth: statusWidth
Layout.preferredHeight: trHeight
color: "transparent"
CheckBox
property bool saveStatus
Image {
id: saveStatusImage
source: "qrc:/qml/img/recycle-discard@2x.png"
width: statusWidth
fillMode: Image.PreserveAspectFit
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
}
Component.onCompleted:
{
id: saveStatus
checked: {
if (index >= 0)
return transactions.get(index).saveStatus
else
return true
}
onCheckedChanged:
if (index >= 0)
saveStatus = transactions.get(index).saveStatus
}
onSaveStatusChanged:
{
if (saveStatus)
saveStatusImage.source = "qrc:/qml/img/recycle-keep@2x.png"
else
saveStatusImage.source = "qrc:/qml/img/recycle-discard@2x.png"
if (index >= 0)
transactions.get(index).saveStatus = saveStatus
}
MouseArea {
id: statusMouseArea
anchors.fill: parent
onClicked:
{
if (index >= 0)
transactions.get(index).saveStatus = checked
parent.saveStatus = !parent.saveStatus
}
}
}
Rectangle
{
width: parent.width
height: 50
color: "#cccccc"
radius: 4
Row
Layout.preferredWidth: blockWidth
Layout.preferredHeight: parent.height
color: "#DEDCDC"
RowLayout
{
Label
{
id: status
width: statusWidth
}
Label
anchors.verticalCenter: parent.verticalCenter
spacing: cellSpacing
Text
{
id: hash
width: fromWidth
anchors.left: parent.left
anchors.leftMargin: horizontalMargin
Layout.preferredWidth: fromWidth
elide: Text.ElideRight
maximumLineCount: 1
text: {
if (index >= 0)
return transactions.get(index).sender
else
return ""
}
clip: true
}
Label
Text
{
id: func
text: {
@ -95,9 +133,9 @@ ColumnLayout
else
return ""
}
width: toWidth
clip: true
elide: Text.ElideRight
maximumLineCount: 1
Layout.preferredWidth: toWidth
}
function userFrienldyToken(value)
@ -108,43 +146,52 @@ ColumnLayout
return value
}
Label
Text
{
id: returnValue
width: valueWidth
elide: Text.ElideRight
maximumLineCount: 1
Layout.preferredWidth: valueWidth
text: {
if (index >= 0 && transactions.get(index).returned)
return transactions.get(index).returned
else
return ""
}
clip: true
}
Label
Rectangle
{
id: logs
Layout.preferredWidth: logsWidth
Layout.preferredHeight: trHeight - 10
width: logsWidth
text: {
if (index >= 0 && transactions.get(index).logs)
{
for (var k in transactions.get(index).logs)
color: "transparent"
Text
{
id: logs
anchors.left: parent.left
anchors.leftMargin: 10
text: {
if (index >= 0 && transactions.get(index).logs && transactions.get(index).logs.count)
{
console.log("_________________________")
console.log(JSON.stringify(transactions.get(index).logs[k]))
console.log("_________________________")
for (var k = 0; k < transactions.get(index).logs.count; k++)
{
/*console.log("_________________________")
console.log(JSON.stringify(transactions.get(index).logs[k]))
console.log("_________________________")*/
}
return transactions.get(index).logs.count
}
return transactions.get(index).logs.length
else
return ""
}
else
return 0
}
}
Button
{
id: debug
width: debugActionWidth
Layout.preferredWidth: debugActionWidth
text: "debug"
onClicked:
{

334
mix/qml/BlockChain.qml

@ -11,91 +11,126 @@ import "js/TransactionHelper.js" as TransactionHelper
import "js/QEtherHelper.js" as QEtherHelper
import "."
Column {
ColumnLayout {
id: blockChainPanel
property variant model
spacing: 5
spacing: 0
property int previousWidth
onWidthChanged:
{
if (width <= 630 || previousWidth <= 630)
{
fromWidth = 100
toWidth = 100
valueWidth = 200
}
else
{
var diff = (width - previousWidth) / 3;
fromWidth = fromWidth + diff < 100 ? 100 : fromWidth + diff
toWidth = toWidth + diff < 100 ? 100 : toWidth + diff
valueWidth = valueWidth + diff < 200 ? 200 : valueWidth + diff
}
previousWidth = width
}
function load(scenario)
{
if (!scenario)
return;
model = scenario
blockModel.clear()
for (var b in model.blocks)
blockModel.append(model.blocks[b])
previousWidth = width
}
property int statusWidth: 50
property int statusWidth: 30
property int fromWidth: 100
property int toWidth: 250
property int valueWidth: 50
property int toWidth: 100
property int valueWidth: 200
property int logsWidth: 50
property int debugActionWidth: 50
property int horizontalMargin: 10
property int cellSpacing: 10
Row
RowLayout
{
id: header
width: parent.width
Label
{
text: "Status"
width: statusWidth
spacing: 0
Layout.preferredHeight: 25
Image {
id: debugImage
source: "qrc:/qml/img/recycle-icon@2x.png"
Layout.preferredWidth: statusWidth
Layout.preferredHeight: 25
fillMode: Image.PreserveAspectFit
}
Label
Rectangle
{
text: "From"
width: fromWidth
Layout.preferredWidth: fromWidth + cellSpacing
Label
{
anchors.verticalCenter: parent.verticalCenter
text: "From"
anchors.left: parent.left
anchors.leftMargin: horizontalMargin + 5
}
}
Label
{
text: "To"
width: toWidth
Layout.preferredWidth: toWidth + cellSpacing
}
Label
{
text: "Value"
width: valueWidth
Layout.preferredWidth: valueWidth + cellSpacing
}
Label
{
text: "Logs"
width: logsWidth
Layout.preferredWidth: logsWidth + cellSpacing
}
Label
{
text: "Action"
width: debugActionWidth
Layout.preferredWidth: debugActionWidth
}
}
Rectangle
{
width: parent.width
height: 500
Layout.preferredHeight: 500
Layout.preferredWidth: parent.width
//height: 500
border.color: "#cccccc"
border.width: 2
color: "white"
ScrollView
{
width: parent.width
height: parent.height
id: blockChainScrollView
anchors.fill: parent
anchors.topMargin: 10
ColumnLayout
{
id: blockChainLayout
width: parent.width
spacing: 10
Repeater // List of blocks
{
id: blockChainRepeater
width: parent.width
model: blockModel
Block
{
height:
Layout.preferredWidth: blockChainScrollView.width
Layout.preferredHeight:
{
if (index >= 0)
return 50 + 50 * blockModel.get(index).transactions.length
return 30 + 30 * blockModel.get(index).transactions.count
else
return 0
return 50
}
transactions:
@ -143,8 +178,6 @@ Column {
function removeTransaction(blockIndex, trIndex)
{
console.log(blockIndex)
console.log(trIndex)
blockModel.get(blockIndex).transactions.remove(trIndex)
}
@ -160,139 +193,174 @@ Column {
function getTransaction(block, tr)
{
return blockModel.get(block - 1).transactions.get(tr)
return blockModel.get(block).transactions.get(tr)
}
function setTransaction(blockIndex, trIndex, tr)
{
blockModel.get(blockIndex).transactions.set(trIndex, tr)
}
function setTransactionProperty(blockIndex, trIndex, propertyName, value)
{
blockModel.get(blockIndex).transactions.set(trIndex, { propertyName: value })
}
}
RowLayout
Rectangle
{
width: parent.width
Button {
id: rebuild
text: qsTr("Rebuild")
onClicked:
{
for (var j = 0; j < model.blocks.length; j++)
Layout.preferredWidth: parent.width
RowLayout
{
width: parent.width
anchors.top: parent.top
anchors.topMargin: 10
ScenarioButton {
id: rebuild
text: qsTr("Rebuild")
onClicked:
{
for (var k = 0; k < model.blocks[j].transactions.length; k++)
for (var j = 0; j < model.blocks.length; j++)
{
if (!blockModel.get(j).transactions.get(k).saveStatus)
for (var k = 0; k < model.blocks[j].transactions.length; k++)
{
model.blocks[j].transactions.splice(k, 1)
blockModel.removeTransaction(j, k)
if (model.blocks[j].transactions.length === 0)
if (!blockModel.get(j).transactions.get(k).saveStatus)
{
model.blocks[j].splice(j, 1);
blockModel.removeBlock(j);
model.blocks[j].transactions.splice(k, 1)
blockModel.removeTransaction(j, k)
if (model.blocks[j].transactions.length === 0)
{
model.blocks.splice(j, 1);
blockModel.removeBlock(j);
}
}
}
}
clientModel.setupScenario(model);
}
clientModel.setupScenario(model);
}
}
Button {
id: addTransaction
text: qsTr("Add Transaction")
onClicked:
{
var lastBlock = model.blocks[model.blocks.length - 1];
if (lastBlock.status === "mined")
model.blocks.push(projectModel.stateListModel.createEmptyBlock());
var item = TransactionHelper.defaultTransaction()
transactionDialog.stateAccounts = model.accounts
transactionDialog.open(model.blocks[model.blocks.length - 1].transactions.length, model.blocks.length - 1, item)
Layout.preferredWidth: 100
Layout.preferredHeight: 30
buttonShortcut: ""
sourceImg: "qrc:/qml/img/recycle-icon@2x.png"
}
}
Button {
id: addBlockBtn
text: qsTr("Add Block")
onClicked:
{
var lastBlock = model.blocks[model.blocks.length - 1]
if (lastBlock.status === "pending")
clientModel.mine()
else
addNewBlock()
}
function addNewBlock()
{
var block = projectModel.stateListModel.createEmptyBlock()
model.blocks.push(block)
blockModel.appendBlock(block)
ScenarioButton {
id: addTransaction
text: qsTr("Add Transaction")
onClicked:
{
var lastBlock = model.blocks[model.blocks.length - 1];
if (lastBlock.status === "mined")
model.blocks.push(projectModel.stateListModel.createEmptyBlock());
var item = TransactionHelper.defaultTransaction()
transactionDialog.stateAccounts = model.accounts
transactionDialog.open(model.blocks[model.blocks.length - 1].transactions.length, model.blocks.length - 1, item)
}
Layout.preferredWidth: 100
Layout.preferredHeight: 30
buttonShortcut: ""
sourceImg: "qrc:/qml/img/recycle-icon@2x.png"
}
}
Connections
{
target: clientModel
onNewBlock:
{
if (!clientModel.running)
ScenarioButton {
id: addBlockBtn
text: qsTr("Add Block")
onClicked:
{
var lastBlock = model.blocks[model.blocks.length - 1]
lastBlock.status = "mined"
lastBlock.number = model.blocks.length
var lastB = blockModel.get(model.blocks.length - 1)
lastB.status = "mined"
lastB.number = model.blocks.length
addBlockBtn.addNewBlock()
if (lastBlock.status === "pending")
clientModel.mine()
else
addNewBlock()
}
function addNewBlock()
{
var block = projectModel.stateListModel.createEmptyBlock()
model.blocks.push(block)
blockModel.appendBlock(block)
}
Layout.preferredWidth: 100
Layout.preferredHeight: 30
buttonShortcut: ""
sourceImg: "qrc:/qml/img/recycle-icon@2x.png"
}
onStateCleared:
{
}
onNewRecord:
Connections
{
var blockIndex = _r.transactionIndex.split(":")[0]
var trIndex = _r.transactionIndex.split(":")[1]
if (parseInt(blockIndex) <= model.blocks.length)
target: clientModel
onNewBlock:
{
var item = model.blocks[parseInt(blockIndex) - 1];
if (parseInt(trIndex) <= item.transactions.length)
if (!clientModel.running)
{
var tr = item.transactions[parseInt(trIndex)];
tr.returned = _r.returned;
blockModel.getTransaction(blockIndex, trIndex).returned = _r.returned;
tr.recordIndex = _r.recordIndex;
blockModel.getTransaction(blockIndex, trIndex).recordIndex = _r.recordIndex;
tr.logs = _r.logs;
blockModel.getTransaction(blockIndex, trIndex).logs = _r.logs;
return;
var lastBlock = model.blocks[model.blocks.length - 1]
lastBlock.status = "mined"
lastBlock.number = model.blocks.length
var lastB = blockModel.get(model.blocks.length - 1)
lastB.status = "mined"
lastB.number = model.blocks.length
addBlockBtn.addNewBlock()
}
}
onStateCleared:
{
}
onNewRecord:
{
var blockIndex = parseInt(_r.transactionIndex.split(":")[0]) - 1
var trIndex = parseInt(_r.transactionIndex.split(":")[1])
if (blockIndex <= model.blocks.length)
{
var item = model.blocks[blockIndex]
if (trIndex <= item.transactions.length)
{
var tr = item.transactions[trIndex]
tr.returned = _r.returned
tr.recordIndex = _r.recordIndex
tr.logs = _r.logs
var trModel = blockModel.getTransaction(blockIndex, trIndex)
trModel.returned = _r.returned
trModel.recordIndex = _r.recordIndex
trModel.logs = _r.logs
blockModel.setTransaction(blockIndex, trIndex, trModel)
return;
}
}
// tr is not in the list. coming from JavaScript
var itemTr = TransactionHelper.defaultTransaction()
itemTr.functionId = _r.function
itemTr.contractId = _r.contract
itemTr.gasAuto = true
itemTr.parameters = _r.parameters
itemTr.isContractCreation = itemTr.functionId === itemTr.contractId
itemTr.label = _r.label
itemTr.isFunctionCall = itemTr.functionId !== ""
itemTr.returned = _r.returned
itemTr.value = QEtherHelper.createEther(_r.value, QEther.Wei)
itemTr.sender = _r.sender
itemTr.recordIndex = _r.recordIndex
itemTr.logs = _r.logs
model.blocks[model.blocks.length - 1].transactions.push(itemTr)
blockModel.appendTransaction(itemTr)
}
onMiningComplete:
{
// tr is not in the list. coming from JavaScript
var itemTr = TransactionHelper.defaultTransaction()
itemTr.saveStatus = false
itemTr.functionId = _r.function
itemTr.contractId = _r.contract
itemTr.gasAuto = true
itemTr.parameters = _r.parameters
itemTr.isContractCreation = itemTr.functionId === itemTr.contractId
itemTr.label = _r.label
itemTr.isFunctionCall = itemTr.functionId !== ""
itemTr.returned = _r.returned
itemTr.value = QEtherHelper.createEther(_r.value, QEther.Wei)
itemTr.sender = _r.sender
itemTr.recordIndex = _r.recordIndex
itemTr.logs = _r.logs
model.blocks[model.blocks.length - 1].transactions.push(itemTr)
blockModel.appendTransaction(itemTr)
}
onMiningComplete:
{
}
}
}
Button {
id: newAccount
text: qsTr("New Account")
onClicked: {
model.accounts.push(projectModel.stateListModel.newAccount("1000000", QEther.Ether))
ScenarioButton {
id: newAccount
text: qsTr("New Account")
onClicked: {
model.accounts.push(projectModel.stateListModel.newAccount("1000000", QEther.Ether))
}
Layout.preferredWidth: 100
Layout.preferredHeight: 30
buttonShortcut: ""
sourceImg: "qrc:/qml/img/recycle-icon@2x.png"
}
}
}

62
mix/qml/ScenarioButton.qml

@ -0,0 +1,62 @@
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.0
import QtQuick.Controls.Styles 1.1
Rectangle {
id: buttonActionContainer
property string text
property string buttonShortcut
property string sourceImg
signal clicked
Rectangle {
id: contentRectangle
anchors.fill: parent
border.color: "#cccccc"
border.width: 1
radius: 4
Image {
id: debugImage
anchors {
centerIn: parent
bottomMargin: debugImg.pressed ? 0 : 1;
topMargin: debugImg.pressed ? 1 : 0;
}
source: sourceImg
fillMode: Image.PreserveAspectFit
height: 30
}
Button {
anchors.fill: parent
id: debugImg
action: buttonAction
style: ButtonStyle {
background: Rectangle {
color: "transparent"
}
}
}
Action {
id: buttonAction
shortcut: buttonShortcut
onTriggered: {
buttonActionContainer.clicked();
}
}
}
Rectangle
{
anchors.top: contentRectangle.bottom
anchors.topMargin: 15
width: parent.width
Text
{
text: buttonActionContainer.text
anchors.centerIn: parent
}
}
}

7
mix/qml/ScenarioExecution.qml

@ -9,9 +9,7 @@ import "js/ErrorLocationFormater.js" as ErrorLocationFormater
import "."
Rectangle {
border.color: "red"
border.width: 1
color: "#ededed"
Connections
{
@ -26,9 +24,10 @@ Rectangle {
{
anchors.margins: 10
anchors.fill: parent
spacing: 5
spacing: 10
ScenarioLoader
{
height: 70
width: parent.width
id: loader
}

27
mix/qml/ScenarioLoader.qml

@ -37,32 +37,39 @@ RowLayout
loaded(state)
}
}
Button
{
ScenarioButton {
id: restoreScenario
text: qsTr("Restore")
Layout.preferredWidth: 100
Layout.preferredHeight: 30
buttonShortcut: ""
sourceImg: "qrc:/qml/img/restoreIcon@2x.png"
onClicked: {
restore()
}
text: qsTr("Restore")
function restore()
{
var state = projectModel.stateListModel.reloadStateFromFromProject(scenarioList.currentIndex)
restored(state)
loaded(state)
}
}
Button
{
ScenarioButton {
id: saveScenario
text: qsTr("Save")
onClicked: {
projectModel.saveProjectFile()
saved(state)
}
Layout.preferredWidth: 100
Layout.preferredHeight: 30
buttonShortcut: ""
sourceImg: "qrc:/qml/img/saveIcon@2x.png"
}
Button
ScenarioButton
{
id: duplicateScenario
text: qsTr("Duplicate")
@ -73,5 +80,9 @@ RowLayout
projectModel.stateListModel.save()
duplicated(state)
}
Layout.preferredWidth: 100
Layout.preferredHeight: 30
buttonShortcut: ""
sourceImg: "qrc:/qml/img/duplicateIcon@2x.png"
}
}

5
mix/qml/StateListModel.qml

@ -16,7 +16,9 @@ Item {
property string defaultAccount: "cb73d9408c4720e230387d956eb0f829d8a4dd2c1055f96257167e14e7169074" //support for old project
function fromPlainStateItem(s) {
if (!s.accounts)
console.log("èèèèèèèèèèèè");
console.log(s);
if (!s.accounts)
s.accounts = [stateListModel.newAccount("1000000", QEther.Ether, defaultAccount)]; //support for old project
if (!s.contracts)
s.contracts = [];
@ -137,7 +139,6 @@ Item {
}
function toPlainTransactionItem(t) {
console.log(JSON.stringify(t));
var r = {
type: t.type,
contractId: t.contractId,

BIN
mix/qml/img/duplicateIcon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1020 B

BIN
mix/qml/img/duplicateIcon@2x.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
mix/qml/img/newIcon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 801 B

BIN
mix/qml/img/newIcon@2x.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
mix/qml/img/recycle-discard.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 723 B

BIN
mix/qml/img/recycle-discard@2x.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
mix/qml/img/recycle-icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 697 B

BIN
mix/qml/img/recycle-icon@2x.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
mix/qml/img/recycle-keep.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 904 B

BIN
mix/qml/img/recycle-keep@2x.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
mix/qml/img/restoreIcon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
mix/qml/img/restoreIcon@2x.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
mix/qml/img/saveIcon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

BIN
mix/qml/img/saveIcon@2x.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

12
mix/res.qrc

@ -68,5 +68,17 @@
<file>qml/img/warningicon.png</file>
<file>qml/img/warningicon@2x.png</file>
<file>qml/QAddressView.qml</file>
<file>qml/img/recycle-discard.png</file>
<file>qml/img/recycle-discard@2x.png</file>
<file>qml/img/recycle-icon.png</file>
<file>qml/img/recycle-icon@2x.png</file>
<file>qml/img/recycle-keep.png</file>
<file>qml/img/recycle-keep@2x.png</file>
<file>qml/img/restoreIcon.png</file>
<file>qml/img/restoreIcon@2x.png</file>
<file>qml/img/saveIcon.png</file>
<file>qml/img/saveIcon@2x.png</file>
<file>qml/img/duplicateIcon.png</file>
<file>qml/img/duplicateIcon@2x.png</file>
</qresource>
</RCC>

Loading…
Cancel
Save