Browse Source

Merge pull request #1348 from arkpar/mix_ux

Mix: UI improvements
cl-refactor
Arkadiy Paronyan 10 years ago
parent
commit
4deb812114
  1. 15
      mix/ClientModel.cpp
  2. 2
      mix/CodeModel.cpp
  3. 2
      mix/CodeModel.h
  4. 1
      mix/Exceptions.h
  5. 1
      mix/MachineStates.h
  6. 31
      mix/MixClient.cpp
  7. 5
      mix/MixClient.h
  8. 4
      mix/qml/CodeEditorView.qml
  9. 59
      mix/qml/DebugInfoList.qml
  10. 4
      mix/qml/Debugger.qml
  11. 4
      mix/qml/ProjectModel.qml
  12. 44
      mix/qml/StateListModel.qml
  13. 6
      mix/qml/StructView.qml
  14. 6
      mix/qml/TransactionLog.qml
  15. 3
      mix/qml/WebCodeEditor.qml
  16. 4
      mix/qml/js/ProjectModel.js
  17. 5
      mix/qml/js/TransactionHelper.js

15
mix/ClientModel.cpp

@ -221,9 +221,11 @@ void ClientModel::executeSequence(std::vector<TransactionSettings> const& _seque
{
//std contract
dev::bytes const& stdContractCode = m_context->codeModel()->getStdContractCode(transaction.contractId, transaction.stdContractUrl);
Address address = deployContract(stdContractCode, transaction);
m_stdContractAddresses[transaction.contractId] = address;
m_stdContractNames[address] = transaction.contractId;
TransactionSettings stdTransaction = transaction;
stdTransaction.gas = 500000;// TODO: get this from std contracts library
Address address = deployContract(stdContractCode, stdTransaction);
m_stdContractAddresses[stdTransaction.contractId] = address;
m_stdContractNames[address] = stdTransaction.contractId;
}
else
{
@ -296,7 +298,7 @@ void ClientModel::executeSequence(std::vector<TransactionSettings> const& _seque
void ClientModel::showDebugger()
{
ExecutionResult const& last = m_client->lastExecution();
ExecutionResult last = m_client->lastExecution();
showDebuggerForTransaction(last);
}
@ -433,7 +435,7 @@ void ClientModel::emptyRecord()
void ClientModel::debugRecord(unsigned _index)
{
ExecutionResult const& e = m_client->executions().at(_index);
ExecutionResult e = m_client->execution(_index);
showDebuggerForTransaction(e);
}
@ -479,7 +481,7 @@ void ClientModel::onNewTransaction()
{
ExecutionResult const& tr = m_client->lastExecution();
unsigned block = m_client->number() + 1;
unsigned recordIndex = m_client->executions().size() - 1;
unsigned recordIndex = tr.executonIndex;
QString transactionIndex = tr.isCall() ? QObject::tr("Call") : QString("%1:%2").arg(block).arg(tr.transactionIndex);
QString address = QString::fromStdString(toJS(tr.address));
QString value = QString::fromStdString(dev::toString(tr.value));
@ -503,6 +505,7 @@ void ClientModel::onNewTransaction()
}
else
function = QObject::tr("Constructor");
address = QObject::tr("(Create contract)");
}
else
{

2
mix/CodeModel.cpp

@ -262,6 +262,8 @@ void CodeModel::runCompilationJob(int _jobId)
CompiledContract* prevContract = m_contractMap.value(name);
if (prevContract != nullptr && prevContract->contractInterface() != result[name]->contractInterface())
emit contractInterfaceChanged(name);
if (prevContract == nullptr)
emit newContractCompiled(name);
}
releaseContracts();
m_contractMap.swap(result);

2
mix/CodeModel.h

@ -163,6 +163,8 @@ signals:
void codeChanged();
/// Emitted if there are any changes in the contract interface
void contractInterfaceChanged(QString _documentId);
/// Emitted if there is a new contract compiled for the first time
void newContractCompiled(QString _documentId);
public slots:
/// Update code model on source code change

1
mix/Exceptions.h

@ -39,6 +39,7 @@ struct InvalidBlockException: virtual Exception {};
struct FunctionNotFoundException: virtual Exception {};
struct ExecutionStateException: virtual Exception {};
struct ParameterChangedException: virtual Exception {};
struct OutOfGasException: virtual Exception {};
using QmlErrorInfo = boost::error_info<struct tagQmlError, QQmlError>;
using FileError = boost::error_info<struct tagFileError, std::string>;

1
mix/MachineStates.h

@ -80,6 +80,7 @@ namespace mix
dev::Address contractAddress;
dev::u256 value;
unsigned transactionIndex;
unsigned executonIndex = 0;
bool isCall() const { return transactionIndex == std::numeric_limits<unsigned>::max(); }
bool isConstructor() const { return !isCall() && !address; }

31
mix/MixClient.cpp

@ -104,6 +104,7 @@ void MixClient::resetState(std::map<Secret, u256> _accounts)
m_state = eth::State(genesisState.begin()->first , m_stateDB, BaseState::Empty);
m_state.sync(bc());
m_startState = m_state;
WriteGuard lx(x_executions);
m_executions.clear();
}
@ -186,12 +187,14 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c
d.contractAddress = right160(sha3(rlpList(_t.sender(), _t.nonce())));
if (!_call)
d.transactionIndex = m_state.pending().size();
m_executions.emplace_back(std::move(d));
d.executonIndex = m_executions.size();
// execute on a state
if (!_call)
{
_state.execute(lastHashes, rlp, nullptr, true);
if (_t.isCreation() && _state.code(d.contractAddress).empty())
BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas for contract deployment"));
// collect watches
h256Set changed;
Guard l(m_filterLock);
@ -211,6 +214,8 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c
changed.insert(dev::eth::PendingChangedFilter);
noteChanged(changed);
}
WriteGuard l(x_executions);
m_executions.emplace_back(std::move(d));
}
void MixClient::mine()
@ -226,14 +231,16 @@ void MixClient::mine()
noteChanged(changed);
}
ExecutionResult const& MixClient::lastExecution() const
ExecutionResult MixClient::lastExecution() const
{
return m_executions.back();
ReadGuard l(x_executions);
return m_executions.empty() ? ExecutionResult() : m_executions.back();
}
ExecutionResults const& MixClient::executions() const
ExecutionResult MixClient::execution(unsigned _index) const
{
return m_executions;
ReadGuard l(x_executions);
return m_executions.at(_index);
}
State MixClient::asOf(int _block) const
@ -441,32 +448,38 @@ LocalisedLogEntries MixClient::checkWatch(unsigned _watchId)
h256 MixClient::hashFromNumber(unsigned _number) const
{
ReadGuard l(x_state);
return bc().numberHash(_number);
}
eth::BlockInfo MixClient::blockInfo(h256 _hash) const
{
ReadGuard l(x_state);
return BlockInfo(bc().block(_hash));
}
eth::BlockInfo MixClient::blockInfo() const
{
ReadGuard l(x_state);
return BlockInfo(bc().block());
}
eth::BlockDetails MixClient::blockDetails(h256 _hash) const
{
ReadGuard l(x_state);
return bc().details(_hash);
}
Transaction MixClient::transaction(h256 _transactionHash) const
{
ReadGuard l(x_state);
return Transaction(bc().transaction(_transactionHash), CheckSignature::Range);
}
eth::Transaction MixClient::transaction(h256 _blockHash, unsigned _i) const
{
ReadGuard l(x_state);
auto bl = bc().block(_blockHash);
RLP b(bl);
if (_i < b[1].itemCount())
@ -477,6 +490,7 @@ eth::Transaction MixClient::transaction(h256 _blockHash, unsigned _i) const
eth::BlockInfo MixClient::uncle(h256 _blockHash, unsigned _i) const
{
ReadGuard l(x_state);
auto bl = bc().block(_blockHash);
RLP b(bl);
if (_i < b[2].itemCount())
@ -487,6 +501,7 @@ eth::BlockInfo MixClient::uncle(h256 _blockHash, unsigned _i) const
unsigned MixClient::transactionCount(h256 _blockHash) const
{
ReadGuard l(x_state);
auto bl = bc().block(_blockHash);
RLP b(bl);
return b[1].itemCount();
@ -494,6 +509,7 @@ unsigned MixClient::transactionCount(h256 _blockHash) const
unsigned MixClient::uncleCount(h256 _blockHash) const
{
ReadGuard l(x_state);
auto bl = bc().block(_blockHash);
RLP b(bl);
return b[2].itemCount();
@ -501,6 +517,7 @@ unsigned MixClient::uncleCount(h256 _blockHash) const
Transactions MixClient::transactions(h256 _blockHash) const
{
ReadGuard l(x_state);
auto bl = bc().block(_blockHash);
RLP b(bl);
Transactions res;
@ -511,21 +528,25 @@ Transactions MixClient::transactions(h256 _blockHash) const
TransactionHashes MixClient::transactionHashes(h256 _blockHash) const
{
ReadGuard l(x_state);
return bc().transactionHashes(_blockHash);
}
unsigned MixClient::number() const
{
ReadGuard l(x_state);
return bc().number();
}
eth::Transactions MixClient::pending() const
{
ReadGuard l(x_state);
return m_state.pending();
}
eth::StateDiff MixClient::diff(unsigned _txi, h256 _block) const
{
ReadGuard l(x_state);
State st(m_stateDB, bc(), _block);
return st.fromPending(_txi).diff(st.fromPending(_txi + 1));
}

5
mix/MixClient.h

@ -44,8 +44,8 @@ public:
/// Reset state to the empty state with given balance.
void resetState(std::map<Secret, u256> _accounts);
void mine();
ExecutionResult const& lastExecution() const;
ExecutionResults const& executions() const;
ExecutionResult lastExecution() const;
ExecutionResult execution(unsigned _index) const;
//dev::eth::Interface
void transact(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) override;
@ -108,6 +108,7 @@ private:
OverlayDB m_stateDB;
std::auto_ptr<MixBlockChain> m_bc;
mutable boost::shared_mutex x_state;
mutable boost::shared_mutex x_executions;
mutable std::mutex m_filterLock;
std::map<h256, dev::eth::InstalledFilter> m_filters;
std::map<unsigned, dev::eth::ClientWatch> m_watches;

4
mix/qml/CodeEditorView.qml

@ -116,7 +116,9 @@ Item {
for (var i = 0; i < editorListModel.count; i++)
{
var doc = editorListModel.get(i);
fileIo.writeFile(doc.path, editors.itemAt(i).item.getText());
var editor = editors.itemAt(i).item;
if (editor)
fileIo.writeFile(doc.path, item.getText());
}
}

59
mix/qml/DebugInfoList.qml

@ -8,6 +8,7 @@ ColumnLayout {
property string title
property variant listModel;
property bool collapsible;
property bool collapsed;
property bool enableSelection: false;
property real storedHeight: 0;
property Component itemDelegate
@ -19,18 +20,20 @@ ColumnLayout {
function collapse()
{
storedHeight = childrenRect.height;
storageContainer.state = "collapsed";
storageContainer.collapse();
}
function show()
{
storageContainer.state = "";
storageContainer.expand();
}
Component.onCompleted:
{
if (storageContainer.parent.parent.height === 25)
storageContainer.state = "collapsed";
storageContainer.collapse();
else
storageContainer.expand();
}
RowLayout {
@ -59,15 +62,15 @@ ColumnLayout {
onClicked: {
if (collapsible)
{
if (storageContainer.state == "collapsed")
if (collapsed)
{
storageContainer.state = "";
storageContainer.expand();
storageContainer.parent.parent.height = storedHeight;
}
else
{
storedHeight = root.childrenRect.height;
storageContainer.state = "collapsed";
storageContainer.collapse();
}
}
}
@ -80,19 +83,19 @@ ColumnLayout {
border.color: "#deddd9"
Layout.fillWidth: true
Layout.fillHeight: true
states: [
State {
name: "collapsed"
PropertyChanges {
target: storageImgArrow
source: "qrc:/qml/img/closedtriangleindicator.png"
}
PropertyChanges {
target: storageContainer.parent.parent
height: 25
function collapse() {
storageImgArrow.source = "qrc:/qml/img/closedtriangleindicator.png";
if (storageContainer.parent.parent.height > 25)
storageContainer.parent.parent.height = 25;
collapsed = true;
}
function expand() {
storageImgArrow.source = "qrc:/qml/img/opentriangleindicator.png";
collapsed = false;
}
]
Loader
{
id: loader
@ -102,6 +105,17 @@ ColumnLayout {
anchors.leftMargin: 3
width: parent.width - 3
height: parent.height - 6
onHeightChanged: {
if (height <= 0 && collapsible) {
if (storedHeight <= 0)
storedHeight = 200;
storageContainer.collapse();
}
else if (height > 0 && collapsed) {
storageContainer.expand();
}
}
sourceComponent: componentDelegate ? componentDelegate : table
}
Component
@ -116,17 +130,6 @@ ColumnLayout {
selectionMode: enableSelection ? SelectionMode.SingleSelection : SelectionMode.NoSelection
headerDelegate: null
itemDelegate: root.itemDelegate
onHeightChanged: {
if (height <= 0 && collapsible) {
if (storedHeight <= 0)
storedHeight = 200;
storageContainer.state = "collapsed";
}
else if (height > 0 && storageContainer.state == "collapsed") {
//TODO: fix increasing size
//storageContainer.state = "";
}
}
onActivated: rowActivated(row);
Keys.onPressed: {
if ((event.modifiers & Qt.ControlModifier) && event.key === Qt.Key_C && currentRow >=0 && currentRow < listModel.length) {

4
mix/qml/Debugger.qml

@ -170,7 +170,7 @@ Rectangle {
TransactionLog {
id: transactionLog
Layout.fillWidth: true
Layout.minimumHeight: 60
Layout.minimumHeight: 120
height: 250
anchors.top: parent.top
anchors.left: parent.left
@ -233,6 +233,7 @@ Rectangle {
height: 30
buttonShortcut: "Ctrl+Shift+F5"
buttonTooltip: qsTr("Run Back")
visible: false
}
StepActionImage
@ -245,6 +246,7 @@ Rectangle {
height: 30
buttonShortcut: "Ctrl+Shift+F11"
buttonTooltip: qsTr("Step Out Back")
visible: false
}
StepActionImage

4
mix/qml/ProjectModel.qml

@ -18,8 +18,10 @@ Item {
signal documentRemoved(var documentId)
signal documentUpdated(var documentId) //renamed
signal documentAdded(var documentId)
signal projectSaving(var projectData)
signal projectSaving()
signal projectFileSaving(var projectData)
signal projectSaved()
signal projectFileSaved()
signal newProject(var projectData)
signal documentSaved(var documentId)
signal contractSaved(var documentId)

44
mix/qml/StateListModel.qml

@ -6,12 +6,14 @@ 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 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
@ -105,7 +107,7 @@ Item {
codeModel.reset();
}
onProjectLoading: stateListModel.loadStatesFromProject(projectData);
onProjectSaving: {
onProjectFileSaving: {
projectData.states = []
for(var i = 0; i < stateListModel.count; i++) {
projectData.states.push(toPlainStateItem(stateList[i]));
@ -121,6 +123,13 @@ Item {
}
}
Connections {
target: codeModel
onNewContractCompiled: {
stateListModel.addNewContracts();
}
}
StateDialog {
id: stateDialog
onAccepted: {
@ -154,12 +163,7 @@ Item {
signal stateRun(int index)
function defaultTransactionItem() {
return {
value: QEtherHelper.createEther("100", QEther.Wei),
gas: QEtherHelper.createBigInt("125000"),
gasPrice: QEtherHelper.createEther("10000000000000", QEther.Wei),
stdContract: false
};
return TransactionHelper.defaultTransaction();
}
function newAccount(_balance, _unit, _secret)
@ -202,6 +206,32 @@ Item {
return item;
}
function addNewContracts() {
//add new contracts for all states
for(var c in codeModel.contracts) {
for (var s = 0; s < stateListModel.count; s++) {
var state = stateList[s];//toPlainStateItem(stateListModel.get(s));
for (var t = 0; t < state.transactions.length; t++) {
var transaction = state.transactions[t];
if (transaction.functionId === c && transaction.contractId === c)
break;
}
if (t === state.transactions.length) {
//append this contract
var ctorTr = defaultTransactionItem();
ctorTr.functionId = c;
ctorTr.contractId = c;
ctorTr.sender = state.accounts[0].secret;
state.transactions.push(ctorTr);
var item = state;//fromPlainStateItem(state);
stateListModel.set(s, item);
stateList[s] = item;
}
}
}
save();
}
function addState() {
var item = createDefaultState();
stateDialog.open(stateListModel.count, item, false);

6
mix/qml/StructView.qml

@ -7,7 +7,7 @@ Column
{
id: root
property alias members: repeater.model //js array
property var value : { }
property var value: ({})
Layout.fillWidth: true
Repeater
@ -24,13 +24,13 @@ Column
height: 20
id: typeLabel
text: modelData.type.name
Layout.preferredWidth: 50
Layout.preferredWidth: 60
}
DefaultLabel {
id: nameLabel
text: modelData.name
Layout.preferredWidth: 80
Layout.preferredWidth: 100
}
DefaultLabel {

6
mix/qml/TransactionLog.qml

@ -125,7 +125,7 @@ Item {
TableViewColumn {
role: "transactionIndex"
title: qsTr("Index")
title: qsTr("#")
width: 40
}
TableViewColumn {
@ -145,8 +145,8 @@ Item {
}
TableViewColumn {
role: "address"
title: qsTr("Address")
width: 120
title: qsTr("Destination")
width: 130
}
TableViewColumn {
role: "returned"

3
mix/qml/WebCodeEditor.qml

@ -40,6 +40,7 @@ Item {
}
function highlightExecution(location) {
if (initialized)
editorBrowser.runJavaScript("highlightExecution(" + location.start + "," + location.end + ")");
}
@ -48,10 +49,12 @@ Item {
}
function toggleBreakpoint() {
if (initialized)
editorBrowser.runJavaScript("toggleBreakpoint()");
}
function changeGeneration() {
if (initialized)
editorBrowser.runJavaScript("changeGeneration()", function(result) {});
}

4
mix/qml/js/ProjectModel.js

@ -61,10 +61,10 @@ function closeProject(callBack) {
function saveProject() {
if (!isEmpty) {
projectSaving();
var projectData = saveProjectFile();
if (projectData !== null)
{
projectSaving(projectData);
projectSaved();
}
}
@ -86,9 +86,11 @@ function saveProjectFile()
for (var i = 0; i < projectListModel.count; i++)
projectData.files.push(projectListModel.get(i).fileName);
projectFileSaving(projectData);
var json = JSON.stringify(projectData, null, "\t");
var projectFile = projectPath + projectFileName;
fileIo.writeFile(projectFile, json);
projectFileSaved(projectData);
return projectData;
}
return null;

5
mix/qml/js/TransactionHelper.js

@ -5,9 +5,10 @@ function defaultTransaction()
return {
value: createEther("0", QEther.Wei),
functionId: "",
gas: createBigInt("125000"),
gas: createBigInt("250000"),
gasPrice: createEther("100000", QEther.Wei),
parameters: {}
parameters: {},
stdContract: false
};
}

Loading…
Cancel
Save