Browse Source

Merge branch 'develop' of github.com:ethereum/cpp-ethereum into develop

cl-refactor
Gav Wood 10 years ago
parent
commit
175e0c0d17
  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. 44
      evmjit/libevmjit/RuntimeManager.cpp
  8. 5
      evmjit/libevmjit/RuntimeManager.h
  9. 31
      libp2p/Host.cpp
  10. 1
      libp2p/Peer.cpp
  11. 3
      libp2p/Peer.h
  12. 14
      libp2p/Session.cpp
  13. 5
      libweb3jsonrpc/WebThreeStubServerBase.cpp
  14. 1
      libweb3jsonrpc/WebThreeStubServerBase.h
  15. 7
      libweb3jsonrpc/abstractwebthreestubserver.h
  16. 1
      libweb3jsonrpc/spec.json
  17. 2
      libwhisper/WhisperHost.cpp
  18. 49
      mix/CMakeLists.txt
  19. 5
      mix/ClientModel.cpp
  20. 2
      mix/ClientModel.h
  21. 44
      mix/MixApplication.cpp
  22. 21
      mix/MixApplication.h
  23. 41
      mix/QBasicNodeDefinition.cpp
  24. 12
      mix/QBasicNodeDefinition.h
  25. 1
      mix/QVariableDeclaration.cpp
  26. 5
      mix/QVariableDeclaration.h
  27. 37
      mix/QVariableDefinition.cpp
  28. 8
      mix/QVariableDefinition.h
  29. 18
      mix/main.cpp
  30. 7
      mix/qml.qrc
  31. 15
      mix/qml/Application.qml
  32. 5
      mix/qml/CallStack.qml
  33. 51
      mix/qml/CodeEditor.qml
  34. 1
      mix/qml/CodeEditorStyle.qml
  35. 45
      mix/qml/CodeEditorView.qml
  36. 2
      mix/qml/CommonSeparator.qml
  37. 12
      mix/qml/Debugger.qml
  38. 1
      mix/qml/DebuggerPaneStyle.qml
  39. 1
      mix/qml/DefaultLabel.qml
  40. 4
      mix/qml/DeploymentDialog.qml
  41. 30
      mix/qml/FilesSection.qml
  42. 4
      mix/qml/ItemDelegateDataDump.qml
  43. 115
      mix/qml/LogsPane.qml
  44. 1
      mix/qml/LogsPaneStyle.qml
  45. 1
      mix/qml/MainContent.qml
  46. 1
      mix/qml/NewProjectDialog.qml
  47. 1
      mix/qml/ProjectFilesStyle.qml
  48. 21
      mix/qml/ProjectList.qml
  49. 2
      mix/qml/ProjectModel.qml
  50. 3
      mix/qml/Splitter.qml
  51. 16
      mix/qml/StateDialog.qml
  52. 1
      mix/qml/StateDialogStyle.qml
  53. 1
      mix/qml/StateListModel.qml
  54. 6
      mix/qml/StatusPane.qml
  55. 1
      mix/qml/StatusPaneStyle.qml
  56. 4
      mix/qml/StorageView.qml
  57. 1
      mix/qml/Style.qml
  58. 45
      mix/qml/TransactionDialog.qml
  59. 19
      mix/qml/WebCodeEditor.qml
  60. 21
      mix/qml/WebPreview.qml
  61. 1
      mix/qml/WebPreviewStyle.qml
  62. 8
      mix/qml/qmldir
  63. 6
      mix/test.qrc
  64. 50
      mix/test/TestMain.cpp
  65. 194
      mix/test/TestService.cpp
  66. 59
      mix/test/TestService.h
  67. 142
      mix/test/qml/TestMain.qml
  68. 84
      mix/web.qrc
  69. 33
      test/Stats.cpp
  70. 13
      test/Stats.h
  71. 19
      test/TestHelper.cpp
  72. 4
      test/TestHelper.h
  73. 5
      test/state.cpp
  74. 5
      test/vm.cpp
  75. 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);
m_bblock.m_currentStack.push_back(_value);
m_bblock.m_tosOffset += 1;
m_maxSize = std::max(m_maxSize, m_bblock.m_currentStack.size());
}
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.
void swap(size_t _index);
size_t getMaxSize() const { return m_maxSize; }
int getDiff() const { return m_bblock.m_tosOffset; }
private:
LocalStack(BasicBlock& _owner);
LocalStack(LocalStack const&) = delete;
@ -49,6 +52,7 @@ public:
private:
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);

31
evmjit/libevmjit/Cache.cpp

@ -4,6 +4,7 @@
#include <llvm/IR/Module.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Instructions.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/Support/Path.h>
#include <llvm/Support/FileSystem.h>
#include <llvm/Support/raw_os_ostream.h>
@ -59,6 +60,36 @@ void Cache::clear()
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)
{
if (g_mode != CacheMode::on && g_mode != CacheMode::read)

12
evmjit/libevmjit/Cache.h

@ -1,9 +1,15 @@
#pragma once
#include <memory>
#include <unordered_map>
#include <llvm/ExecutionEngine/ObjectCache.h>
namespace llvm
{
class ExecutionEngine;
}
namespace dev
{
namespace eth
@ -18,7 +24,8 @@ enum class CacheMode
off,
read,
write,
clear
clear,
preload
};
class ObjectCache : public llvm::ObjectCache
@ -43,6 +50,9 @@ public:
/// Clears cache storage
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.
if (!_basicBlock.llvm()->getTerminator())
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::write, "w", "Write only. No objects are loaded from cache."),
clEnumValN(CacheMode::clear, "c", "Clear the cache storage. Cache is disabled."),
clEnumValN(CacheMode::preload, "p", "Preload all cached objects."),
clEnumValEnd)};
cl::opt<bool> g_stats{"st", cl::desc{"Statistics"}};
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};
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;
static std::unordered_map<std::string, uint64_t> funcCache;
static std::unique_ptr<llvm::ExecutionEngine> ee;
if (!ee)
{
@ -138,6 +146,9 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
return ReturnCode::LLVMConfigError;
module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module
ee->setObjectCache(objectCache);
if (preloadCache)
Cache::preload(*ee, funcCache);
}
static StatsCollector statsCollector;
@ -146,10 +157,9 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
m_runtime.init(_data, _env);
EntryFuncPtr entryFuncPtr = nullptr;
static std::unordered_map<std::string, EntryFuncPtr> funcCache;
auto it = funcCache.find(mainFuncName);
if (it != funcCache.end())
entryFuncPtr = it->second;
entryFuncPtr = (EntryFuncPtr) it->second;
if (!entryFuncPtr)
{
@ -177,7 +187,8 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
if (!CHECK(entryFuncPtr))
return ReturnCode::LLVMLinkError;
funcCache[mainFuncName] = entryFuncPtr;
if (it == funcCache.end())
funcCache[mainFuncName] = (uint64_t) entryFuncPtr;
listener->stateChanged(ExecState::Execution);
auto returnCode = entryFuncPtr(&m_runtime);

44
evmjit/libevmjit/RuntimeManager.cpp

@ -78,7 +78,7 @@ llvm::Twine getName(RuntimeData::Index _index)
case RuntimeData::CodeSize: return "code";
case RuntimeData::CallDataSize: return "callDataSize";
case RuntimeData::Gas: return "gas";
case RuntimeData::Number: return "number";
case RuntimeData::Number: return "number";
case RuntimeData::Timestamp: return "timestamp";
}
}
@ -101,6 +101,48 @@ RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder, code_iterator _codeB
assert(m_memPtr->getType() == Array::getType()->getPointerTo());
m_envPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(rtPtr, 1), "env");
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()

5
evmjit/libevmjit/RuntimeManager.h

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

31
libp2p/Host.cpp

@ -182,10 +182,8 @@ void Host::startPeerSession(Public const& _id, RLP const& _rlp, RLPXFrameIO* _io
}
else
p = m_peers[_id];
p->m_lastDisconnect = NoDisconnect;
if (p->isOffline())
p->m_lastConnected = std::chrono::system_clock::now();
p->m_failedAttempts = 0;
p->endpoint.tcp.address(_endpoint.address());
auto protocolVersion = _rlp[0].toInt<unsigned>();
@ -219,16 +217,19 @@ void Host::startPeerSession(Public const& _id, RLP const& _rlp, RLPXFrameIO* _io
ps->disconnect(DuplicatePeer);
return;
}
// todo: mutex Session::m_capabilities and move for(:caps) out of mutex.
unsigned o = (unsigned)UserPacket;
for (auto const& i: caps)
if (haveCapability(i))
{
ps->m_capabilities[i] = shared_ptr<Capability>(m_capabilities[i]->newPeerCapability(ps.get(), o));
o += m_capabilities[i]->messageCount();
}
ps->start();
m_sessions[_id] = ps;
}
ps->start();
unsigned o = (unsigned)UserPacket;
for (auto const& i: caps)
if (haveCapability(i))
{
ps->m_capabilities[i] = shared_ptr<Capability>(m_capabilities[i]->newPeerCapability(ps.get(), o));
o += m_capabilities[i]->messageCount();
}
clog(NetNote) << "p2p.host.peer.register" << _id.abridged();
StructuredLogger::p2pConnected(_id.abridged(), ps->m_peer->peerEndpoint(), ps->m_peer->m_lastConnected, clientVersion, peerCount());
}
@ -484,12 +485,14 @@ void Host::connect(std::shared_ptr<Peer> const& _p)
auto socket = make_shared<RLPXSocket>(new bi::tcp::socket(m_ioService));
socket->ref().async_connect(_p->peerEndpoint(), [=](boost::system::error_code const& ec)
{
_p->m_lastAttempted = std::chrono::system_clock::now();
_p->m_failedAttempts++;
if (ec)
{
clog(NetConnect) << "Connection refused to node" << _p->id.abridged() << "@" << _p->peerEndpoint() << "(" << ec.message() << ")";
// Manually set error (session not present)
_p->m_lastDisconnect = TCPError;
_p->m_lastAttempted = std::chrono::system_clock::now();
_p->m_failedAttempts++;
}
else
{
@ -499,9 +502,7 @@ void Host::connect(std::shared_ptr<Peer> const& _p)
Guard l(x_connecting);
m_connecting.push_back(handshake);
}
// preempt setting failedAttempts; this value is cleared upon success
_p->m_failedAttempts++;
handshake->start();
}

1
libp2p/Peer.cpp

@ -44,6 +44,7 @@ unsigned Peer::fallbackSeconds() const
return 30 * (m_failedAttempts + 1);
case UselessPeer:
case TooManyPeers:
return 25 * (m_failedAttempts + 1);
case ClientQuit:
return 15 * (m_failedAttempts + 1);
case NoDisconnect:

3
libp2p/Peer.h

@ -75,6 +75,9 @@ public:
/// Reason peer was previously disconnected.
DisconnectReason lastDisconnect() const { return m_lastDisconnect; }
/// Peer session is noted as useful.
void noteSessionGood() { m_failedAttempts = 0; }
protected:
/// Returns number of seconds to wait until attempting connection, based on attempted connection history.
unsigned fallbackSeconds() const;

14
libp2p/Session.cpp

@ -46,6 +46,7 @@ Session::Session(Host* _s, RLPXFrameIO* _io, std::shared_ptr<Peer> const& _n, Pe
m_info(_info),
m_ping(chrono::steady_clock::time_point::max())
{
m_peer->m_lastDisconnect = NoDisconnect;
m_lastReceived = m_connect = chrono::steady_clock::now();
}
@ -358,16 +359,11 @@ void Session::drop(DisconnectReason _reason)
}
catch (...) {}
if (m_peer)
m_peer->m_lastDisconnect = _reason;
if (_reason == BadProtocol)
{
if (_reason != m_peer->m_lastDisconnect || _reason == NoDisconnect || _reason == ClientQuit || _reason == DisconnectRequested)
m_peer->m_failedAttempts = 0;
m_peer->m_lastDisconnect = _reason;
if (_reason == BadProtocol)
{
m_peer->m_rating /= 2;
m_peer->m_score /= 2;
}
m_peer->m_rating /= 2;
m_peer->m_score /= 2;
}
m_dropped = true;
}

5
libweb3jsonrpc/WebThreeStubServerBase.cpp

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

1
libweb3jsonrpc/WebThreeStubServerBase.h

@ -77,6 +77,7 @@ public:
virtual std::string net_peerCount();
virtual bool net_listening();
virtual std::string eth_protocolVersion();
virtual std::string eth_coinbase();
virtual bool eth_mining();
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_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("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_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);
@ -92,6 +93,11 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
(void)request;
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)
{
(void)request;
@ -302,6 +308,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
virtual std::string net_version() = 0;
virtual std::string net_peerCount() = 0;
virtual bool net_listening() = 0;
virtual std::string eth_protocolVersion() = 0;
virtual std::string eth_coinbase() = 0;
virtual bool eth_mining() = 0;
virtual std::string eth_gasPrice() = 0;

1
libweb3jsonrpc/spec.json

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

2
libwhisper/WhisperHost.cpp

@ -162,7 +162,7 @@ void WhisperHost::uninstallWatch(unsigned _i)
void WhisperHost::doWork()
{
for (auto& i: peerSessions())
for (auto i: peerSessions())
i.first->cap<WhisperPeer>().get()->sendMessages();
cleanup();
}

49
mix/CMakeLists.txt

@ -29,7 +29,9 @@ else()
qt5_add_resources(UI_RESOURCES noweb.qrc)
endif()
add_definitions(-DQT_QML_DEBUG)
if (CMAKE_BUILD_TYPE EQUAL "DEBUG")
add_definitions(-DQT_QML_DEBUG)
endif()
# eth_add_executable is defined in cmake/EthExecutableHelper.cmake
eth_add_executable(${EXECUTABLE}
@ -37,33 +39,15 @@ eth_add_executable(${EXECUTABLE}
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})
add_definitions(-DETH_HAVE_WEBENGINE)
target_link_libraries(${EXECUTABLE} Qt5::WebEngine)
list(APPEND LIBRARIES "Qt5::WebEngine")
endif()
target_link_libraries(${EXECUTABLE} ${LIBRARIES})
# eth_install_executable is defined in cmake/EthExecutableHelper.cmake
eth_install_executable(${EXECUTABLE}
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
file(GLOB_RECURSE QMLFILES "qml/*.*")
file(GLOB_RECURSE TESTFILES "test/qml/*.*")
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()
{
m_runFuture.waitForFinished();
}
QString ClientModel::apiCall(QString const& _message)
@ -113,7 +114,7 @@ void ClientModel::mine()
m_mining = true;
emit miningStarted();
emit miningStateChanged();
QtConcurrent::run([=]()
m_runFuture = QtConcurrent::run([=]()
{
try
{
@ -206,7 +207,7 @@ void ClientModel::executeSequence(std::vector<TransactionSettings> const& _seque
emit runStateChanged();
//run sequence
QtConcurrent::run([=]()
m_runFuture = QtConcurrent::run([=]()
{
try
{

2
mix/ClientModel.h

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

44
mix/MixApplication.cpp

@ -23,6 +23,7 @@
#include <QQmlApplicationEngine>
#include <QUrl>
#include <QIcon>
#include <QFont>
#ifdef ETH_HAVE_WEBENGINE
#include <QtWebEngine/QtWebEngine>
#endif
@ -37,21 +38,49 @@
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[]):
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"));
setOrganizationDomain(tr("ethereum.org"));
setApplicationName(tr("Mix"));
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<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<QEther>("org.ethereum.qml.QEther", 1, 0, "QEther");
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");
qRegisterMetaType<CodeModel*>("CodeModel*");
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"));
qRegisterMetaType<ClientModel*>("ClientModel*");
}
MixApplication::~MixApplication()

21
mix/MixApplication.h

@ -33,12 +33,33 @@ namespace dev
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
{
Q_OBJECT
public:
MixApplication(int& _argc, char* _argv[]);
static void initialize();
virtual ~MixApplication();
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
#include <string>
#include <QObject>
#include <libsolidity/AST.h>
namespace dev
{
namespace solidity
{
class Declaration;
}
namespace mix
{
@ -37,8 +43,8 @@ class QBasicNodeDefinition: public QObject
public:
QBasicNodeDefinition(QObject* _parent = nullptr): QObject(_parent) {}
~QBasicNodeDefinition() {}
QBasicNodeDefinition(QObject* _parent, solidity::Declaration const* _d): QObject(_parent), m_name(QString::fromStdString(_d->getName())) {}
QBasicNodeDefinition(QObject* _parent, std::string const& _name): QObject(_parent), m_name(QString::fromStdString(_name)) {}
QBasicNodeDefinition(QObject* _parent, solidity::Declaration const* _d);
QBasicNodeDefinition(QObject* _parent, std::string const& _name);
/// Get the name of the node.
QString name() const { return m_name; }

1
mix/QVariableDeclaration.cpp

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

5
mix/QVariableDeclaration.h

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

18
mix/main.cpp

@ -22,27 +22,17 @@
#include <iostream>
#include <stdlib.h>
#include <boost/exception/exception.hpp>
#include <boost/exception/diagnostic_information.hpp>
#include "MixApplication.h"
#include "Exceptions.h"
using namespace dev::mix;
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
{
MixApplication::initialize();
MixApplication app(_argc, _argv);
return app.exec();
}

7
mix/qml.qrc

@ -1,6 +1,7 @@
<RCC>
<qresource prefix="/">
<file>qml/AlertMessageDialog.qml</file>
<file>qml/Application.qml</file>
<file>qml/BasicMessage.qml</file>
<file>qml/BigIntValue.qml</file>
<file>qml/CallStack.qml</file>
@ -47,7 +48,8 @@
<file>qml/StatusPaneStyle.qml</file>
<file>qml/StepActionImage.qml</file>
<file>qml/StorageView.qml</file>
<file>qml/StructView.qml</file>
<file>qml/StatesComboBox.qml</file>
<file>qml/StructView.qml</file>
<file>qml/Style.qml</file>
<file>qml/TabStyle.qml</file>
<file>qml/TransactionDialog.qml</file>
@ -59,8 +61,5 @@
<file>qml/js/ProjectModel.js</file>
<file>qml/js/QEtherHelper.js</file>
<file>qml/js/TransactionHelper.js</file>
<file>qml/main.qml</file>
<file>qml/qmldir</file>
<file>qml/StatesComboBox.qml</file>
</qresource>
</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.FileIo 1.0
import org.ethereum.qml.Clipboard 1.0
import org.ethereum.qml.ApplicationService 1.0
ApplicationWindow {
@ -22,6 +23,16 @@ ApplicationWindow {
minimumWidth: 400
minimumHeight: 300
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 {
id: codeModel
@ -44,6 +55,10 @@ ApplicationWindow {
id: clipboard
}
Style {
id: appStyle
}
Connections {
target: mainApplication
onClosing:

5
mix/qml/CallStack.qml

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

51
mix/qml/CodeEditor.qml

@ -24,31 +24,36 @@ Item {
id: contentView
width: parent.width
height: parent.height * 0.7
Rectangle {
id: lineColumn
property int rowHeight: codeEditor.font.pixelSize + 3
color: "#202020"
width: 50
height: parent.height
Column {
y: -codeEditor.flickableItem.contentY + 4
width: parent.width
Repeater {
model: Math.max(codeEditor.lineCount + 2, (lineColumn.height/lineColumn.rowHeight))
delegate: Text {
id: text
color: codeEditor.textColor
font: codeEditor.font
width: lineColumn.width - 4
horizontalAlignment: Text.AlignRight
verticalAlignment: Text.AlignVCenter
height: lineColumn.rowHeight
renderType: Text.NativeRendering
text: index + 1
}
CodeEditorStyle {
id: style
}
Rectangle {
id: lineColumn
property int rowHeight: codeEditor.font.pixelSize + 3
color: "#202020"
width: 50
height: parent.height
Column {
y: -codeEditor.flickableItem.contentY + 4
width: parent.width
Repeater {
model: Math.max(codeEditor.lineCount + 2, (lineColumn.height/lineColumn.rowHeight))
delegate: Text {
id: text
color: codeEditor.textColor
font: codeEditor.font
width: lineColumn.width - 4
horizontalAlignment: Text.AlignRight
verticalAlignment: Text.AlignVCenter
height: lineColumn.rowHeight
renderType: Text.NativeRendering
text: index + 1
}
}
}
}
TextArea {
id: codeEditor
@ -66,7 +71,7 @@ Item {
height: parent.height
font.family: "Monospace"
font.pointSize: CodeEditorStyle.general.basicFontSize
font.pointSize: style.general.basicFontSize
width: parent.width
tabChangesFocus: false

1
mix/qml/CodeEditorStyle.qml

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

45
mix/qml/CodeEditorView.qml

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

2
mix/qml/CommonSeparator.qml

@ -4,6 +4,6 @@ import "."
Rectangle
{
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);
}
DebuggerPaneStyle {
id: dbgStyle
}
Connections {
target: clientModel
onDebugDataReady: {
@ -449,7 +453,7 @@ Rectangle {
color: "#b2b3ae"
text: styleData.value.split(' ')[0]
font.family: "monospace"
font.pointSize: DebuggerPaneStyle.general.basicFontSize
font.pointSize: dbgStyle.general.basicFontSize
wrapMode: Text.NoWrap
id: id
}
@ -459,7 +463,7 @@ Rectangle {
color: styleData.selected ? "white" : "black"
font.family: "monospace"
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"
color: "#4a4a4a"
text: styleData.row;
font.pointSize: DebuggerPaneStyle.general.basicFontSize
font.pointSize: dbgStyle.general.basicFontSize
}
}
@ -550,7 +554,7 @@ Rectangle {
anchors.verticalCenter: parent.verticalCenter
color: "#4a4a4a"
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
QtObject {

1
mix/qml/DefaultLabel.qml

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

4
mix/qml/DeploymentDialog.qml

@ -31,7 +31,7 @@ Window {
property string currentAccount
property alias gasToUse: gasToUseInput.text
color: Style.generic.layout.backgroundColor
color: appStyle.generic.layout.backgroundColor
function close()
{
@ -329,7 +329,7 @@ Window {
anchors.verticalCenter: parent.verticalCenter;
anchors.left: applicationUrlEth.right
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 variant selManager;
property int index;
color: index % 2 === 0 ? "transparent" : ProjectFilesStyle.title.background
color: index % 2 === 0 ? "transparent" : projectFilesStyle.title.background
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()
{
return section.state === "hidden" ? 0 : ProjectFilesStyle.documentsList.fileNameHeight * wrapperItem.model.count;
return section.state === "hidden" ? 0 : projectFilesStyle.documentsList.fileNameHeight * wrapperItem.model.count;
}
function hiddenHeightElement()
{
return section.state === "hidden" ? 0 : ProjectFilesStyle.documentsList.fileNameHeight;
return section.state === "hidden" ? 0 : projectFilesStyle.documentsList.fileNameHeight;
}
function getDocumentIndex(documentId)
@ -68,7 +68,7 @@ Rectangle
{
anchors.top: parent.top
id: rowCol
height: ProjectFilesStyle.documentsList.height
height: projectFilesStyle.documentsList.height
Layout.fillWidth: true
@ -88,15 +88,15 @@ Rectangle
id: section
text: sectionName
anchors.left: parent.left
anchors.leftMargin: ProjectFilesStyle.general.leftMargin
color: ProjectFilesStyle.documentsList.sectionColor
anchors.leftMargin: projectFilesStyle.general.leftMargin
color: projectFilesStyle.documentsList.sectionColor
font.family: boldFont.name
font.pointSize: ProjectFilesStyle.documentsList.sectionFontSize
font.pointSize: projectFilesStyle.documentsList.sectionFontSize
states: [
State {
name: "hidden"
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" }
}
]
@ -138,7 +138,7 @@ Rectangle
Layout.preferredHeight: wrapperItem.hiddenHeightElement()
Layout.maximumHeight: wrapperItem.hiddenHeightElement()
height: wrapperItem.hiddenHeightElement()
color: isSelected ? ProjectFilesStyle.documentsList.highlightColor : "transparent"
color: isSelected ? projectFilesStyle.documentsList.highlightColor : "transparent"
property bool isSelected
property bool renameMode
@ -147,15 +147,15 @@ Rectangle
anchors.verticalCenter: parent.verticalCenter
anchors.fill: parent
anchors.left: parent.left
anchors.leftMargin: ProjectFilesStyle.general.leftMargin + 2
anchors.leftMargin: projectFilesStyle.general.leftMargin + 2
Text {
id: nameText
height: parent.height
visible: !renameMode
color: rootItem.isSelected ? ProjectFilesStyle.documentsList.selectedColor : ProjectFilesStyle.documentsList.color
color: rootItem.isSelected ? projectFilesStyle.documentsList.selectedColor : projectFilesStyle.documentsList.color
text: name;
font.family: fileNameFont.name
font.pointSize: ProjectFilesStyle.documentsList.fontSize
font.pointSize: projectFilesStyle.documentsList.fontSize
verticalAlignment: Text.AlignVCenter
Connections
@ -182,7 +182,7 @@ Rectangle
DefaultLabel {
id: editStatusLabel
visible: false
color: rootItem.isSelected ? ProjectFilesStyle.documentsList.selectedColor : ProjectFilesStyle.documentsList.color
color: rootItem.isSelected ? projectFilesStyle.documentsList.selectedColor : projectFilesStyle.documentsList.color
verticalAlignment: Text.AlignVCenter
text: "*"
width: 10
@ -196,7 +196,7 @@ Rectangle
visible: renameMode
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: ProjectFilesStyle.general.leftMargin
anchors.leftMargin: projectFilesStyle.general.leftMargin
MouseArea {
id: textMouseArea
anchors.fill: parent

4
mix/qml/ItemDelegateDataDump.qml

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

1
mix/qml/LogsPaneStyle.qml

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

1
mix/qml/MainContent.qml

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

1
mix/qml/NewProjectDialog.qml

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

1
mix/qml/ProjectFilesStyle.qml

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

21
mix/qml/ProjectList.qml

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

2
mix/qml/ProjectModel.qml

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

3
mix/qml/Splitter.qml

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

16
mix/qml/StateDialog.qml

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

1
mix/qml/StateDialogStyle.qml

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

1
mix/qml/StateListModel.qml

@ -12,6 +12,7 @@ Item {
property alias model: stateListModel
property var stateList: []
property alias stateDialog: stateDialog
property string defaultAccount: "cb73d9408c4720e230387d956eb0f829d8a4dd2c1055f96257167e14e7169074" //support for old project
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" }
}
StatusPaneStyle {
id: statusPaneStyle
}
Connections {
target: webPreview
onJavaScriptMessage:
@ -123,7 +127,7 @@ Rectangle {
Text {
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
font.pointSize: Style.absoluteSize(-1)
font.pointSize: appStyle.absoluteSize(-1)
height: 15
font.family: "sans serif"
objectName: "status"

1
mix/qml/StatusPaneStyle.qml

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

4
mix/qml/StorageView.qml

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

45
mix/qml/TransactionDialog.qml

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

19
mix/qml/WebCodeEditor.qml

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

21
mix/qml/WebPreview.qml

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

1
mix/qml/WebPreviewStyle.qml

@ -1,4 +1,3 @@
pragma Singleton
import QtQuick 2.0
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
}
}

84
mix/web.qrc

@ -1,44 +1,44 @@
<RCC>
<qresource prefix="/">
<file>qml/WebPreview.qml</file>
<file>qml/html/WebContainer.html</file>
<file>qml/html/cm/active-line.js</file>
<file>qml/html/codeeditor.html</file>
<file>qml/html/cm/codemirror.css</file>
<file>qml/html/cm/codemirror.js</file>
<file>qml/html/cm/javascript.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/solidity.js</file>
<file>qml/html/cm/dialog.css</file>
<file>qml/html/cm/dialog.js</file>
<file>qml/html/cm/search.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/closebrackets.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/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/acorn.js</file>
<file>qml/html/cm/acorn_loose.js</file>
<file>qml/html/cm/walk.js</file>
<file>qml/html/cm/mark-selection.js</file>
</qresource>
<qresource prefix="/">
<file>qml/WebCodeEditor.qml</file>
<file>qml/WebPreview.qml</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/anyword-hint.js</file>
<file>qml/html/cm/closebrackets.js</file>
<file>qml/html/cm/codemirror.css</file>
<file>qml/html/cm/codemirror.js</file>
<file>qml/html/cm/comment.js</file>
<file>qml/html/cm/css.js</file>
<file>qml/html/cm/def.js</file>
<file>qml/html/cm/dialog.css</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/searchcursor.js</file>
<file>qml/html/cm/show-hint.css</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/tern.js</file>
<file>qml/html/cm/ternserver.js</file>
<file>qml/html/cm/walk.js</file>
<file>qml/html/cm/xml.js</file>
<file>qml/html/codeeditor.html</file>
<file>qml/html/codeeditor.js</file>
</qresource>
</RCC>

33
test/Stats.cpp

@ -19,6 +19,7 @@
#include <iterator>
#include <numeric>
#include <fstream>
namespace dev
{
@ -31,6 +32,11 @@ Stats& Stats::get()
return instance;
}
void Stats::suiteStarted(std::string const& _name)
{
m_currentSuite = _name;
}
void Stats::testStarted(std::string const& _name)
{
m_currentTest = _name;
@ -39,7 +45,7 @@ void Stats::testStarted(std::string const& _name)
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)
@ -52,31 +58,42 @@ Stats::~Stats()
if (m_stats.empty())
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 itr = m_stats.begin();
auto min = *itr;
auto max = *m_stats.rbegin();
std::advance(itr, m_stats.size() / 2);
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(' ');
if (Options::get().statsFull)
if (Options::get().statsOutFile == "out")
{
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";
}
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"
<< " avg: " << (tot / m_stats.size()) << "\n\n"
<< " min: " << min.first << " (" << min.second << ")\n"
<< " med: " << med.first << " (" << med.second << ")\n"
<< " max: " << max.first << " (" << max.second << ")\n";
<< " min: " << min.duration << " (" << min.name << ")\n"
<< " med: " << med.duration << " (" << med.name << ")\n"
<< " max: " << max.duration << " (" << max.name << ")\n";
}
}

13
test/Stats.h

@ -18,7 +18,7 @@
#pragma once
#include <chrono>
#include <map>
#include <vector>
#include "TestHelper.h"
@ -31,19 +31,26 @@ class Stats: public Listener
{
public:
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();
~Stats();
void suiteStarted(std::string const& _name) override;
void testStarted(std::string const& _name) override;
void testFinished() override;
private:
clock::time_point m_tp;
std::string m_currentSuite;
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 <liblll/Compiler.h>
#include <libevm/VMFactory.h>
#include "Stats.h"
using namespace std;
using namespace dev::eth;
@ -431,6 +432,9 @@ void executeTests(const string& _name, const string& _testPathAppendix, std::fun
string testPath = getTestPath();
testPath += _testPathAppendix;
if (Options::get().stats)
Listener::registerListener(Stats::get());
if (Options::get().fillTests)
{
try
@ -462,6 +466,7 @@ void executeTests(const string& _name, const string& _testPathAppendix, std::fun
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?");
json_spirit::read_string(s, v);
Listener::notifySuiteStarted(_name);
doTests(v, false);
}
catch (Exception const& _e)
@ -535,10 +540,12 @@ Options::Options()
vmtrace = true;
else if (arg == "--filltests")
fillTests = true;
else if (arg == "--stats")
else if (arg.compare(0, 7, "--stats") == 0)
{
stats = true;
else if (arg == "--stats=full")
stats = statsFull = true;
if (arg.size() > 7)
statsOutFile = arg.substr(8); // skip '=' char
}
else if (arg == "--performance")
performance = true;
else if (arg == "--quadratic")
@ -586,6 +593,12 @@ void Listener::registerListener(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)
{
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 fillTests = false; ///< Create JSON test files from execution results
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
/// @{
@ -191,10 +191,12 @@ class Listener
public:
virtual ~Listener() = default;
virtual void suiteStarted(std::string const&) {}
virtual void testStarted(std::string const& _name) = 0;
virtual void testFinished() = 0;
static void registerListener(Listener& _listener);
static void notifySuiteStarted(std::string const& _name);
static void notifyTestStarted(std::string const& _name);
static void notifyTestFinished();

5
test/state.cpp

@ -31,7 +31,6 @@
#include <libethereum/Defaults.h>
#include <libevm/VM.h>
#include "TestHelper.h"
#include "Stats.h"
using namespace std;
using namespace json_spirit;
@ -42,9 +41,6 @@ namespace dev { namespace test {
void doStateTests(json_spirit::mValue& v, bool _fillin)
{
if (Options::get().stats)
Listener::registerListener(Stats::get());
for (auto& i: v.get_obj())
{
std::cout << " " << i.first << "\n";
@ -254,6 +250,7 @@ BOOST_AUTO_TEST_CASE(stRandom)
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?");
json_spirit::read_string(s, v);
test::Listener::notifySuiteStarted(path.filename().string());
dev::test::doStateTests(v, false);
}
catch (Exception const& _e)

5
test/vm.cpp

@ -25,7 +25,6 @@
#include <libethereum/Executive.h>
#include <libevm/VMFactory.h>
#include "vm.h"
#include "Stats.h"
using namespace std;
using namespace json_spirit;
@ -311,9 +310,6 @@ namespace dev { namespace test {
void doVMTests(json_spirit::mValue& v, bool _fillin)
{
if (Options::get().stats)
Listener::registerListener(Stats::get());
for (auto& i: v.get_obj())
{
std::cout << " " << i.first << "\n";
@ -549,6 +545,7 @@ BOOST_AUTO_TEST_CASE(vmRandom)
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?");
json_spirit::read_string(s, v);
test::Listener::notifySuiteStarted(path.filename().string());
doVMTests(v, false);
}
catch (Exception const& _e)

10
test/webthreestubclient.h

@ -62,6 +62,16 @@ class WebThreeStubClient : public jsonrpc::Client
else
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)
{
Json::Value p;

Loading…
Cancel
Save