Gav Wood
10 years ago
46 changed files with 1531 additions and 1168 deletions
@ -0,0 +1,170 @@ |
|||
/*
|
|||
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 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 <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file CodeHighlighter.cpp
|
|||
* @author Arkadiy Paronyan arkadiy@ethdev.com |
|||
* @date 2015 |
|||
* Ethereum IDE client. |
|||
*/ |
|||
|
|||
#include <algorithm> |
|||
#include <QRegularExpression> |
|||
#include <QTextDocument> |
|||
#include <QTextBlock> |
|||
#include <QTextLayout> |
|||
#include <libsolidity/ASTVisitor.h> |
|||
#include <libsolidity/AST.h> |
|||
#include <libsolidity/Scanner.h> |
|||
#include <libsolidity/Exceptions.h> |
|||
#include "CodeHighlighter.h" |
|||
|
|||
using namespace dev::mix; |
|||
|
|||
CodeHighlighterSettings::CodeHighlighterSettings() |
|||
{ |
|||
backgroundColor = QColor(0x00, 0x2b, 0x36); |
|||
foregroundColor = QColor(0xee, 0xe8, 0xd5); |
|||
formats[Keyword].setForeground(QColor(0x93, 0xa1, 0xa1)); |
|||
formats[Comment].setForeground(QColor(0x85, 0x99, 0x00)); |
|||
formats[StringLiteral].setForeground(QColor(0xdc, 0x32, 0x2f)); |
|||
formats[NumLiteral].setForeground(foregroundColor); |
|||
formats[Import].setForeground(QColor(0x6c, 0x71, 0xc4)); |
|||
formats[CompilationError].setUnderlineColor(Qt::red); |
|||
formats[CompilationError].setUnderlineStyle(QTextCharFormat::SingleUnderline); |
|||
} |
|||
|
|||
namespace |
|||
{ |
|||
using namespace dev::solidity; |
|||
class HighlightVisitor: public ASTConstVisitor |
|||
{ |
|||
public: |
|||
HighlightVisitor(CodeHighlighter::Formats* _formats) { m_formats = _formats; } |
|||
private: |
|||
CodeHighlighter::Formats* m_formats; |
|||
|
|||
virtual bool visit(ImportDirective const& _node) |
|||
{ |
|||
m_formats->push_back(CodeHighlighter::FormatRange(CodeHighlighterSettings::Import, _node.getLocation())); |
|||
return true; |
|||
} |
|||
}; |
|||
} |
|||
|
|||
CodeHighlighter::FormatRange::FormatRange(CodeHighlighterSettings::Token _t, solidity::Location const& _location): |
|||
token(_t), start(_location.start), length(_location.end - _location.start) |
|||
{} |
|||
|
|||
void CodeHighlighter::processSource(std::string const& _source) |
|||
{ |
|||
processComments(_source); |
|||
solidity::CharStream stream(_source); |
|||
solidity::Scanner scanner(stream); |
|||
solidity::Token::Value token = scanner.getCurrentToken(); |
|||
while (token != Token::EOS) |
|||
{ |
|||
if ((token >= Token::BREAK && token < Token::TYPES_END) || |
|||
token == Token::IN || token == Token::DELETE || token == Token::NULL_LITERAL || token == Token::TRUE_LITERAL || token == Token::FALSE_LITERAL) |
|||
m_formats.push_back(FormatRange(CodeHighlighterSettings::Keyword, scanner.getCurrentLocation())); |
|||
else if (token == Token::STRING_LITERAL) |
|||
m_formats.push_back(FormatRange(CodeHighlighterSettings::StringLiteral, scanner.getCurrentLocation())); |
|||
else if (token == Token::COMMENT_LITERAL) |
|||
m_formats.push_back(FormatRange(CodeHighlighterSettings::Comment, scanner.getCurrentLocation())); |
|||
else if (token == Token::NUMBER) |
|||
m_formats.push_back(FormatRange(CodeHighlighterSettings::NumLiteral, scanner.getCurrentLocation())); |
|||
|
|||
token = scanner.next(); |
|||
} |
|||
std::sort(m_formats.begin(), m_formats.end()); |
|||
} |
|||
|
|||
void CodeHighlighter::processAST(solidity::ASTNode const& _ast) |
|||
{ |
|||
HighlightVisitor visitor(&m_formats); |
|||
_ast.accept(visitor); |
|||
|
|||
std::sort(m_formats.begin(), m_formats.end()); |
|||
} |
|||
|
|||
void CodeHighlighter::processError(dev::Exception const& _exception) |
|||
{ |
|||
Location const* location = boost::get_error_info<errinfo_sourceLocation>(_exception); |
|||
m_formats.push_back(FormatRange(CodeHighlighterSettings::CompilationError, *location)); |
|||
} |
|||
|
|||
void CodeHighlighter::processComments(std::string const& _source) |
|||
{ |
|||
unsigned i = 0; |
|||
unsigned size = _source.size(); |
|||
if (size == 0) |
|||
return; |
|||
while (i < size - 1) |
|||
{ |
|||
if (_source[i] == '/' && _source[i + 1] == '/') |
|||
{ |
|||
//add single line comment
|
|||
int start = i; |
|||
i += 2; |
|||
while (_source[i] != '\n' && i < size) |
|||
++i; |
|||
m_formats.push_back(FormatRange(CodeHighlighterSettings::Comment, start, i - start)); |
|||
} |
|||
else if (_source[i] == '/' && _source[i + 1] == '*') |
|||
{ |
|||
//add multiline comment
|
|||
int start = i; |
|||
i += 2; |
|||
while ((_source[i] != '/' || _source[i - 1] != '*') && i < size) |
|||
++i; |
|||
m_formats.push_back(FormatRange(CodeHighlighterSettings::Comment, start, i - start + 1)); |
|||
} |
|||
++i; |
|||
} |
|||
} |
|||
|
|||
void CodeHighlighter::updateFormatting(QTextDocument* _document, CodeHighlighterSettings const& _settings) |
|||
{ |
|||
QTextBlock block = _document->firstBlock(); |
|||
QList<QTextLayout::FormatRange> ranges; |
|||
|
|||
Formats::const_iterator format = m_formats.begin(); |
|||
while (true) |
|||
{ |
|||
while ((format == m_formats.end() || (block.position() + block.length() <= format->start)) && block.isValid()) |
|||
{ |
|||
auto layout = block.layout(); |
|||
layout->clearAdditionalFormats(); |
|||
layout->setAdditionalFormats(ranges); |
|||
_document->markContentsDirty(block.position(), block.length()); |
|||
block = block.next(); |
|||
ranges.clear(); |
|||
} |
|||
if (!block.isValid()) |
|||
break; |
|||
|
|||
int intersectionStart = std::max(format->start, block.position()); |
|||
int intersectionLength = std::min(format->start + format->length, block.position() + block.length()) - intersectionStart; |
|||
if (intersectionLength > 0) |
|||
{ |
|||
QTextLayout::FormatRange range; |
|||
range.format = _settings.formats[format->token]; |
|||
range.start = format->start - block.position(); |
|||
range.length = format->length; |
|||
ranges.append(range); |
|||
} |
|||
++format; |
|||
} |
|||
} |
@ -0,0 +1,109 @@ |
|||
/*
|
|||
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 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 <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file CodeHighlighter.h
|
|||
* @author Arkadiy Paronyan arkadiy@ethdev.com |
|||
* @date 2015 |
|||
* Ethereum IDE client. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <vector> |
|||
#include <QString> |
|||
#include <QTextCharFormat> |
|||
|
|||
class QTextDocument; |
|||
|
|||
namespace dev |
|||
{ |
|||
|
|||
struct Exception; |
|||
|
|||
namespace solidity |
|||
{ |
|||
class ASTNode; |
|||
struct Location; |
|||
} |
|||
|
|||
namespace mix |
|||
{ |
|||
|
|||
/// Code highligting settings
|
|||
class CodeHighlighterSettings |
|||
{ |
|||
public: |
|||
enum Token |
|||
{ |
|||
Import, |
|||
Keyword, |
|||
Comment, |
|||
StringLiteral, |
|||
NumLiteral, |
|||
CompilationError, |
|||
Size, //this must be kept last
|
|||
}; |
|||
|
|||
CodeHighlighterSettings(); |
|||
///Format for each token
|
|||
QTextCharFormat formats[Size]; |
|||
///Background color
|
|||
QColor backgroundColor; |
|||
///Foreground color
|
|||
QColor foregroundColor; |
|||
}; |
|||
|
|||
/// Code highlighting engine class
|
|||
class CodeHighlighter |
|||
{ |
|||
public: |
|||
/// Formatting range
|
|||
struct FormatRange |
|||
{ |
|||
FormatRange(CodeHighlighterSettings::Token _t, int _start, int _length): token(_t), start(_start), length(_length) {} |
|||
FormatRange(CodeHighlighterSettings::Token _t, solidity::Location const& _location); |
|||
bool operator<(FormatRange const& _other) const { return start < _other.start || (start == _other.start && length < _other.length); } |
|||
|
|||
CodeHighlighterSettings::Token token; |
|||
int start; |
|||
int length; |
|||
}; |
|||
typedef std::vector<FormatRange> Formats; // Sorted by start position
|
|||
|
|||
public: |
|||
/// Collect highligting information by lexing the source
|
|||
void processSource(std::string const& _source); |
|||
/// Collect additional highligting information from AST
|
|||
void processAST(solidity::ASTNode const& _ast); |
|||
/// Collect highlighting information from compilation exception
|
|||
void processError(dev::Exception const& _exception); |
|||
|
|||
/// Apply formatting for a text document
|
|||
/// @todo Remove this once editor is reworked
|
|||
void updateFormatting(QTextDocument* _document, CodeHighlighterSettings const& _settings); |
|||
|
|||
private: |
|||
/// Collect highligting information by paring for comments
|
|||
/// @todo Support this in solidity?
|
|||
void processComments(std::string const& _source); |
|||
|
|||
private: |
|||
Formats m_formats; |
|||
}; |
|||
|
|||
} |
|||
|
|||
} |
@ -0,0 +1,177 @@ |
|||
/*
|
|||
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 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 <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file CodeModel.cpp
|
|||
* @author Arkadiy Paronyan arkadiy@ethdev.com |
|||
* @date 2014 |
|||
* Ethereum IDE client. |
|||
*/ |
|||
|
|||
#include <sstream> |
|||
#include <QDebug> |
|||
#include <QApplication> |
|||
#include <QtQml> |
|||
#include <libsolidity/CompilerStack.h> |
|||
#include <libsolidity/SourceReferenceFormatter.h> |
|||
#include <libevmcore/Instruction.h> |
|||
#include "QContractDefinition.h" |
|||
#include "QFunctionDefinition.h" |
|||
#include "QVariableDeclaration.h" |
|||
#include "CodeHighlighter.h" |
|||
#include "CodeModel.h" |
|||
|
|||
using namespace dev::mix; |
|||
|
|||
void BackgroundWorker::queueCodeChange(int _jobId, QString const& _content) |
|||
{ |
|||
m_model->runCompilationJob(_jobId, _content); |
|||
} |
|||
|
|||
CompilationResult::CompilationResult(): |
|||
QObject(nullptr), |
|||
m_successful(false), |
|||
m_codeHash(qHash(QString())), |
|||
m_contract(new QContractDefinition()), |
|||
m_codeHighlighter(new CodeHighlighter()) |
|||
{} |
|||
|
|||
CompilationResult::CompilationResult(const solidity::CompilerStack& _compiler): |
|||
QObject(nullptr), |
|||
m_successful(true), |
|||
m_codeHash(qHash(QString())) |
|||
{ |
|||
if (!_compiler.getContractNames().empty()) |
|||
{ |
|||
m_contract.reset(new QContractDefinition(&_compiler.getContractDefinition(std::string()))); |
|||
m_bytes = _compiler.getBytecode(); |
|||
m_assemblyCode = QString::fromStdString(dev::eth::disassemble(m_bytes)); |
|||
} |
|||
else |
|||
m_contract.reset(new QContractDefinition()); |
|||
} |
|||
|
|||
CompilationResult::CompilationResult(CompilationResult const& _prev, QString const& _compilerMessage): |
|||
QObject(nullptr), |
|||
m_successful(false), |
|||
m_codeHash(qHash(QString())), |
|||
m_contract(_prev.m_contract), |
|||
m_compilerMessage(_compilerMessage), |
|||
m_bytes(_prev.m_bytes), |
|||
m_assemblyCode(_prev.m_assemblyCode), |
|||
m_codeHighlighter(_prev.m_codeHighlighter) |
|||
{} |
|||
|
|||
CodeModel::CodeModel(QObject* _parent): |
|||
QObject(_parent), |
|||
m_compiling(false), |
|||
m_result(new CompilationResult()), |
|||
m_codeHighlighterSettings(new CodeHighlighterSettings()), |
|||
m_backgroundWorker(this), |
|||
m_backgroundJobId(0) |
|||
{ |
|||
m_backgroundWorker.moveToThread(&m_backgroundThread); |
|||
connect(this, &CodeModel::scheduleCompilationJob, &m_backgroundWorker, &BackgroundWorker::queueCodeChange, Qt::QueuedConnection); |
|||
connect(this, &CodeModel::compilationCompleteInternal, this, &CodeModel::onCompilationComplete, Qt::QueuedConnection); |
|||
qRegisterMetaType<CompilationResult*>("CompilationResult*"); |
|||
qRegisterMetaType<QContractDefinition*>("QContractDefinition*"); |
|||
qRegisterMetaType<QFunctionDefinition*>("QFunctionDefinition*"); |
|||
qRegisterMetaType<QVariableDeclaration*>("QVariableDeclaration*"); |
|||
qmlRegisterType<QFunctionDefinition>("org.ethereum.qml", 1, 0, "QFunctionDefinition"); |
|||
qmlRegisterType<QVariableDeclaration>("org.ethereum.qml", 1, 0, "QVariableDeclaration"); |
|||
m_backgroundThread.start(); |
|||
} |
|||
|
|||
CodeModel::~CodeModel() |
|||
{ |
|||
stop(); |
|||
disconnect(this); |
|||
} |
|||
|
|||
void CodeModel::stop() |
|||
{ |
|||
///@todo: cancel bg job
|
|||
m_backgroundThread.exit(); |
|||
m_backgroundThread.wait(); |
|||
} |
|||
|
|||
void CodeModel::registerCodeChange(QString const& _code) |
|||
{ |
|||
// launch the background thread
|
|||
uint hash = qHash(_code); |
|||
if (m_result->m_codeHash == hash) |
|||
return; |
|||
m_backgroundJobId++; |
|||
m_compiling = true; |
|||
emit stateChanged(); |
|||
emit scheduleCompilationJob(m_backgroundJobId, _code); |
|||
} |
|||
|
|||
void CodeModel::runCompilationJob(int _jobId, QString const& _code) |
|||
{ |
|||
if (_jobId != m_backgroundJobId) |
|||
return; //obsolete job
|
|||
|
|||
solidity::CompilerStack cs; |
|||
std::unique_ptr<CompilationResult> result; |
|||
|
|||
std::string source = _code.toStdString(); |
|||
// run syntax highlighting first
|
|||
// @todo combine this with compilation step
|
|||
auto codeHighlighter = std::make_shared<CodeHighlighter>(); |
|||
codeHighlighter->processSource(source); |
|||
|
|||
// run compilation
|
|||
try |
|||
{ |
|||
cs.setSource(source); |
|||
cs.compile(false); |
|||
codeHighlighter->processAST(cs.getAST()); |
|||
result.reset(new CompilationResult(cs)); |
|||
qDebug() << QString(QApplication::tr("compilation succeeded")); |
|||
} |
|||
catch (dev::Exception const& _exception) |
|||
{ |
|||
std::ostringstream error; |
|||
solidity::SourceReferenceFormatter::printExceptionInformation(error, _exception, "Error", cs); |
|||
result.reset(new CompilationResult(*m_result, QString::fromStdString(error.str()))); |
|||
codeHighlighter->processError(_exception); |
|||
qDebug() << QString(QApplication::tr("compilation failed:") + " " + result->compilerMessage()); |
|||
} |
|||
result->m_codeHighlighter = codeHighlighter; |
|||
result->m_codeHash = qHash(_code); |
|||
|
|||
emit compilationCompleteInternal(result.release()); |
|||
} |
|||
|
|||
void CodeModel::onCompilationComplete(CompilationResult*_newResult) |
|||
{ |
|||
m_compiling = false; |
|||
m_result.reset(_newResult); |
|||
emit compilationComplete(); |
|||
emit stateChanged(); |
|||
if (m_result->successfull()) |
|||
emit codeChanged(); |
|||
} |
|||
|
|||
bool CodeModel::hasContract() const |
|||
{ |
|||
return m_result->contract()->functionsList().size() > 0; |
|||
} |
|||
|
|||
void CodeModel::updateFormatting(QTextDocument* _document) |
|||
{ |
|||
m_result->codeHighlighter()->updateFormatting(_document, *m_codeHighlighterSettings); |
|||
} |
@ -0,0 +1,163 @@ |
|||
/*
|
|||
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 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 <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file CodeModel.h
|
|||
* @author Arkadiy Paronyan arkadiy@ethdev.com |
|||
* @date 2014 |
|||
* Ethereum IDE client. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <memory> |
|||
#include <atomic> |
|||
#include <QObject> |
|||
#include <QThread> |
|||
#include <libdevcore/Common.h> |
|||
|
|||
class QTextDocument; |
|||
|
|||
namespace dev |
|||
{ |
|||
|
|||
namespace solidity |
|||
{ |
|||
class CompilerStack; |
|||
} |
|||
|
|||
namespace mix |
|||
{ |
|||
|
|||
class CodeModel; |
|||
class CodeHighlighter; |
|||
class CodeHighlighterSettings; |
|||
class QContractDefinition; |
|||
|
|||
//utility class to perform tasks in background thread
|
|||
class BackgroundWorker: public QObject |
|||
{ |
|||
Q_OBJECT |
|||
|
|||
public: |
|||
BackgroundWorker(CodeModel* _model): QObject(), m_model(_model) {} |
|||
|
|||
public slots: |
|||
void queueCodeChange(int _jobId, QString const& _content); |
|||
private: |
|||
CodeModel* m_model; |
|||
}; |
|||
|
|||
///Compilation result model. Contains all the compiled contract data required by UI
|
|||
class CompilationResult: public QObject |
|||
{ |
|||
Q_OBJECT |
|||
Q_PROPERTY(QContractDefinition* contract READ contract) |
|||
|
|||
public: |
|||
/// Empty compilation result constructor
|
|||
CompilationResult(); |
|||
/// Successfull compilation result constructor
|
|||
CompilationResult(solidity::CompilerStack const& _compiler); |
|||
/// Failed compilation result constructor
|
|||
CompilationResult(CompilationResult const& _prev, QString const& _compilerMessage); |
|||
|
|||
/// @returns contract definition for QML property
|
|||
QContractDefinition* contract() { return m_contract.get(); } |
|||
/// @returns contract definition
|
|||
std::shared_ptr<QContractDefinition> sharedContract() { return m_contract; } |
|||
/// Indicates if the compilation was successfull
|
|||
bool successfull() const { return m_successful; } |
|||
/// @returns compiler error message in case of unsuccessfull compilation
|
|||
QString compilerMessage() const { return m_compilerMessage; } |
|||
/// @returns contract bytecode
|
|||
dev::bytes const& bytes() const { return m_bytes; } |
|||
/// @returns contract bytecode in human-readable form
|
|||
QString assemblyCode() const { return m_assemblyCode; } |
|||
/// Get code highlighter
|
|||
std::shared_ptr<CodeHighlighter> codeHighlighter() { return m_codeHighlighter; } |
|||
|
|||
private: |
|||
bool m_successful; |
|||
uint m_codeHash; |
|||
std::shared_ptr<QContractDefinition> m_contract; |
|||
QString m_compilerMessage; ///< @todo: use some structure here
|
|||
dev::bytes m_bytes; |
|||
QString m_assemblyCode; |
|||
std::shared_ptr<CodeHighlighter> m_codeHighlighter; |
|||
|
|||
friend class CodeModel; |
|||
}; |
|||
|
|||
/// Background code compiler
|
|||
class CodeModel: public QObject |
|||
{ |
|||
Q_OBJECT |
|||
|
|||
public: |
|||
CodeModel(QObject* _parent); |
|||
~CodeModel(); |
|||
|
|||
/// @returns latest compilation result
|
|||
CompilationResult* code() { return m_result.get(); } |
|||
/// @returns latest compilation resul
|
|||
CompilationResult const* code() const { return m_result.get(); } |
|||
|
|||
Q_PROPERTY(CompilationResult* code READ code NOTIFY codeChanged) |
|||
Q_PROPERTY(bool compiling READ isCompiling NOTIFY stateChanged) |
|||
Q_PROPERTY(bool hasContract READ hasContract NOTIFY codeChanged) |
|||
|
|||
/// @returns compilation status
|
|||
bool isCompiling() const { return m_compiling; } |
|||
/// @returns true if contract has at least one function
|
|||
bool hasContract() const; |
|||
/// Apply text document formatting. @todo Move this to editor module
|
|||
void updateFormatting(QTextDocument* _document); |
|||
|
|||
signals: |
|||
/// Emited on compilation state change
|
|||
void stateChanged(); |
|||
/// Emitted on compilation complete
|
|||
void compilationComplete(); |
|||
/// Internal signal used to transfer compilation job to background thread
|
|||
void scheduleCompilationJob(int _jobId, QString const& _content); |
|||
/// Emitted if there are any changes in the code model
|
|||
void codeChanged(); |
|||
/// Emitted on compilation complete. Internal
|
|||
void compilationCompleteInternal(CompilationResult* _newResult); |
|||
|
|||
private slots: |
|||
void onCompilationComplete(CompilationResult* _newResult); |
|||
|
|||
public slots: |
|||
/// Update code model on source code change
|
|||
void registerCodeChange(QString const& _code); |
|||
|
|||
private: |
|||
void runCompilationJob(int _jobId, QString const& _content); |
|||
void stop(); |
|||
|
|||
std::atomic<bool> m_compiling; |
|||
std::unique_ptr<CompilationResult> m_result; |
|||
std::unique_ptr<CodeHighlighterSettings> m_codeHighlighterSettings; |
|||
QThread m_backgroundThread; |
|||
BackgroundWorker m_backgroundWorker; |
|||
int m_backgroundJobId = 0; //protects from starting obsolete compilation job
|
|||
friend class BackgroundWorker; |
|||
}; |
|||
|
|||
} |
|||
|
|||
} |
@ -1,66 +0,0 @@ |
|||
/*
|
|||
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 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 <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file ConstantCompilationModel.cpp
|
|||
* @author Yann yann@ethdev.com |
|||
* @date 2014 |
|||
* Ethereum IDE client. |
|||
*/ |
|||
|
|||
#include <QApplication> |
|||
#include <QObject> |
|||
#include <libevm/VM.h> |
|||
#include <libsolidity/Scanner.h> |
|||
#include <libsolidity/Parser.h> |
|||
#include <libsolidity/CompilerStack.h> |
|||
#include <libsolidity/SourceReferenceFormatter.h> |
|||
#include <libsolidity/NameAndTypeResolver.h> |
|||
#include "ConstantCompilationModel.h" |
|||
using namespace std; |
|||
using namespace dev; |
|||
using namespace dev::eth; |
|||
using namespace dev::mix; |
|||
using namespace dev::solidity; |
|||
|
|||
CompilerResult ConstantCompilationModel::compile(QString _code) |
|||
{ |
|||
dev::solidity::CompilerStack compiler; |
|||
dev::bytes m_data; |
|||
CompilerResult res; |
|||
try |
|||
{ |
|||
m_data = compiler.compile(_code.toStdString(), true); |
|||
res.success = true; |
|||
res.comment = "ok"; |
|||
res.hexCode = QString::fromStdString(dev::eth::disassemble(m_data)); |
|||
res.bytes = m_data; |
|||
} |
|||
catch (dev::Exception const& _exception) |
|||
{ |
|||
ostringstream error; |
|||
solidity::SourceReferenceFormatter::printExceptionInformation(error, _exception, "Error", compiler); |
|||
res.success = false; |
|||
res.comment = QString::fromStdString(error.str()); |
|||
res.hexCode = ""; |
|||
} |
|||
catch (...) |
|||
{ |
|||
res.success = false; |
|||
res.comment = QApplication::tr("Uncaught exception."); |
|||
res.hexCode = ""; |
|||
} |
|||
return res; |
|||
} |
@ -1,60 +0,0 @@ |
|||
/*
|
|||
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 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 <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file ConstantCompilationModel.h
|
|||
* @author Yann yann@ethdev.com |
|||
* @date 2014 |
|||
* Ethereum IDE client. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <QObject> |
|||
#include <libevm/VM.h> |
|||
#include <libsolidity/AST.h> |
|||
|
|||
namespace dev |
|||
{ |
|||
namespace mix |
|||
{ |
|||
|
|||
/**
|
|||
* @brief Provides compiler result information. |
|||
*/ |
|||
struct CompilerResult |
|||
{ |
|||
QString hexCode; |
|||
QString comment; |
|||
dev::bytes bytes; |
|||
bool success; |
|||
}; |
|||
|
|||
/**
|
|||
* @brief Compile source code using the solidity library. |
|||
*/ |
|||
class ConstantCompilationModel |
|||
{ |
|||
|
|||
public: |
|||
ConstantCompilationModel() {} |
|||
~ConstantCompilationModel() {} |
|||
/// Compile code.
|
|||
CompilerResult compile(QString _code); |
|||
}; |
|||
|
|||
} |
|||
|
|||
} |
@ -1,41 +0,0 @@ |
|||
/*
|
|||
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 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 <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file KeyEventManager.cpp
|
|||
* @author Yann yann@ethdev.com |
|||
* @date 2014 |
|||
* Used as an event handler for all classes which need keyboard interactions. |
|||
* Can be improve by adding the possibility to register to a specific key. |
|||
*/ |
|||
|
|||
#include <QDebug> |
|||
#include <QKeySequence> |
|||
#include "KeyEventManager.h" |
|||
|
|||
void KeyEventManager::registerEvent(const QObject* _receiver, const char* _slot) |
|||
{ |
|||
QObject::connect(this, SIGNAL(onKeyPressed(int)), _receiver, _slot); |
|||
} |
|||
|
|||
void KeyEventManager::unRegisterEvent(QObject* _receiver) |
|||
{ |
|||
QObject::disconnect(_receiver); |
|||
} |
|||
|
|||
void KeyEventManager::keyPressed(QVariant _event) |
|||
{ |
|||
emit onKeyPressed(_event.toInt()); |
|||
} |
@ -1,47 +0,0 @@ |
|||
/*
|
|||
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 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 <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file KeyEventManager.h
|
|||
* @author Yann yann@ethdev.com |
|||
* @date 2014 |
|||
* Used as an event handler for all classes which need keyboard interactions |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <QObject> |
|||
#include <QVariant> |
|||
|
|||
class KeyEventManager: public QObject |
|||
{ |
|||
Q_OBJECT |
|||
|
|||
public: |
|||
KeyEventManager() {} |
|||
/// Allows _receiver to handle key pressed event.
|
|||
void registerEvent(const QObject* _receiver, const char* _slot); |
|||
/// Unregister _receiver.
|
|||
void unRegisterEvent(QObject* _receiver); |
|||
|
|||
signals: |
|||
/// Emited when a key is pressed.
|
|||
void onKeyPressed(int _event); |
|||
|
|||
public slots: |
|||
/// Called when a key is pressed.
|
|||
void keyPressed(QVariant _event); |
|||
}; |
|||
|
@ -1,221 +0,0 @@ |
|||
/*
|
|||
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 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 <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file TransactionListModel.cpp
|
|||
* @author Arkadiy Paronyan arkadiy@ethdev.com |
|||
* @date 2014 |
|||
* Ethereum IDE client. |
|||
*/ |
|||
|
|||
#include <QObject> |
|||
#include <QQmlEngine> |
|||
#include <QTextDocument> |
|||
#include <QAbstractListModel> |
|||
#include <libdevcore/CommonJS.h> |
|||
#include "TransactionListModel.h" |
|||
#include "QContractDefinition.h" |
|||
#include "QFunctionDefinition.h" |
|||
#include "QVariableDeclaration.h" |
|||
|
|||
|
|||
namespace dev |
|||
{ |
|||
namespace mix |
|||
{ |
|||
|
|||
/// @todo Move this to QML
|
|||
u256 fromQString(QString const& _s) |
|||
{ |
|||
return dev::jsToU256(_s.toStdString()); |
|||
} |
|||
|
|||
/// @todo Move this to QML
|
|||
QString toQString(u256 _value) |
|||
{ |
|||
std::ostringstream s; |
|||
s << _value; |
|||
return QString::fromStdString(s.str()); |
|||
} |
|||
|
|||
TransactionListItem::TransactionListItem(int _index, TransactionSettings const& _t, QObject* _parent): |
|||
QObject(_parent), m_index(_index), m_title(_t.title), m_functionId(_t.functionId), m_value(toQString(_t.value)), |
|||
m_gas(toQString(_t.gas)), m_gasPrice(toQString(_t.gasPrice)) |
|||
{} |
|||
|
|||
TransactionListModel::TransactionListModel(QObject* _parent, QTextDocument* _document): |
|||
QAbstractListModel(_parent), m_document(_document) |
|||
{ |
|||
qRegisterMetaType<TransactionListItem*>("TransactionListItem*"); |
|||
} |
|||
|
|||
QHash<int, QByteArray> TransactionListModel::roleNames() const |
|||
{ |
|||
QHash<int, QByteArray> roles; |
|||
roles[TitleRole] = "title"; |
|||
roles[IdRole] = "transactionIndex"; |
|||
return roles; |
|||
} |
|||
|
|||
int TransactionListModel::rowCount(QModelIndex const& _parent) const |
|||
{ |
|||
Q_UNUSED(_parent); |
|||
return m_transactions.size(); |
|||
} |
|||
|
|||
QVariant TransactionListModel::data(QModelIndex const& _index, int _role) const |
|||
{ |
|||
if (_index.row() < 0 || _index.row() >= (int)m_transactions.size()) |
|||
return QVariant(); |
|||
auto const& transaction = m_transactions.at(_index.row()); |
|||
switch (_role) |
|||
{ |
|||
case TitleRole: |
|||
return QVariant(transaction.title); |
|||
case IdRole: |
|||
return QVariant(_index.row()); |
|||
default: |
|||
return QVariant(); |
|||
} |
|||
} |
|||
|
|||
///@todo: get parameters from code model
|
|||
QList<TransactionParameterItem*> buildParameters(QTextDocument* _document, TransactionSettings const& _transaction, QString const& _functionId) |
|||
{ |
|||
QList<TransactionParameterItem*> params; |
|||
try |
|||
{ |
|||
std::shared_ptr<QContractDefinition> contract = QContractDefinition::Contract(_document->toPlainText()); |
|||
auto functions = contract->functions(); |
|||
for (auto f : functions) |
|||
{ |
|||
if (f->name() != _functionId) |
|||
continue; |
|||
|
|||
auto parameters = f->parameters(); |
|||
//build a list of parameters for a function. If the function is selected as current, add parameter values as well
|
|||
for (auto p : parameters) |
|||
{ |
|||
QString paramValue; |
|||
if (f->name() == _transaction.functionId) |
|||
{ |
|||
auto paramValueIter = _transaction.parameterValues.find(p->name()); |
|||
if (paramValueIter != _transaction.parameterValues.cend()) |
|||
paramValue = toQString(paramValueIter->second); |
|||
} |
|||
|
|||
TransactionParameterItem* item = new TransactionParameterItem(p->name(), p->type(), paramValue); |
|||
QQmlEngine::setObjectOwnership(item, QQmlEngine::JavaScriptOwnership); |
|||
params.append(item); |
|||
} |
|||
} |
|||
} |
|||
catch (boost::exception const&) |
|||
{ |
|||
//TODO:
|
|||
} |
|||
|
|||
return params; |
|||
} |
|||
|
|||
///@todo: get fnctions from code model
|
|||
QList<QString> TransactionListModel::getFunctions() |
|||
{ |
|||
QList<QString> functionNames; |
|||
try |
|||
{ |
|||
QString code = m_document->toPlainText(); |
|||
std::shared_ptr<QContractDefinition> contract(QContractDefinition::Contract(code)); |
|||
auto functions = contract->functions(); |
|||
for (auto f : functions) |
|||
{ |
|||
functionNames.append(f->name()); |
|||
} |
|||
} |
|||
catch (boost::exception const&) |
|||
{ |
|||
} |
|||
return functionNames; |
|||
} |
|||
|
|||
QVariantList TransactionListModel::getParameters(int _index, QString const& _functionId) |
|||
{ |
|||
TransactionSettings const& transaction = (_index >= 0 && _index < (int)m_transactions.size()) ? m_transactions[_index] : TransactionSettings(); |
|||
auto plist = buildParameters(m_document, transaction, _functionId); |
|||
QVariantList vl; |
|||
for (QObject* p : plist) |
|||
vl.append(QVariant::fromValue(p)); |
|||
return vl; |
|||
} |
|||
|
|||
TransactionListItem* TransactionListModel::getItem(int _index) |
|||
{ |
|||
TransactionSettings const& transaction = (_index >= 0 && _index < (int)m_transactions.size()) ? m_transactions[_index] : TransactionSettings(); |
|||
TransactionListItem* item = new TransactionListItem(_index, transaction, nullptr); |
|||
QQmlEngine::setObjectOwnership(item, QQmlEngine::JavaScriptOwnership); |
|||
return item; |
|||
} |
|||
|
|||
void TransactionListModel::edit(QObject* _data) |
|||
{ |
|||
//these properties come from TransactionDialog QML object
|
|||
///@todo change the model to a qml component
|
|||
int index = _data->property("transactionIndex").toInt(); |
|||
QString title = _data->property("transactionTitle").toString(); |
|||
QString gas = _data->property("gas").toString(); |
|||
QString gasPrice = _data->property("gasPrice").toString(); |
|||
QString value = _data->property("transactionValue").toString(); |
|||
QString functionId = _data->property("functionId").toString(); |
|||
QAbstractListModel* paramsModel = qvariant_cast<QAbstractListModel*>(_data->property("transactionParams")); |
|||
TransactionSettings transaction(title, functionId, fromQString(value), fromQString(gas), fromQString(gasPrice)); |
|||
int paramCount = paramsModel->rowCount(QModelIndex()); |
|||
for (int p = 0; p < paramCount; ++p) |
|||
{ |
|||
QString paramName = paramsModel->data(paramsModel->index(p, 0), Qt::DisplayRole).toString(); |
|||
QString paramValue = paramsModel->data(paramsModel->index(p, 0), Qt::DisplayRole + 2).toString(); |
|||
if (!paramValue.isEmpty() && !paramName.isEmpty()) |
|||
transaction.parameterValues[paramName] = fromQString(paramValue); |
|||
} |
|||
|
|||
if (index >= 0 && index < (int)m_transactions.size()) |
|||
{ |
|||
beginRemoveRows(QModelIndex(), index, index); |
|||
m_transactions.erase(m_transactions.begin() + index); |
|||
endRemoveRows(); |
|||
} |
|||
else |
|||
index = rowCount(QModelIndex()); |
|||
|
|||
beginInsertRows(QModelIndex(), index, index); |
|||
m_transactions.push_back(transaction); |
|||
emit countChanged(); |
|||
endInsertRows(); |
|||
} |
|||
|
|||
int TransactionListModel::getCount() const |
|||
{ |
|||
return rowCount(QModelIndex()); |
|||
} |
|||
|
|||
void TransactionListModel::runTransaction(int _index) |
|||
{ |
|||
TransactionSettings tr = m_transactions.at(_index); |
|||
emit transactionStarted(tr); |
|||
} |
|||
|
|||
|
|||
} |
|||
} |
|||
|
@ -1,168 +0,0 @@ |
|||
/*
|
|||
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 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 <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file TransactionListView.h
|
|||
* @author Arkadiy Paronyan arkadiy@ethdev.com |
|||
* @date 2014 |
|||
* Ethereum IDE client. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <QObject> |
|||
#include <QVariant> |
|||
#include <QAbstractListModel> |
|||
#include <QHash> |
|||
#include <QByteArray> |
|||
#include <libdevcore/Common.h> |
|||
#include <libethcore/CommonEth.h> |
|||
|
|||
class QTextDocument; |
|||
|
|||
namespace dev |
|||
{ |
|||
namespace mix |
|||
{ |
|||
|
|||
/// Backend transaction config class
|
|||
struct TransactionSettings |
|||
{ |
|||
TransactionSettings(): |
|||
value(0), gas(10000), gasPrice(10 * dev::eth::szabo) {} |
|||
|
|||
TransactionSettings(QString const& _title, QString const& _functionId, u256 _value, u256 _gas, u256 _gasPrice): |
|||
title(_title), functionId(_functionId), value(_value), gas(_gas), gasPrice(_gasPrice) {} |
|||
|
|||
/// User specified transaction title
|
|||
QString title; |
|||
/// Contract function name
|
|||
QString functionId; |
|||
/// Transaction value
|
|||
u256 value; |
|||
/// Gas
|
|||
u256 gas; |
|||
/// Gas price
|
|||
u256 gasPrice; |
|||
/// Mapping from contract function parameter name to value
|
|||
std::map<QString, u256> parameterValues; |
|||
}; |
|||
|
|||
/// QML transaction parameter class
|
|||
class TransactionParameterItem: public QObject |
|||
{ |
|||
Q_OBJECT |
|||
Q_PROPERTY(QString name READ name CONSTANT) |
|||
Q_PROPERTY(QString type READ type CONSTANT) |
|||
Q_PROPERTY(QString value READ value CONSTANT) |
|||
public: |
|||
TransactionParameterItem(QString const& _name, QString const& _type, QString const& _value): |
|||
m_name(_name), m_type(_type), m_value(_value) {} |
|||
|
|||
/// Parameter name, set by contract definition
|
|||
QString name() { return m_name; } |
|||
/// Parameter type, set by contract definition
|
|||
QString type() { return m_type; } |
|||
/// Parameter value, set by user
|
|||
QString value() { return m_value; } |
|||
|
|||
private: |
|||
QString m_name; |
|||
QString m_type; |
|||
QString m_value; |
|||
}; |
|||
|
|||
class TransactionListItem: public QObject |
|||
{ |
|||
Q_OBJECT |
|||
Q_PROPERTY(int index READ index CONSTANT) |
|||
Q_PROPERTY(QString title READ title CONSTANT) |
|||
Q_PROPERTY(QString functionId READ functionId CONSTANT) |
|||
Q_PROPERTY(QString gas READ gas CONSTANT) |
|||
Q_PROPERTY(QString gasPrice READ gasPrice CONSTANT) |
|||
Q_PROPERTY(QString value READ value CONSTANT) |
|||
|
|||
public: |
|||
TransactionListItem(int _index, TransactionSettings const& _t, QObject* _parent); |
|||
|
|||
/// User specified transaction title
|
|||
QString title() { return m_title; } |
|||
/// Gas
|
|||
QString gas() { return m_gas; } |
|||
/// Gas cost
|
|||
QString gasPrice() { return m_gasPrice; } |
|||
/// Transaction value
|
|||
QString value() { return m_value; } |
|||
/// Contract function name
|
|||
QString functionId() { return m_functionId; } |
|||
/// Index of this transaction in the transactions list
|
|||
int index() { return m_index; } |
|||
|
|||
private: |
|||
int m_index; |
|||
QString m_title; |
|||
QString m_functionId; |
|||
QString m_value; |
|||
QString m_gas; |
|||
QString m_gasPrice; |
|||
}; |
|||
|
|||
/// QML model for a list of transactions
|
|||
class TransactionListModel: public QAbstractListModel |
|||
{ |
|||
Q_OBJECT |
|||
Q_PROPERTY(int count READ getCount() NOTIFY countChanged()) |
|||
|
|||
enum Roles |
|||
{ |
|||
TitleRole = Qt::DisplayRole, |
|||
IdRole = Qt::UserRole + 1 |
|||
}; |
|||
|
|||
public: |
|||
TransactionListModel(QObject* _parent, QTextDocument* _document); |
|||
~TransactionListModel() {} |
|||
|
|||
QHash<int, QByteArray> roleNames() const override; |
|||
int rowCount(QModelIndex const& _parent) const override; |
|||
QVariant data(QModelIndex const& _index, int _role) const override; |
|||
int getCount() const; |
|||
/// Apply changes from transaction dialog. Argument is a dialog model as defined in TransactionDialog.qml
|
|||
/// @todo Change that to transaction item
|
|||
Q_INVOKABLE void edit(QObject* _data); |
|||
/// @returns transaction item for a give index
|
|||
Q_INVOKABLE TransactionListItem* getItem(int _index); |
|||
/// @returns a list of functions for current contract
|
|||
Q_INVOKABLE QList<QString> getFunctions(); |
|||
/// @returns function parameters along with parameter values if set. @see TransactionParameterItem
|
|||
Q_INVOKABLE QVariantList getParameters(int _id, QString const& _functionId); |
|||
/// Launch transaction execution UI handler
|
|||
Q_INVOKABLE void runTransaction(int _index); |
|||
|
|||
signals: |
|||
/// Transaction count has changed
|
|||
void countChanged(); |
|||
/// Transaction has been launched
|
|||
void transactionStarted(dev::mix::TransactionSettings); |
|||
|
|||
private: |
|||
std::vector<TransactionSettings> m_transactions; |
|||
QTextDocument* m_document; |
|||
}; |
|||
|
|||
} |
|||
|
|||
} |
|||
|
@ -0,0 +1,182 @@ |
|||
import QtQuick 2.2 |
|||
import QtQuick.Controls 1.2 |
|||
import QtQuick.Layouts 1.1 |
|||
import QtQuick.Window 2.0 |
|||
|
|||
Window { |
|||
modality: Qt.WindowModal |
|||
|
|||
width:640 |
|||
height:480 |
|||
|
|||
visible: false |
|||
|
|||
property alias stateTitle : titleField.text |
|||
property alias stateBalance : balanceField.text |
|||
property int stateIndex |
|||
property var stateTransactions: [] |
|||
signal accepted |
|||
|
|||
function open(index, item) { |
|||
stateIndex = index; |
|||
stateTitle = item.title; |
|||
stateBalance = item.balance; |
|||
transactionsModel.clear(); |
|||
stateTransactions = []; |
|||
var transactions = item.transactions; |
|||
for (var t = 0; t < transactions.length; t++) { |
|||
transactionsModel.append(item.transactions[t]); |
|||
stateTransactions.push(item.transactions[t]); |
|||
} |
|||
visible = true; |
|||
titleField.focus = true; |
|||
} |
|||
|
|||
function close() { |
|||
visible = false; |
|||
} |
|||
|
|||
function getItem() { |
|||
var item = { |
|||
title: stateDialog.stateTitle, |
|||
balance: stateDialog.stateBalance, |
|||
transactions: [] |
|||
} |
|||
item.transactions = stateTransactions; |
|||
return item; |
|||
} |
|||
|
|||
GridLayout { |
|||
id: dialogContent |
|||
columns: 2 |
|||
anchors.fill: parent |
|||
anchors.margins: 10 |
|||
rowSpacing: 10 |
|||
columnSpacing: 10 |
|||
|
|||
Label { |
|||
text: qsTr("Title") |
|||
} |
|||
TextField { |
|||
id: titleField |
|||
focus: true |
|||
Layout.fillWidth: true |
|||
} |
|||
|
|||
Label { |
|||
text: qsTr("Balance") |
|||
} |
|||
TextField { |
|||
id: balanceField |
|||
Layout.fillWidth: true |
|||
} |
|||
|
|||
Label { |
|||
text: qsTr("Transactions") |
|||
} |
|||
ListView { |
|||
Layout.fillWidth: true |
|||
Layout.fillHeight: true |
|||
model: transactionsModel |
|||
delegate: transactionRenderDelegate |
|||
} |
|||
|
|||
Label { |
|||
|
|||
} |
|||
Button { |
|||
text: qsTr("Add") |
|||
onClicked: transactionsModel.addTransaction() |
|||
} |
|||
} |
|||
|
|||
RowLayout { |
|||
anchors.bottom: parent.bottom |
|||
anchors.right: parent.right; |
|||
|
|||
Button { |
|||
text: qsTr("Ok"); |
|||
onClicked: { |
|||
close(); |
|||
accepted(); |
|||
} |
|||
} |
|||
Button { |
|||
text: qsTr("Cancel"); |
|||
onClicked: close(); |
|||
} |
|||
} |
|||
|
|||
ListModel { |
|||
id: transactionsModel |
|||
|
|||
function editTransaction(index) { |
|||
transactionDialog.open(index, transactionsModel.get(index)); |
|||
} |
|||
|
|||
function addTransaction() { |
|||
|
|||
// Set next id here to work around Qt bug |
|||
// https://bugreports.qt-project.org/browse/QTBUG-41327 |
|||
// Second call to signal handler would just edit the item that was just created, no harm done |
|||
var item = { |
|||
value: "0", |
|||
functionId: "", |
|||
gas: "1000000000000", |
|||
gasPrice: "100000" |
|||
}; |
|||
|
|||
transactionDialog.open(transactionsModel.count, item); |
|||
} |
|||
|
|||
function deleteTransaction(index) { |
|||
stateTransactions.splice(index, 1); |
|||
transactionsModel.remove(index); |
|||
} |
|||
} |
|||
|
|||
Component { |
|||
id: transactionRenderDelegate |
|||
Item { |
|||
id: wrapperItem |
|||
height: 20 |
|||
width: parent.width |
|||
RowLayout { |
|||
anchors.fill: parent |
|||
Text { |
|||
Layout.fillWidth: true |
|||
Layout.fillHeight: true |
|||
text: functionId |
|||
font.pointSize: 12 |
|||
verticalAlignment: Text.AlignBottom |
|||
} |
|||
ToolButton { |
|||
text: qsTr("Edit"); |
|||
Layout.fillHeight: true |
|||
onClicked: transactionsModel.editTransaction(index) |
|||
} |
|||
ToolButton { |
|||
text: qsTr("Delete"); |
|||
Layout.fillHeight: true |
|||
onClicked: transactionsModel.deleteTransaction(index) |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
TransactionDialog { |
|||
id: transactionDialog |
|||
onAccepted: { |
|||
var item = transactionDialog.getItem(); |
|||
|
|||
if (transactionDialog.transactionIndex < transactionsModel.count) { |
|||
transactionsModel.set(transactionDialog.transactionIndex, item); |
|||
stateTransactions[index] = item; |
|||
} else { |
|||
transactionsModel.append(item); |
|||
stateTransactions.push(item); |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
@ -0,0 +1,132 @@ |
|||
import QtQuick 2.2 |
|||
import QtQuick.Controls.Styles 1.2 |
|||
import QtQuick.Controls 1.2 |
|||
import QtQuick.Dialogs 1.2 |
|||
import QtQuick.Layouts 1.1 |
|||
|
|||
Rectangle { |
|||
color: "transparent" |
|||
id: stateListContainer |
|||
focus: true |
|||
anchors.topMargin: 10 |
|||
anchors.left: parent.left |
|||
height: parent.height |
|||
width: parent.width |
|||
property var stateList: [] |
|||
|
|||
Connections { |
|||
target: appContext |
|||
onProjectLoaded: { |
|||
var items = JSON.parse(_json); |
|||
for(var i = 0; i < items.length; i++) { |
|||
stateListModel.append(items[i]); |
|||
stateList.push(items[i]) |
|||
} |
|||
} |
|||
} |
|||
|
|||
ListView { |
|||
anchors.top: parent.top |
|||
height: parent.height |
|||
width: parent.width |
|||
model: stateListModel |
|||
delegate: renderDelegate |
|||
} |
|||
|
|||
Button { |
|||
anchors.bottom: parent.bottom |
|||
action: addStateAction |
|||
} |
|||
|
|||
StateDialog { |
|||
id: stateDialog |
|||
onAccepted: { |
|||
var item = stateDialog.getItem(); |
|||
if (stateDialog.stateIndex < stateListModel.count) { |
|||
stateList[stateDialog.stateIndex] = item; |
|||
stateListModel.set(stateDialog.stateIndex, item); |
|||
} else { |
|||
stateList.push(item); |
|||
stateListModel.append(item); |
|||
} |
|||
|
|||
stateListModel.save(); |
|||
} |
|||
} |
|||
|
|||
ListModel { |
|||
id: stateListModel |
|||
|
|||
function addState() { |
|||
var item = { |
|||
title: "", |
|||
balance: "100000000000000000000000000", |
|||
transactions: [] |
|||
}; |
|||
stateDialog.open(stateListModel.count, item); |
|||
} |
|||
|
|||
function editState(index) { |
|||
stateDialog.open(index, stateList[index]); |
|||
} |
|||
|
|||
function runState(index) { |
|||
var item = stateList[index]; |
|||
debugModel.debugState(item); |
|||
} |
|||
|
|||
function deleteState(index) { |
|||
stateListModel.remove(index); |
|||
stateList.splice(index, 1); |
|||
save(); |
|||
} |
|||
|
|||
function save() { |
|||
var json = JSON.stringify(stateList); |
|||
appContext.saveProject(json); |
|||
} |
|||
} |
|||
|
|||
Component { |
|||
id: renderDelegate |
|||
Item { |
|||
id: wrapperItem |
|||
height: 20 |
|||
width: parent.width |
|||
RowLayout { |
|||
anchors.fill: parent |
|||
Text { |
|||
Layout.fillWidth: true |
|||
Layout.fillHeight: true |
|||
text: title |
|||
font.pointSize: 12 |
|||
verticalAlignment: Text.AlignBottom |
|||
} |
|||
ToolButton { |
|||
text: qsTr("Edit"); |
|||
Layout.fillHeight: true |
|||
onClicked: stateListModel.editState(index); |
|||
} |
|||
ToolButton { |
|||
text: qsTr("Delete"); |
|||
Layout.fillHeight: true |
|||
onClicked: stateListModel.deleteState(index); |
|||
} |
|||
ToolButton { |
|||
text: qsTr("Run"); |
|||
Layout.fillHeight: true |
|||
onClicked: stateListModel.runState(index); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
Action { |
|||
id: addStateAction |
|||
text: "&Add State" |
|||
shortcut: "Ctrl+N" |
|||
enabled: codeModel.hasContract && !debugModel.running; |
|||
onTriggered: stateListModel.addState(); |
|||
} |
|||
} |
|||
|
@ -1,89 +0,0 @@ |
|||
import QtQuick 2.2 |
|||
import QtQuick.Controls.Styles 1.2 |
|||
import QtQuick.Controls 1.2 |
|||
import QtQuick.Dialogs 1.2 |
|||
import QtQuick.Layouts 1.1 |
|||
|
|||
|
|||
Rectangle { |
|||
color: "transparent" |
|||
id: transactionListContainer |
|||
focus: true |
|||
anchors.topMargin: 10 |
|||
anchors.left: parent.left |
|||
height: parent.height |
|||
width: parent.width |
|||
|
|||
ListView { |
|||
anchors.top: parent.top |
|||
height: parent.height |
|||
width: parent.width |
|||
id: transactionList |
|||
model: transactionListModel |
|||
delegate: renderDelegate |
|||
} |
|||
|
|||
Button { |
|||
anchors.bottom: parent.bottom |
|||
text: qsTr("Add") |
|||
onClicked: |
|||
{ |
|||
// Set next id here to work around Qt bug |
|||
// https://bugreports.qt-project.org/browse/QTBUG-41327 |
|||
// Second call to signal handle would just edit the item that was just created, no harm done |
|||
transactionDialog.reset(transactionListModel.count, transactionListModel); |
|||
transactionDialog.open(); |
|||
transactionDialog.focus = true; |
|||
} |
|||
} |
|||
|
|||
TransactionDialog { |
|||
id: transactionDialog |
|||
onAccepted: { |
|||
transactionListModel.edit(transactionDialog); |
|||
} |
|||
} |
|||
|
|||
Component { |
|||
id: renderDelegate |
|||
Item { |
|||
id: wrapperItem |
|||
height: 20 |
|||
width: parent.width |
|||
RowLayout |
|||
{ |
|||
anchors.fill: parent |
|||
Text { |
|||
//anchors.fill: parent |
|||
Layout.fillWidth: true |
|||
Layout.fillHeight: true |
|||
text: title |
|||
font.pointSize: 12 |
|||
verticalAlignment: Text.AlignBottom |
|||
} |
|||
ToolButton { |
|||
text: qsTr("Edit"); |
|||
Layout.fillHeight: true |
|||
onClicked: { |
|||
transactionDialog.reset(index, transactionListModel); |
|||
transactionDialog.open(); |
|||
transactionDialog.focus = true; |
|||
} |
|||
} |
|||
ToolButton { |
|||
text: qsTr("Delete"); |
|||
Layout.fillHeight: true |
|||
onClicked: { |
|||
} |
|||
} |
|||
ToolButton { |
|||
text: qsTr("Run"); |
|||
Layout.fillHeight: true |
|||
onClicked: { |
|||
transactionListModel.runTransaction(index); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
Loading…
Reference in new issue