diff --git a/libdevcore/CommonJS.cpp b/libdevcore/CommonJS.cpp index ee2074cd1..980cb9081 100644 --- a/libdevcore/CommonJS.cpp +++ b/libdevcore/CommonJS.cpp @@ -45,6 +45,12 @@ bytes padded(bytes _b, unsigned _l) return asBytes(asString(_b).substr(_b.size() - std::max(_l, _l))); } +bytes paddedRight(bytes _b, unsigned _l) +{ + _b.resize(_l); + return _b; +} + bytes unpadded(bytes _b) { auto p = asString(_b).find_last_not_of((char)0); @@ -52,12 +58,18 @@ bytes unpadded(bytes _b) return _b; } -std::string unpadLeft(std::string _b) +bytes unpadLeft(bytes _b) { - auto p = _b.find_first_not_of('0'); - if (p == std::string::npos) - return "0"; - return _b.substr(p, _b.length() - 1); + unsigned int i = 0; + if (_b.size() == 0) + return _b; + + while (i < _b.size() && _b[i] == byte(0)) + i++; + + if (i != 0) + _b.erase(_b.begin(), _b.begin() + i); + return _b; } std::string prettyU256(u256 _n) diff --git a/libdevcore/CommonJS.h b/libdevcore/CommonJS.h index 8e6c5fe53..59e6c1d34 100644 --- a/libdevcore/CommonJS.h +++ b/libdevcore/CommonJS.h @@ -48,12 +48,14 @@ inline std::string toJS(dev::bytes const& _n) /// Convert string to byte array. Input parameters can be hex or dec. Returns empty array if invalid input e.g neither dec or hex. bytes jsToBytes(std::string const& _s); -/// Add '0' on the head of _b until _l. +/// Add '0' on the head of @a _b until @a _l. bytes padded(bytes _b, unsigned _l); +/// Add '0' on the queue of @a _b until @a _l. +bytes paddedRight(bytes _b, unsigned _l); /// Removing all trailing '0'. Returns empty array if input contains only '0' char. bytes unpadded(bytes _s); -/// Remove all '0' on the head of _s. Returns 0 if _s contains only '0'. -std::string unpadLeft(std::string _s); +/// Remove all 0 byte on the head of @a _s. +bytes unpadLeft(bytes _s); /// Convert u256 into user-readable string. Returns int/hex value of 64 bits int, hex of 160 bits FixedHash. As a fallback try to handle input as h256. std::string prettyU256(u256 _n); /// Convert h256 into user-readable string (by directly using std::string constructor). diff --git a/mix/AppContext.cpp b/mix/AppContext.cpp index ad9c78e9b..e27eac9fd 100644 --- a/mix/AppContext.cpp +++ b/mix/AppContext.cpp @@ -63,6 +63,12 @@ void AppContext::load() m_applicationEngine->rootContext()->setContextProperty("fileIo", m_fileIo.get()); qmlRegisterType("org.ethereum.qml.QEther", 1, 0, "QEther"); qmlRegisterType("org.ethereum.qml.QBigInt", 1, 0, "QBigInt"); + qmlRegisterType("org.ethereum.qml.QIntType", 1, 0, "QIntType"); + qmlRegisterType("org.ethereum.qml.QRealType", 1, 0, "QRealType"); + qmlRegisterType("org.ethereum.qml.QStringType", 1, 0, "QStringType"); + qmlRegisterType("org.ethereum.qml.QHashType", 1, 0, "QHashType"); + qmlRegisterType("org.ethereum.qml.QBoolType", 1, 0, "QBoolType"); + qmlRegisterType("org.ethereum.qml.QVariableDeclaration", 1, 0, "QVariableDeclaration"); QQmlComponent projectModelComponent(m_applicationEngine, QUrl("qrc:/qml/ProjectModel.qml")); QObject* projectModel = projectModelComponent.create(); if (projectModelComponent.isError()) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 7fe514c09..365dce9a9 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -66,6 +66,10 @@ ClientModel::ClientModel(AppContext* _context): m_context(_context), m_running(false), m_rpcConnector(new RpcConnector()), m_contractAddress(Address()) { qRegisterMetaType("QBigInt*"); + qRegisterMetaType("QIntType*"); + qRegisterMetaType("QStringType*"); + qRegisterMetaType("QRealType*"); + qRegisterMetaType("QHashType*"); qRegisterMetaType("QEther*"); qRegisterMetaType("QVariableDefinition*"); qRegisterMetaType("QVariableDefinitionList*"); @@ -146,13 +150,13 @@ void ClientModel::setupState(QVariantMap _state) } else { - QVariantMap params = transaction.value("parameters").toMap(); + QVariantList qParams = transaction.value("qType").toList(); TransactionSettings transactionSettings(functionId, value, gas, gasPrice); - for (auto p = params.cbegin(); p != params.cend(); ++p) + for (QVariant const& variant: qParams) { - QBigInt* param = qvariant_cast(p.value()); - transactionSettings.parameterValues.insert(std::make_pair(p.key(), boost::get(param->internalValue()))); + QVariableDefinition* param = qvariant_cast(variant); + transactionSettings.parameterValues.push_back(param); } if (transaction.value("executeConstructor").toBool()) @@ -212,14 +216,11 @@ void ClientModel::executeSequence(std::vector const& _seque BOOST_THROW_EXCEPTION(FunctionNotFoundException() << FunctionName(transaction.functionId.toStdString())); encoder.encode(f); - for (int p = 0; p < f->parametersList().size(); p++) + for (int p = 0; p < transaction.parameterValues.size(); p++) { - QVariableDeclaration* var = f->parametersList().at(p); - u256 value = 0; - auto v = transaction.parameterValues.find(var->name()); - if (v != transaction.parameterValues.cend()) - value = v->second; - encoder.encode(var, value); + if (f->parametersList().at(p)->type() != transaction.parameterValues.at(p)->declaration()->type()) + BOOST_THROW_EXCEPTION(ParameterChangedException() << FunctionName(f->parametersList().at(p)->type().toStdString())); + encoder.push(transaction.parameterValues.at(p)->encodeValue()); } if (transaction.functionId.isEmpty()) @@ -330,11 +331,6 @@ void ClientModel::onNewTransaction() bool creation = tr.contractAddress != 0; - if (creation) - returned = QString::fromStdString(toJS(tr.contractAddress)); - else - returned = QString::fromStdString(toJS(tr.returnValue)); - //TODO: handle value transfer FixedHash<4> functionHash; bool call = false; @@ -363,6 +359,9 @@ void ClientModel::onNewTransaction() function = QObject::tr(""); } + if (creation) + returned = QString::fromStdString(toJS(tr.contractAddress)); + if (m_contractAddress != 0 && (tr.address == m_contractAddress || tr.contractAddress == m_contractAddress)) { auto compilerRes = m_context->codeModel()->code(); @@ -372,7 +371,13 @@ void ClientModel::onNewTransaction() { QFunctionDefinition* funcDef = def->getFunction(functionHash); if (funcDef) + { function = funcDef->name(); + ContractCallDataEncoder encoder; + QList returnValues = encoder.decode(funcDef->returnParameters(), tr.returnValue); + for (auto const& var: returnValues) + returned += var->value() + " | "; + } } } diff --git a/mix/ClientModel.h b/mix/ClientModel.h index 63731badf..1eb508dac 100644 --- a/mix/ClientModel.h +++ b/mix/ClientModel.h @@ -27,6 +27,7 @@ #include #include #include "MixClient.h" +#include "QVariableDefinition.h" namespace dev { @@ -59,7 +60,7 @@ struct TransactionSettings /// Gas price u256 gasPrice; /// Mapping from contract function parameter name to value - std::map parameterValues; + QList parameterValues; /// Standard contract url QString stdContractUrl; }; diff --git a/mix/CodeHighlighter.cpp b/mix/CodeHighlighter.cpp index 49d01b418..c1ef39d5d 100644 --- a/mix/CodeHighlighter.cpp +++ b/mix/CodeHighlighter.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of cpp-ethereum. - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . */ /** @file CodeHighlighter.cpp * @author Arkadiy Paronyan arkadiy@ethdev.com diff --git a/mix/ContractCallDataEncoder.cpp b/mix/ContractCallDataEncoder.cpp index 7a38db22b..bdec95ca4 100644 --- a/mix/ContractCallDataEncoder.cpp +++ b/mix/ContractCallDataEncoder.cpp @@ -44,89 +44,37 @@ void ContractCallDataEncoder::encode(QFunctionDefinition const* _function) m_encodedData.insert(m_encodedData.end(), hash.begin(), hash.end()); } -void ContractCallDataEncoder::encode(QVariableDeclaration const* _dec, bool _value) +void ContractCallDataEncoder::push(bytes const& _b) { - return encode(_dec, QString(formatBool(_value))); + m_encodedData.insert(m_encodedData.end(), _b.begin(), _b.end()); } -void ContractCallDataEncoder::encode(QVariableDeclaration const* _dec, QString _value) -{ - int padding = this->padding(_dec->type()); - bytes data = padded(jsToBytes(_value.toStdString()), padding); - m_encodedData.insert(m_encodedData.end(), data.begin(), data.end()); -} - -void ContractCallDataEncoder::encode(QVariableDeclaration const* _dec, u256 _value) -{ - int padding = this->padding(_dec->type()); - std::ostringstream s; - s << std::hex << "0x" << _value; - bytes data = padded(jsToBytes(s.str()), padding); - m_encodedData.insert(m_encodedData.end(), data.begin(), data.end()); - encodedData(); -} - -QList ContractCallDataEncoder::decode(QList _returnParameters, bytes _value) +QList ContractCallDataEncoder::decode(QList const& _returnParameters, bytes _value) { QList r; - std::string returnValue = toJS(_value); - returnValue = returnValue.substr(2, returnValue.length() - 1); for (int k = 0; k <_returnParameters.length(); k++) { QVariableDeclaration* dec = (QVariableDeclaration*)_returnParameters.at(k); - int padding = this->padding(dec->type()); - std::string rawParam = returnValue.substr(0, padding * 2); - r.append(new QVariableDefinition(dec, convertToReadable(unpadLeft(rawParam), dec))); - returnValue = returnValue.substr(rawParam.length(), returnValue.length() - 1); + QVariableDefinition* def = nullptr; + if (dec->type().contains("int")) + def = new QIntType(dec, QString()); + else if (dec->type().contains("real")) + def = new QRealType(dec, QString()); + else if (dec->type().contains("bool")) + def = new QBoolType(dec, QString()); + else if (dec->type().contains("string") || dec->type().contains("text")) + def = new QStringType(dec, QString()); + else if (dec->type().contains("hash") || dec->type().contains("address")) + def = new QHashType(dec, QString()); + else + BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Parameter declaration not found")); + + bytes rawParam(_value.begin(), _value.begin() + 32); + def->decodeValue(rawParam); + r.push_back(def); + if (_value.size() > 32) + _value = bytes(_value.begin() + 32, _value.end()); + qDebug() << "decoded return value : " << dec->type() << " " << def->value(); } return r; } - -int ContractCallDataEncoder::padding(QString type) -{ - // TODO : to be improved (load types automatically from solidity library). - if (type.indexOf("uint") != -1) - return integerPadding(type.remove("uint").toInt()); - else if (type.indexOf("int") != -1) - return integerPadding(type.remove("int").toInt()); - else if (type.indexOf("bool") != -1) - return 1; - else if ((type.indexOf("address") != -1)) - return 32; - else - return 0; -} - -int ContractCallDataEncoder::integerPadding(int bitValue) -{ - return bitValue / 8; -} - -QString ContractCallDataEncoder::formatBool(bool _value) -{ - return (_value ? "1" : "0"); -} - -QString ContractCallDataEncoder::convertToReadable(std::string _v, QVariableDeclaration* _dec) -{ - if (_dec->type().indexOf("int") != -1) - return convertToInt(_v); - else if (_dec->type().indexOf("bool") != -1) - return convertToBool(_v); - else - return QString::fromStdString(_v); -} - -QString ContractCallDataEncoder::convertToBool(std::string _v) -{ - return _v == "1" ? "true" : "false"; -} - -QString ContractCallDataEncoder::convertToInt(std::string _v) -{ - //TO DO to be improve to manage all int, uint size (128, 256, ...) in ethereum QML types task #612. - int x = std::stol(_v, nullptr, 16); - std::stringstream ss; - ss << std::dec << x; - return QString::fromStdString(ss.str()); -} diff --git a/mix/ContractCallDataEncoder.h b/mix/ContractCallDataEncoder.h index 49410a7cd..718beb8e0 100644 --- a/mix/ContractCallDataEncoder.h +++ b/mix/ContractCallDataEncoder.h @@ -41,27 +41,17 @@ class ContractCallDataEncoder { public: ContractCallDataEncoder() {} - /// Encode variable in order to be sent as parameter. - void encode(QVariableDeclaration const* _dec, QString _value); - /// Encode variable in order to be sent as parameter. - void encode(QVariableDeclaration const* _dec, u256 _value); - /// Encode variable in order to be sent as parameter. - void encode(QVariableDeclaration const* _dec, bool _value); /// Encode hash of the function to call. void encode(QFunctionDefinition const* _function); /// Decode variable in order to be sent to QML view. - QList decode(QList _dec, bytes _value); + QList decode(QList const& _dec, bytes _value); /// Get all encoded data encoded by encode function. bytes encodedData(); + /// Push the given @a _b to the current param context. + void push(bytes const& _b); private: - int padding(QString _type); bytes m_encodedData; - static QString convertToReadable(std::string _v, QVariableDeclaration* _dec); - static QString convertToBool(std::string _v); - static QString convertToInt(std::string _v); - static int integerPadding(int _bitValue); - static QString formatBool(bool _value); }; } diff --git a/mix/Exceptions.h b/mix/Exceptions.h index ea4cb87b3..5403879f1 100644 --- a/mix/Exceptions.h +++ b/mix/Exceptions.h @@ -38,6 +38,7 @@ struct FileIoException: virtual Exception {}; struct InvalidBlockException: virtual Exception {}; struct FunctionNotFoundException: virtual Exception {}; struct ExecutionStateException: virtual Exception {}; +struct ParameterChangedException: virtual Exception {}; typedef boost::error_info QmlErrorInfo; typedef boost::error_info FileError; diff --git a/mix/QBigInt.h b/mix/QBigInt.h index 842b86c7d..c6ec72305 100644 --- a/mix/QBigInt.h +++ b/mix/QBigInt.h @@ -36,7 +36,7 @@ namespace dev namespace mix { -using BigIntVariant = boost::variant; +using BigIntVariant = boost::variant; struct add: public boost::static_visitor { @@ -75,6 +75,7 @@ public: QBigInt(dev::u256 const& _value, QObject* _parent = 0): QObject(_parent), m_internalValue(_value) { QQmlEngine::setObjectOwnership(this, QQmlEngine::JavaScriptOwnership); } QBigInt(dev::bigint const& _value, QObject* _parent = 0): QObject(_parent), m_internalValue(_value) { QQmlEngine::setObjectOwnership(this, QQmlEngine::JavaScriptOwnership); } QBigInt(BigIntVariant const& _value, QObject* _parent = 0): QObject(_parent), m_internalValue(_value){ QQmlEngine::setObjectOwnership(this, QQmlEngine::JavaScriptOwnership); } + QBigInt(dev::s256 const& _value, QObject* _parent = 0): QObject(_parent), m_internalValue(_value) { QQmlEngine::setObjectOwnership(this, QQmlEngine::JavaScriptOwnership); } ~QBigInt() {} /// @returns the current used big integer. diff --git a/mix/QVariableDeclaration.h b/mix/QVariableDeclaration.h index f9cc5265f..fcd83cb30 100644 --- a/mix/QVariableDeclaration.h +++ b/mix/QVariableDeclaration.h @@ -19,6 +19,8 @@ * @date 2014 */ +#include +#include #include #include "QBasicNodeDefinition.h" @@ -32,16 +34,20 @@ namespace mix class QVariableDeclaration: public QBasicNodeDefinition { Q_OBJECT - Q_PROPERTY(QString type READ type CONSTANT) + Q_PROPERTY(QString type READ type WRITE setType) public: QVariableDeclaration() {} QVariableDeclaration(solidity::VariableDeclaration const* _v): QBasicNodeDefinition(_v), m_type(QString::fromStdString(_v->getType()->toString())) {} QVariableDeclaration(std::string const& _name, std::string const& _type): QBasicNodeDefinition(_name), m_type(QString::fromStdString(_type)) {} QString type() const { return m_type; } + void setType(QString _type) { m_type = _type; } + private: QString m_type; }; } } + +Q_DECLARE_METATYPE(dev::mix::QVariableDeclaration*) diff --git a/mix/QVariableDefinition.cpp b/mix/QVariableDefinition.cpp index 4f38e84b2..a76388d68 100644 --- a/mix/QVariableDefinition.cpp +++ b/mix/QVariableDefinition.cpp @@ -19,6 +19,8 @@ * @date 2014 */ +#include +#include #include "QVariableDefinition.h" using namespace dev::mix; @@ -53,3 +55,91 @@ QVariableDefinition* QVariableDefinitionList::val(int _idx) return nullptr; return m_def.at(_idx); } + +/* + * QIntType + */ +void QIntType::setValue(dev::bigint _value) +{ + m_bigIntvalue = _value; + std::stringstream str; + str << std::dec << m_bigIntvalue; + m_value = QString::fromStdString(str.str()); +} + +dev::bytes QIntType::encodeValue() +{ + dev::bigint i(value().toStdString()); + bytes ret(32); + toBigEndian((u256)i, ret); + return ret; +} + +void QIntType::decodeValue(dev::bytes const& _rawValue) +{ + dev::u256 un = dev::fromBigEndian(_rawValue); + if (un >> 255) + setValue(-s256(~un + 1)); + else + setValue(un); +} + +/* + * QHashType + */ +dev::bytes QHashType::encodeValue() +{ + QByteArray bytesAr = value().toLocal8Bit(); + bytes r = bytes(bytesAr.begin(), bytesAr.end()); + return padded(r, 32); +} + +void QHashType::decodeValue(dev::bytes const& _rawValue) +{ + std::string _ret = asString(unpadLeft(_rawValue)); + setValue(QString::fromStdString(_ret)); +} + +/* + * QRealType + */ +dev::bytes QRealType::encodeValue() +{ + return bytes(); +} + +void QRealType::decodeValue(dev::bytes const& _rawValue) +{ + Q_UNUSED(_rawValue); +} + +/* + * QStringType + */ +dev::bytes QStringType::encodeValue() +{ + QByteArray b = value().toUtf8(); + bytes r = bytes(b.begin(), b.end()); + return paddedRight(r, 32); +} + +void QStringType::decodeValue(dev::bytes const& _rawValue) +{ + setValue(QString::fromUtf8((char*)_rawValue.data())); +} + +/* + * QBoolType + */ +dev::bytes QBoolType::encodeValue() +{ + return padded(jsToBytes(value().toStdString()), 32); +} + +void QBoolType::decodeValue(dev::bytes const& _rawValue) +{ + byte ret = _rawValue.at(_rawValue.size() - 1); + bool boolRet = (ret == byte(1)); + m_boolValue = boolRet; + m_value = m_boolValue ? "1" : "0"; +} diff --git a/mix/QVariableDefinition.h b/mix/QVariableDefinition.h index f55e51346..ae9bf9459 100644 --- a/mix/QVariableDefinition.h +++ b/mix/QVariableDefinition.h @@ -22,6 +22,7 @@ #pragma once #include +#include "QBigInt.h" #include "QVariableDeclaration.h" namespace dev @@ -37,15 +38,26 @@ class QVariableDefinition: public QObject Q_PROPERTY(QVariableDeclaration* declaration READ declaration CONSTANT) public: + QVariableDefinition() {} QVariableDefinition(QVariableDeclaration* _def, QString _value): QObject(), m_value(_value), m_dec(_def) {} - /// Return the associated declaration of this variable definition. - QVariableDeclaration* declaration() const { return m_dec; } + /// Return the associated declaration of this variable definition. Invokable from QML. + Q_INVOKABLE QVariableDeclaration* declaration() const { return m_dec; } /// Return the variable value. QString value() const { return m_value; } + /// Set a new value for this instance. Invokable from QML. + Q_INVOKABLE void setValue(QString _value) { m_value = _value; } + /// Set a new Declaration for this instance. Invokable from QML. + Q_INVOKABLE void setDeclaration(QVariableDeclaration* _dec) { m_dec = _dec; } + /// Encode the current value in order to be used as function parameter. + virtual bytes encodeValue() = 0; + /// Decode the return value @a _rawValue. + virtual void decodeValue(dev::bytes const& _rawValue) = 0; + +protected: + QString m_value; private: - QString m_value; QVariableDeclaration* m_dec; }; @@ -67,7 +79,77 @@ private: QList m_def; }; +class QIntType: public QVariableDefinition +{ + Q_OBJECT + +public: + QIntType() {} + QIntType(QVariableDeclaration* _def, QString _value): QVariableDefinition(_def, _value) {} + dev::bytes encodeValue() override; + void decodeValue(dev::bytes const& _rawValue) override; + /// @returns an instance of QBigInt for the current value. + QBigInt* toBigInt() { return new QBigInt(m_bigIntvalue); } + dev::bigint bigInt() { return m_bigIntvalue; } + void setValue(dev::bigint _value); + +private: + dev::bigint m_bigIntvalue; +}; + +class QRealType: public QVariableDefinition +{ + Q_OBJECT + +public: + QRealType() {} + QRealType(QVariableDeclaration* _def, QString _value): QVariableDefinition(_def, _value) {} + dev::bytes encodeValue() override; + void decodeValue(dev::bytes const& _rawValue) override; +}; + +class QStringType: public QVariableDefinition +{ + Q_OBJECT + +public: + QStringType() {} + QStringType(QVariableDeclaration* _def, QString _value): QVariableDefinition(_def, _value) {} + dev::bytes encodeValue() override; + void decodeValue(dev::bytes const& _rawValue) override; +}; + +class QHashType: public QVariableDefinition +{ + Q_OBJECT + +public: + QHashType() {} + QHashType(QVariableDeclaration* _def, QString _value): QVariableDefinition(_def, _value) {} + dev::bytes encodeValue() override; + void decodeValue(dev::bytes const& _rawValue) override; +}; + +class QBoolType: public QVariableDefinition +{ + Q_OBJECT + +public: + QBoolType() {} + QBoolType(QVariableDeclaration* _def, QString _value): QVariableDefinition(_def, _value) {} + dev::bytes encodeValue() override; + void decodeValue(dev::bytes const& _rawValue) override; + /// @returns the boolean value for the current definition. + bool toBool() { return m_boolValue; } + +private: + bool m_boolValue; +}; + } } -Q_DECLARE_METATYPE(dev::mix::QVariableDefinition*) +Q_DECLARE_METATYPE(dev::mix::QIntType*) +Q_DECLARE_METATYPE(dev::mix::QStringType*) +Q_DECLARE_METATYPE(dev::mix::QHashType*) +Q_DECLARE_METATYPE(dev::mix::QBoolType*) diff --git a/mix/qml/QBoolType.qml b/mix/qml/QBoolType.qml new file mode 100644 index 000000000..9f5fe6fd7 --- /dev/null +++ b/mix/qml/QBoolType.qml @@ -0,0 +1,7 @@ +import QtQuick 2.0 +import org.ethereum.qml.QBoolType 1.0 + +QBoolType +{ +} + diff --git a/mix/qml/QBoolTypeView.qml b/mix/qml/QBoolTypeView.qml new file mode 100644 index 000000000..a52601bdb --- /dev/null +++ b/mix/qml/QBoolTypeView.qml @@ -0,0 +1,42 @@ +import QtQuick 2.0 +import QtQuick.Controls 1.3 + +Item +{ + id: editRoot + property string text + property string defaultValue + + Rectangle { + anchors.fill: parent + ComboBox + { + property bool inited: false + Component.onCompleted: + { + if (text === "") + currentIndex = parseInt(defaultValue); + else + currentIndex = parseInt(text); + inited = true + } + + id: boolCombo + anchors.fill: parent + onCurrentIndexChanged: + { + if (inited) + text = comboModel.get(currentIndex).value; + } + model: ListModel + { + id: comboModel + ListElement { text: qsTr("False"); value: "0" } + ListElement { text: qsTr("True"); value: "1" } + } + } + } +} + + + diff --git a/mix/qml/QHashType.qml b/mix/qml/QHashType.qml new file mode 100644 index 000000000..cbd2618cf --- /dev/null +++ b/mix/qml/QHashType.qml @@ -0,0 +1,7 @@ +import QtQuick 2.0 +import org.ethereum.qml.QHashType 1.0 + +QHashType +{ +} + diff --git a/mix/qml/QHashTypeView.qml b/mix/qml/QHashTypeView.qml new file mode 100644 index 000000000..e36514fab --- /dev/null +++ b/mix/qml/QHashTypeView.qml @@ -0,0 +1,22 @@ +import QtQuick 2.0 + +Item +{ + property alias text: textinput.text + id: editRoot + Rectangle { + anchors.fill: parent + TextInput { + id: textinput + text: text + anchors.fill: parent + wrapMode: Text.WrapAnywhere + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + onClicked: textinput.forceActiveFocus() + } + } + } +} diff --git a/mix/qml/QIntType.qml b/mix/qml/QIntType.qml new file mode 100644 index 000000000..241bd4a12 --- /dev/null +++ b/mix/qml/QIntType.qml @@ -0,0 +1,7 @@ +import QtQuick 2.0 +import org.ethereum.qml.QIntType 1.0 + +QIntType +{ +} + diff --git a/mix/qml/QIntTypeView.qml b/mix/qml/QIntTypeView.qml new file mode 100644 index 000000000..f794a3b2d --- /dev/null +++ b/mix/qml/QIntTypeView.qml @@ -0,0 +1,24 @@ +import QtQuick 2.0 + +Item +{ + property alias text: textinput.text + id: editRoot + Rectangle { + anchors.fill: parent + TextInput { + id: textinput + text: text + anchors.fill: parent + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + onClicked: textinput.forceActiveFocus() + } + } + } +} + + + diff --git a/mix/qml/QRealType.qml b/mix/qml/QRealType.qml new file mode 100644 index 000000000..9a015b1c7 --- /dev/null +++ b/mix/qml/QRealType.qml @@ -0,0 +1,7 @@ +import QtQuick 2.0 +import org.ethereum.qml.QRealType 1.0 + +QRealType +{ +} + diff --git a/mix/qml/QRealTypeView.qml b/mix/qml/QRealTypeView.qml new file mode 100644 index 000000000..96db4de75 --- /dev/null +++ b/mix/qml/QRealTypeView.qml @@ -0,0 +1,15 @@ +import QtQuick 2.0 + +Component +{ + Rectangle { + anchors.fill: parent + Text{ + anchors.fill: parent + text: qsTr("Real") + } + } +} + + + diff --git a/mix/qml/QStringType.qml b/mix/qml/QStringType.qml new file mode 100644 index 000000000..4113fec20 --- /dev/null +++ b/mix/qml/QStringType.qml @@ -0,0 +1,7 @@ +import QtQuick 2.0 +import org.ethereum.qml.QStringType 1.0 + +QStringType +{ +} + diff --git a/mix/qml/QStringTypeView.qml b/mix/qml/QStringTypeView.qml new file mode 100644 index 000000000..a78fc1d26 --- /dev/null +++ b/mix/qml/QStringTypeView.qml @@ -0,0 +1,25 @@ +import QtQuick 2.0 + +Item +{ + property alias text: textinput.text + id: editRoot + Rectangle { + anchors.fill: parent + TextInput { + id: textinput + text: text + anchors.fill: parent + wrapMode: Text.WrapAnywhere + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + onClicked: textinput.forceActiveFocus() + } + } + } +} + + + diff --git a/mix/qml/QVariableDeclaration.qml b/mix/qml/QVariableDeclaration.qml new file mode 100644 index 000000000..dc21d40a7 --- /dev/null +++ b/mix/qml/QVariableDeclaration.qml @@ -0,0 +1,7 @@ +import QtQuick 2.0 +import org.ethereum.qml.QVariableDeclaration 1.0 + +QVariableDeclaration +{ +} + diff --git a/mix/qml/QVariableDefinition.qml b/mix/qml/QVariableDefinition.qml new file mode 100644 index 000000000..af0cd4ea0 --- /dev/null +++ b/mix/qml/QVariableDefinition.qml @@ -0,0 +1,13 @@ +/* + * Used to instanciate a QVariableDefinition obj using Qt.createComponent function. +*/ +import QtQuick 2.2 +import QtQuick.Controls 1.1 +import QtQuick.Layouts 1.1 +import QtQuick.Controls.Styles 1.1 +import org.ethereum.qml.QVariableDefinition 1.0 + +QVariableDefinition +{ + id: qVariableDefinition +} diff --git a/mix/qml/StateListModel.qml b/mix/qml/StateListModel.qml index 6f8fd3a1a..1a85bbf19 100644 --- a/mix/qml/StateListModel.qml +++ b/mix/qml/StateListModel.qml @@ -31,12 +31,30 @@ Item { stdContract: t.stdContract, parameters: {} }; - for (var key in t.parameters) { - var intComponent = Qt.createComponent("qrc:/qml/BigIntValue.qml"); - var param = intComponent.createObject(); - param.setValue(t.parameters[key]); - r.parameters[key] = param; + var qType = []; + for (var key in t.parameters) + { + r.parameters[key] = t.parameters[key].value; + var type = t.parameters[key].type; + var varComponent; + if (type.indexOf("int") !== -1) + varComponent = Qt.createComponent("qrc:/qml/QIntType.qml"); + else if (type.indexOf("real") !== -1) + varComponent = Qt.createComponent("qrc:/qml/QRealType.qml"); + else if (type.indexOf("string") !== -1 || type.indexOf("text") !== -1) + varComponent = Qt.createComponent("qrc:/qml/QStringType.qml"); + else if (type.indexOf("hash") !== -1 || type.indexOf("address") !== -1) + varComponent = Qt.createComponent("qrc:/qml/QHashType.qml"); + else if (type.indexOf("bool") !== -1) + varComponent = Qt.createComponent("qrc:/qml/QBoolType.qml"); + + var param = varComponent.createObject(stateListModel); + var dec = Qt.createComponent("qrc:/qml/QVariableDeclaration.qml"); + param.setDeclaration(dec.createObject(stateListModel, { "type": type })); + param.setValue(r.parameters[key]); + qType.push(param); } + r.qType = qType; return r; } @@ -48,6 +66,16 @@ Item { }; } + function getParamType(param, params) + { + for (var k in params) + { + if (params[k].declaration.name === param) + return params[k].declaration.type; + } + return ''; + } + function toPlainTransactionItem(t) { var r = { functionId: t.functionId, @@ -60,7 +88,14 @@ Item { parameters: {} }; for (var key in t.parameters) - r.parameters[key] = t.parameters[key].value(); + { + var param = { + name: key, + value: t.parameters[key], + type: getParamType(key, t.qType) + } + r.parameters[key] = param; + } return r; } diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index 5eb3fbb13..4d50db7b1 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -9,7 +9,7 @@ Window { id: modalTransactionDialog modality: Qt.WindowModal width:640 - height:480 + height:640 visible: false property int transactionIndex @@ -21,10 +21,12 @@ Window { property var itemParams; property bool isConstructorTransaction; property bool useTransactionDefaultValue: false + property var qType; signal accepted; function open(index, item) { + qType = []; rowFunction.visible = !useTransactionDefaultValue; rowValue.visible = !useTransactionDefaultValue; rowGas.visible = !useTransactionDefaultValue; @@ -68,6 +70,7 @@ Window { } function loadParameters() { + paramsModel.clear(); if (!paramsModel) return; if (functionComboBox.currentIndex >= 0 && functionComboBox.currentIndex < functionsModel.count) { @@ -75,7 +78,27 @@ Window { var parameters = func.parameters; for (var p = 0; p < parameters.length; p++) { var pname = parameters[p].name; - paramsModel.append({ name: pname, type: parameters[p].type, value: itemParams[pname] !== undefined ? itemParams[pname].value() : "" }); + var varComponent; + var type = parameters[p].type; + + if (type.indexOf("int") !== -1) + varComponent = Qt.createComponent("qrc:/qml/QIntType.qml"); + else if (type.indexOf("real") !== -1) + varComponent = Qt.createComponent("qrc:/qml/QRealType.qml"); + else if (type.indexOf("string") !== -1 || type.indexOf("text") !== -1) + varComponent = Qt.createComponent("qrc:/qml/QStringType.qml"); + else if (type.indexOf("hash") !== -1 || type.indexOf("address") !== -1) + varComponent = Qt.createComponent("qrc:/qml/QHashType.qml"); + else if (type.indexOf("bool") !== -1) + varComponent = Qt.createComponent("qrc:/qml/QBoolType.qml"); + + var param = varComponent.createObject(modalTransactionDialog); + var value = itemParams[pname] !== undefined ? itemParams[pname] : ""; + + param.setValue(value); + param.setDeclaration(parameters[p]); + qType.push({ name: pname, value: param }); + paramsModel.append({ name: pname, type: parameters[p].type, value: value }); } } } @@ -85,6 +108,15 @@ Window { visible = false; } + function qTypeParam(name) + { + for (var k in qType) + { + if (qType[k].name === name) + return qType[k].value; + } + } + function getItem() { var item; @@ -109,14 +141,15 @@ Window { if (isConstructorTransaction) item.functionId = qsTr("Constructor"); + var orderedQType = []; for (var p = 0; p < transactionDialog.transactionParams.count; p++) { var parameter = transactionDialog.transactionParams.get(p); - var intComponent = Qt.createComponent("qrc:/qml/BigIntValue.qml"); - var param = intComponent.createObject(modalTransactionDialog); - - param.setValue(parameter.value); - item.parameters[parameter.name] = param; + var qtypeParam = qTypeParam(parameter.name); + qtypeParam.setValue(parameter.value); + orderedQType.push(qtypeParam); + item.parameters[parameter.name] = parameter.value; } + item.qType = orderedQType; return item; } @@ -219,8 +252,10 @@ Window { } TableView { model: paramsModel - Layout.fillWidth: true - + Layout.preferredWidth: 120 * 2 + 240 + Layout.minimumHeight: 150 + Layout.preferredHeight: 400 + Layout.maximumHeight: 600 TableViewColumn { role: "name" title: qsTr("Name") @@ -234,12 +269,11 @@ Window { TableViewColumn { role: "value" title: qsTr("Value") - width: 120 + width: 240 } - itemDelegate: { - return editableDelegate; - } + rowDelegate: rowDelegate + itemDelegate: editableDelegate } } } @@ -268,19 +302,15 @@ Window { } Component { - id: editableDelegate + id: rowDelegate Item { + height: 100 + } + } - Text { - width: parent.width - anchors.margins: 4 - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - elide: styleData.elideMode - text: styleData.value !== undefined ? styleData.value : "" - color: styleData.textColor - visible: !styleData.selected - } + Component { + id: editableDelegate + Item { Loader { id: loaderEditor anchors.fill: parent @@ -289,14 +319,87 @@ Window { target: loaderEditor.item onTextChanged: { if (styleData.role === "value" && styleData.row < paramsModel.count) - paramsModel.setProperty(styleData.row, styleData.role, loaderEditor.item.text); + loaderEditor.updateValue(styleData.row, styleData.role, loaderEditor.item.text); } } - sourceComponent: (styleData.selected) ? editor : null + + function updateValue(row, role, value) + { + paramsModel.setProperty(styleData.row, styleData.role, value); + } + + sourceComponent: + { + if (styleData.role === "value") + { + if (paramsModel.get(styleData.row) === undefined) + return null; + if (paramsModel.get(styleData.row).type.indexOf("int") !== -1) + return intViewComp; + else if (paramsModel.get(styleData.row).type.indexOf("bool") !== -1) + return boolViewComp; + else if (paramsModel.get(styleData.row).type.indexOf("string") !== -1) + return stringViewComp; + else if (paramsModel.get(styleData.row).type.indexOf("hash") !== -1) + return hashViewComp; + } + else + return editor; + } + + Component + { + id: intViewComp + QIntTypeView + { + id: intView + text: styleData.value + } + } + + Component + { + id: boolViewComp + QBoolTypeView + { + id: boolView + defaultValue: "1" + Component.onCompleted: + { + loaderEditor.updateValue(styleData.row, styleData.role, + (paramsModel.get(styleData.row).value === "" ? defaultValue : + paramsModel.get(styleData.row).value)); + text = (paramsModel.get(styleData.row).value === "" ? defaultValue : paramsModel.get(styleData.row).value); + } + } + } + + Component + { + id: stringViewComp + QStringTypeView + { + id: stringView + text: styleData.value + } + } + + + Component + { + id: hashViewComp + QHashTypeView + { + id: hashView + text: styleData.value + } + } + Component { id: editor TextInput { id: textinput + readOnly: true color: styleData.textColor text: styleData.value MouseArea { diff --git a/mix/res.qrc b/mix/res.qrc index b511217e6..d73635f9d 100644 --- a/mix/res.qrc +++ b/mix/res.qrc @@ -42,8 +42,19 @@ qml/Ether.qml qml/EtherValue.qml qml/BigIntValue.qml + qml/QVariableDefinition.qml + qml/QBoolType.qml + qml/QHashType.qml + qml/QIntType.qml + qml/QRealType.qml qml/js/QEtherHelper.js qml/js/TransactionHelper.js + qml/QStringType.qml + qml/QBoolTypeView.qml + qml/QIntTypeView.qml + qml/QRealTypeView.qml + qml/QStringTypeView.qml + qml/QHashTypeView.qml qml/ContractLibrary.qml stdc/config.sol stdc/namereg.sol @@ -51,5 +62,6 @@ qml/TransactionLog.qml res/mix_256x256x32.png qml/CallStack.qml + qml/QVariableDeclaration.qml