Browse Source

Merge branch 'develop' into pacify

cl-refactor
subtly 10 years ago
parent
commit
a80fca04fa
  1. 1
      evmjit/libevmjit/BasicBlock.cpp
  2. 4
      evmjit/libevmjit/BasicBlock.h
  3. 31
      evmjit/libevmjit/Cache.cpp
  4. 12
      evmjit/libevmjit/Cache.h
  5. 3
      evmjit/libevmjit/Compiler.cpp
  6. 17
      evmjit/libevmjit/ExecutionEngine.cpp
  7. 42
      evmjit/libevmjit/RuntimeManager.cpp
  8. 5
      evmjit/libevmjit/RuntimeManager.h
  9. 5
      libweb3jsonrpc/WebThreeStubServerBase.cpp
  10. 1
      libweb3jsonrpc/WebThreeStubServerBase.h
  11. 7
      libweb3jsonrpc/abstractwebthreestubserver.h
  12. 1
      libweb3jsonrpc/spec.json
  13. 47
      mix/CMakeLists.txt
  14. 5
      mix/ClientModel.cpp
  15. 2
      mix/ClientModel.h
  16. 44
      mix/MixApplication.cpp
  17. 21
      mix/MixApplication.h
  18. 41
      mix/QBasicNodeDefinition.cpp
  19. 12
      mix/QBasicNodeDefinition.h
  20. 1
      mix/QVariableDeclaration.cpp
  21. 5
      mix/QVariableDeclaration.h
  22. 37
      mix/QVariableDefinition.cpp
  23. 8
      mix/QVariableDefinition.h
  24. 18
      mix/main.cpp
  25. 5
      mix/qml.qrc
  26. 15
      mix/qml/Application.qml
  27. 5
      mix/qml/CallStack.qml
  28. 7
      mix/qml/CodeEditor.qml
  29. 1
      mix/qml/CodeEditorStyle.qml
  30. 43
      mix/qml/CodeEditorView.qml
  31. 2
      mix/qml/CommonSeparator.qml
  32. 12
      mix/qml/Debugger.qml
  33. 1
      mix/qml/DebuggerPaneStyle.qml
  34. 1
      mix/qml/DefaultLabel.qml
  35. 4
      mix/qml/DeploymentDialog.qml
  36. 30
      mix/qml/FilesSection.qml
  37. 4
      mix/qml/ItemDelegateDataDump.qml
  38. 115
      mix/qml/LogsPane.qml
  39. 1
      mix/qml/LogsPaneStyle.qml
  40. 1
      mix/qml/MainContent.qml
  41. 1
      mix/qml/NewProjectDialog.qml
  42. 1
      mix/qml/ProjectFilesStyle.qml
  43. 21
      mix/qml/ProjectList.qml
  44. 2
      mix/qml/ProjectModel.qml
  45. 3
      mix/qml/Splitter.qml
  46. 16
      mix/qml/StateDialog.qml
  47. 1
      mix/qml/StateDialogStyle.qml
  48. 1
      mix/qml/StateListModel.qml
  49. 6
      mix/qml/StatusPane.qml
  50. 1
      mix/qml/StatusPaneStyle.qml
  51. 4
      mix/qml/StorageView.qml
  52. 1
      mix/qml/Style.qml
  53. 45
      mix/qml/TransactionDialog.qml
  54. 17
      mix/qml/WebCodeEditor.qml
  55. 21
      mix/qml/WebPreview.qml
  56. 1
      mix/qml/WebPreviewStyle.qml
  57. 8
      mix/qml/qmldir
  58. 6
      mix/test.qrc
  59. 50
      mix/test/TestMain.cpp
  60. 194
      mix/test/TestService.cpp
  61. 59
      mix/test/TestService.h
  62. 142
      mix/test/qml/TestMain.qml
  63. 50
      mix/web.qrc
  64. 33
      test/Stats.cpp
  65. 13
      test/Stats.h
  66. 19
      test/TestHelper.cpp
  67. 4
      test/TestHelper.h
  68. 5
      test/state.cpp
  69. 5
      test/vm.cpp
  70. 10
      test/webthreestubclient.h

1
evmjit/libevmjit/BasicBlock.cpp

@ -49,6 +49,7 @@ void BasicBlock::LocalStack::push(llvm::Value* _value)
assert(_value->getType() == Type::Word); assert(_value->getType() == Type::Word);
m_bblock.m_currentStack.push_back(_value); m_bblock.m_currentStack.push_back(_value);
m_bblock.m_tosOffset += 1; m_bblock.m_tosOffset += 1;
m_maxSize = std::max(m_maxSize, m_bblock.m_currentStack.size());
} }
llvm::Value* BasicBlock::LocalStack::pop() llvm::Value* BasicBlock::LocalStack::pop()

4
evmjit/libevmjit/BasicBlock.h

@ -33,6 +33,9 @@ public:
/// @param _index Index of value to be swaped. Must be > 0. /// @param _index Index of value to be swaped. Must be > 0.
void swap(size_t _index); void swap(size_t _index);
size_t getMaxSize() const { return m_maxSize; }
int getDiff() const { return m_bblock.m_tosOffset; }
private: private:
LocalStack(BasicBlock& _owner); LocalStack(BasicBlock& _owner);
LocalStack(LocalStack const&) = delete; LocalStack(LocalStack const&) = delete;
@ -49,6 +52,7 @@ public:
private: private:
BasicBlock& m_bblock; BasicBlock& m_bblock;
size_t m_maxSize = 0; ///< Max size reached by the stack.
}; };
explicit BasicBlock(instr_idx _firstInstrIdx, code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest); explicit BasicBlock(instr_idx _firstInstrIdx, code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest);

31
evmjit/libevmjit/Cache.cpp

@ -4,6 +4,7 @@
#include <llvm/IR/Module.h> #include <llvm/IR/Module.h>
#include <llvm/IR/LLVMContext.h> #include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Instructions.h> #include <llvm/IR/Instructions.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/Support/Path.h> #include <llvm/Support/Path.h>
#include <llvm/Support/FileSystem.h> #include <llvm/Support/FileSystem.h>
#include <llvm/Support/raw_os_ostream.h> #include <llvm/Support/raw_os_ostream.h>
@ -59,6 +60,36 @@ void Cache::clear()
fs::remove(it->path()); fs::remove(it->path());
} }
void Cache::preload(llvm::ExecutionEngine& _ee, std::unordered_map<std::string, uint64_t>& _funcCache)
{
// TODO: Cache dir should be in one place
using namespace llvm::sys;
llvm::SmallString<256> cachePath;
path::system_temp_directory(false, cachePath);
path::append(cachePath, "evm_objs");
// Disable listener
auto listener = g_listener;
g_listener = nullptr;
std::error_code err;
for (auto it = fs::directory_iterator{cachePath.str(), err}; it != fs::directory_iterator{}; it.increment(err))
{
auto name = it->path().substr(cachePath.size() + 1);
if (auto module = getObject(name))
{
DLOG(cache) << "Preload: " << name << "\n";
_ee.addModule(module.get());
module.release();
auto addr = _ee.getFunctionAddress(name);
assert(addr);
_funcCache[std::move(name)] = addr;
}
}
g_listener = listener;
}
std::unique_ptr<llvm::Module> Cache::getObject(std::string const& id) std::unique_ptr<llvm::Module> Cache::getObject(std::string const& id)
{ {
if (g_mode != CacheMode::on && g_mode != CacheMode::read) if (g_mode != CacheMode::on && g_mode != CacheMode::read)

12
evmjit/libevmjit/Cache.h

@ -1,9 +1,15 @@
#pragma once #pragma once
#include <memory> #include <memory>
#include <unordered_map>
#include <llvm/ExecutionEngine/ObjectCache.h> #include <llvm/ExecutionEngine/ObjectCache.h>
namespace llvm
{
class ExecutionEngine;
}
namespace dev namespace dev
{ {
namespace eth namespace eth
@ -18,7 +24,8 @@ enum class CacheMode
off, off,
read, read,
write, write,
clear clear,
preload
}; };
class ObjectCache : public llvm::ObjectCache class ObjectCache : public llvm::ObjectCache
@ -43,6 +50,9 @@ public:
/// Clears cache storage /// Clears cache storage
static void clear(); static void clear();
/// Loads all available cached objects to ExecutionEngine
static void preload(llvm::ExecutionEngine& _ee, std::unordered_map<std::string, uint64_t>& _funcCache);
}; };
} }

3
evmjit/libevmjit/Compiler.cpp

@ -838,6 +838,9 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti
// Block may have no terminator if the next instruction is a jump destination. // Block may have no terminator if the next instruction is a jump destination.
if (!_basicBlock.llvm()->getTerminator()) if (!_basicBlock.llvm()->getTerminator())
m_builder.CreateBr(_nextBasicBlock); m_builder.CreateBr(_nextBasicBlock);
m_builder.SetInsertPoint(_basicBlock.llvm()->getFirstNonPHI());
_runtimeManager.checkStackLimit(_basicBlock.localStack().getMaxSize(), _basicBlock.localStack().getDiff());
} }

17
evmjit/libevmjit/ExecutionEngine.cpp

@ -76,6 +76,7 @@ cl::opt<CacheMode> g_cache{"cache", cl::desc{"Cache compiled EVM code on disk"},
clEnumValN(CacheMode::read, "r", "Read only. No new objects are added to cache."), clEnumValN(CacheMode::read, "r", "Read only. No new objects are added to cache."),
clEnumValN(CacheMode::write, "w", "Write only. No objects are loaded from cache."), clEnumValN(CacheMode::write, "w", "Write only. No objects are loaded from cache."),
clEnumValN(CacheMode::clear, "c", "Clear the cache storage. Cache is disabled."), clEnumValN(CacheMode::clear, "c", "Clear the cache storage. Cache is disabled."),
clEnumValN(CacheMode::preload, "p", "Preload all cached objects."),
clEnumValEnd)}; clEnumValEnd)};
cl::opt<bool> g_stats{"st", cl::desc{"Statistics"}}; cl::opt<bool> g_stats{"st", cl::desc{"Statistics"}};
cl::opt<bool> g_dump{"dump", cl::desc{"Dump LLVM IR module"}}; cl::opt<bool> g_dump{"dump", cl::desc{"Dump LLVM IR module"}};
@ -111,8 +112,15 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
std::unique_ptr<ExecStats> listener{new ExecStats}; std::unique_ptr<ExecStats> listener{new ExecStats};
listener->stateChanged(ExecState::Started); listener->stateChanged(ExecState::Started);
bool preloadCache = g_cache == CacheMode::preload;
if (preloadCache)
g_cache = CacheMode::on;
// TODO: Do not pseudo-init the cache every time
auto objectCache = (g_cache != CacheMode::off && g_cache != CacheMode::clear) ? Cache::getObjectCache(g_cache, listener.get()) : nullptr; auto objectCache = (g_cache != CacheMode::off && g_cache != CacheMode::clear) ? Cache::getObjectCache(g_cache, listener.get()) : nullptr;
static std::unordered_map<std::string, uint64_t> funcCache;
static std::unique_ptr<llvm::ExecutionEngine> ee; static std::unique_ptr<llvm::ExecutionEngine> ee;
if (!ee) if (!ee)
{ {
@ -138,6 +146,9 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
return ReturnCode::LLVMConfigError; return ReturnCode::LLVMConfigError;
module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module
ee->setObjectCache(objectCache); ee->setObjectCache(objectCache);
if (preloadCache)
Cache::preload(*ee, funcCache);
} }
static StatsCollector statsCollector; static StatsCollector statsCollector;
@ -146,10 +157,9 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
m_runtime.init(_data, _env); m_runtime.init(_data, _env);
EntryFuncPtr entryFuncPtr = nullptr; EntryFuncPtr entryFuncPtr = nullptr;
static std::unordered_map<std::string, EntryFuncPtr> funcCache;
auto it = funcCache.find(mainFuncName); auto it = funcCache.find(mainFuncName);
if (it != funcCache.end()) if (it != funcCache.end())
entryFuncPtr = it->second; entryFuncPtr = (EntryFuncPtr) it->second;
if (!entryFuncPtr) if (!entryFuncPtr)
{ {
@ -177,7 +187,8 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
if (!CHECK(entryFuncPtr)) if (!CHECK(entryFuncPtr))
return ReturnCode::LLVMLinkError; return ReturnCode::LLVMLinkError;
funcCache[mainFuncName] = entryFuncPtr; if (it == funcCache.end())
funcCache[mainFuncName] = (uint64_t) entryFuncPtr;
listener->stateChanged(ExecState::Execution); listener->stateChanged(ExecState::Execution);
auto returnCode = entryFuncPtr(&m_runtime); auto returnCode = entryFuncPtr(&m_runtime);

42
evmjit/libevmjit/RuntimeManager.cpp

@ -101,6 +101,48 @@ RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder, code_iterator _codeB
assert(m_memPtr->getType() == Array::getType()->getPointerTo()); assert(m_memPtr->getType() == Array::getType()->getPointerTo());
m_envPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(rtPtr, 1), "env"); m_envPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(rtPtr, 1), "env");
assert(m_envPtr->getType() == Type::EnvPtr); assert(m_envPtr->getType() == Type::EnvPtr);
m_stackSize = m_builder.CreateAlloca(Type::Size, nullptr, "stackSize");
m_builder.CreateStore(m_builder.getInt64(0), m_stackSize);
llvm::Type* checkStackLimitArgs[] = {Type::Size->getPointerTo(), Type::Size, Type::Size, Type::BytePtr};
m_checkStackLimit = llvm::Function::Create(llvm::FunctionType::get(Type::Void, checkStackLimitArgs, false), llvm::Function::PrivateLinkage, "stack.checkSize", getModule());
m_checkStackLimit->setDoesNotThrow();
m_checkStackLimit->setDoesNotCapture(1);
auto checkBB = llvm::BasicBlock::Create(_builder.getContext(), "Check", m_checkStackLimit);
auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "Update", m_checkStackLimit);
auto outOfStackBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfStack", m_checkStackLimit);
auto currSizePtr = &m_checkStackLimit->getArgumentList().front();
currSizePtr->setName("currSize");
auto max = currSizePtr->getNextNode();
max->setName("max");
auto diff = max->getNextNode();
diff->setName("diff");
auto jmpBuf = diff->getNextNode();
jmpBuf->setName("jmpBuf");
InsertPointGuard guard{m_builder};
m_builder.SetInsertPoint(checkBB);
auto currSize = m_builder.CreateLoad(currSizePtr, "cur");
auto maxSize = m_builder.CreateNUWAdd(currSize, max, "maxSize");
auto ok = m_builder.CreateICmpULE(maxSize, m_builder.getInt64(1024), "ok");
m_builder.CreateCondBr(ok, updateBB, outOfStackBB, Type::expectTrue);
m_builder.SetInsertPoint(updateBB);
auto newSize = m_builder.CreateNSWAdd(currSize, diff);
m_builder.CreateStore(newSize, currSizePtr);
m_builder.CreateRetVoid();
m_builder.SetInsertPoint(outOfStackBB);
abort(jmpBuf);
m_builder.CreateUnreachable();
}
void RuntimeManager::checkStackLimit(size_t _max, int _diff)
{
createCall(m_checkStackLimit, {m_stackSize, m_builder.getInt64(_max), m_builder.getInt64(_diff), getJmpBuf()});
} }
llvm::Value* RuntimeManager::getRuntimePtr() llvm::Value* RuntimeManager::getRuntimePtr()

5
evmjit/libevmjit/RuntimeManager.h

@ -48,6 +48,8 @@ public:
static llvm::StructType* getRuntimeType(); static llvm::StructType* getRuntimeType();
static llvm::StructType* getRuntimeDataType(); static llvm::StructType* getRuntimeDataType();
void checkStackLimit(size_t _max, int _diff);
private: private:
llvm::Value* getPtr(RuntimeData::Index _index); llvm::Value* getPtr(RuntimeData::Index _index);
void set(RuntimeData::Index _index, llvm::Value* _value); void set(RuntimeData::Index _index, llvm::Value* _value);
@ -59,6 +61,9 @@ private:
llvm::Value* m_memPtr = nullptr; llvm::Value* m_memPtr = nullptr;
llvm::Value* m_envPtr = nullptr; llvm::Value* m_envPtr = nullptr;
llvm::Value* m_stackSize = nullptr;
llvm::Function* m_checkStackLimit = nullptr;
code_iterator m_codeBegin = {}; code_iterator m_codeBegin = {};
code_iterator m_codeEnd = {}; code_iterator m_codeEnd = {};

5
libweb3jsonrpc/WebThreeStubServerBase.cpp

@ -296,6 +296,11 @@ bool WebThreeStubServerBase::net_listening()
return network()->isNetworkStarted(); return network()->isNetworkStarted();
} }
string WebThreeStubServerBase::eth_protocolVersion()
{
return toJS(eth::c_protocolVersion);
}
string WebThreeStubServerBase::eth_coinbase() string WebThreeStubServerBase::eth_coinbase()
{ {
return toJS(client()->address()); return toJS(client()->address());

1
libweb3jsonrpc/WebThreeStubServerBase.h

@ -77,6 +77,7 @@ public:
virtual std::string net_peerCount(); virtual std::string net_peerCount();
virtual bool net_listening(); virtual bool net_listening();
virtual std::string eth_protocolVersion();
virtual std::string eth_coinbase(); virtual std::string eth_coinbase();
virtual bool eth_mining(); virtual bool eth_mining();
virtual std::string eth_gasPrice(); virtual std::string eth_gasPrice();

7
libweb3jsonrpc/abstractwebthreestubserver.h

@ -17,6 +17,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
this->bindAndAddMethod(jsonrpc::Procedure("net_version", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::net_versionI); this->bindAndAddMethod(jsonrpc::Procedure("net_version", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::net_versionI);
this->bindAndAddMethod(jsonrpc::Procedure("net_peerCount", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::net_peerCountI); this->bindAndAddMethod(jsonrpc::Procedure("net_peerCount", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::net_peerCountI);
this->bindAndAddMethod(jsonrpc::Procedure("net_listening", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::net_listeningI); this->bindAndAddMethod(jsonrpc::Procedure("net_listening", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::net_listeningI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_protocolVersion", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_protocolVersionI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_coinbase", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_coinbaseI); this->bindAndAddMethod(jsonrpc::Procedure("eth_coinbase", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_coinbaseI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_mining", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::eth_miningI); this->bindAndAddMethod(jsonrpc::Procedure("eth_mining", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::eth_miningI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_gasPrice", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_gasPriceI); this->bindAndAddMethod(jsonrpc::Procedure("eth_gasPrice", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_gasPriceI);
@ -92,6 +93,11 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
(void)request; (void)request;
response = this->net_listening(); response = this->net_listening();
} }
inline virtual void eth_protocolVersionI(const Json::Value &request, Json::Value &response)
{
(void)request;
response = this->eth_protocolVersion();
}
inline virtual void eth_coinbaseI(const Json::Value &request, Json::Value &response) inline virtual void eth_coinbaseI(const Json::Value &request, Json::Value &response)
{ {
(void)request; (void)request;
@ -302,6 +308,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
virtual std::string net_version() = 0; virtual std::string net_version() = 0;
virtual std::string net_peerCount() = 0; virtual std::string net_peerCount() = 0;
virtual bool net_listening() = 0; virtual bool net_listening() = 0;
virtual std::string eth_protocolVersion() = 0;
virtual std::string eth_coinbase() = 0; virtual std::string eth_coinbase() = 0;
virtual bool eth_mining() = 0; virtual bool eth_mining() = 0;
virtual std::string eth_gasPrice() = 0; virtual std::string eth_gasPrice() = 0;

1
libweb3jsonrpc/spec.json

@ -6,6 +6,7 @@
{ "name": "net_peerCount", "params": [], "order": [], "returns" : "" }, { "name": "net_peerCount", "params": [], "order": [], "returns" : "" },
{ "name": "net_listening", "params": [], "order": [], "returns" : false }, { "name": "net_listening", "params": [], "order": [], "returns" : false },
{ "name": "eth_protocolVersion", "params": [], "order": [], "returns" : "" },
{ "name": "eth_coinbase", "params": [], "order": [], "returns" : "" }, { "name": "eth_coinbase", "params": [], "order": [], "returns" : "" },
{ "name": "eth_mining", "params": [], "order": [], "returns" : false }, { "name": "eth_mining", "params": [], "order": [], "returns" : false },
{ "name": "eth_gasPrice", "params": [], "order": [], "returns" : "" }, { "name": "eth_gasPrice", "params": [], "order": [], "returns" : "" },

47
mix/CMakeLists.txt

@ -29,7 +29,9 @@ else()
qt5_add_resources(UI_RESOURCES noweb.qrc) qt5_add_resources(UI_RESOURCES noweb.qrc)
endif() endif()
if (CMAKE_BUILD_TYPE EQUAL "DEBUG")
add_definitions(-DQT_QML_DEBUG) add_definitions(-DQT_QML_DEBUG)
endif()
# eth_add_executable is defined in cmake/EthExecutableHelper.cmake # eth_add_executable is defined in cmake/EthExecutableHelper.cmake
eth_add_executable(${EXECUTABLE} eth_add_executable(${EXECUTABLE}
@ -37,33 +39,15 @@ eth_add_executable(${EXECUTABLE}
UI_RESOURCES ${UI_RESOURCES} UI_RESOURCES ${UI_RESOURCES}
) )
target_link_libraries(${EXECUTABLE} Qt5::Core)
target_link_libraries(${EXECUTABLE} Qt5::Gui)
target_link_libraries(${EXECUTABLE} Qt5::Widgets)
target_link_libraries(${EXECUTABLE} Qt5::Network)
target_link_libraries(${EXECUTABLE} Qt5::Quick)
target_link_libraries(${EXECUTABLE} Qt5::Qml)
target_link_libraries(${EXECUTABLE} webthree)
target_link_libraries(${EXECUTABLE} ethereum)
target_link_libraries(${EXECUTABLE} evm)
target_link_libraries(${EXECUTABLE} ethcore)
target_link_libraries(${EXECUTABLE} devcrypto)
target_link_libraries(${EXECUTABLE} secp256k1)
if (NOT ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC"))
target_link_libraries(${EXECUTABLE} serpent)
endif()
target_link_libraries(${EXECUTABLE} lll)
target_link_libraries(${EXECUTABLE} solidity)
target_link_libraries(${EXECUTABLE} evmcore)
target_link_libraries(${EXECUTABLE} devcore)
target_link_libraries(${EXECUTABLE} jsqrc)
target_link_libraries(${EXECUTABLE} web3jsonrpc)
set(LIBRARIES "Qt5::Core;Qt5::Gui;Qt5::Widgets;Qt5::Network;Qt5::Quick;Qt5::Qml;webthree;ethereum;evm;ethcore;devcrypto;solidity;evmcore;devcore;jsqrc;web3jsonrpc")
if (${ETH_HAVE_WEBENGINE}) if (${ETH_HAVE_WEBENGINE})
add_definitions(-DETH_HAVE_WEBENGINE) add_definitions(-DETH_HAVE_WEBENGINE)
target_link_libraries(${EXECUTABLE} Qt5::WebEngine) list(APPEND LIBRARIES "Qt5::WebEngine")
endif() endif()
target_link_libraries(${EXECUTABLE} ${LIBRARIES})
# eth_install_executable is defined in cmake/EthExecutableHelper.cmake # eth_install_executable is defined in cmake/EthExecutableHelper.cmake
eth_install_executable(${EXECUTABLE} eth_install_executable(${EXECUTABLE}
QMLDIR ${CMAKE_CURRENT_SOURCE_DIR}/qml QMLDIR ${CMAKE_CURRENT_SOURCE_DIR}/qml
@ -71,5 +55,22 @@ eth_install_executable(${EXECUTABLE}
#add qml asnd stdc files to project tree in Qt creator #add qml asnd stdc files to project tree in Qt creator
file(GLOB_RECURSE QMLFILES "qml/*.*") file(GLOB_RECURSE QMLFILES "qml/*.*")
file(GLOB_RECURSE TESTFILES "test/qml/*.*")
file(GLOB_RECURSE SOLFILES "stdc/*.*") file(GLOB_RECURSE SOLFILES "stdc/*.*")
add_custom_target(mix_qml SOURCES ${QMLFILES} ${SOLFILES}) add_custom_target(mix_qml SOURCES ${QMLFILES} ${SOLFILES} ${TESTFILES})
#test target
find_package(Qt5QuickTest REQUIRED)
find_package(Qt5Test REQUIRED)
set(TEST_EXECUTABLE mix_test)
list(APPEND LIBRARIES "Qt5::QuickTest")
list(APPEND LIBRARIES "Qt5::Test")
list(REMOVE_ITEM SRC_LIST "./main.cpp")
aux_source_directory(test SRC_LIST)
file(GLOB HEADERS "test/*.h")
add_executable(${TEST_EXECUTABLE} ${UI_RESOURCES} ${SRC_LIST} ${HEADERS})
target_link_libraries(${TEST_EXECUTABLE} ${LIBRARIES})
set_target_properties(${TEST_EXECUTABLE} PROPERTIES EXCLUDE_FROM_ALL 1 EXCLUDE_FROM_DEFAULT_BUILD 1)

5
mix/ClientModel.cpp

@ -90,6 +90,7 @@ ClientModel::ClientModel():
ClientModel::~ClientModel() ClientModel::~ClientModel()
{ {
m_runFuture.waitForFinished();
} }
QString ClientModel::apiCall(QString const& _message) QString ClientModel::apiCall(QString const& _message)
@ -113,7 +114,7 @@ void ClientModel::mine()
m_mining = true; m_mining = true;
emit miningStarted(); emit miningStarted();
emit miningStateChanged(); emit miningStateChanged();
QtConcurrent::run([=]() m_runFuture = QtConcurrent::run([=]()
{ {
try try
{ {
@ -206,7 +207,7 @@ void ClientModel::executeSequence(std::vector<TransactionSettings> const& _seque
emit runStateChanged(); emit runStateChanged();
//run sequence //run sequence
QtConcurrent::run([=]() m_runFuture = QtConcurrent::run([=]()
{ {
try try
{ {

2
mix/ClientModel.h

@ -27,6 +27,7 @@
#include <map> #include <map>
#include <QString> #include <QString>
#include <QVariantMap> #include <QVariantMap>
#include <QFuture>
#include "MachineStates.h" #include "MachineStates.h"
namespace dev namespace dev
@ -203,6 +204,7 @@ private:
std::atomic<bool> m_running; std::atomic<bool> m_running;
std::atomic<bool> m_mining; std::atomic<bool> m_mining;
QFuture<void> m_runFuture;
std::unique_ptr<MixClient> m_client; std::unique_ptr<MixClient> m_client;
std::unique_ptr<RpcConnector> m_rpcConnector; std::unique_ptr<RpcConnector> m_rpcConnector;
std::unique_ptr<Web3Server> m_web3Server; std::unique_ptr<Web3Server> m_web3Server;

44
mix/MixApplication.cpp

@ -23,6 +23,7 @@
#include <QQmlApplicationEngine> #include <QQmlApplicationEngine>
#include <QUrl> #include <QUrl>
#include <QIcon> #include <QIcon>
#include <QFont>
#ifdef ETH_HAVE_WEBENGINE #ifdef ETH_HAVE_WEBENGINE
#include <QtWebEngine/QtWebEngine> #include <QtWebEngine/QtWebEngine>
#endif #endif
@ -37,21 +38,49 @@
using namespace dev::mix; using namespace dev::mix;
ApplicationService::ApplicationService()
{
#ifdef ETH_HAVE_WEBENGINE
QtWebEngine::initialize();
#endif
QFont f;
m_systemPointSize = f.pointSize();
}
MixApplication::MixApplication(int& _argc, char* _argv[]): MixApplication::MixApplication(int& _argc, char* _argv[]):
QApplication(_argc, _argv), m_engine(new QQmlApplicationEngine()) QApplication(_argc, _argv), m_engine(new QQmlApplicationEngine())
{ {
m_engine->load(QUrl("qrc:/qml/Application.qml"));
if (!m_engine->rootObjects().empty())
{
QWindow *window = qobject_cast<QWindow*>(m_engine->rootObjects().at(0));
if (window)
window->setIcon(QIcon(":/res/mix_256x256x32.png"));
}
}
void MixApplication::initialize()
{
#if __linux
//work around ubuntu appmenu-qt5 bug
//https://bugs.launchpad.net/ubuntu/+source/appmenu-qt5/+bug/1323853
putenv((char*)"QT_QPA_PLATFORMTHEME=");
putenv((char*)"QSG_RENDER_LOOP=threaded");
#endif
#if (defined(_WIN32) || defined(_WIN64))
if (!getenv("OPENSSL_CONF"))
putenv((char*)"OPENSSL_CONF=c:\\");
#endif
setOrganizationName(tr("Ethereum")); setOrganizationName(tr("Ethereum"));
setOrganizationDomain(tr("ethereum.org")); setOrganizationDomain(tr("ethereum.org"));
setApplicationName(tr("Mix")); setApplicationName(tr("Mix"));
setApplicationVersion("0.1"); setApplicationVersion("0.1");
#ifdef ETH_HAVE_WEBENGINE
QtWebEngine::initialize();
#endif
QFont f;
m_engine->rootContext()->setContextProperty("systemPointSize", f.pointSize());
qmlRegisterType<CodeModel>("org.ethereum.qml.CodeModel", 1, 0, "CodeModel"); qmlRegisterType<CodeModel>("org.ethereum.qml.CodeModel", 1, 0, "CodeModel");
qmlRegisterType<ClientModel>("org.ethereum.qml.ClientModel", 1, 0, "ClientModel"); qmlRegisterType<ClientModel>("org.ethereum.qml.ClientModel", 1, 0, "ClientModel");
qmlRegisterType<ApplicationService>("org.ethereum.qml.ApplicationService", 1, 0, "ApplicationService");
qmlRegisterType<FileIo>("org.ethereum.qml.FileIo", 1, 0, "FileIo"); qmlRegisterType<FileIo>("org.ethereum.qml.FileIo", 1, 0, "FileIo");
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");
@ -63,10 +92,7 @@ MixApplication::MixApplication(int& _argc, char* _argv[]):
qmlRegisterType<HttpServer>("HttpServer", 1, 0, "HttpServer"); qmlRegisterType<HttpServer>("HttpServer", 1, 0, "HttpServer");
qRegisterMetaType<CodeModel*>("CodeModel*"); qRegisterMetaType<CodeModel*>("CodeModel*");
qRegisterMetaType<ClientModel*>("ClientModel*"); qRegisterMetaType<ClientModel*>("ClientModel*");
qRegisterMetaType<ClientModel*>("ClientModel*");
m_engine->load(QUrl("qrc:/qml/main.qml"));
QWindow *window = qobject_cast<QWindow*>(m_engine->rootObjects().at(0));
window->setIcon(QIcon(":/res/mix_256x256x32.png"));
} }
MixApplication::~MixApplication() MixApplication::~MixApplication()

21
mix/MixApplication.h

@ -33,12 +33,33 @@ namespace dev
namespace mix namespace mix
{ {
class ApplicationService: public QObject
{
Q_OBJECT
Q_PROPERTY(int systemPointSize READ systemPointSize CONSTANT)
Q_PROPERTY(bool haveWebEngine READ haveWebEngine CONSTANT)
public:
ApplicationService();
int systemPointSize() const { return m_systemPointSize; }
#ifdef ETH_HAVE_WEBENGINE
bool haveWebEngine() const { return true; }
#else
bool haveWebEngine() const { return false; }
#endif
private:
int m_systemPointSize = 0;
};
class MixApplication: public QApplication class MixApplication: public QApplication
{ {
Q_OBJECT Q_OBJECT
public: public:
MixApplication(int& _argc, char* _argv[]); MixApplication(int& _argc, char* _argv[]);
static void initialize();
virtual ~MixApplication(); virtual ~MixApplication();
QQmlApplicationEngine* engine() { return m_engine.get(); } QQmlApplicationEngine* engine() { return m_engine.get(); }

41
mix/QBasicNodeDefinition.cpp

@ -0,0 +1,41 @@
/*
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 QBasicNodeDefinition.cpp
* @author Yann yann@ethdev.com
* @date 2014
*/
#include "QBasicNodeDefinition.h"
#include <libsolidity/AST.h>
namespace dev
{
namespace mix
{
QBasicNodeDefinition::QBasicNodeDefinition(QObject* _parent, solidity::Declaration const* _d):
QObject(_parent), m_name(QString::fromStdString(_d->getName()))
{
}
QBasicNodeDefinition::QBasicNodeDefinition(QObject* _parent, std::string const& _name):
QObject(_parent), m_name(QString::fromStdString(_name))
{
}
}
}

12
mix/QBasicNodeDefinition.h

@ -21,11 +21,17 @@
#pragma once #pragma once
#include <string>
#include <QObject> #include <QObject>
#include <libsolidity/AST.h>
namespace dev namespace dev
{ {
namespace solidity
{
class Declaration;
}
namespace mix namespace mix
{ {
@ -37,8 +43,8 @@ class QBasicNodeDefinition: public QObject
public: public:
QBasicNodeDefinition(QObject* _parent = nullptr): QObject(_parent) {} QBasicNodeDefinition(QObject* _parent = nullptr): QObject(_parent) {}
~QBasicNodeDefinition() {} ~QBasicNodeDefinition() {}
QBasicNodeDefinition(QObject* _parent, solidity::Declaration const* _d): QObject(_parent), m_name(QString::fromStdString(_d->getName())) {} QBasicNodeDefinition(QObject* _parent, solidity::Declaration const* _d);
QBasicNodeDefinition(QObject* _parent, std::string const& _name): QObject(_parent), m_name(QString::fromStdString(_name)) {} QBasicNodeDefinition(QObject* _parent, std::string const& _name);
/// Get the name of the node. /// Get the name of the node.
QString name() const { return m_name; } QString name() const { return m_name; }

1
mix/QVariableDeclaration.cpp

@ -21,6 +21,7 @@
*/ */
#include "QVariableDeclaration.h" #include "QVariableDeclaration.h"
#include <libsolidity/AST.h>
#include "CodeModel.h" #include "CodeModel.h"
namespace dev namespace dev

5
mix/QVariableDeclaration.h

@ -26,14 +26,15 @@
#pragma once #pragma once
namespace dev
{
namespace solidity namespace solidity
{ {
class Type; class Type;
class VariableDeclaration; class VariableDeclaration;
} }
namespace dev
{
namespace mix namespace mix
{ {

37
mix/QVariableDefinition.cpp

@ -0,0 +1,37 @@
/*
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 QVariableDefinition.cpp
* @author Yann yann@ethdev.com
* @date 2014
*/
#include "QVariableDefinition.h"
#include <libdevcore/CommonJS.h>
namespace dev
{
namespace mix
{
QString QVariableDefinition::encodeValueAsString()
{
return QString::fromStdString(dev::toHex(encodeValue()));
}
}
}

8
mix/QVariableDefinition.h

@ -21,14 +21,14 @@
#pragma once #pragma once
#include <QAbstractListModel> #include <QObject>
#include "QBigInt.h" #include <libdevcore/Common.h>
#include "QVariableDeclaration.h"
namespace dev namespace dev
{ {
namespace mix namespace mix
{ {
class QVariableDeclaration;
class QVariableDefinition: public QObject class QVariableDefinition: public QObject
{ {
@ -54,7 +54,7 @@ public:
/// Decode the return value @a _rawValue. /// Decode the return value @a _rawValue.
virtual void decodeValue(dev::bytes const& _rawValue) = 0; virtual void decodeValue(dev::bytes const& _rawValue) = 0;
/// returns String representation of the encoded value. /// returns String representation of the encoded value.
Q_INVOKABLE QString encodeValueAsString() { return QString::fromStdString(dev::toHex(encodeValue())); } Q_INVOKABLE QString encodeValueAsString();
protected: protected:
QString m_value; QString m_value;

18
mix/main.cpp

@ -22,27 +22,17 @@
#include <iostream> #include <iostream>
#include <stdlib.h> #include <stdlib.h>
#include <boost/exception/exception.hpp>
#include <boost/exception/diagnostic_information.hpp>
#include "MixApplication.h" #include "MixApplication.h"
#include "Exceptions.h"
using namespace dev::mix; using namespace dev::mix;
int main(int _argc, char* _argv[]) int main(int _argc, char* _argv[])
{ {
#ifdef ETH_HAVE_WEBENGINE
Q_INIT_RESOURCE(js);
#endif
#if __linux
//work around ubuntu appmenu-qt5 bug
//https://bugs.launchpad.net/ubuntu/+source/appmenu-qt5/+bug/1323853
putenv((char*)"QT_QPA_PLATFORMTHEME=");
putenv((char*)"QSG_RENDER_LOOP=threaded");
#endif
#if (defined(_WIN32) || defined(_WIN64))
if (!getenv("OPENSSL_CONF"))
putenv((char*)"OPENSSL_CONF=c:\\");
#endif
try try
{ {
MixApplication::initialize();
MixApplication app(_argc, _argv); MixApplication app(_argc, _argv);
return app.exec(); return app.exec();
} }

5
mix/qml.qrc

@ -1,6 +1,7 @@
<RCC> <RCC>
<qresource prefix="/"> <qresource prefix="/">
<file>qml/AlertMessageDialog.qml</file> <file>qml/AlertMessageDialog.qml</file>
<file>qml/Application.qml</file>
<file>qml/BasicMessage.qml</file> <file>qml/BasicMessage.qml</file>
<file>qml/BigIntValue.qml</file> <file>qml/BigIntValue.qml</file>
<file>qml/CallStack.qml</file> <file>qml/CallStack.qml</file>
@ -47,6 +48,7 @@
<file>qml/StatusPaneStyle.qml</file> <file>qml/StatusPaneStyle.qml</file>
<file>qml/StepActionImage.qml</file> <file>qml/StepActionImage.qml</file>
<file>qml/StorageView.qml</file> <file>qml/StorageView.qml</file>
<file>qml/StatesComboBox.qml</file>
<file>qml/StructView.qml</file> <file>qml/StructView.qml</file>
<file>qml/Style.qml</file> <file>qml/Style.qml</file>
<file>qml/TabStyle.qml</file> <file>qml/TabStyle.qml</file>
@ -59,8 +61,5 @@
<file>qml/js/ProjectModel.js</file> <file>qml/js/ProjectModel.js</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/main.qml</file>
<file>qml/qmldir</file>
<file>qml/StatesComboBox.qml</file>
</qresource> </qresource>
</RCC> </RCC>

15
mix/qml/main.qml → mix/qml/Application.qml

@ -11,6 +11,7 @@ import org.ethereum.qml.CodeModel 1.0
import org.ethereum.qml.ClientModel 1.0 import org.ethereum.qml.ClientModel 1.0
import org.ethereum.qml.FileIo 1.0 import org.ethereum.qml.FileIo 1.0
import org.ethereum.qml.Clipboard 1.0 import org.ethereum.qml.Clipboard 1.0
import org.ethereum.qml.ApplicationService 1.0
ApplicationWindow { ApplicationWindow {
@ -22,6 +23,16 @@ ApplicationWindow {
minimumWidth: 400 minimumWidth: 400
minimumHeight: 300 minimumHeight: 300
title: qsTr("Mix") title: qsTr("Mix")
property alias systemPointSize: appService.systemPointSize;
property alias mainContent: mainContent;
property alias codeModel: codeModel;
property alias clientModel: clientModel;
property alias projectModel: projectModel;
property alias appService: appService;
ApplicationService {
id: appService
}
CodeModel { CodeModel {
id: codeModel id: codeModel
@ -44,6 +55,10 @@ ApplicationWindow {
id: clipboard id: clipboard
} }
Style {
id: appStyle
}
Connections { Connections {
target: mainApplication target: mainApplication
onClosing: onClosing:

5
mix/qml/CallStack.qml

@ -2,7 +2,6 @@ import QtQuick 2.2
import QtQuick.Controls 1.1 import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1 import QtQuick.Controls.Styles 1.1
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import "."
DebugInfoList DebugInfoList
{ {
@ -37,7 +36,7 @@ DebugInfoList
anchors.leftMargin: 5 anchors.leftMargin: 5
color: "#4a4a4a" color: "#4a4a4a"
text: styleData.row; text: styleData.row;
font.pointSize: DebuggerPaneStyle.general.basicFontSize font.pointSize: dbgStyle.general.basicFontSize
width: parent.width - 5 width: parent.width - 5
elide: Text.ElideRight elide: Text.ElideRight
} }
@ -58,7 +57,7 @@ DebugInfoList
color: "#4a4a4a" color: "#4a4a4a"
text: styleData.value; text: styleData.value;
elide: Text.ElideRight elide: Text.ElideRight
font.pointSize: DebuggerPaneStyle.general.basicFontSize font.pointSize: dbgStyle.general.basicFontSize
} }
} }
} }

7
mix/qml/CodeEditor.qml

@ -24,6 +24,11 @@ Item {
id: contentView id: contentView
width: parent.width width: parent.width
height: parent.height * 0.7 height: parent.height * 0.7
CodeEditorStyle {
id: style
}
Rectangle { Rectangle {
id: lineColumn id: lineColumn
property int rowHeight: codeEditor.font.pixelSize + 3 property int rowHeight: codeEditor.font.pixelSize + 3
@ -66,7 +71,7 @@ Item {
height: parent.height height: parent.height
font.family: "Monospace" font.family: "Monospace"
font.pointSize: CodeEditorStyle.general.basicFontSize font.pointSize: style.general.basicFontSize
width: parent.width width: parent.width
tabChangesFocus: false tabChangesFocus: false

1
mix/qml/CodeEditorStyle.qml

@ -1,4 +1,3 @@
pragma Singleton
import QtQuick 2.0 import QtQuick 2.0
QtObject { QtObject {

43
mix/qml/CodeEditorView.qml

@ -7,13 +7,15 @@ import QtQuick.Dialogs 1.1
Item { Item {
id: codeEditorView id: codeEditorView
property string currentDocumentId: "" property string currentDocumentId: ""
property int openDocCount: 0
signal documentEdit(string documentId) signal documentEdit(string documentId)
signal breakpointsChanged(string documentId) signal breakpointsChanged(string documentId)
signal isCleanChanged(var isClean, string documentId) signal isCleanChanged(var isClean, string documentId)
signal loadComplete
function getDocumentText(documentId) { function getDocumentText(documentId) {
for (var i = 0; i < editorListModel.count; i++) { for (var i = 0; i < openDocCount; i++) {
if (editorListModel.get(i).documentId === documentId) { if (editorListModel.get(i).documentId === documentId) {
return editors.itemAt(i).item.getText(); return editors.itemAt(i).item.getText();
} }
@ -22,7 +24,7 @@ Item {
} }
function isDocumentOpen(documentId) { function isDocumentOpen(documentId) {
for (var i = 0; i < editorListModel.count; i++) for (var i = 0; i < openDocCount; i++)
if (editorListModel.get(i).documentId === documentId && if (editorListModel.get(i).documentId === documentId &&
editors.itemAt(i).item) editors.itemAt(i).item)
return true; return true;
@ -35,15 +37,27 @@ Item {
} }
function loadDocument(document) { function loadDocument(document) {
for (var i = 0; i < editorListModel.count; i++) for (var i = 0; i < openDocCount; i++)
if (editorListModel.get(i).documentId === document.documentId) if (editorListModel.get(i).documentId === document.documentId)
return; //already open return; //already open
if (editorListModel.count <= openDocCount)
editorListModel.append(document); editorListModel.append(document);
else
{
editorListModel.set(openDocCount, document);
editors.itemAt(openDocCount).visible = true;
doLoadDocument(editors.itemAt(openDocCount).item, editorListModel.get(openDocCount))
}
openDocCount++;
} }
function doLoadDocument(editor, document) { function doLoadDocument(editor, document) {
var data = fileIo.readFile(document.path); var data = fileIo.readFile(document.path);
editor.onLoadComplete.connect(function() {
loadComplete();
});
editor.onEditorTextChanged.connect(function() { editor.onEditorTextChanged.connect(function() {
documentEdit(document.documentId); documentEdit(document.documentId);
if (document.isContract) if (document.isContract)
@ -60,7 +74,7 @@ Item {
} }
function getEditor(documentId) { function getEditor(documentId) {
for (var i = 0; i < editorListModel.count; i++) for (var i = 0; i < openDocCount; i++)
{ {
if (editorListModel.get(i).documentId === documentId) if (editorListModel.get(i).documentId === documentId)
return editors.itemAt(i).item; return editors.itemAt(i).item;
@ -91,7 +105,7 @@ Item {
} }
function editingContract() { function editingContract() {
for (var i = 0; i < editorListModel.count; i++) for (var i = 0; i < openDocCount; i++)
if (editorListModel.get(i).documentId === currentDocumentId) if (editorListModel.get(i).documentId === currentDocumentId)
return editorListModel.get(i).isContract; return editorListModel.get(i).isContract;
return false; return false;
@ -99,7 +113,7 @@ Item {
function getBreakpoints() { function getBreakpoints() {
var bpMap = {}; var bpMap = {};
for (var i = 0; i < editorListModel.count; i++) { for (var i = 0; i < openDocCount; i++) {
var documentId = editorListModel.get(i).documentId; var documentId = editorListModel.get(i).documentId;
var editor = editors.itemAt(i).item; var editor = editors.itemAt(i).item;
if (editor) { if (editor) {
@ -130,7 +144,7 @@ Item {
} }
onProjectSaving: { onProjectSaving: {
for (var i = 0; i < editorListModel.count; i++) for (var i = 0; i < openDocCount; i++)
{ {
var doc = editorListModel.get(i); var doc = editorListModel.get(i);
var editor = editors.itemAt(i).item; var editor = editors.itemAt(i).item;
@ -142,7 +156,7 @@ Item {
onProjectSaved: { onProjectSaved: {
if (projectModel.appIsClosing || projectModel.projectIsClosing) if (projectModel.appIsClosing || projectModel.projectIsClosing)
return; return;
for (var i = 0; i < editorListModel.count; i++) for (var i = 0; i < openDocCount; i++)
{ {
var doc = editorListModel.get(i); var doc = editorListModel.get(i);
resetEditStatus(doc.documentId); resetEditStatus(doc.documentId);
@ -152,8 +166,9 @@ Item {
onProjectClosed: { onProjectClosed: {
for (var i = 0; i < editorListModel.count; i++) for (var i = 0; i < editorListModel.count; i++)
editors.itemAt(i).visible = false; editors.itemAt(i).visible = false;
editorListModel.clear(); //editorListModel.clear();
currentDocumentId = ""; currentDocumentId = "";
openDocCount = 0;
} }
onDocumentSaved: { onDocumentSaved: {
@ -177,6 +192,11 @@ Item {
} }
} }
CodeEditorStyle
{
id: style;
}
MessageDialog MessageDialog
{ {
id: messageDialog id: messageDialog
@ -194,12 +214,15 @@ Item {
Repeater { Repeater {
id: editors id: editors
model: editorListModel model: editorListModel
onItemRemoved: {
item.item.unloaded = true;
}
delegate: Loader { delegate: Loader {
id: loader id: loader
active: false active: false
asynchronous: true asynchronous: true
anchors.fill: parent anchors.fill: parent
source: "CodeEditor.qml" source: appService.haveWebEngine ? "WebCodeEditor.qml" : "CodeEditor.qml"
visible: (index >= 0 && index < editorListModel.count && currentDocumentId === editorListModel.get(index).documentId) visible: (index >= 0 && index < editorListModel.count && currentDocumentId === editorListModel.get(index).documentId)
property bool changed: false property bool changed: false
onVisibleChanged: { onVisibleChanged: {

2
mix/qml/CommonSeparator.qml

@ -4,6 +4,6 @@ import "."
Rectangle Rectangle
{ {
height: 1 height: 1
color: Style.generic.layout.separatorColor color: appStyle.generic.layout.separatorColor
} }

12
mix/qml/Debugger.qml

@ -65,6 +65,10 @@ Rectangle {
Debugger.setBreakpoints(bp); Debugger.setBreakpoints(bp);
} }
DebuggerPaneStyle {
id: dbgStyle
}
Connections { Connections {
target: clientModel target: clientModel
onDebugDataReady: { onDebugDataReady: {
@ -449,7 +453,7 @@ Rectangle {
color: "#b2b3ae" color: "#b2b3ae"
text: styleData.value.split(' ')[0] text: styleData.value.split(' ')[0]
font.family: "monospace" font.family: "monospace"
font.pointSize: DebuggerPaneStyle.general.basicFontSize font.pointSize: dbgStyle.general.basicFontSize
wrapMode: Text.NoWrap wrapMode: Text.NoWrap
id: id id: id
} }
@ -459,7 +463,7 @@ Rectangle {
color: styleData.selected ? "white" : "black" color: styleData.selected ? "white" : "black"
font.family: "monospace" font.family: "monospace"
text: styleData.value.replace(styleData.value.split(' ')[0], '') text: styleData.value.replace(styleData.value.split(' ')[0], '')
font.pointSize: DebuggerPaneStyle.general.basicFontSize font.pointSize: dbgStyle.general.basicFontSize
} }
} }
} }
@ -532,7 +536,7 @@ Rectangle {
font.family: "monospace" font.family: "monospace"
color: "#4a4a4a" color: "#4a4a4a"
text: styleData.row; text: styleData.row;
font.pointSize: DebuggerPaneStyle.general.basicFontSize font.pointSize: dbgStyle.general.basicFontSize
} }
} }
@ -550,7 +554,7 @@ Rectangle {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
color: "#4a4a4a" color: "#4a4a4a"
text: styleData.value text: styleData.value
font.pointSize: DebuggerPaneStyle.general.basicFontSize font.pointSize: dbgStyle.general.basicFontSize
} }
} }
} }

1
mix/qml/DebuggerPaneStyle.qml

@ -1,4 +1,3 @@
pragma Singleton
import QtQuick 2.0 import QtQuick 2.0
QtObject { QtObject {

1
mix/qml/DefaultLabel.qml

@ -1,6 +1,5 @@
import QtQuick 2.0 import QtQuick 2.0
import QtQuick.Controls 1.1 import QtQuick.Controls 1.1
import "."
Label { Label {
text: text text: text

4
mix/qml/DeploymentDialog.qml

@ -31,7 +31,7 @@ Window {
property string currentAccount property string currentAccount
property alias gasToUse: gasToUseInput.text property alias gasToUse: gasToUseInput.text
color: Style.generic.layout.backgroundColor color: appStyle.generic.layout.backgroundColor
function close() function close()
{ {
@ -329,7 +329,7 @@ Window {
anchors.verticalCenter: parent.verticalCenter; anchors.verticalCenter: parent.verticalCenter;
anchors.left: applicationUrlEth.right anchors.left: applicationUrlEth.right
font.italic: true font.italic: true
font.pointSize: Style.absoluteSize(-1) font.pointSize: appStyle.absoluteSize(-1)
} }
} }
} }

30
mix/qml/FilesSection.qml

@ -18,21 +18,21 @@ Rectangle
property string sectionName; property string sectionName;
property variant selManager; property variant selManager;
property int index; property int index;
color: index % 2 === 0 ? "transparent" : ProjectFilesStyle.title.background color: index % 2 === 0 ? "transparent" : projectFilesStyle.title.background
function hiddenHeightTopLevel() function hiddenHeightTopLevel()
{ {
return section.state === "hidden" ? ProjectFilesStyle.documentsList.height : ProjectFilesStyle.documentsList.fileNameHeight * model.count + ProjectFilesStyle.documentsList.height; return section.state === "hidden" ? projectFilesStyle.documentsList.height : projectFilesStyle.documentsList.fileNameHeight * model.count + projectFilesStyle.documentsList.height;
} }
function hiddenHeightRepeater() function hiddenHeightRepeater()
{ {
return section.state === "hidden" ? 0 : ProjectFilesStyle.documentsList.fileNameHeight * wrapperItem.model.count; return section.state === "hidden" ? 0 : projectFilesStyle.documentsList.fileNameHeight * wrapperItem.model.count;
} }
function hiddenHeightElement() function hiddenHeightElement()
{ {
return section.state === "hidden" ? 0 : ProjectFilesStyle.documentsList.fileNameHeight; return section.state === "hidden" ? 0 : projectFilesStyle.documentsList.fileNameHeight;
} }
function getDocumentIndex(documentId) function getDocumentIndex(documentId)
@ -68,7 +68,7 @@ Rectangle
{ {
anchors.top: parent.top anchors.top: parent.top
id: rowCol id: rowCol
height: ProjectFilesStyle.documentsList.height height: projectFilesStyle.documentsList.height
Layout.fillWidth: true Layout.fillWidth: true
@ -88,15 +88,15 @@ Rectangle
id: section id: section
text: sectionName text: sectionName
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: ProjectFilesStyle.general.leftMargin anchors.leftMargin: projectFilesStyle.general.leftMargin
color: ProjectFilesStyle.documentsList.sectionColor color: projectFilesStyle.documentsList.sectionColor
font.family: boldFont.name font.family: boldFont.name
font.pointSize: ProjectFilesStyle.documentsList.sectionFontSize font.pointSize: projectFilesStyle.documentsList.sectionFontSize
states: [ states: [
State { State {
name: "hidden" name: "hidden"
PropertyChanges { target: filesList; visible: false; } PropertyChanges { target: filesList; visible: false; }
PropertyChanges { target: rowCol; Layout.minimumHeight: ProjectFilesStyle.documentsList.height; Layout.maximumHeight: ProjectFilesStyle.documentsList.height; height: ProjectFilesStyle.documentsList.height; } PropertyChanges { target: rowCol; Layout.minimumHeight: projectFilesStyle.documentsList.height; Layout.maximumHeight: projectFilesStyle.documentsList.height; height: projectFilesStyle.documentsList.height; }
PropertyChanges { target: imgArrow; source: "qrc:/qml/img/closedtriangleindicator_filesproject.png" } PropertyChanges { target: imgArrow; source: "qrc:/qml/img/closedtriangleindicator_filesproject.png" }
} }
] ]
@ -138,7 +138,7 @@ Rectangle
Layout.preferredHeight: wrapperItem.hiddenHeightElement() Layout.preferredHeight: wrapperItem.hiddenHeightElement()
Layout.maximumHeight: wrapperItem.hiddenHeightElement() Layout.maximumHeight: wrapperItem.hiddenHeightElement()
height: wrapperItem.hiddenHeightElement() height: wrapperItem.hiddenHeightElement()
color: isSelected ? ProjectFilesStyle.documentsList.highlightColor : "transparent" color: isSelected ? projectFilesStyle.documentsList.highlightColor : "transparent"
property bool isSelected property bool isSelected
property bool renameMode property bool renameMode
@ -147,15 +147,15 @@ Rectangle
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.fill: parent anchors.fill: parent
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: ProjectFilesStyle.general.leftMargin + 2 anchors.leftMargin: projectFilesStyle.general.leftMargin + 2
Text { Text {
id: nameText id: nameText
height: parent.height height: parent.height
visible: !renameMode visible: !renameMode
color: rootItem.isSelected ? ProjectFilesStyle.documentsList.selectedColor : ProjectFilesStyle.documentsList.color color: rootItem.isSelected ? projectFilesStyle.documentsList.selectedColor : projectFilesStyle.documentsList.color
text: name; text: name;
font.family: fileNameFont.name font.family: fileNameFont.name
font.pointSize: ProjectFilesStyle.documentsList.fontSize font.pointSize: projectFilesStyle.documentsList.fontSize
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
Connections Connections
@ -182,7 +182,7 @@ Rectangle
DefaultLabel { DefaultLabel {
id: editStatusLabel id: editStatusLabel
visible: false visible: false
color: rootItem.isSelected ? ProjectFilesStyle.documentsList.selectedColor : ProjectFilesStyle.documentsList.color color: rootItem.isSelected ? projectFilesStyle.documentsList.selectedColor : projectFilesStyle.documentsList.color
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
text: "*" text: "*"
width: 10 width: 10
@ -196,7 +196,7 @@ Rectangle
visible: renameMode visible: renameMode
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: ProjectFilesStyle.general.leftMargin anchors.leftMargin: projectFilesStyle.general.leftMargin
MouseArea { MouseArea {
id: textMouseArea id: textMouseArea
anchors.fill: parent anchors.fill: parent

4
mix/qml/ItemDelegateDataDump.qml

@ -28,7 +28,7 @@ Rectangle {
font.bold: true font.bold: true
color: "#4a4a4a" color: "#4a4a4a"
text: modelData[0] text: modelData[0]
font.pointSize: DebuggerPaneStyle.general.dataDumpFontSize; font.pointSize: dbgStyle.general.dataDumpFontSize;
} }
} }
@ -47,7 +47,7 @@ Rectangle {
anchors.leftMargin: 4 anchors.leftMargin: 4
color: "#4a4a4a" color: "#4a4a4a"
text: modelData[1] text: modelData[1]
font.pointSize: DebuggerPaneStyle.general.dataDumpFontSize font.pointSize: dbgStyle.general.dataDumpFontSize
} }
} }
} }

115
mix/qml/LogsPane.qml

@ -3,7 +3,6 @@ import QtQuick.Layouts 1.0
import QtQuick.Controls 1.1 import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.3 import QtQuick.Controls.Styles 1.3
import org.ethereum.qml.SortFilterProxyModel 1.0 import org.ethereum.qml.SortFilterProxyModel 1.0
import "."
Rectangle Rectangle
{ {
@ -28,6 +27,10 @@ Rectangle
} }
} }
LogsPaneStyle {
id: logStyle
}
anchors.fill: parent anchors.fill: parent
radius: 10 radius: 10
color: "transparent" color: "transparent"
@ -99,15 +102,15 @@ Rectangle
Rectangle Rectangle
{ {
width: LogsPaneStyle.generic.layout.dateWidth + LogsPaneStyle.generic.layout.contentWidth + LogsPaneStyle.generic.layout.typeWidth width: logStyle.generic.layout.dateWidth + logStyle.generic.layout.contentWidth + logStyle.generic.layout.typeWidth
height: 30 height: 30
color: color:
{ {
var cl; var cl;
if (level === "warning" || level === "error") if (level === "warning" || level === "error")
cl = LogsPaneStyle.generic.layout.errorColor; cl = logStyle.generic.layout.errorColor;
else else
cl = index % 2 === 0 ? "transparent" : LogsPaneStyle.generic.layout.logAlternateColor; cl = index % 2 === 0 ? "transparent" : logStyle.generic.layout.logAlternateColor;
if (index === 0) if (index === 0)
logsRepeater.frontColor = cl; logsRepeater.frontColor = cl;
return cl; return cl;
@ -137,9 +140,9 @@ Rectangle
DefaultLabel { DefaultLabel {
text: date; text: date;
font.family: LogsPaneStyle.generic.layout.logLabelFont font.family: logStyle.generic.layout.logLabelFont
width: LogsPaneStyle.generic.layout.dateWidth width: logStyle.generic.layout.dateWidth
font.pointSize: Style.absoluteSize(-1) font.pointSize: appStyle.absoluteSize(-1)
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: 15 anchors.leftMargin: 15
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
@ -150,9 +153,9 @@ Rectangle
DefaultLabel { DefaultLabel {
text: type; text: type;
font.family: LogsPaneStyle.generic.layout.logLabelFont font.family: logStyle.generic.layout.logLabelFont
width: LogsPaneStyle.generic.layout.typeWidth width: logStyle.generic.layout.typeWidth
font.pointSize: Style.absoluteSize(-1) font.pointSize: appStyle.absoluteSize(-1)
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: 100 anchors.leftMargin: 100
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
@ -164,9 +167,9 @@ Rectangle
Text { Text {
id: logContent id: logContent
text: content; text: content;
font.family: LogsPaneStyle.generic.layout.logLabelFont font.family: logStyle.generic.layout.logLabelFont
width: LogsPaneStyle.generic.layout.contentWidth width: logStyle.generic.layout.contentWidth
font.pointSize: Style.absoluteSize(-1) font.pointSize: appStyle.absoluteSize(-1)
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
elide: Text.ElideRight elide: Text.ElideRight
anchors.left: parent.left anchors.left: parent.left
@ -194,8 +197,8 @@ Rectangle
id: itemDelegate id: itemDelegate
DefaultLabel { DefaultLabel {
text: styleData.value; text: styleData.value;
font.family: LogsPaneStyle.generic.layout.logLabelFont font.family: logStyle.generic.layout.logLabelFont
font.pointSize: Style.absoluteSize(-1) font.pointSize: appStyle.absoluteSize(-1)
color: { color: {
if (proxyModel.get(styleData.row).level === "error") if (proxyModel.get(styleData.row).level === "error")
return "red"; return "red";
@ -214,16 +217,16 @@ Rectangle
GradientStop { position: 0.0; color: "#f1f1f1" } GradientStop { position: 0.0; color: "#f1f1f1" }
GradientStop { position: 1.0; color: "#d9d7da" } GradientStop { position: 1.0; color: "#d9d7da" }
} }
Layout.preferredHeight: LogsPaneStyle.generic.layout.headerHeight Layout.preferredHeight: logStyle.generic.layout.headerHeight
height: LogsPaneStyle.generic.layout.headerHeight height: logStyle.generic.layout.headerHeight
width: logsPane.width width: logsPane.width
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
Row Row
{ {
id: rowAction id: rowAction
anchors.leftMargin: LogsPaneStyle.generic.layout.leftMargin anchors.leftMargin: logStyle.generic.layout.leftMargin
anchors.left: parent.left anchors.left: parent.left
spacing: LogsPaneStyle.generic.layout.headerButtonSpacing spacing: logStyle.generic.layout.headerButtonSpacing
height: parent.height height: parent.height
Rectangle Rectangle
{ {
@ -233,9 +236,9 @@ Rectangle
DefaultLabel DefaultLabel
{ {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
color: LogsPaneStyle.generic.layout.logLabelColor color: logStyle.generic.layout.logLabelColor
font.pointSize: Style.absoluteSize(-3) font.pointSize: appStyle.absoluteSize(-3)
font.family: LogsPaneStyle.generic.layout.logLabelFont font.family: logStyle.generic.layout.logLabelFont
text: qsTr("Show:") text: qsTr("Show:")
} }
} }
@ -244,20 +247,20 @@ Rectangle
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
width: 1; width: 1;
height: parent.height height: parent.height
color: LogsPaneStyle.generic.layout.buttonSeparatorColor1 color: logStyle.generic.layout.buttonSeparatorColor1
} }
Rectangle { Rectangle {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
width: 2; width: 2;
height: parent.height height: parent.height
color: LogsPaneStyle.generic.layout.buttonSeparatorColor2 color: logStyle.generic.layout.buttonSeparatorColor2
} }
ToolButton { ToolButton {
id: javascriptButton id: javascriptButton
checkable: true checkable: true
height: LogsPaneStyle.generic.layout.headerButtonHeight height: logStyle.generic.layout.headerButtonHeight
width: 20 width: 20
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
checked: true checked: true
@ -270,16 +273,16 @@ Rectangle
label: label:
Item { Item {
DefaultLabel { DefaultLabel {
font.family: LogsPaneStyle.generic.layout.logLabelFont font.family: logStyle.generic.layout.logLabelFont
font.pointSize: Style.absoluteSize(-3) font.pointSize: appStyle.absoluteSize(-3)
color: LogsPaneStyle.generic.layout.logLabelColor color: logStyle.generic.layout.logLabelColor
anchors.centerIn: parent anchors.centerIn: parent
text: qsTr("JS") text: qsTr("JS")
} }
} }
background: background:
Rectangle { Rectangle {
color: javascriptButton.checked ? LogsPaneStyle.generic.layout.buttonSelected : "transparent" color: javascriptButton.checked ? logStyle.generic.layout.buttonSelected : "transparent"
} }
} }
} }
@ -288,20 +291,20 @@ Rectangle
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
width: 1; width: 1;
height: parent.height height: parent.height
color: LogsPaneStyle.generic.layout.buttonSeparatorColor1 color: logStyle.generic.layout.buttonSeparatorColor1
} }
Rectangle { Rectangle {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
width: 2; width: 2;
height: parent.height height: parent.height
color: LogsPaneStyle.generic.layout.buttonSeparatorColor2 color: logStyle.generic.layout.buttonSeparatorColor2
} }
ToolButton { ToolButton {
id: runButton id: runButton
checkable: true checkable: true
height: LogsPaneStyle.generic.layout.headerButtonHeight height: logStyle.generic.layout.headerButtonHeight
width: 30 width: 30
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
checked: true checked: true
@ -314,16 +317,16 @@ Rectangle
label: label:
Item { Item {
DefaultLabel { DefaultLabel {
font.family: LogsPaneStyle.generic.layout.logLabelFont font.family: logStyle.generic.layout.logLabelFont
font.pointSize: Style.absoluteSize(-3) font.pointSize: appStyle.absoluteSize(-3)
color: LogsPaneStyle.generic.layout.logLabelColor color: logStyle.generic.layout.logLabelColor
anchors.centerIn: parent anchors.centerIn: parent
text: qsTr("Run") text: qsTr("Run")
} }
} }
background: background:
Rectangle { Rectangle {
color: runButton.checked ? LogsPaneStyle.generic.layout.buttonSelected : "transparent" color: runButton.checked ? logStyle.generic.layout.buttonSelected : "transparent"
} }
} }
} }
@ -332,20 +335,20 @@ Rectangle
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
width: 1; width: 1;
height: parent.height height: parent.height
color: LogsPaneStyle.generic.layout.buttonSeparatorColor1 color: logStyle.generic.layout.buttonSeparatorColor1
} }
Rectangle { Rectangle {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
width: 2; width: 2;
height: parent.height height: parent.height
color: LogsPaneStyle.generic.layout.buttonSeparatorColor2 color: logStyle.generic.layout.buttonSeparatorColor2
} }
ToolButton { ToolButton {
id: stateButton id: stateButton
checkable: true checkable: true
height: LogsPaneStyle.generic.layout.headerButtonHeight height: logStyle.generic.layout.headerButtonHeight
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
width: 35 width: 35
checked: true checked: true
@ -358,16 +361,16 @@ Rectangle
label: label:
Item { Item {
DefaultLabel { DefaultLabel {
font.family: LogsPaneStyle.generic.layout.logLabelFont font.family: logStyle.generic.layout.logLabelFont
font.pointSize: Style.absoluteSize(-3) font.pointSize: appStyle.absoluteSize(-3)
color: LogsPaneStyle.generic.layout.logLabelColor color: logStyle.generic.layout.logLabelColor
anchors.centerIn: parent anchors.centerIn: parent
text: qsTr("State") text: qsTr("State")
} }
} }
background: background:
Rectangle { Rectangle {
color: stateButton.checked ? LogsPaneStyle.generic.layout.buttonSelected : "transparent" color: stateButton.checked ? logStyle.generic.layout.buttonSelected : "transparent"
} }
} }
} }
@ -376,14 +379,14 @@ Rectangle
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
width: 1; width: 1;
height: parent.height height: parent.height
color: LogsPaneStyle.generic.layout.buttonSeparatorColor1 color: logStyle.generic.layout.buttonSeparatorColor1
} }
Rectangle { Rectangle {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
width: 2; width: 2;
height: parent.height height: parent.height
color: LogsPaneStyle.generic.layout.buttonSeparatorColor2 color: logStyle.generic.layout.buttonSeparatorColor2
} }
} }
@ -395,7 +398,7 @@ Rectangle
spacing: 10 spacing: 10
Rectangle Rectangle
{ {
height: LogsPaneStyle.generic.layout.headerButtonHeight height: logStyle.generic.layout.headerButtonHeight
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
color: "transparent" color: "transparent"
width: 20 width: 20
@ -410,8 +413,8 @@ Rectangle
ButtonStyle { ButtonStyle {
background: background:
Rectangle { Rectangle {
height: LogsPaneStyle.generic.layout.headerButtonHeight height: logStyle.generic.layout.headerButtonHeight
implicitHeight: LogsPaneStyle.generic.layout.headerButtonHeight implicitHeight: logStyle.generic.layout.headerButtonHeight
color: "transparent" color: "transparent"
} }
} }
@ -438,7 +441,7 @@ Rectangle
Rectangle Rectangle
{ {
height: LogsPaneStyle.generic.layout.headerButtonHeight height: logStyle.generic.layout.headerButtonHeight
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
color: "transparent" color: "transparent"
width: 20 width: 20
@ -453,8 +456,8 @@ Rectangle
ButtonStyle { ButtonStyle {
background: background:
Rectangle { Rectangle {
height: LogsPaneStyle.generic.layout.headerButtonHeight height: logStyle.generic.layout.headerButtonHeight
implicitHeight: LogsPaneStyle.generic.layout.headerButtonHeight implicitHeight: logStyle.generic.layout.headerButtonHeight
color: "transparent" color: "transparent"
} }
} }
@ -510,8 +513,8 @@ Rectangle
width: 100 width: 100
anchors.left: searchImg.right anchors.left: searchImg.right
anchors.leftMargin: -7 anchors.leftMargin: -7
font.family: LogsPaneStyle.generic.layout.logLabelFont font.family: logStyle.generic.layout.logLabelFont
font.pointSize: Style.absoluteSize(-3) font.pointSize: appStyle.absoluteSize(-3)
font.italic: true font.italic: true
text: qsTr(" - Search - ") text: qsTr(" - Search - ")
onFocusChanged: onFocusChanged:
@ -540,7 +543,7 @@ Rectangle
Rectangle Rectangle
{ {
height: LogsPaneStyle.generic.layout.headerButtonHeight height: logStyle.generic.layout.headerButtonHeight
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
color: "transparent" color: "transparent"
width: 20 width: 20
@ -555,8 +558,8 @@ Rectangle
ButtonStyle { ButtonStyle {
background: background:
Rectangle { Rectangle {
height: LogsPaneStyle.generic.layout.headerButtonHeight height: logStyle.generic.layout.headerButtonHeight
implicitHeight: LogsPaneStyle.generic.layout.headerButtonHeight implicitHeight: logStyle.generic.layout.headerButtonHeight
color: "transparent" color: "transparent"
} }
} }

1
mix/qml/LogsPaneStyle.qml

@ -1,4 +1,3 @@
pragma Singleton
import QtQuick 2.0 import QtQuick 2.0
QtObject { QtObject {

1
mix/qml/MainContent.qml

@ -22,6 +22,7 @@ Rectangle {
property alias rightViewVisible: rightView.visible property alias rightViewVisible: rightView.visible
property alias webViewVisible: webPreview.visible property alias webViewVisible: webPreview.visible
property alias webView: webPreview
property alias projectViewVisible: projectList.visible property alias projectViewVisible: projectList.visible
property alias runOnProjectLoad: mainSettings.runOnProjectLoad property alias runOnProjectLoad: mainSettings.runOnProjectLoad
property alias rightPane: rightView property alias rightPane: rightView

1
mix/qml/NewProjectDialog.qml

@ -15,6 +15,7 @@ Window {
property alias projectTitle: titleField.text property alias projectTitle: titleField.text
readonly property string projectPath: "file://" + pathField.text readonly property string projectPath: "file://" + pathField.text
property alias pathFieldText: pathField.text
signal accepted signal accepted
function open() { function open() {

1
mix/qml/ProjectFilesStyle.qml

@ -1,4 +1,3 @@
pragma Singleton
import QtQuick 2.0 import QtQuick 2.0
QtObject { QtObject {

21
mix/qml/ProjectList.qml

@ -8,6 +8,11 @@ import "."
Item { Item {
property bool renameMode: false; property bool renameMode: false;
ProjectFilesStyle {
id: projectFilesStyle
}
ColumnLayout { ColumnLayout {
anchors.fill: parent anchors.fill: parent
id: filesCol id: filesCol
@ -20,8 +25,8 @@ Item {
Rectangle Rectangle
{ {
color: ProjectFilesStyle.title.background color: projectFilesStyle.title.background
height: ProjectFilesStyle.title.height height: projectFilesStyle.title.height
Layout.fillWidth: true Layout.fillWidth: true
Image { Image {
id: projectIcon id: projectIcon
@ -37,14 +42,14 @@ Item {
Text Text
{ {
id: projectTitle id: projectTitle
color: ProjectFilesStyle.title.color color: projectFilesStyle.title.color
text: projectModel.projectTitle text: projectModel.projectTitle
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
visible: !projectModel.isEmpty; visible: !projectModel.isEmpty;
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: ProjectFilesStyle.general.leftMargin anchors.leftMargin: projectFilesStyle.general.leftMargin
font.family: srcSansProLight.name font.family: srcSansProLight.name
font.pointSize: ProjectFilesStyle.title.fontSize font.pointSize: projectFilesStyle.title.fontSize
font.weight: Font.Light font.weight: Font.Light
} }
@ -54,7 +59,7 @@ Item {
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 15 anchors.rightMargin: 15
font.family: srcSansProLight.name font.family: srcSansProLight.name
font.pointSize: ProjectFilesStyle.title.fontSize font.pointSize: projectFilesStyle.title.fontSize
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
font.weight: Font.Light font.weight: Font.Light
} }
@ -64,14 +69,14 @@ Item {
{ {
Layout.fillWidth: true Layout.fillWidth: true
height: 3 height: 3
color: ProjectFilesStyle.documentsList.background color: projectFilesStyle.documentsList.background
} }
Rectangle Rectangle
{ {
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
color: ProjectFilesStyle.documentsList.background color: projectFilesStyle.documentsList.background
ColumnLayout ColumnLayout
{ {

2
mix/qml/ProjectModel.qml

@ -43,8 +43,10 @@ Item {
property string deploymentDir property string deploymentDir
property var listModel: projectListModel property var listModel: projectListModel
property var stateListModel: projectStateListModel.model property var stateListModel: projectStateListModel.model
property alias stateDialog: projectStateListModel.stateDialog
property CodeEditorView codeEditor: null property CodeEditorView codeEditor: null
property var unsavedFiles: [] property var unsavedFiles: []
property alias newProjectDialog: newProjectDialog
//interface //interface
function saveAll() { ProjectModelCode.saveAll(); } function saveAll() { ProjectModelCode.saveAll(); }

3
mix/qml/Splitter.qml

@ -9,6 +9,3 @@ SplitView
color: "#cccccc" color: "#cccccc"
} }
} }

16
mix/qml/StateDialog.qml

@ -17,10 +17,12 @@ Window {
height: 480 height: 480
title: qsTr("Edit State") title: qsTr("Edit State")
visible: false visible: false
color: StateDialogStyle.generic.backgroundColor color: stateDialogStyle.generic.backgroundColor
property alias stateTitle: titleField.text property alias stateTitle: titleField.text
property alias isDefault: defaultCheckBox.checked property alias isDefault: defaultCheckBox.checked
property alias model: transactionsModel
property alias transactionDialog: transactionDialog
property int stateIndex property int stateIndex
property var stateTransactions: [] property var stateTransactions: []
property var stateAccounts: [] property var stateAccounts: []
@ -56,6 +58,11 @@ Window {
forceActiveFocus(); forceActiveFocus();
} }
function acceptAndClose() {
close();
accepted();
}
function close() { function close() {
visible = false; visible = false;
} }
@ -71,6 +78,10 @@ Window {
return item; return item;
} }
StateDialogStyle {
id: stateDialogStyle
}
ColumnLayout { ColumnLayout {
anchors.fill: parent anchors.fill: parent
anchors.margins: 10 anchors.margins: 10
@ -292,8 +303,7 @@ Window {
Button { Button {
text: qsTr("OK"); text: qsTr("OK");
onClicked: { onClicked: {
close(); acceptAndClose();
accepted();
} }
} }
Button { Button {

1
mix/qml/StateDialogStyle.qml

@ -1,4 +1,3 @@
pragma Singleton
import QtQuick 2.0 import QtQuick 2.0
QtObject { QtObject {

1
mix/qml/StateListModel.qml

@ -12,6 +12,7 @@ Item {
property alias model: stateListModel property alias model: stateListModel
property var stateList: [] property var stateList: []
property alias stateDialog: stateDialog
property string defaultAccount: "cb73d9408c4720e230387d956eb0f829d8a4dd2c1055f96257167e14e7169074" //support for old project property string defaultAccount: "cb73d9408c4720e230387d956eb0f829d8a4dd2c1055f96257167e14e7169074" //support for old project
function fromPlainStateItem(s) { function fromPlainStateItem(s) {

6
mix/qml/StatusPane.qml

@ -54,6 +54,10 @@ Rectangle {
currentStatus = { "type": type, "date": Qt.formatDateTime(new Date(), "hh:mm:ss"), "content": text, "level": "error" } currentStatus = { "type": type, "date": Qt.formatDateTime(new Date(), "hh:mm:ss"), "content": text, "level": "error" }
} }
StatusPaneStyle {
id: statusPaneStyle
}
Connections { Connections {
target: webPreview target: webPreview
onJavaScriptMessage: onJavaScriptMessage:
@ -123,7 +127,7 @@ Rectangle {
Text { Text {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
font.pointSize: Style.absoluteSize(-1) font.pointSize: appStyle.absoluteSize(-1)
height: 15 height: 15
font.family: "sans serif" font.family: "sans serif"
objectName: "status" objectName: "status"

1
mix/qml/StatusPaneStyle.qml

@ -1,4 +1,3 @@
pragma Singleton
import QtQuick 2.0 import QtQuick 2.0
QtObject { QtObject {

4
mix/qml/StorageView.qml

@ -29,7 +29,7 @@ DebugInfoList
anchors.leftMargin: 5 anchors.leftMargin: 5
color: "#4a4a4a" color: "#4a4a4a"
text: styleData.value.split('\t')[0]; text: styleData.value.split('\t')[0];
font.pointSize: DebuggerPaneStyle.general.basicFontSize font.pointSize: dbgStyle.general.basicFontSize
width: parent.width - 5 width: parent.width - 5
elide: Text.ElideRight elide: Text.ElideRight
} }
@ -52,7 +52,7 @@ DebugInfoList
color: "#4a4a4a" color: "#4a4a4a"
text: styleData.value.split('\t')[1]; text: styleData.value.split('\t')[1];
elide: Text.ElideRight elide: Text.ElideRight
font.pointSize: DebuggerPaneStyle.general.basicFontSize font.pointSize: dbgStyle.general.basicFontSize
} }
} }
} }

1
mix/qml/Style.qml

@ -1,4 +1,3 @@
pragma Singleton
import QtQuick 2.0 import QtQuick 2.0
QtObject { QtObject {

45
mix/qml/TransactionDialog.qml

@ -13,7 +13,7 @@ Window {
width: 520 width: 520
height: 500; height: 500;
visible: false visible: false
color: StateDialogStyle.generic.backgroundColor color: transactionDialogStyle.generic.backgroundColor
title: qsTr("Edit Transaction") title: qsTr("Edit Transaction")
property int transactionIndex property int transactionIndex
property alias gas: gasValueEdit.gasValue; property alias gas: gasValueEdit.gasValue;
@ -59,16 +59,7 @@ Window {
contractComboBox.currentIndex = contractIndex; contractComboBox.currentIndex = contractIndex;
loadFunctions(contractComboBox.currentValue()); loadFunctions(contractComboBox.currentValue());
selectFunction(functionId);
var functionIndex = -1;
for (var f = 0; f < functionsModel.count; f++)
if (functionsModel.get(f).text === item.functionId)
functionIndex = f;
if (functionIndex == -1 && functionsModel.count > 0)
functionIndex = 0; //@todo suggest unused function
functionComboBox.currentIndex = functionIndex;
paramsModel = []; paramsModel = [];
if (functionId !== contractComboBox.currentValue()) if (functionId !== contractComboBox.currentValue())
@ -87,9 +78,6 @@ Window {
visible = true; visible = true;
valueField.focus = true; valueField.focus = true;
modalTransactionDialog.height = (paramsModel.length > 0 ? 500 : 300);
paramLabel.visible = paramsModel.length > 0;
paramScroll.visible = paramsModel.length > 0;
} }
function loadFunctions(contractId) function loadFunctions(contractId)
@ -107,6 +95,19 @@ Window {
} }
function selectFunction(functionId)
{
var functionIndex = -1;
for (var f = 0; f < functionsModel.count; f++)
if (functionsModel.get(f).text === functionId)
functionIndex = f;
if (functionIndex == -1 && functionsModel.count > 0)
functionIndex = 0; //@todo suggest unused function
functionComboBox.currentIndex = functionIndex;
}
function loadParameter(parameter) function loadParameter(parameter)
{ {
var type = parameter.type; var type = parameter.type;
@ -136,6 +137,15 @@ Window {
typeLoader.members = [] typeLoader.members = []
typeLoader.value = paramValues; typeLoader.value = paramValues;
typeLoader.members = paramsModel; typeLoader.members = paramsModel;
paramLabel.visible = paramsModel.length > 0;
paramScroll.visible = paramsModel.length > 0;
modalTransactionDialog.height = (paramsModel.length > 0 ? 500 : 300);
}
function acceptAndClose()
{
close();
accepted();
} }
function close() function close()
@ -169,6 +179,10 @@ Window {
return item; return item;
} }
StateDialogStyle {
id: transactionDialogStyle
}
ColumnLayout { ColumnLayout {
anchors.fill: parent anchors.fill: parent
anchors.margins: 10 anchors.margins: 10
@ -365,8 +379,7 @@ Window {
Button { Button {
text: qsTr("OK"); text: qsTr("OK");
onClicked: { onClicked: {
close(); acceptAndClose();
accepted();
} }
} }
Button { Button {

17
mix/qml/WebCodeEditor.qml

@ -4,23 +4,27 @@ import QtQuick.Layouts 1.0
import QtQuick.Controls.Styles 1.1 import QtQuick.Controls.Styles 1.1
import QtWebEngine 1.0 import QtWebEngine 1.0
import QtWebEngine.experimental 1.0 import QtWebEngine.experimental 1.0
import org.ethereum.qml.Clipboard 1.0
import "js/ErrorLocationFormater.js" as ErrorLocationFormater import "js/ErrorLocationFormater.js" as ErrorLocationFormater
Item { Item {
signal editorTextChanged
signal breakpointsChanged signal breakpointsChanged
signal editorTextChanged
signal loadComplete
property bool isClean: true property bool isClean: true
property string currentText: "" property string currentText: ""
property string currentMode: "" property string currentMode: ""
property bool initialized: false property bool initialized: false
property bool unloaded: false
property var currentBreakpoints: []; property var currentBreakpoints: [];
function setText(text, mode) { function setText(text, mode) {
currentText = text; currentText = text;
if (mode !== undefined)
currentMode = mode; currentMode = mode;
if (initialized && editorBrowser) { if (initialized && editorBrowser) {
editorBrowser.runJavaScript("setTextBase64(\"" + Qt.btoa(text) + "\")"); editorBrowser.runJavaScript("setTextBase64(\"" + Qt.btoa(text) + "\")");
editorBrowser.runJavaScript("setMode(\"" + mode + "\")"); editorBrowser.runJavaScript("setMode(\"" + currentMode + "\")");
} }
setFocus(); setFocus();
} }
@ -65,6 +69,11 @@ Item {
editorBrowser.runJavaScript("changeGeneration()", function(result) {}); editorBrowser.runJavaScript("changeGeneration()", function(result) {});
} }
Clipboard
{
id: clipboard
}
Connections { Connections {
target: clipboard target: clipboard
onClipboardChanged: syncClipboard() onClipboardChanged: syncClipboard()
@ -133,7 +142,7 @@ Item {
if (!editorBrowser) if (!editorBrowser)
return; return;
editorBrowser.runJavaScript("getTextChanged()", function(result) { editorBrowser.runJavaScript("getTextChanged()", function(result) {
if (result === true) { if (result === true && editorBrowser) {
editorBrowser.runJavaScript("getText()" , function(textValue) { editorBrowser.runJavaScript("getText()" , function(textValue) {
currentText = textValue; currentText = textValue;
editorTextChanged(); editorTextChanged();
@ -141,7 +150,7 @@ Item {
} }
}); });
editorBrowser.runJavaScript("getBreakpointsChanged()", function(result) { editorBrowser.runJavaScript("getBreakpointsChanged()", function(result) {
if (result === true) { if (result === true && editorBrowser) {
editorBrowser.runJavaScript("getBreakpoints()" , function(bp) { editorBrowser.runJavaScript("getBreakpoints()" , function(bp) {
if (currentBreakpoints !== bp) { if (currentBreakpoints !== bp) {
currentBreakpoints = bp; currentBreakpoints = bp;

21
mix/qml/WebPreview.qml

@ -12,6 +12,7 @@ Item {
id: webPreview id: webPreview
property string pendingPageUrl: "" property string pendingPageUrl: ""
property bool initialized: false property bool initialized: false
property alias urlInput: urlInput
signal javaScriptMessage(var _level, string _sourceId, var _lineNb, string _content) signal javaScriptMessage(var _level, string _sourceId, var _lineNb, string _content)
function setPreviewUrl(url) { function setPreviewUrl(url) {
@ -60,6 +61,10 @@ Item {
setPreviewUrl(urlInput.text); setPreviewUrl(urlInput.text);
} }
WebPreviewStyle {
id: webPreviewStyle
}
Connections { Connections {
target: mainApplication target: mainApplication
onLoaded: { onLoaded: {
@ -183,7 +188,7 @@ Item {
Rectangle Rectangle
{ {
anchors.leftMargin: 4 anchors.leftMargin: 4
color: WebPreviewStyle.general.headerBackgroundColor color: webPreviewStyle.general.headerBackgroundColor
Layout.preferredWidth: parent.width Layout.preferredWidth: parent.width
Layout.preferredHeight: 32 Layout.preferredHeight: 32
Row { Row {
@ -230,7 +235,7 @@ Item {
{ {
width: 1 width: 1
height: parent.height - 10 height: parent.height - 10
color: WebPreviewStyle.general.separatorColor color: webPreviewStyle.general.separatorColor
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
@ -251,7 +256,7 @@ Item {
{ {
width: 1 width: 1
height: parent.height - 10 height: parent.height - 10
color: WebPreviewStyle.general.separatorColor color: webPreviewStyle.general.separatorColor
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
@ -285,7 +290,7 @@ Item {
{ {
Layout.preferredHeight: 1 Layout.preferredHeight: 1
Layout.preferredWidth: parent.width Layout.preferredWidth: parent.width
color: WebPreviewStyle.general.separatorColor color: webPreviewStyle.general.separatorColor
} }
Splitter Splitter
@ -355,9 +360,9 @@ Item {
id: expressionInput id: expressionInput
width: parent.width - 15 width: parent.width - 15
height: 20 height: 20
font.family: WebPreviewStyle.general.fontName font.family: webPreviewStyle.general.fontName
font.italic: true font.italic: true
font.pointSize: Style.absoluteSize(-3) font.pointSize: appStyle.absoluteSize(-3)
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
property var history: [] property var history: []
@ -417,8 +422,8 @@ Item {
id: resultTextArea id: resultTextArea
width: expressionPanel.width width: expressionPanel.width
wrapMode: Text.Wrap wrapMode: Text.Wrap
font.family: WebPreviewStyle.general.fontName font.family: webPreviewStyle.general.fontName
font.pointSize: Style.absoluteSize(-3) font.pointSize: appStyle.absoluteSize(-3)
backgroundVisible: true backgroundVisible: true
style: TextAreaStyle { style: TextAreaStyle {
backgroundColor: "#f0f0f0" backgroundColor: "#f0f0f0"

1
mix/qml/WebPreviewStyle.qml

@ -1,4 +1,3 @@
pragma Singleton
import QtQuick 2.0 import QtQuick 2.0
QtObject { QtObject {

8
mix/qml/qmldir

@ -1,8 +0,0 @@
singleton Style 1.0 Style.qml
singleton StateDialogStyle 1.0 StateDialogStyle.qml
singleton ProjectFilesStyle 1.0 ProjectFilesStyle.qml
singleton DebuggerPaneStyle 1.0 DebuggerPaneStyle.qml
singleton StateStyle 1.0 StateStyle.qml
singleton StatusPaneStyle 1.0 StatusPaneStyle.qml
singleton WebPreviewStyle 1.0 WebPreviewStyle.qml
singleton LogsPaneStyle 1.0 LogsPaneStyle.qml

6
mix/test.qrc

@ -0,0 +1,6 @@
<RCC>
<qresource prefix="/">
<file>test/TestMain.qml</file>
<file>test/TestTransactionDebug.qml</file>
</qresource>
</RCC>

50
mix/test/TestMain.cpp

@ -0,0 +1,50 @@
/*
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 main.cpp
* @author Yann yann@ethdev.com
* @date 2014
* Ethereum IDE client.
*/
#include <iostream>
#include <stdlib.h>
#include <quicktest.h>
#include <QtQml>
#include "MixApplication.h"
#include "Exceptions.h"
#include "TestService.h"
using namespace dev::mix;
int main(int _argc, char* _argv[])
{
try
{
MixApplication::initialize();
qmlRegisterType<TestService>("org.ethereum.qml.TestService", 1, 0, "TestService");
return quick_test_main(_argc, _argv, "mix", _argv[1]);
}
catch (boost::exception const& _e)
{
std::cerr << boost::diagnostic_information(_e);
}
catch (std::exception const& _e)
{
std::cerr << _e.what();
}
}

194
mix/test/TestService.cpp

@ -0,0 +1,194 @@
/*
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 TestService.cpp
* @author Arkadiy Paronyan arkadiy@ethdev.com
* @date 2015
* Ethereum IDE client.
*/
#include "TestService.h"
#include <QtTest/QSignalSpy>
#include <QElapsedTimer>
#include <QQuickItem>
#include <QQuickWindow>
#include <QtTest/QTest>
#include <QtTest/qtestkeyboard.h>
namespace dev
{
namespace mix
{
enum MouseAction { MousePress, MouseRelease, MouseClick, MouseDoubleClick, MouseMove };
static void mouseEvent(MouseAction _action, QWindow* _window, QObject* _item, Qt::MouseButton _button, Qt::KeyboardModifiers _stateKey, QPointF _pos, int _delay = -1)
{
if (_delay == -1 || _delay < 30)
_delay = 30;
if (_delay > 0)
QTest::qWait(_delay);
if (_action == MouseClick)
{
mouseEvent(MousePress, _window, _item, _button, _stateKey, _pos);
mouseEvent(MouseRelease, _window, _item, _button, _stateKey, _pos);
return;
}
QPoint pos = _pos.toPoint();
QQuickItem* sgitem = qobject_cast<QQuickItem*>(_item);
if (sgitem)
pos = sgitem->mapToScene(_pos).toPoint();
_stateKey &= static_cast<unsigned int>(Qt::KeyboardModifierMask);
QMouseEvent me(QEvent::User, QPoint(), Qt::LeftButton, _button, _stateKey);
switch (_action)
{
case MousePress:
me = QMouseEvent(QEvent::MouseButtonPress, pos, _window->mapToGlobal(pos), _button, _button, _stateKey);
break;
case MouseRelease:
me = QMouseEvent(QEvent::MouseButtonRelease, pos, _window->mapToGlobal(pos), _button, 0, _stateKey);
break;
case MouseDoubleClick:
me = QMouseEvent(QEvent::MouseButtonDblClick, pos, _window->mapToGlobal(pos), _button, _button, _stateKey);
break;
case MouseMove:
// with move event the _button is NoButton, but 'buttons' holds the currently pressed buttons
me = QMouseEvent(QEvent::MouseMove, pos, _window->mapToGlobal(pos), Qt::NoButton, _button, _stateKey);
break;
default:
break;
}
QSpontaneKeyEvent::setSpontaneous(&me);
if (!qApp->notify(_window, &me))
{
static const char* mouseActionNames[] = { "MousePress", "MouseRelease", "MouseClick", "MouseDoubleClick", "MouseMove" };
QString warning = QString::fromLatin1("Mouse event \"%1\" not accepted by receiving window");
QWARN(warning.arg(QString::fromLatin1(mouseActionNames[static_cast<int>(_action)])).toLatin1().data());
}
}
bool TestService::waitForSignal(QObject* _item, QString _signalName, int _timeout)
{
QSignalSpy spy(_item, ("2" + _signalName.toStdString()).c_str());
QMetaObject const* mo = _item->metaObject();
QStringList methods;
for (int i = mo->methodOffset(); i < mo->methodCount(); ++i)
if (mo->method(i).methodType() == QMetaMethod::Signal)
methods << QString::fromLatin1(mo->method(i).methodSignature());
QElapsedTimer timer;
timer.start();
while (!spy.size())
{
int remaining = _timeout - int(timer.elapsed());
if (remaining <= 0)
break;
QCoreApplication::processEvents(QEventLoop::AllEvents, remaining);
QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
QTest::qSleep(10);
}
return spy.size();
}
bool TestService::keyPress(QObject* _item, int _key, int _modifiers, int _delay)
{
QWindow* window = eventWindow(_item);
QTest::keyPress(window, Qt::Key(_key), Qt::KeyboardModifiers(_modifiers), _delay);
return true;
}
bool TestService::keyRelease(QObject* _item, int _key, int _modifiers, int _delay)
{
QWindow* window = eventWindow(_item);
QTest::keyRelease(window, Qt::Key(_key), Qt::KeyboardModifiers(_modifiers), _delay);
return true;
}
bool TestService::keyClick(QObject* _item, int _key, int _modifiers, int _delay)
{
QWindow* window = eventWindow(_item);
QTest::keyClick(window, Qt::Key(_key), Qt::KeyboardModifiers(_modifiers), _delay);
return true;
}
bool TestService::keyPressChar(QObject* _item, QString const& _character, int _modifiers, int _delay)
{
QWindow* window = eventWindow(_item);
QTest::keyPress(window, _character[0].toLatin1(), Qt::KeyboardModifiers(_modifiers), _delay);
return true;
}
bool TestService::keyReleaseChar(QObject* _item, QString const& _character, int _modifiers, int _delay)
{
QWindow* window = eventWindow(_item);
QTest::keyRelease(window, _character[0].toLatin1(), Qt::KeyboardModifiers(_modifiers), _delay);
return true;
}
bool TestService::keyClickChar(QObject* _item, QString const& _character, int _modifiers, int _delay)
{
QWindow* window = eventWindow(_item);
QTest::keyClick(window, _character[0].toLatin1(), Qt::KeyboardModifiers(_modifiers), _delay);
return true;
}
bool TestService::mouseClick(QObject* _item, qreal _x, qreal _y, int _button, int _modifiers, int _delay)
{
QWindow* window = qobject_cast<QWindow*>(_item);
if (!window)
window = eventWindow(_item);
mouseEvent(MouseClick, window, _item, Qt::MouseButton(_button), Qt::KeyboardModifiers(_modifiers), QPointF(_x, _y), _delay);
return true;
}
void TestService::setTargetWindow(QObject* _window)
{
QQuickWindow* window = qobject_cast<QQuickWindow*>(_window);
if (window)
m_targetWindow = window;
window->requestActivate();
}
QWindow* TestService::eventWindow(QObject* _item)
{
QQuickItem* item = qobject_cast<QQuickItem*>(_item);
if (item && item->window())
return item->window();
QQuickWindow* window = qobject_cast<QQuickWindow*>(_item);
if (!window)
window = qobject_cast<QQuickWindow*>(m_targetWindow);
if (window)
{
window->requestActivate();
return window;
}
item = qobject_cast<QQuickItem*>(m_targetWindow);
if (item)
return item->window();
return 0;
}
}
}

59
mix/test/TestService.h

@ -0,0 +1,59 @@
/*
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 TestService.h
* @author Arkadiy Paronyan arkadiy@ethdev.com
* @date 2015
* Ethereum IDE client.
*/
#pragma once
#include <QObject>
class QWindow;
namespace dev
{
namespace mix
{
class TestService: public QObject
{
Q_OBJECT
Q_PROPERTY(QObject* targetWindow READ targetWindow WRITE setTargetWindow)
public:
QObject* targetWindow() const { return m_targetWindow; }
void setTargetWindow(QObject* _window);
public slots:
bool waitForSignal(QObject* _item, QString _signalName, int _timeout);
bool keyPress(QObject* _item, int _key, int _modifiers, int _delay);
bool keyRelease(QObject* _item, int _key, int _modifiers, int _delay);
bool keyClick(QObject* _item, int _key, int _modifiers, int _delay);
bool keyPressChar(QObject* _item, QString const& _character, int _modifiers, int _delay);
bool keyReleaseChar(QObject* _item, QString const& _character, int _modifiers, int _delay);
bool keyClickChar(QObject* _item, QString const& _character, int _modifiers, int _delay);
bool mouseClick(QObject* _item, qreal _x, qreal _y, int _button, int _modifiers, int _delay);
private:
QWindow* eventWindow(QObject* _item);
QObject* m_targetWindow;
};
}
}

142
mix/test/qml/TestMain.qml

@ -0,0 +1,142 @@
import QtQuick 2.2
import QtTest 1.1
import org.ethereum.qml.TestService 1.0
import "../../qml"
TestCase
{
id: tc
TestService
{
id: ts
targetWindow: mainApplication
function typeString(str, el)
{
if (el === undefined)
el = mainApplication;
for (var c in str)
{
ts.keyPressChar(el, str[c], Qt.NoModifier, 0);
ts.keyReleaseChar(el, str[c], Qt.NoModifier, 0);
}
}
}
function newProject()
{
waitForRendering(mainApplication.mainContent, 10000);
mainApplication.projectModel.createProject();
var projectDlg = mainApplication.projectModel.newProjectDialog;
wait(30);
projectDlg.projectTitle = "TestProject";
projectDlg.pathFieldText = "/tmp/MixTest"; //TODO: get platform temp path
projectDlg.acceptAndClose();
wait(30);
}
function editContract(c)
{
mainApplication.mainContent.codeEditor.getEditor("contract.sol").setText(c);
ts.keyPressChar(mainApplication, "S", Qt.ControlModifier, 200); //Ctrl+S
if (!ts.waitForSignal(mainApplication.codeModel, "compilationComplete()", 5000))
fail("not compiled");
}
function clickElement(el, x, y)
{
ts.mouseClick(el, x, y, Qt.LeftButton, Qt.NoModifier, 10)
}
function test_defaultTransactionSequence()
{
newProject();
editContract(
"contract Contract {\r" +
" function Contract() {\r" +
" uint x = 69;\r" +
" uint y = 5;\r" +
" for (uint i = 0; i < y; ++i) {\r" +
" x += 42;\r" +
" z += x;\r" +
" }\r" +
" }\r" +
" uint z;\r" +
"}\r"
);
if (!ts.waitForSignal(mainApplication.clientModel, "runComplete()", 5000))
fail("not run");
tryCompare(mainApplication.mainContent.rightPane.transactionLog.transactionModel, "count", 3);
}
function test_transactionWithParameter()
{
newProject();
editContract(
"contract Contract {\r" +
" function setZ(uint256 x) {\r" +
" z = x;\r" +
" }\r" +
" function getZ() returns(uint256) {\r" +
" return z;\r" +
" }\r" +
" uint z;\r" +
"}\r"
);
mainApplication.projectModel.stateListModel.editState(0);
mainApplication.projectModel.stateDialog.model.addTransaction();
var transactionDialog = mainApplication.projectModel.stateDialog.transactionDialog;
transactionDialog.selectFunction("setZ");
clickElement(transactionDialog, 140, 300);
ts.typeString("442", transactionDialog);
transactionDialog.acceptAndClose();
mainApplication.projectModel.stateDialog.model.addTransaction();
transactionDialog.selectFunction("getZ");
transactionDialog.acceptAndClose();
mainApplication.projectModel.stateDialog.acceptAndClose();
mainApplication.mainContent.startQuickDebugging();
wait(1);
if (!ts.waitForSignal(mainApplication.clientModel, "runComplete()", 5000))
fail("not run");
tryCompare(mainApplication.mainContent.rightPane.transactionLog.transactionModel, "count", 5);
tryCompare(mainApplication.mainContent.rightPane.transactionLog.transactionModel.get(4), "returned", "(442)");
}
function test_constructorParameters()
{
newProject();
editContract(
"contract Contract {\r" +
" function Contract(uint256 x) {\r" +
" z = x;\r" +
" }\r" +
" function getZ() returns(uint256) {\r" +
" return z;\r" +
" }\r" +
" uint z;\r" +
"}\r"
);
mainApplication.projectModel.stateListModel.editState(0);
mainApplication.projectModel.stateDialog.model.editTransaction(2);
var transactionDialog = mainApplication.projectModel.stateDialog.transactionDialog;
clickElement(transactionDialog, 140, 300);
ts.typeString("442", transactionDialog);
transactionDialog.acceptAndClose();
mainApplication.projectModel.stateDialog.model.addTransaction();
transactionDialog.selectFunction("getZ");
transactionDialog.acceptAndClose();
mainApplication.projectModel.stateDialog.acceptAndClose();
wait(1);
mainApplication.mainContent.startQuickDebugging();
if (!ts.waitForSignal(mainApplication.clientModel, "runComplete()", 5000))
fail("not run");
tryCompare(mainApplication.mainContent.rightPane.transactionLog.transactionModel, "count", 4);
tryCompare(mainApplication.mainContent.rightPane.transactionLog.transactionModel.get(3), "returned", "(442)");
}
Application
{
id: mainApplication
}
}

50
mix/web.qrc

@ -1,44 +1,44 @@
<RCC> <RCC>
<qresource prefix="/"> <qresource prefix="/">
<file>qml/WebCodeEditor.qml</file>
<file>qml/WebPreview.qml</file> <file>qml/WebPreview.qml</file>
<file>qml/html/WebContainer.html</file> <file>qml/html/WebContainer.html</file>
<file>qml/html/cm/acorn.js</file>
<file>qml/html/cm/acorn_loose.js</file>
<file>qml/html/cm/active-line.js</file> <file>qml/html/cm/active-line.js</file>
<file>qml/html/codeeditor.html</file> <file>qml/html/cm/anyword-hint.js</file>
<file>qml/html/cm/closebrackets.js</file>
<file>qml/html/cm/codemirror.css</file> <file>qml/html/cm/codemirror.css</file>
<file>qml/html/cm/codemirror.js</file> <file>qml/html/cm/codemirror.js</file>
<file>qml/html/cm/javascript.js</file> <file>qml/html/cm/comment.js</file>
<file>qml/html/cm/matchbrackets.js</file>
<file alias="qml/CodeEditor.qml">qml/WebCodeEditor.qml</file>
<file>qml/html/codeeditor.js</file>
<file>qml/html/cm/fullscreen.css</file>
<file>qml/html/cm/fullscreen.js</file>
<file>qml/html/cm/solarized.css</file>
<file>qml/html/cm/xml.js</file>
<file>qml/html/cm/htmlmixed.js</file>
<file>qml/html/cm/css.js</file> <file>qml/html/cm/css.js</file>
<file>qml/html/cm/solidity.js</file> <file>qml/html/cm/def.js</file>
<file>qml/html/cm/dialog.css</file> <file>qml/html/cm/dialog.css</file>
<file>qml/html/cm/dialog.js</file> <file>qml/html/cm/dialog.js</file>
<file>qml/html/cm/doc_comment.js</file>
<file>qml/html/cm/ecma5spec.js</file>
<file>qml/html/cm/errorannotation.js</file>
<file>qml/html/cm/fullscreen.css</file>
<file>qml/html/cm/fullscreen.js</file>
<file>qml/html/cm/htmlmixed.js</file>
<file>qml/html/cm/infer.js</file>
<file>qml/html/cm/javascript-hint.js</file>
<file>qml/html/cm/javascript.js</file>
<file>qml/html/cm/mark-selection.js</file>
<file>qml/html/cm/matchbrackets.js</file>
<file>qml/html/cm/search.js</file> <file>qml/html/cm/search.js</file>
<file>qml/html/cm/searchcursor.js</file> <file>qml/html/cm/searchcursor.js</file>
<file>qml/html/cm/anyword-hint.js</file>
<file>qml/html/cm/show-hint.js</file>
<file>qml/html/cm/show-hint.css</file> <file>qml/html/cm/show-hint.css</file>
<file>qml/html/cm/closebrackets.js</file> <file>qml/html/cm/show-hint.js</file>
<file>qml/html/cm/signal.js</file>
<file>qml/html/cm/solarized.css</file>
<file>qml/html/cm/solidity.js</file>
<file>qml/html/cm/solidityToken.js</file> <file>qml/html/cm/solidityToken.js</file>
<file>qml/html/cm/javascript-hint.js</file>
<file>qml/html/cm/errorannotation.js</file>
<file>qml/html/cm/tern.js</file> <file>qml/html/cm/tern.js</file>
<file>qml/html/cm/ecma5spec.js</file>
<file>qml/html/cm/comment.js</file>
<file>qml/html/cm/def.js</file>
<file>qml/html/cm/doc_comment.js</file>
<file>qml/html/cm/infer.js</file>
<file>qml/html/cm/signal.js</file>
<file>qml/html/cm/ternserver.js</file> <file>qml/html/cm/ternserver.js</file>
<file>qml/html/cm/acorn.js</file>
<file>qml/html/cm/acorn_loose.js</file>
<file>qml/html/cm/walk.js</file> <file>qml/html/cm/walk.js</file>
<file>qml/html/cm/mark-selection.js</file> <file>qml/html/cm/xml.js</file>
<file>qml/html/codeeditor.html</file>
<file>qml/html/codeeditor.js</file>
</qresource> </qresource>
</RCC> </RCC>

33
test/Stats.cpp

@ -19,6 +19,7 @@
#include <iterator> #include <iterator>
#include <numeric> #include <numeric>
#include <fstream>
namespace dev namespace dev
{ {
@ -31,6 +32,11 @@ Stats& Stats::get()
return instance; return instance;
} }
void Stats::suiteStarted(std::string const& _name)
{
m_currentSuite = _name;
}
void Stats::testStarted(std::string const& _name) void Stats::testStarted(std::string const& _name)
{ {
m_currentTest = _name; m_currentTest = _name;
@ -39,7 +45,7 @@ void Stats::testStarted(std::string const& _name)
void Stats::testFinished() void Stats::testFinished()
{ {
m_stats[clock::now() - m_tp] = std::move(m_currentTest); m_stats.push_back({clock::now() - m_tp, m_currentSuite + "/" + m_currentTest});
} }
std::ostream& operator<<(std::ostream& out, Stats::clock::duration const& d) std::ostream& operator<<(std::ostream& out, Stats::clock::duration const& d)
@ -52,31 +58,42 @@ Stats::~Stats()
if (m_stats.empty()) if (m_stats.empty())
return; return;
std::sort(m_stats.begin(), m_stats.end(), [](Stats::Item const& a, Stats::Item const& b){
return a.duration < b.duration;
});
auto& out = std::cout; auto& out = std::cout;
auto itr = m_stats.begin(); auto itr = m_stats.begin();
auto min = *itr; auto min = *itr;
auto max = *m_stats.rbegin(); auto max = *m_stats.rbegin();
std::advance(itr, m_stats.size() / 2); std::advance(itr, m_stats.size() / 2);
auto med = *itr; auto med = *itr;
auto tot = std::accumulate(m_stats.begin(), m_stats.end(), clock::duration{}, [](clock::duration const& a, stats_t::value_type const& v) auto tot = std::accumulate(m_stats.begin(), m_stats.end(), clock::duration{}, [](clock::duration const& a, Stats::Item const& v)
{ {
return a + v.first; return a + v.duration;
}); });
out << "\nSTATS:\n\n" << std::setfill(' '); out << "\nSTATS:\n\n" << std::setfill(' ');
if (Options::get().statsFull) if (Options::get().statsOutFile == "out")
{ {
for (auto&& s: m_stats) for (auto&& s: m_stats)
out << " " << std::setw(40) << std::left << s.second.substr(0, 40) << s.first << " \n"; out << " " << std::setw(40) << std::left << s.name.substr(0, 40) << s.duration << " \n";
out << "\n"; out << "\n";
} }
else if (!Options::get().statsOutFile.empty())
{
// Output stats to file
std::ofstream file{Options::get().statsOutFile};
for (auto&& s: m_stats)
file << s.name << "\t" << std::chrono::duration_cast<std::chrono::microseconds>(s.duration).count() << "\n";
}
out << " tot: " << tot << "\n" out << " tot: " << tot << "\n"
<< " avg: " << (tot / m_stats.size()) << "\n\n" << " avg: " << (tot / m_stats.size()) << "\n\n"
<< " min: " << min.first << " (" << min.second << ")\n" << " min: " << min.duration << " (" << min.name << ")\n"
<< " med: " << med.first << " (" << med.second << ")\n" << " med: " << med.duration << " (" << med.name << ")\n"
<< " max: " << max.first << " (" << max.second << ")\n"; << " max: " << max.duration << " (" << max.name << ")\n";
} }
} }

13
test/Stats.h

@ -18,7 +18,7 @@
#pragma once #pragma once
#include <chrono> #include <chrono>
#include <map> #include <vector>
#include "TestHelper.h" #include "TestHelper.h"
@ -31,19 +31,26 @@ class Stats: public Listener
{ {
public: public:
using clock = std::chrono::high_resolution_clock; using clock = std::chrono::high_resolution_clock;
using stats_t = std::map<clock::duration, std::string>;
struct Item
{
clock::duration duration;
std::string name;
};
static Stats& get(); static Stats& get();
~Stats(); ~Stats();
void suiteStarted(std::string const& _name) override;
void testStarted(std::string const& _name) override; void testStarted(std::string const& _name) override;
void testFinished() override; void testFinished() override;
private: private:
clock::time_point m_tp; clock::time_point m_tp;
std::string m_currentSuite;
std::string m_currentTest; std::string m_currentTest;
stats_t m_stats; std::vector<Item> m_stats;
}; };
} }

19
test/TestHelper.cpp

@ -29,6 +29,7 @@
#include <libethereum/Client.h> #include <libethereum/Client.h>
#include <liblll/Compiler.h> #include <liblll/Compiler.h>
#include <libevm/VMFactory.h> #include <libevm/VMFactory.h>
#include "Stats.h"
using namespace std; using namespace std;
using namespace dev::eth; using namespace dev::eth;
@ -431,6 +432,9 @@ void executeTests(const string& _name, const string& _testPathAppendix, std::fun
string testPath = getTestPath(); string testPath = getTestPath();
testPath += _testPathAppendix; testPath += _testPathAppendix;
if (Options::get().stats)
Listener::registerListener(Stats::get());
if (Options::get().fillTests) if (Options::get().fillTests)
{ {
try try
@ -462,6 +466,7 @@ void executeTests(const string& _name, const string& _testPathAppendix, std::fun
string s = asString(dev::contents(testPath + "/" + _name + ".json")); string s = asString(dev::contents(testPath + "/" + _name + ".json"));
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + testPath + "/" + _name + ".json is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?"); BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + testPath + "/" + _name + ".json is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?");
json_spirit::read_string(s, v); json_spirit::read_string(s, v);
Listener::notifySuiteStarted(_name);
doTests(v, false); doTests(v, false);
} }
catch (Exception const& _e) catch (Exception const& _e)
@ -535,10 +540,12 @@ Options::Options()
vmtrace = true; vmtrace = true;
else if (arg == "--filltests") else if (arg == "--filltests")
fillTests = true; fillTests = true;
else if (arg == "--stats") else if (arg.compare(0, 7, "--stats") == 0)
{
stats = true; stats = true;
else if (arg == "--stats=full") if (arg.size() > 7)
stats = statsFull = true; statsOutFile = arg.substr(8); // skip '=' char
}
else if (arg == "--performance") else if (arg == "--performance")
performance = true; performance = true;
else if (arg == "--quadratic") else if (arg == "--quadratic")
@ -586,6 +593,12 @@ void Listener::registerListener(Listener& _listener)
g_listener = &_listener; g_listener = &_listener;
} }
void Listener::notifySuiteStarted(std::string const& _name)
{
if (g_listener)
g_listener->suiteStarted(_name);
}
void Listener::notifyTestStarted(std::string const& _name) void Listener::notifyTestStarted(std::string const& _name)
{ {
if (g_listener) if (g_listener)

4
test/TestHelper.h

@ -164,7 +164,7 @@ public:
bool vmtrace = false; ///< Create EVM execution tracer // TODO: Link with log verbosity? bool vmtrace = false; ///< Create EVM execution tracer // TODO: Link with log verbosity?
bool fillTests = false; ///< Create JSON test files from execution results bool fillTests = false; ///< Create JSON test files from execution results
bool stats = false; ///< Execution time stats bool stats = false; ///< Execution time stats
bool statsFull = false; ///< Output full stats - execution times for every test std::string statsOutFile; ///< Stats output file. "out" for standard output
/// Test selection /// Test selection
/// @{ /// @{
@ -191,10 +191,12 @@ class Listener
public: public:
virtual ~Listener() = default; virtual ~Listener() = default;
virtual void suiteStarted(std::string const&) {}
virtual void testStarted(std::string const& _name) = 0; virtual void testStarted(std::string const& _name) = 0;
virtual void testFinished() = 0; virtual void testFinished() = 0;
static void registerListener(Listener& _listener); static void registerListener(Listener& _listener);
static void notifySuiteStarted(std::string const& _name);
static void notifyTestStarted(std::string const& _name); static void notifyTestStarted(std::string const& _name);
static void notifyTestFinished(); static void notifyTestFinished();

5
test/state.cpp

@ -31,7 +31,6 @@
#include <libethereum/Defaults.h> #include <libethereum/Defaults.h>
#include <libevm/VM.h> #include <libevm/VM.h>
#include "TestHelper.h" #include "TestHelper.h"
#include "Stats.h"
using namespace std; using namespace std;
using namespace json_spirit; using namespace json_spirit;
@ -42,9 +41,6 @@ namespace dev { namespace test {
void doStateTests(json_spirit::mValue& v, bool _fillin) void doStateTests(json_spirit::mValue& v, bool _fillin)
{ {
if (Options::get().stats)
Listener::registerListener(Stats::get());
for (auto& i: v.get_obj()) for (auto& i: v.get_obj())
{ {
std::cout << " " << i.first << "\n"; std::cout << " " << i.first << "\n";
@ -254,6 +250,7 @@ BOOST_AUTO_TEST_CASE(stRandom)
string s = asString(dev::contents(path.string())); string s = asString(dev::contents(path.string()));
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Content of " + path.string() + " is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?"); BOOST_REQUIRE_MESSAGE(s.length() > 0, "Content of " + path.string() + " is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?");
json_spirit::read_string(s, v); json_spirit::read_string(s, v);
test::Listener::notifySuiteStarted(path.filename().string());
dev::test::doStateTests(v, false); dev::test::doStateTests(v, false);
} }
catch (Exception const& _e) catch (Exception const& _e)

5
test/vm.cpp

@ -25,7 +25,6 @@
#include <libethereum/Executive.h> #include <libethereum/Executive.h>
#include <libevm/VMFactory.h> #include <libevm/VMFactory.h>
#include "vm.h" #include "vm.h"
#include "Stats.h"
using namespace std; using namespace std;
using namespace json_spirit; using namespace json_spirit;
@ -311,9 +310,6 @@ namespace dev { namespace test {
void doVMTests(json_spirit::mValue& v, bool _fillin) void doVMTests(json_spirit::mValue& v, bool _fillin)
{ {
if (Options::get().stats)
Listener::registerListener(Stats::get());
for (auto& i: v.get_obj()) for (auto& i: v.get_obj())
{ {
std::cout << " " << i.first << "\n"; std::cout << " " << i.first << "\n";
@ -549,6 +545,7 @@ BOOST_AUTO_TEST_CASE(vmRandom)
string s = asString(dev::contents(path.string())); string s = asString(dev::contents(path.string()));
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Content of " + path.string() + " is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?"); BOOST_REQUIRE_MESSAGE(s.length() > 0, "Content of " + path.string() + " is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?");
json_spirit::read_string(s, v); json_spirit::read_string(s, v);
test::Listener::notifySuiteStarted(path.filename().string());
doVMTests(v, false); doVMTests(v, false);
} }
catch (Exception const& _e) catch (Exception const& _e)

10
test/webthreestubclient.h

@ -62,6 +62,16 @@ class WebThreeStubClient : public jsonrpc::Client
else else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
} }
std::string eth_protocolVersion() throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p = Json::nullValue;
Json::Value result = this->CallMethod("eth_protocolVersion",p);
if (result.isString())
return result.asString();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
std::string eth_coinbase() throw (jsonrpc::JsonRpcException) std::string eth_coinbase() throw (jsonrpc::JsonRpcException)
{ {
Json::Value p; Json::Value p;

Loading…
Cancel
Save