diff --git a/mix/qml.qrc b/mix/qml.qrc index 0227b4efd..16bb01b83 100644 --- a/mix/qml.qrc +++ b/mix/qml.qrc @@ -68,5 +68,6 @@ qml/BlockChain.qml qml/ScenarioExecution.qml qml/ScenarioLoader.qml + qml/ScenarioButton.qml diff --git a/mix/qml/Block.qml b/mix/qml/Block.qml index c3ce7865a..d3775ea5c 100644 --- a/mix/qml/Block.qml +++ b/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: { diff --git a/mix/qml/BlockChain.qml b/mix/qml/BlockChain.qml index 6098ec035..2fc78b0b1 100644 --- a/mix/qml/BlockChain.qml +++ b/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" } } } diff --git a/mix/qml/ScenarioButton.qml b/mix/qml/ScenarioButton.qml new file mode 100644 index 000000000..e8884cc2e --- /dev/null +++ b/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 + } + } +} diff --git a/mix/qml/ScenarioExecution.qml b/mix/qml/ScenarioExecution.qml index 5fcbfab3e..d02e7d3f8 100644 --- a/mix/qml/ScenarioExecution.qml +++ b/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 } diff --git a/mix/qml/ScenarioLoader.qml b/mix/qml/ScenarioLoader.qml index 0b703c860..b89c1222b 100644 --- a/mix/qml/ScenarioLoader.qml +++ b/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" } } diff --git a/mix/qml/StateListModel.qml b/mix/qml/StateListModel.qml index d08ed668d..44873e8db 100644 --- a/mix/qml/StateListModel.qml +++ b/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, diff --git a/mix/qml/img/duplicateIcon.png b/mix/qml/img/duplicateIcon.png new file mode 100644 index 000000000..b3a255420 Binary files /dev/null and b/mix/qml/img/duplicateIcon.png differ diff --git a/mix/qml/img/duplicateIcon@2x.png b/mix/qml/img/duplicateIcon@2x.png new file mode 100644 index 000000000..d0f5274d3 Binary files /dev/null and b/mix/qml/img/duplicateIcon@2x.png differ diff --git a/mix/qml/img/newIcon.png b/mix/qml/img/newIcon.png new file mode 100644 index 000000000..016d0ddbb Binary files /dev/null and b/mix/qml/img/newIcon.png differ diff --git a/mix/qml/img/newIcon@2x.png b/mix/qml/img/newIcon@2x.png new file mode 100644 index 000000000..085fcb686 Binary files /dev/null and b/mix/qml/img/newIcon@2x.png differ diff --git a/mix/qml/img/recycle-discard.png b/mix/qml/img/recycle-discard.png new file mode 100644 index 000000000..af1d09594 Binary files /dev/null and b/mix/qml/img/recycle-discard.png differ diff --git a/mix/qml/img/recycle-discard@2x.png b/mix/qml/img/recycle-discard@2x.png new file mode 100644 index 000000000..c51c21d21 Binary files /dev/null and b/mix/qml/img/recycle-discard@2x.png differ diff --git a/mix/qml/img/recycle-icon.png b/mix/qml/img/recycle-icon.png new file mode 100644 index 000000000..2f5139ad8 Binary files /dev/null and b/mix/qml/img/recycle-icon.png differ diff --git a/mix/qml/img/recycle-icon@2x.png b/mix/qml/img/recycle-icon@2x.png new file mode 100644 index 000000000..75b590b2a Binary files /dev/null and b/mix/qml/img/recycle-icon@2x.png differ diff --git a/mix/qml/img/recycle-keep.png b/mix/qml/img/recycle-keep.png new file mode 100644 index 000000000..d9c39a6de Binary files /dev/null and b/mix/qml/img/recycle-keep.png differ diff --git a/mix/qml/img/recycle-keep@2x.png b/mix/qml/img/recycle-keep@2x.png new file mode 100644 index 000000000..616fa5622 Binary files /dev/null and b/mix/qml/img/recycle-keep@2x.png differ diff --git a/mix/qml/img/restoreIcon.png b/mix/qml/img/restoreIcon.png new file mode 100644 index 000000000..9fc6e8f22 Binary files /dev/null and b/mix/qml/img/restoreIcon.png differ diff --git a/mix/qml/img/restoreIcon@2x.png b/mix/qml/img/restoreIcon@2x.png new file mode 100644 index 000000000..3160b0bf3 Binary files /dev/null and b/mix/qml/img/restoreIcon@2x.png differ diff --git a/mix/qml/img/saveIcon.png b/mix/qml/img/saveIcon.png new file mode 100644 index 000000000..46e17522b Binary files /dev/null and b/mix/qml/img/saveIcon.png differ diff --git a/mix/qml/img/saveIcon@2x.png b/mix/qml/img/saveIcon@2x.png new file mode 100644 index 000000000..0f77a1af8 Binary files /dev/null and b/mix/qml/img/saveIcon@2x.png differ diff --git a/mix/res.qrc b/mix/res.qrc index ac0af57ac..e84f77d84 100644 --- a/mix/res.qrc +++ b/mix/res.qrc @@ -68,5 +68,17 @@ qml/img/warningicon.png qml/img/warningicon@2x.png qml/QAddressView.qml + qml/img/recycle-discard.png + qml/img/recycle-discard@2x.png + qml/img/recycle-icon.png + qml/img/recycle-icon@2x.png + qml/img/recycle-keep.png + qml/img/recycle-keep@2x.png + qml/img/restoreIcon.png + qml/img/restoreIcon@2x.png + qml/img/saveIcon.png + qml/img/saveIcon@2x.png + qml/img/duplicateIcon.png + qml/img/duplicateIcon@2x.png