Browse Source

Merge pull request #895 from yann300/param_types

Manage solidity types
cl-refactor
Gav Wood 10 years ago
parent
commit
edd8aa36e0
  1. 22
      libdevcore/CommonJS.cpp
  2. 8
      libdevcore/CommonJS.h
  3. 6
      mix/AppContext.cpp
  4. 37
      mix/ClientModel.cpp
  5. 3
      mix/ClientModel.h
  6. 98
      mix/ContractCallDataEncoder.cpp
  7. 16
      mix/ContractCallDataEncoder.h
  8. 1
      mix/Exceptions.h
  9. 3
      mix/QBigInt.h
  10. 8
      mix/QVariableDeclaration.h
  11. 90
      mix/QVariableDefinition.cpp
  12. 90
      mix/QVariableDefinition.h
  13. 7
      mix/qml/QBoolType.qml
  14. 42
      mix/qml/QBoolTypeView.qml
  15. 7
      mix/qml/QHashType.qml
  16. 22
      mix/qml/QHashTypeView.qml
  17. 7
      mix/qml/QIntType.qml
  18. 24
      mix/qml/QIntTypeView.qml
  19. 7
      mix/qml/QRealType.qml
  20. 15
      mix/qml/QRealTypeView.qml
  21. 7
      mix/qml/QStringType.qml
  22. 25
      mix/qml/QStringTypeView.qml
  23. 7
      mix/qml/QVariableDeclaration.qml
  24. 13
      mix/qml/QVariableDefinition.qml
  25. 49
      mix/qml/StateListModel.qml
  26. 155
      mix/qml/TransactionDialog.qml
  27. 12
      mix/res.qrc

22
libdevcore/CommonJS.cpp

@ -45,6 +45,12 @@ bytes padded(bytes _b, unsigned _l)
return asBytes(asString(_b).substr(_b.size() - std::max(_l, _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) bytes unpadded(bytes _b)
{ {
auto p = asString(_b).find_last_not_of((char)0); auto p = asString(_b).find_last_not_of((char)0);
@ -52,12 +58,18 @@ bytes unpadded(bytes _b)
return _b; return _b;
} }
std::string unpadLeft(std::string _b) bytes unpadLeft(bytes _b)
{ {
auto p = _b.find_first_not_of('0'); unsigned int i = 0;
if (p == std::string::npos) if (_b.size() == 0)
return "0"; return _b;
return _b.substr(p, _b.length() - 1);
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) std::string prettyU256(u256 _n)

8
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. /// 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); 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); 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. /// Removing all trailing '0'. Returns empty array if input contains only '0' char.
bytes unpadded(bytes _s); bytes unpadded(bytes _s);
/// Remove all '0' on the head of _s. Returns 0 if _s contains only '0'. /// Remove all 0 byte on the head of @a _s.
std::string unpadLeft(std::string _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. /// 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); std::string prettyU256(u256 _n);
/// Convert h256 into user-readable string (by directly using std::string constructor). /// Convert h256 into user-readable string (by directly using std::string constructor).

6
mix/AppContext.cpp

@ -63,6 +63,12 @@ void AppContext::load()
m_applicationEngine->rootContext()->setContextProperty("fileIo", m_fileIo.get()); m_applicationEngine->rootContext()->setContextProperty("fileIo", m_fileIo.get());
qmlRegisterType<QEther>("org.ethereum.qml.QEther", 1, 0, "QEther"); qmlRegisterType<QEther>("org.ethereum.qml.QEther", 1, 0, "QEther");
qmlRegisterType<QBigInt>("org.ethereum.qml.QBigInt", 1, 0, "QBigInt"); qmlRegisterType<QBigInt>("org.ethereum.qml.QBigInt", 1, 0, "QBigInt");
qmlRegisterType<QIntType>("org.ethereum.qml.QIntType", 1, 0, "QIntType");
qmlRegisterType<QRealType>("org.ethereum.qml.QRealType", 1, 0, "QRealType");
qmlRegisterType<QStringType>("org.ethereum.qml.QStringType", 1, 0, "QStringType");
qmlRegisterType<QHashType>("org.ethereum.qml.QHashType", 1, 0, "QHashType");
qmlRegisterType<QBoolType>("org.ethereum.qml.QBoolType", 1, 0, "QBoolType");
qmlRegisterType<QVariableDeclaration>("org.ethereum.qml.QVariableDeclaration", 1, 0, "QVariableDeclaration");
QQmlComponent projectModelComponent(m_applicationEngine, QUrl("qrc:/qml/ProjectModel.qml")); QQmlComponent projectModelComponent(m_applicationEngine, QUrl("qrc:/qml/ProjectModel.qml"));
QObject* projectModel = projectModelComponent.create(); QObject* projectModel = projectModelComponent.create();
if (projectModelComponent.isError()) if (projectModelComponent.isError())

37
mix/ClientModel.cpp

@ -66,6 +66,10 @@ ClientModel::ClientModel(AppContext* _context):
m_context(_context), m_running(false), m_rpcConnector(new RpcConnector()), m_contractAddress(Address()) m_context(_context), m_running(false), m_rpcConnector(new RpcConnector()), m_contractAddress(Address())
{ {
qRegisterMetaType<QBigInt*>("QBigInt*"); qRegisterMetaType<QBigInt*>("QBigInt*");
qRegisterMetaType<QIntType*>("QIntType*");
qRegisterMetaType<QStringType*>("QStringType*");
qRegisterMetaType<QRealType*>("QRealType*");
qRegisterMetaType<QHashType*>("QHashType*");
qRegisterMetaType<QEther*>("QEther*"); qRegisterMetaType<QEther*>("QEther*");
qRegisterMetaType<QVariableDefinition*>("QVariableDefinition*"); qRegisterMetaType<QVariableDefinition*>("QVariableDefinition*");
qRegisterMetaType<QVariableDefinitionList*>("QVariableDefinitionList*"); qRegisterMetaType<QVariableDefinitionList*>("QVariableDefinitionList*");
@ -146,13 +150,13 @@ void ClientModel::setupState(QVariantMap _state)
} }
else else
{ {
QVariantMap params = transaction.value("parameters").toMap(); QVariantList qParams = transaction.value("qType").toList();
TransactionSettings transactionSettings(functionId, value, gas, gasPrice); TransactionSettings transactionSettings(functionId, value, gas, gasPrice);
for (auto p = params.cbegin(); p != params.cend(); ++p) for (QVariant const& variant: qParams)
{ {
QBigInt* param = qvariant_cast<QBigInt*>(p.value()); QVariableDefinition* param = qvariant_cast<QVariableDefinition*>(variant);
transactionSettings.parameterValues.insert(std::make_pair(p.key(), boost::get<dev::u256>(param->internalValue()))); transactionSettings.parameterValues.push_back(param);
} }
if (transaction.value("executeConstructor").toBool()) if (transaction.value("executeConstructor").toBool())
@ -212,14 +216,11 @@ void ClientModel::executeSequence(std::vector<TransactionSettings> const& _seque
BOOST_THROW_EXCEPTION(FunctionNotFoundException() << FunctionName(transaction.functionId.toStdString())); BOOST_THROW_EXCEPTION(FunctionNotFoundException() << FunctionName(transaction.functionId.toStdString()));
encoder.encode(f); 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); if (f->parametersList().at(p)->type() != transaction.parameterValues.at(p)->declaration()->type())
u256 value = 0; BOOST_THROW_EXCEPTION(ParameterChangedException() << FunctionName(f->parametersList().at(p)->type().toStdString()));
auto v = transaction.parameterValues.find(var->name()); encoder.push(transaction.parameterValues.at(p)->encodeValue());
if (v != transaction.parameterValues.cend())
value = v->second;
encoder.encode(var, value);
} }
if (transaction.functionId.isEmpty()) if (transaction.functionId.isEmpty())
@ -330,11 +331,6 @@ void ClientModel::onNewTransaction()
bool creation = tr.contractAddress != 0; bool creation = tr.contractAddress != 0;
if (creation)
returned = QString::fromStdString(toJS(tr.contractAddress));
else
returned = QString::fromStdString(toJS(tr.returnValue));
//TODO: handle value transfer //TODO: handle value transfer
FixedHash<4> functionHash; FixedHash<4> functionHash;
bool call = false; bool call = false;
@ -363,6 +359,9 @@ void ClientModel::onNewTransaction()
function = QObject::tr("<none>"); function = QObject::tr("<none>");
} }
if (creation)
returned = QString::fromStdString(toJS(tr.contractAddress));
if (m_contractAddress != 0 && (tr.address == m_contractAddress || tr.contractAddress == m_contractAddress)) if (m_contractAddress != 0 && (tr.address == m_contractAddress || tr.contractAddress == m_contractAddress))
{ {
auto compilerRes = m_context->codeModel()->code(); auto compilerRes = m_context->codeModel()->code();
@ -372,7 +371,13 @@ void ClientModel::onNewTransaction()
{ {
QFunctionDefinition* funcDef = def->getFunction(functionHash); QFunctionDefinition* funcDef = def->getFunction(functionHash);
if (funcDef) if (funcDef)
{
function = funcDef->name(); function = funcDef->name();
ContractCallDataEncoder encoder;
QList<QVariableDefinition*> returnValues = encoder.decode(funcDef->returnParameters(), tr.returnValue);
for (auto const& var: returnValues)
returned += var->value() + " | ";
}
} }
} }

3
mix/ClientModel.h

@ -27,6 +27,7 @@
#include <map> #include <map>
#include <QString> #include <QString>
#include "MixClient.h" #include "MixClient.h"
#include "QVariableDefinition.h"
namespace dev namespace dev
{ {
@ -59,7 +60,7 @@ struct TransactionSettings
/// Gas price /// Gas price
u256 gasPrice; u256 gasPrice;
/// Mapping from contract function parameter name to value /// Mapping from contract function parameter name to value
std::map<QString, u256> parameterValues; QList<QVariableDefinition*> parameterValues;
/// Standard contract url /// Standard contract url
QString stdContractUrl; QString stdContractUrl;
}; };

98
mix/ContractCallDataEncoder.cpp

@ -44,89 +44,37 @@ void ContractCallDataEncoder::encode(QFunctionDefinition const* _function)
m_encodedData.insert(m_encodedData.end(), hash.begin(), hash.end()); 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) QList<QVariableDefinition*> ContractCallDataEncoder::decode(QList<QVariableDeclaration*> const& _returnParameters, bytes _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<QVariableDefinition*> ContractCallDataEncoder::decode(QList<QVariableDeclaration*> _returnParameters, bytes _value)
{ {
QList<QVariableDefinition*> r; QList<QVariableDefinition*> r;
std::string returnValue = toJS(_value);
returnValue = returnValue.substr(2, returnValue.length() - 1);
for (int k = 0; k <_returnParameters.length(); k++) for (int k = 0; k <_returnParameters.length(); k++)
{ {
QVariableDeclaration* dec = (QVariableDeclaration*)_returnParameters.at(k); QVariableDeclaration* dec = (QVariableDeclaration*)_returnParameters.at(k);
int padding = this->padding(dec->type()); QVariableDefinition* def = nullptr;
std::string rawParam = returnValue.substr(0, padding * 2); if (dec->type().contains("int"))
r.append(new QVariableDefinition(dec, convertToReadable(unpadLeft(rawParam), dec))); def = new QIntType(dec, QString());
returnValue = returnValue.substr(rawParam.length(), returnValue.length() - 1); else if (dec->type().contains("real"))
} def = new QRealType(dec, QString());
return r; else if (dec->type().contains("bool"))
} def = new QBoolType(dec, QString());
else if (dec->type().contains("string") || dec->type().contains("text"))
int ContractCallDataEncoder::padding(QString type) def = new QStringType(dec, QString());
{ else if (dec->type().contains("hash") || dec->type().contains("address"))
// TODO : to be improved (load types automatically from solidity library). def = new QHashType(dec, QString());
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 else
return 0; BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Parameter declaration not found"));
}
bytes rawParam(_value.begin(), _value.begin() + 32);
int ContractCallDataEncoder::integerPadding(int bitValue) def->decodeValue(rawParam);
{ r.push_back(def);
return bitValue / 8; if (_value.size() > 32)
_value = bytes(_value.begin() + 32, _value.end());
qDebug() << "decoded return value : " << dec->type() << " " << def->value();
} }
return r;
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());
} }

16
mix/ContractCallDataEncoder.h

@ -41,27 +41,17 @@ class ContractCallDataEncoder
{ {
public: public:
ContractCallDataEncoder() {} 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. /// Encode hash of the function to call.
void encode(QFunctionDefinition const* _function); void encode(QFunctionDefinition const* _function);
/// Decode variable in order to be sent to QML view. /// Decode variable in order to be sent to QML view.
QList<QVariableDefinition*> decode(QList<QVariableDeclaration*> _dec, bytes _value); QList<QVariableDefinition*> decode(QList<QVariableDeclaration*> const& _dec, bytes _value);
/// Get all encoded data encoded by encode function. /// Get all encoded data encoded by encode function.
bytes encodedData(); bytes encodedData();
/// Push the given @a _b to the current param context.
void push(bytes const& _b);
private: private:
int padding(QString _type);
bytes m_encodedData; 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);
}; };
} }

1
mix/Exceptions.h

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

3
mix/QBigInt.h

@ -36,7 +36,7 @@ namespace dev
namespace mix namespace mix
{ {
using BigIntVariant = boost::variant<dev::u256, dev::bigint>; using BigIntVariant = boost::variant<dev::u256, dev::bigint, dev::s256>;
struct add: public boost::static_visitor<BigIntVariant> struct add: public boost::static_visitor<BigIntVariant>
{ {
@ -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::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(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(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() {} ~QBigInt() {}
/// @returns the current used big integer. /// @returns the current used big integer.

8
mix/QVariableDeclaration.h

@ -19,6 +19,8 @@
* @date 2014 * @date 2014
*/ */
#include <QDebug>
#include <QStringList>
#include <libsolidity/AST.h> #include <libsolidity/AST.h>
#include "QBasicNodeDefinition.h" #include "QBasicNodeDefinition.h"
@ -32,16 +34,20 @@ namespace mix
class QVariableDeclaration: public QBasicNodeDefinition class QVariableDeclaration: public QBasicNodeDefinition
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QString type READ type CONSTANT) Q_PROPERTY(QString type READ type WRITE setType)
public: public:
QVariableDeclaration() {} QVariableDeclaration() {}
QVariableDeclaration(solidity::VariableDeclaration const* _v): QBasicNodeDefinition(_v), m_type(QString::fromStdString(_v->getType()->toString())) {} 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)) {} QVariableDeclaration(std::string const& _name, std::string const& _type): QBasicNodeDefinition(_name), m_type(QString::fromStdString(_type)) {}
QString type() const { return m_type; } QString type() const { return m_type; }
void setType(QString _type) { m_type = _type; }
private: private:
QString m_type; QString m_type;
}; };
} }
} }
Q_DECLARE_METATYPE(dev::mix::QVariableDeclaration*)

90
mix/QVariableDefinition.cpp

@ -19,6 +19,8 @@
* @date 2014 * @date 2014
*/ */
#include <libdevcore/CommonData.h>
#include <libdevcore/CommonJS.h>
#include "QVariableDefinition.h" #include "QVariableDefinition.h"
using namespace dev::mix; using namespace dev::mix;
@ -53,3 +55,91 @@ QVariableDefinition* QVariableDefinitionList::val(int _idx)
return nullptr; return nullptr;
return m_def.at(_idx); 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<dev::u256>(_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";
}

90
mix/QVariableDefinition.h

@ -22,6 +22,7 @@
#pragma once #pragma once
#include <QAbstractListModel> #include <QAbstractListModel>
#include "QBigInt.h"
#include "QVariableDeclaration.h" #include "QVariableDeclaration.h"
namespace dev namespace dev
@ -37,15 +38,26 @@ class QVariableDefinition: public QObject
Q_PROPERTY(QVariableDeclaration* declaration READ declaration CONSTANT) Q_PROPERTY(QVariableDeclaration* declaration READ declaration CONSTANT)
public: public:
QVariableDefinition() {}
QVariableDefinition(QVariableDeclaration* _def, QString _value): QObject(), m_value(_value), m_dec(_def) {} QVariableDefinition(QVariableDeclaration* _def, QString _value): QObject(), m_value(_value), m_dec(_def) {}
/// Return the associated declaration of this variable definition. /// Return the associated declaration of this variable definition. Invokable from QML.
QVariableDeclaration* declaration() const { return m_dec; } Q_INVOKABLE QVariableDeclaration* declaration() const { return m_dec; }
/// Return the variable value. /// Return the variable value.
QString value() const { return m_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: private:
QString m_value;
QVariableDeclaration* m_dec; QVariableDeclaration* m_dec;
}; };
@ -67,7 +79,77 @@ private:
QList<QVariableDefinition*> m_def; QList<QVariableDefinition*> 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*)

7
mix/qml/QBoolType.qml

@ -0,0 +1,7 @@
import QtQuick 2.0
import org.ethereum.qml.QBoolType 1.0
QBoolType
{
}

42
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" }
}
}
}
}

7
mix/qml/QHashType.qml

@ -0,0 +1,7 @@
import QtQuick 2.0
import org.ethereum.qml.QHashType 1.0
QHashType
{
}

22
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()
}
}
}
}

7
mix/qml/QIntType.qml

@ -0,0 +1,7 @@
import QtQuick 2.0
import org.ethereum.qml.QIntType 1.0
QIntType
{
}

24
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()
}
}
}
}

7
mix/qml/QRealType.qml

@ -0,0 +1,7 @@
import QtQuick 2.0
import org.ethereum.qml.QRealType 1.0
QRealType
{
}

15
mix/qml/QRealTypeView.qml

@ -0,0 +1,15 @@
import QtQuick 2.0
Component
{
Rectangle {
anchors.fill: parent
Text{
anchors.fill: parent
text: qsTr("Real")
}
}
}

7
mix/qml/QStringType.qml

@ -0,0 +1,7 @@
import QtQuick 2.0
import org.ethereum.qml.QStringType 1.0
QStringType
{
}

25
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()
}
}
}
}

7
mix/qml/QVariableDeclaration.qml

@ -0,0 +1,7 @@
import QtQuick 2.0
import org.ethereum.qml.QVariableDeclaration 1.0
QVariableDeclaration
{
}

13
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
}

49
mix/qml/StateListModel.qml

@ -31,12 +31,30 @@ Item {
stdContract: t.stdContract, stdContract: t.stdContract,
parameters: {} parameters: {}
}; };
for (var key in t.parameters) { var qType = [];
var intComponent = Qt.createComponent("qrc:/qml/BigIntValue.qml"); for (var key in t.parameters)
var param = intComponent.createObject(); {
param.setValue(t.parameters[key]); r.parameters[key] = t.parameters[key].value;
r.parameters[key] = param; 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; 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) { function toPlainTransactionItem(t) {
var r = { var r = {
functionId: t.functionId, functionId: t.functionId,
@ -60,7 +88,14 @@ Item {
parameters: {} parameters: {}
}; };
for (var key in t.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; return r;
} }

155
mix/qml/TransactionDialog.qml

@ -9,7 +9,7 @@ Window {
id: modalTransactionDialog id: modalTransactionDialog
modality: Qt.WindowModal modality: Qt.WindowModal
width:640 width:640
height:480 height:640
visible: false visible: false
property int transactionIndex property int transactionIndex
@ -21,10 +21,12 @@ Window {
property var itemParams; property var itemParams;
property bool isConstructorTransaction; property bool isConstructorTransaction;
property bool useTransactionDefaultValue: false property bool useTransactionDefaultValue: false
property var qType;
signal accepted; signal accepted;
function open(index, item) { function open(index, item) {
qType = [];
rowFunction.visible = !useTransactionDefaultValue; rowFunction.visible = !useTransactionDefaultValue;
rowValue.visible = !useTransactionDefaultValue; rowValue.visible = !useTransactionDefaultValue;
rowGas.visible = !useTransactionDefaultValue; rowGas.visible = !useTransactionDefaultValue;
@ -68,6 +70,7 @@ Window {
} }
function loadParameters() { function loadParameters() {
paramsModel.clear();
if (!paramsModel) if (!paramsModel)
return; return;
if (functionComboBox.currentIndex >= 0 && functionComboBox.currentIndex < functionsModel.count) { if (functionComboBox.currentIndex >= 0 && functionComboBox.currentIndex < functionsModel.count) {
@ -75,7 +78,27 @@ Window {
var parameters = func.parameters; var parameters = func.parameters;
for (var p = 0; p < parameters.length; p++) { for (var p = 0; p < parameters.length; p++) {
var pname = parameters[p].name; 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; visible = false;
} }
function qTypeParam(name)
{
for (var k in qType)
{
if (qType[k].name === name)
return qType[k].value;
}
}
function getItem() function getItem()
{ {
var item; var item;
@ -109,14 +141,15 @@ Window {
if (isConstructorTransaction) if (isConstructorTransaction)
item.functionId = qsTr("Constructor"); item.functionId = qsTr("Constructor");
var orderedQType = [];
for (var p = 0; p < transactionDialog.transactionParams.count; p++) { for (var p = 0; p < transactionDialog.transactionParams.count; p++) {
var parameter = transactionDialog.transactionParams.get(p); var parameter = transactionDialog.transactionParams.get(p);
var intComponent = Qt.createComponent("qrc:/qml/BigIntValue.qml"); var qtypeParam = qTypeParam(parameter.name);
var param = intComponent.createObject(modalTransactionDialog); qtypeParam.setValue(parameter.value);
orderedQType.push(qtypeParam);
param.setValue(parameter.value); item.parameters[parameter.name] = parameter.value;
item.parameters[parameter.name] = param;
} }
item.qType = orderedQType;
return item; return item;
} }
@ -219,8 +252,10 @@ Window {
} }
TableView { TableView {
model: paramsModel model: paramsModel
Layout.fillWidth: true Layout.preferredWidth: 120 * 2 + 240
Layout.minimumHeight: 150
Layout.preferredHeight: 400
Layout.maximumHeight: 600
TableViewColumn { TableViewColumn {
role: "name" role: "name"
title: qsTr("Name") title: qsTr("Name")
@ -234,12 +269,11 @@ Window {
TableViewColumn { TableViewColumn {
role: "value" role: "value"
title: qsTr("Value") title: qsTr("Value")
width: 120 width: 240
} }
itemDelegate: { rowDelegate: rowDelegate
return editableDelegate; itemDelegate: editableDelegate
}
} }
} }
} }
@ -268,19 +302,15 @@ Window {
} }
Component { Component {
id: editableDelegate id: rowDelegate
Item { 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 { Loader {
id: loaderEditor id: loaderEditor
anchors.fill: parent anchors.fill: parent
@ -289,14 +319,87 @@ Window {
target: loaderEditor.item target: loaderEditor.item
onTextChanged: { onTextChanged: {
if (styleData.role === "value" && styleData.row < paramsModel.count) 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);
}
}
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);
} }
} }
sourceComponent: (styleData.selected) ? editor : null }
Component
{
id: stringViewComp
QStringTypeView
{
id: stringView
text: styleData.value
}
}
Component
{
id: hashViewComp
QHashTypeView
{
id: hashView
text: styleData.value
}
}
Component { Component {
id: editor id: editor
TextInput { TextInput {
id: textinput id: textinput
readOnly: true
color: styleData.textColor color: styleData.textColor
text: styleData.value text: styleData.value
MouseArea { MouseArea {

12
mix/res.qrc

@ -42,9 +42,20 @@
<file>qml/Ether.qml</file> <file>qml/Ether.qml</file>
<file>qml/EtherValue.qml</file> <file>qml/EtherValue.qml</file>
<file>qml/BigIntValue.qml</file> <file>qml/BigIntValue.qml</file>
<file>qml/QVariableDefinition.qml</file>
<file>qml/QBoolType.qml</file>
<file>qml/QHashType.qml</file>
<file>qml/QIntType.qml</file>
<file>qml/QRealType.qml</file>
<file>qml/js/QEtherHelper.js</file> <file>qml/js/QEtherHelper.js</file>
<file>qml/js/TransactionHelper.js</file> <file>qml/js/TransactionHelper.js</file>
<file>qml/Splitter.qml</file> <file>qml/Splitter.qml</file>
<file>qml/QStringType.qml</file>
<file>qml/QBoolTypeView.qml</file>
<file>qml/QIntTypeView.qml</file>
<file>qml/QRealTypeView.qml</file>
<file>qml/QStringTypeView.qml</file>
<file>qml/QHashTypeView.qml</file>
<file>qml/ContractLibrary.qml</file> <file>qml/ContractLibrary.qml</file>
<file>stdc/config.sol</file> <file>stdc/config.sol</file>
<file>stdc/namereg.sol</file> <file>stdc/namereg.sol</file>
@ -52,5 +63,6 @@
<file>qml/TransactionLog.qml</file> <file>qml/TransactionLog.qml</file>
<file>res/mix_256x256x32.png</file> <file>res/mix_256x256x32.png</file>
<file>qml/CallStack.qml</file> <file>qml/CallStack.qml</file>
<file>qml/QVariableDeclaration.qml</file>
</qresource> </qresource>
</RCC> </RCC>

Loading…
Cancel
Save