diff --git a/libevm/VM.h b/libevm/VM.h index b14a117df..1cf06b78b 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -56,7 +56,7 @@ public: virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; - void require(u256 _n, u256 _d) { if (m_stack.size() < _n) { if (m_onFail) m_onFail(); BOOST_THROW_EXCEPTION(StackUnderflow() << RequirementError((bigint)_n, (bigint)m_stack.size())); } if (m_stack.size() - _n + _d >= c_stackLimit) { if (m_onFail) m_onFail(); BOOST_THROW_EXCEPTION(OutOfStack() << RequirementError((bigint)(_d - _n), (bigint)m_stack.size())); } } + void require(u256 _n, u256 _d) { if (m_stack.size() < _n) { if (m_onFail) m_onFail(); BOOST_THROW_EXCEPTION(StackUnderflow() << RequirementError((bigint)_n, (bigint)m_stack.size())); } if (m_stack.size() - _n + _d > c_stackLimit) { if (m_onFail) m_onFail(); BOOST_THROW_EXCEPTION(OutOfStack() << RequirementError((bigint)(_d - _n), (bigint)m_stack.size())); } } void requireMem(unsigned _n) { if (m_temp.size() < _n) { m_temp.resize(_n); } } u256 curPC() const { return m_curPC; } diff --git a/libevmcore/Assembly.cpp b/libevmcore/Assembly.cpp index 0301c9325..904903761 100644 --- a/libevmcore/Assembly.cpp +++ b/libevmcore/Assembly.cpp @@ -34,9 +34,9 @@ void Assembly::append(Assembly const& _a) for (AssemblyItem i: _a.m_items) { if (i.type() == Tag || i.type() == PushTag) - i.m_data += m_usedTags; + i.setData(i.data() + m_usedTags); else if (i.type() == PushSub || i.type() == PushSubSize) - i.m_data += m_subs.size(); + i.setData(i.data() + m_usedTags); append(i); } m_deposit = newDeposit; @@ -106,34 +106,34 @@ ostream& Assembly::stream(ostream& _out, string const& _prefix, StringMap const& for (AssemblyItem const& i: m_items) { _out << _prefix; - switch (i.m_type) + switch (i.type()) { case Operation: _out << " " << instructionInfo(i.instruction()).name << "\t" << i.getJumpTypeAsString(); break; case Push: - _out << " PUSH " << i.m_data; + _out << " PUSH " << i.data(); break; case PushString: - _out << " PUSH \"" << m_strings.at((h256)i.m_data) << "\""; + _out << " PUSH \"" << m_strings.at((h256)i.data()) << "\""; break; case PushTag: - _out << " PUSH [tag" << i.m_data << "]"; + _out << " PUSH [tag" << i.data() << "]"; break; case PushSub: - _out << " PUSH [$" << h256(i.m_data).abridged() << "]"; + _out << " PUSH [$" << h256(i.data()).abridged() << "]"; break; case PushSubSize: - _out << " PUSH #[$" << h256(i.m_data).abridged() << "]"; + _out << " PUSH #[$" << h256(i.data()).abridged() << "]"; break; case PushProgramSize: _out << " PUSHSIZE"; break; case Tag: - _out << "tag" << i.m_data << ": " << endl << _prefix << " JUMPDEST"; + _out << "tag" << i.data() << ": " << endl << _prefix << " JUMPDEST"; break; case PushData: - _out << " PUSH [" << hex << (unsigned)i.m_data << "]"; + _out << " PUSH [" << hex << (unsigned)i.data() << "]"; break; default: BOOST_THROW_EXCEPTION(InvalidOpcode()); @@ -189,7 +189,7 @@ Assembly& Assembly::optimise(bool _enable) return *this; std::vector>> rules; // jump to next instruction - rules.push_back({ { PushTag, Instruction::JUMP, Tag }, [](AssemblyItemsConstRef m) -> AssemblyItems { if (m[0].m_data == m[2].m_data) return {m[2]}; else return m.toVector(); }}); + rules.push_back({ { PushTag, Instruction::JUMP, Tag }, [](AssemblyItemsConstRef m) -> AssemblyItems { if (m[0].data() == m[2].data()) return {m[2]}; else return m.toVector(); }}); unsigned total = 0; for (unsigned count = 1; count > 0; total += count) @@ -331,16 +331,16 @@ bytes Assembly::assemble() const // m_data must not change from here on for (AssemblyItem const& i: m_items) - switch (i.m_type) + switch (i.type()) { case Operation: - ret.push_back((byte)i.m_data); + ret.push_back((byte)i.data()); break; case PushString: { ret.push_back((byte)Instruction::PUSH32); unsigned ii = 0; - for (auto j: m_strings.at((h256)i.m_data)) + for (auto j: m_strings.at((h256)i.data())) if (++ii > 32) break; else @@ -351,30 +351,30 @@ bytes Assembly::assemble() const } case Push: { - byte b = max(1, dev::bytesRequired(i.m_data)); + byte b = max(1, dev::bytesRequired(i.data())); ret.push_back((byte)Instruction::PUSH1 - 1 + b); ret.resize(ret.size() + b); bytesRef byr(&ret.back() + 1 - b, b); - toBigEndian(i.m_data, byr); + toBigEndian(i.data(), byr); break; } case PushTag: { ret.push_back(tagPush); - tagRef[ret.size()] = (unsigned)i.m_data; + tagRef[ret.size()] = (unsigned)i.data(); ret.resize(ret.size() + bytesPerTag); break; } case PushData: case PushSub: { ret.push_back(dataRefPush); - dataRef.insert(make_pair((h256)i.m_data, ret.size())); + dataRef.insert(make_pair((h256)i.data(), ret.size())); ret.resize(ret.size() + bytesPerDataRef); break; } case PushSubSize: { - auto s = m_data[i.m_data].size(); + auto s = m_data[i.data()].size(); byte b = max(1, dev::bytesRequired(s)); ret.push_back((byte)Instruction::PUSH1 - 1 + b); ret.resize(ret.size() + b); @@ -390,7 +390,7 @@ bytes Assembly::assemble() const break; } case Tag: - tagPos[(unsigned)i.m_data] = ret.size(); + tagPos[(unsigned)i.data()] = ret.size(); ret.push_back((byte)Instruction::JUMPDEST); break; default: diff --git a/libevmcore/Assembly.h b/libevmcore/Assembly.h index 315e6aaed..2744af900 100644 --- a/libevmcore/Assembly.h +++ b/libevmcore/Assembly.h @@ -65,7 +65,7 @@ public: template Assembly& operator<<(T const& _d) { append(_d); return *this; } AssemblyItems const& getItems() const { return m_items; } AssemblyItem const& back() const { return m_items.back(); } - std::string backString() const { return m_items.size() && m_items.back().m_type == PushString ? m_strings.at((h256)m_items.back().m_data) : std::string(); } + std::string backString() const { return m_items.size() && m_items.back().type() == PushString ? m_strings.at((h256)m_items.back().data()) : std::string(); } void onePath() { if (asserts(!m_totalDeposit && !m_baseDeposit)) BOOST_THROW_EXCEPTION(InvalidDeposit()); m_baseDeposit = m_deposit; m_totalDeposit = INT_MAX; } void otherPath() { donePath(); m_totalDeposit = m_deposit; m_deposit = m_baseDeposit; } diff --git a/libevmcore/AssemblyItem.h b/libevmcore/AssemblyItem.h index e7beced39..3e222a6eb 100644 --- a/libevmcore/AssemblyItem.h +++ b/libevmcore/AssemblyItem.h @@ -40,8 +40,6 @@ class Assembly; class AssemblyItem { - friend class Assembly; - public: enum class JumpType { Ordinary, IntoFunction, OutOfFunction }; @@ -54,6 +52,9 @@ public: AssemblyItemType type() const { return m_type; } u256 const& data() const { return m_data; } + void setType(AssemblyItemType const _type) { m_type = _type; } + void setData(u256 const& _data) { m_data = _data; } + /// @returns the instruction of this item (only valid if type() == Operation) Instruction instruction() const { return Instruction(byte(m_data)); } diff --git a/libevmcore/CommonSubexpressionEliminator.cpp b/libevmcore/CommonSubexpressionEliminator.cpp index 47bb5b512..5c6ba95af 100644 --- a/libevmcore/CommonSubexpressionEliminator.cpp +++ b/libevmcore/CommonSubexpressionEliminator.cpp @@ -24,7 +24,7 @@ #include #include #include -#include +#include using namespace std; using namespace dev; @@ -248,79 +248,6 @@ ExpressionClasses::Id CommonSubexpressionEliminator::loadFromMemory(ExpressionCl return m_memoryContent[_slot] = m_expressionClasses.find(Instruction::MLOAD, {_slot}, true, m_sequenceNumber); } -bool SemanticInformation::breaksBasicBlock(AssemblyItem const& _item) -{ - switch (_item.type()) - { - default: - case UndefinedItem: - case Tag: - return true; - case Push: - case PushString: - case PushTag: - case PushSub: - case PushSubSize: - case PushProgramSize: - case PushData: - return false; - case Operation: - { - if (isSwapInstruction(_item) || isDupInstruction(_item)) - return false; - if (_item.instruction() == Instruction::GAS || _item.instruction() == Instruction::PC) - return true; // GAS and PC assume a specific order of opcodes - if (_item.instruction() == Instruction::MSIZE) - return true; // msize is modified already by memory access, avoid that for now - if (_item.instruction() == Instruction::SHA3) - return true; //@todo: we have to compare sha3's not based on their memory addresses but on the memory content. - InstructionInfo info = instructionInfo(_item.instruction()); - if (_item.instruction() == Instruction::SSTORE) - return false; - if (_item.instruction() == Instruction::MSTORE) - return false; - //@todo: We do not handle the following memory instructions for now: - // calldatacopy, codecopy, extcodecopy, mstore8, - // msize (note that msize also depends on memory read access) - - // the second requirement will be lifted once it is implemented - return info.sideEffects || info.args > 2; - } - } -} - -bool SemanticInformation::isCommutativeOperation(AssemblyItem const& _item) -{ - if (_item.type() != Operation) - return false; - switch (_item.instruction()) - { - case Instruction::ADD: - case Instruction::MUL: - case Instruction::EQ: - case Instruction::AND: - case Instruction::OR: - case Instruction::XOR: - return true; - default: - return false; - } -} - -bool SemanticInformation::isDupInstruction(AssemblyItem const& _item) -{ - if (_item.type() != Operation) - return false; - return Instruction::DUP1 <= _item.instruction() && _item.instruction() <= Instruction::DUP16; -} - -bool SemanticInformation::isSwapInstruction(AssemblyItem const& _item) -{ - if (_item.type() != Operation) - return false; - return Instruction::SWAP1 <= _item.instruction() && _item.instruction() <= Instruction::SWAP16; -} - CSECodeGenerator::CSECodeGenerator( ExpressionClasses& _expressionClasses, vector const& _storeOperations diff --git a/libevmcore/CommonSubexpressionEliminator.h b/libevmcore/CommonSubexpressionEliminator.h index a9a0c60a4..0dbb47b29 100644 --- a/libevmcore/CommonSubexpressionEliminator.h +++ b/libevmcore/CommonSubexpressionEliminator.h @@ -31,6 +31,7 @@ #include #include #include +#include namespace dev { @@ -139,20 +140,6 @@ private: AssemblyItem const* m_breakingItem = nullptr; }; -/** - * Helper functions to provide context-independent information about assembly items. - */ -struct SemanticInformation -{ - /// @returns true if the given items starts a new basic block - static bool breaksBasicBlock(AssemblyItem const& _item); - /// @returns true if the item is a two-argument operation whose value does not depend on the - /// order of its arguments. - static bool isCommutativeOperation(AssemblyItem const& _item); - static bool isDupInstruction(AssemblyItem const& _item); - static bool isSwapInstruction(AssemblyItem const& _item); -}; - /** * Unit that generates code from current stack layout, target stack layout and information about * the equivalence classes. @@ -230,7 +217,7 @@ _AssemblyItemIterator CommonSubexpressionEliminator::feedItems( _AssemblyItemIterator _end ) { - for (; _iterator != _end && !SemanticInformation::breaksBasicBlock(*_iterator); ++_iterator) + for (; _iterator != _end && !SemanticInformation::breaksCSEAnalysisBlock(*_iterator); ++_iterator) feedItem(*_iterator); if (_iterator != _end) m_breakingItem = &(*_iterator++); diff --git a/libevmcore/SemanticInformation.cpp b/libevmcore/SemanticInformation.cpp new file mode 100644 index 000000000..e561e7554 --- /dev/null +++ b/libevmcore/SemanticInformation.cpp @@ -0,0 +1,107 @@ +/* + 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 . +*/ +/** + * @file SemanticInformation.cpp + * @author Christian + * @date 2015 + * Helper to provide semantic information about assembly items. + */ + +#include +#include + +using namespace std; +using namespace dev; +using namespace dev::eth; + +bool SemanticInformation::breaksCSEAnalysisBlock(AssemblyItem const& _item) +{ + switch (_item.type()) + { + default: + case UndefinedItem: + case Tag: + return true; + case Push: + case PushString: + case PushTag: + case PushSub: + case PushSubSize: + case PushProgramSize: + case PushData: + return false; + case Operation: + { + if (isSwapInstruction(_item) || isDupInstruction(_item)) + return false; + if (_item.instruction() == Instruction::GAS || _item.instruction() == Instruction::PC) + return true; // GAS and PC assume a specific order of opcodes + if (_item.instruction() == Instruction::MSIZE) + return true; // msize is modified already by memory access, avoid that for now + if (_item.instruction() == Instruction::SHA3) + return true; //@todo: we have to compare sha3's not based on their memory addresses but on the memory content. + InstructionInfo info = instructionInfo(_item.instruction()); + if (_item.instruction() == Instruction::SSTORE) + return false; + if (_item.instruction() == Instruction::MSTORE) + return false; + //@todo: We do not handle the following memory instructions for now: + // calldatacopy, codecopy, extcodecopy, mstore8, + // msize (note that msize also depends on memory read access) + + // the second requirement will be lifted once it is implemented + return info.sideEffects || info.args > 2; + } + } +} + +bool SemanticInformation::isCommutativeOperation(AssemblyItem const& _item) +{ + if (_item.type() != Operation) + return false; + switch (_item.instruction()) + { + case Instruction::ADD: + case Instruction::MUL: + case Instruction::EQ: + case Instruction::AND: + case Instruction::OR: + case Instruction::XOR: + return true; + default: + return false; + } +} + +bool SemanticInformation::isDupInstruction(AssemblyItem const& _item) +{ + if (_item.type() != Operation) + return false; + return Instruction::DUP1 <= _item.instruction() && _item.instruction() <= Instruction::DUP16; +} + +bool SemanticInformation::isSwapInstruction(AssemblyItem const& _item) +{ + if (_item.type() != Operation) + return false; + return Instruction::SWAP1 <= _item.instruction() && _item.instruction() <= Instruction::SWAP16; +} + +bool SemanticInformation::isJumpInstruction(AssemblyItem const& _item) +{ + return _item == AssemblyItem(Instruction::JUMP) || _item == AssemblyItem(Instruction::JUMPI); +} diff --git a/libevmcore/SemanticInformation.h b/libevmcore/SemanticInformation.h new file mode 100644 index 000000000..7497dc651 --- /dev/null +++ b/libevmcore/SemanticInformation.h @@ -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 . +*/ +/** + * @file SemanticInformation.h + * @author Christian + * @date 2015 + * Helper to provide semantic information about assembly items. + */ + +#pragma once + + +namespace dev +{ +namespace eth +{ + +class AssemblyItem; + +/** + * Helper functions to provide context-independent information about assembly items. + */ +struct SemanticInformation +{ + /// @returns true if the given items starts a new block for common subexpression analysis. + static bool breaksCSEAnalysisBlock(AssemblyItem const& _item); + /// @returns true if the item is a two-argument operation whose value does not depend on the + /// order of its arguments. + static bool isCommutativeOperation(AssemblyItem const& _item); + static bool isDupInstruction(AssemblyItem const& _item); + static bool isSwapInstruction(AssemblyItem const& _item); + static bool isJumpInstruction(AssemblyItem const& _item); +}; + +} +} diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index e3c9bc964..095ba7bf1 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -337,8 +337,14 @@ void FunctionDefinition::checkTypeRequirements() { if (!var->getType()->canLiveOutsideStorage()) BOOST_THROW_EXCEPTION(var->createTypeError("Type is required to live outside storage.")); - if (!(var->getType()->externalType()) && getVisibility() >= Visibility::Public) - BOOST_THROW_EXCEPTION(var->createTypeError("Internal type is not allowed for function with external visibility")); + if (getVisibility() >= Visibility::Public && !(var->getType()->externalType())) + { + // todo delete when will be implemented arrays as parameter type in internal functions + if (getVisibility() == Visibility::Public && var->getType()->getCategory() == Type::Category::Array) + BOOST_THROW_EXCEPTION(var->createTypeError("Arrays only implemented for external functions.")); + else + BOOST_THROW_EXCEPTION(var->createTypeError("Internal type is not allowed for public and external functions.")); + } } for (ASTPointer const& modifier: m_functionModifiers) modifier->checkTypeRequirements(isConstructor() ? @@ -379,7 +385,11 @@ void VariableDeclaration::checkTypeRequirements() m_value->expectType(*m_type); if (m_isStateVariable && !m_type->externalType() && getVisibility() >= Visibility::Public) BOOST_THROW_EXCEPTION(createTypeError("Internal type is not allowed for state variables.")); - } else + + if (!FunctionType(*this).externalType()) + BOOST_THROW_EXCEPTION(createTypeError("Internal type is not allowed for public state variables.")); + } + else { // no type declared and no previous assignment, infer the type m_value->checkTypeRequirements(); diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 5fd7d24a6..78649cc95 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -1103,11 +1103,18 @@ TypePointer FunctionType::externalType() const TypePointers paramTypes; TypePointers retParamTypes; - for (auto it = m_parameterTypes.cbegin(); it != m_parameterTypes.cend(); ++it) - paramTypes.push_back((*it)->externalType()); - for (auto it = m_returnParameterTypes.cbegin(); it != m_returnParameterTypes.cend(); ++it) - retParamTypes.push_back((*it)->externalType()); - + for (auto type: m_parameterTypes) + { + if (!type->externalType()) + return TypePointer(); + paramTypes.push_back(type->externalType()); + } + for (auto type: m_returnParameterTypes) + { + if (!type->externalType()) + return TypePointer(); + retParamTypes.push_back(type->externalType()); + } return make_shared(paramTypes, retParamTypes, m_location, m_arbitraryParameters); } diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 99fd878f0..e1852bc7f 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -512,6 +512,8 @@ public: virtual Category getCategory() const override { return Category::Function; } + /// @returns TypePointer of a new FunctionType object. All input/return parameters are an appropriate external types of input/return parameters of current function. + /// Returns an empty shared pointer if one of the input/return parameters does not have an externaltype. virtual TypePointer externalType() const override; explicit FunctionType(FunctionDefinition const& _function, bool _isInternal = true); diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index a96ab8791..53ec34e2b 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -93,8 +93,23 @@ private: bool m_functionScope; uint m_storageSlot; }; + +dev::eth::AssemblyItems filterLocations(dev::eth::AssemblyItems const& _locations, dev::solidity::ContractDefinition const& _contract, QHash _functions) +{ + dev::eth::AssemblyItems result; + result.reserve(_locations.size()); + for (dev::eth::AssemblyItem item : _locations) + { + dev::SourceLocation const& l = item.getLocation(); + if (_contract.getLocation() == l || _functions.contains(LocationPair(l.start, l.end))) + item.setLocation(dev::SourceLocation(-1, -1, l.sourceName)); + result.push_back(item); + } + return result; } +} //namespace + void BackgroundWorker::queueCodeChange(int _jobId) { m_model->runCompilationJob(_jobId); @@ -105,13 +120,11 @@ CompiledContract::CompiledContract(const dev::solidity::CompilerStack& _compiler m_sourceHash(qHash(_source)) { std::string name = _contractName.toStdString(); - auto const& contractDefinition = _compiler.getContractDefinition(name); + ContractDefinition const& contractDefinition = _compiler.getContractDefinition(name); m_contract.reset(new QContractDefinition(nullptr, &contractDefinition)); QQmlEngine::setObjectOwnership(m_contract.get(), QQmlEngine::CppOwnership); m_contract->moveToThread(QApplication::instance()->thread()); m_bytes = _compiler.getBytecode(_contractName.toStdString()); - m_assemblyItems = _compiler.getRuntimeAssemblyItems(name); - m_constructorAssemblyItems = _compiler.getAssemblyItems(name); dev::solidity::InterfaceHandler interfaceHandler; m_contractInterface = QString::fromStdString(*interfaceHandler.getABIInterface(contractDefinition)); @@ -122,6 +135,8 @@ CompiledContract::CompiledContract(const dev::solidity::CompilerStack& _compiler CollectDeclarationsVisitor visitor(&m_functions, &m_locals, &m_storage); contractDefinition.accept(visitor); + m_assemblyItems = filterLocations(_compiler.getRuntimeAssemblyItems(name), contractDefinition, m_functions); + m_constructorAssemblyItems = filterLocations(_compiler.getAssemblyItems(name), contractDefinition, m_functions); } QString CompiledContract::codeHex() const diff --git a/mix/qml.qrc b/mix/qml.qrc index bed954741..5ceaaced6 100644 --- a/mix/qml.qrc +++ b/mix/qml.qrc @@ -61,5 +61,6 @@ qml/js/TransactionHelper.js qml/main.qml qml/qmldir + qml/StatesComboBox.qml diff --git a/mix/qml/CodeEditorView.qml b/mix/qml/CodeEditorView.qml index 7ea1e30d9..25ecbc98c 100644 --- a/mix/qml/CodeEditorView.qml +++ b/mix/qml/CodeEditorView.qml @@ -11,15 +11,6 @@ Item { signal breakpointsChanged(string documentId) signal isCleanChanged(var isClean, string documentId) - function getDocumentIdByName(fileName) - { - for (var i = 0; i < editorListModel.count; i++) { - if (editorListModel.get(i).fileName === fileName) { - return editorListModel.get(i).documentId; - } - } - return null; - } function getDocumentText(documentId) { for (var i = 0; i < editorListModel.count; i++) { diff --git a/mix/qml/Debugger.qml b/mix/qml/Debugger.qml index 358750b24..836bbaf94 100644 --- a/mix/qml/Debugger.qml +++ b/mix/qml/Debugger.qml @@ -219,6 +219,33 @@ Rectangle { anchors.horizontalCenter: parent.horizontalCenter id: jumpButtons spacing: 3 + + StepActionImage + { + id: playAction + enabledStateImg: "qrc:/qml/img/play_button.png" + disableStateImg: "qrc:/qml/img/play_button.png" + onClicked: projectModel.stateListModel.runState(transactionLog.selectedStateIndex) + width: 30 + height: 30 + buttonShortcut: "Ctrl+Shift+F8" + buttonTooltip: qsTr("Start Debugging") + visible: true + } + + StepActionImage + { + id: pauseAction + enabledStateImg: "qrc:/qml/img/stop_button2x.png" + disableStateImg: "qrc:/qml/img/stop_button2x.png" + onClicked: Debugger.init(null); + width: 30 + height: 30 + buttonShortcut: "Ctrl+Shift+F9" + buttonTooltip: qsTr("Stop Debugging") + visible: true + } + StepActionImage { id: runBackAction; diff --git a/mix/qml/LogsPane.qml b/mix/qml/LogsPane.qml index 3601483a0..ca123f6a0 100644 --- a/mix/qml/LogsPane.qml +++ b/mix/qml/LogsPane.qml @@ -7,81 +7,258 @@ import "." Rectangle { + property variant currentStatus; function push(_level, _type, _content) { _content = _content.replace(/\n/g, " ") - logsModel.insert(0, { "type": _type, "date": Qt.formatDateTime(new Date(), "hh:mm:ss dd.MM.yyyy"), "content": _content, "level": _level }); + logsModel.insert(0, { "type": _type, "date": Qt.formatDateTime(new Date(), "hh:mm:ss"), "content": _content, "level": _level }); + } + + onVisibleChanged: + { + if (visible && (logsModel.count === 0 || (logsModel.get(0).date !== currentStatus.date && logsModel.get(0).content !== currentStatus.content))) + logsModel.insert(0, { "type": currentStatus.type, "date": currentStatus.date, "content": currentStatus.content, "level": currentStatus.level }); + else if (!visible) + { + for (var k = 0; k < logsModel.count; k++) + { + if (logsModel.get(k).type === "Comp") //do not keep compilation logs. + logsModel.remove(k); + } + } } anchors.fill: parent - radius: 5 - color: LogsPaneStyle.generic.layout.backgroundColor - border.color: LogsPaneStyle.generic.layout.borderColor - border.width: LogsPaneStyle.generic.layout.borderWidth - ColumnLayout { + radius: 10 + color: "transparent" + id: logsPane + Column { z: 2 - height: parent.height + height: parent.height - rowAction.height width: parent.width spacing: 0 + ListModel { + id: logsModel + } + + ScrollView + { + id: scrollView + height: parent.height + width: parent.width + horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff + Column + { + id: logsRect + spacing: 0 + Repeater { + id: logsRepeater + clip: true + property string frontColor: "transparent" + model: SortFilterProxyModel { + id: proxyModel + source: logsModel + property var roles: ["-", "javascript", "run", "state", "comp"] + + Component.onCompleted: { + filterType = regEx(proxyModel.roles); + } + + function search(_value) + { + filterContent = _value; + } + + function toogleFilter(_value) + { + var count = roles.length; + for (var i in roles) + { + if (roles[i] === _value) + { + roles.splice(i, 1); + break; + } + } + if (count === roles.length) + roles.push(_value); + + filterType = regEx(proxyModel.roles); + } + + function regEx(_value) + { + return "(?:" + roles.join('|') + ")"; + } + + filterType: "(?:javascript|run|state|comp)" + filterContent: "" + filterSyntax: SortFilterProxyModel.RegExp + filterCaseSensitivity: Qt.CaseInsensitive + } + + Rectangle + { + width: LogsPaneStyle.generic.layout.dateWidth + LogsPaneStyle.generic.layout.contentWidth + LogsPaneStyle.generic.layout.typeWidth + height: 30 + color: + { + var cl; + if (level === "warning" || level === "error") + cl = LogsPaneStyle.generic.layout.errorColor; + else + cl = index % 2 === 0 ? "transparent" : LogsPaneStyle.generic.layout.logAlternateColor; + if (index === 0) + logsRepeater.frontColor = cl; + return cl; + } + + + MouseArea + { + anchors.fill: parent + onClicked: + { + if (logContent.elide === Text.ElideNone) + { + logContent.elide = Text.ElideRight; + logContent.wrapMode = Text.NoWrap + parent.height = 30; + } + else + { + logContent.elide = Text.ElideNone; + logContent.wrapMode = Text.WordWrap; + parent.height = logContent.lineCount * 30; + } + } + } + + + DefaultLabel { + text: date; + font.family: LogsPaneStyle.generic.layout.logLabelFont + width: LogsPaneStyle.generic.layout.dateWidth + font.pointSize: Style.absoluteSize(-1) + anchors.left: parent.left + anchors.leftMargin: 15 + anchors.verticalCenter: parent.verticalCenter + color: { + parent.getColor(level); + } + } + + DefaultLabel { + text: type; + font.family: LogsPaneStyle.generic.layout.logLabelFont + width: LogsPaneStyle.generic.layout.typeWidth + font.pointSize: Style.absoluteSize(-1) + anchors.left: parent.left + anchors.leftMargin: 100 + anchors.verticalCenter: parent.verticalCenter + color: { + parent.getColor(level); + } + } + + Text { + id: logContent + text: content; + font.family: LogsPaneStyle.generic.layout.logLabelFont + width: LogsPaneStyle.generic.layout.contentWidth + font.pointSize: Style.absoluteSize(-1) + anchors.verticalCenter: parent.verticalCenter + elide: Text.ElideRight + anchors.left: parent.left + anchors.leftMargin: 230 + color: { + parent.getColor(level); + } + } + + function getColor() + { + if (level === "error") + return "red"; + else if (level === "warning") + return "orange"; + else + return "#808080"; + } + } + } + } + } + + Component { + id: itemDelegate + DefaultLabel { + text: styleData.value; + font.family: LogsPaneStyle.generic.layout.logLabelFont + font.pointSize: Style.absoluteSize(-1) + color: { + if (proxyModel.get(styleData.row).level === "error") + return "red"; + else if (proxyModel.get(styleData.row).level === "warning") + return "orange"; + else + return "#808080"; + } + } + } + } + + Rectangle + { + gradient: Gradient { + GradientStop { position: 0.0; color: "#f1f1f1" } + GradientStop { position: 1.0; color: "#d9d7da" } + } + Layout.preferredHeight: LogsPaneStyle.generic.layout.headerHeight + height: LogsPaneStyle.generic.layout.headerHeight + width: logsPane.width + anchors.bottom: parent.bottom Row { id: rowAction - Layout.preferredHeight: LogsPaneStyle.generic.layout.headerHeight - height: LogsPaneStyle.generic.layout.headerHeight anchors.leftMargin: LogsPaneStyle.generic.layout.leftMargin anchors.left: parent.left spacing: LogsPaneStyle.generic.layout.headerButtonSpacing - Button + height: parent.height + Rectangle { - height: LogsPaneStyle.generic.layout.headerButtonHeight - anchors.verticalCenter: parent.verticalCenter - action: clearAction - iconSource: "qrc:/qml/img/broom.png" - } - - Action { - id: clearAction - enabled: logsModel.count > 0 - tooltip: qsTr("Clear") - onTriggered: { - logsModel.clear() + color: "transparent" + height: parent.height + width: 40 + DefaultLabel + { + anchors.verticalCenter: parent.verticalCenter + color: LogsPaneStyle.generic.layout.logLabelColor + font.pointSize: Style.absoluteSize(-3) + font.family: LogsPaneStyle.generic.layout.logLabelFont + text: qsTr("Show:") } } - Button - { - height: LogsPaneStyle.generic.layout.headerButtonHeight + Rectangle { anchors.verticalCenter: parent.verticalCenter - action: copytoClipBoardAction - iconSource: "qrc:/qml/img/copy.png" - } - - Action { - id: copytoClipBoardAction - enabled: logsModel.count > 0 - tooltip: qsTr("Copy to Clipboard") - onTriggered: { - var content = ""; - for (var k = 0; k < logsModel.count; k++) - { - var log = logsModel.get(k); - content += log.type + "\t" + log.level + "\t" + log.date + "\t" + log.content + "\n"; - } - clipboard.text = content; - } + width: 1; + height: parent.height + color: LogsPaneStyle.generic.layout.buttonSeparatorColor1 } Rectangle { anchors.verticalCenter: parent.verticalCenter - width: 1; - height: parent.height - 10 - color : "#808080" + width: 2; + height: parent.height + color: LogsPaneStyle.generic.layout.buttonSeparatorColor2 } ToolButton { id: javascriptButton checkable: true height: LogsPaneStyle.generic.layout.headerButtonHeight + width: 20 anchors.verticalCenter: parent.verticalCenter checked: true onCheckedChanged: { @@ -97,16 +274,35 @@ Rectangle font.pointSize: Style.absoluteSize(-3) color: LogsPaneStyle.generic.layout.logLabelColor anchors.centerIn: parent - text: qsTr("JavaScript") + text: qsTr("JS") } } + background: + Rectangle { + color: javascriptButton.checked ? LogsPaneStyle.generic.layout.buttonSelected : "transparent" + } } } + Rectangle { + anchors.verticalCenter: parent.verticalCenter + width: 1; + height: parent.height + color: LogsPaneStyle.generic.layout.buttonSeparatorColor1 + } + + Rectangle { + anchors.verticalCenter: parent.verticalCenter + width: 2; + height: parent.height + color: LogsPaneStyle.generic.layout.buttonSeparatorColor2 + } + ToolButton { id: runButton checkable: true height: LogsPaneStyle.generic.layout.headerButtonHeight + width: 30 anchors.verticalCenter: parent.verticalCenter checked: true onCheckedChanged: { @@ -125,14 +321,33 @@ Rectangle text: qsTr("Run") } } + background: + Rectangle { + color: runButton.checked ? LogsPaneStyle.generic.layout.buttonSelected : "transparent" + } } } + Rectangle { + anchors.verticalCenter: parent.verticalCenter + width: 1; + height: parent.height + color: LogsPaneStyle.generic.layout.buttonSeparatorColor1 + } + + Rectangle { + anchors.verticalCenter: parent.verticalCenter + width: 2; + height: parent.height + color: LogsPaneStyle.generic.layout.buttonSeparatorColor2 + } + ToolButton { id: stateButton checkable: true height: LogsPaneStyle.generic.layout.headerButtonHeight anchors.verticalCenter: parent.verticalCenter + width: 35 checked: true onCheckedChanged: { proxyModel.toogleFilter("state") @@ -145,133 +360,226 @@ Rectangle DefaultLabel { font.family: LogsPaneStyle.generic.layout.logLabelFont font.pointSize: Style.absoluteSize(-3) - color: "#5391d8" + color: LogsPaneStyle.generic.layout.logLabelColor anchors.centerIn: parent text: qsTr("State") } } + background: + Rectangle { + color: stateButton.checked ? LogsPaneStyle.generic.layout.buttonSelected : "transparent" + } } } - DefaultTextField - { - id: searchBox - height: LogsPaneStyle.generic.layout.headerButtonHeight + Rectangle { anchors.verticalCenter: parent.verticalCenter - width: LogsPaneStyle.generic.layout.headerInputWidth - font.family: LogsPaneStyle.generic.layout.logLabelFont - font.pointSize: Style.absoluteSize(-3) - font.italic: true - onTextChanged: { - proxyModel.search(text); - } + width: 1; + height: parent.height + color: LogsPaneStyle.generic.layout.buttonSeparatorColor1 } - } - ListModel { - id: logsModel + Rectangle { + anchors.verticalCenter: parent.verticalCenter + width: 2; + height: parent.height + color: LogsPaneStyle.generic.layout.buttonSeparatorColor2 + } } - TableView { - id: logsTable - clip: true - Layout.fillWidth: true - Layout.preferredHeight: parent.height - rowAction.height - headerVisible : false - onDoubleClicked: + Row + { + height: parent.height + anchors.right: parent.right + anchors.rightMargin: 10 + spacing: 10 + Rectangle { - var log = logsModel.get(logsTable.currentRow); - if (log) - clipboard.text = (log.type + "\t" + log.level + "\t" + log.date + "\t" + log.content); - } + height: LogsPaneStyle.generic.layout.headerButtonHeight + anchors.verticalCenter: parent.verticalCenter + color: "transparent" + width: 20 + Button + { + id: clearButton + action: clearAction + anchors.fill: parent + anchors.verticalCenter: parent.verticalCenter + height: 25 + style: + ButtonStyle { + background: + Rectangle { + height: LogsPaneStyle.generic.layout.headerButtonHeight + implicitHeight: LogsPaneStyle.generic.layout.headerButtonHeight + color: "transparent" + } + } + } - model: SortFilterProxyModel { - id: proxyModel - source: logsModel - property var roles: ["-", "javascript", "run", "state"] + Image { + id: clearImage + source: clearAction.enabled ? "qrc:/qml/img/cleariconactive.png" : "qrc:/qml/img/clearicon.png" + anchors.centerIn: parent + fillMode: Image.PreserveAspectFit + width: 20 + height: 25 + } - Component.onCompleted: { - filterType = regEx(proxyModel.roles); + Action { + id: clearAction + enabled: logsModel.count > 0 + tooltip: qsTr("Clear") + onTriggered: { + logsModel.clear(); + } } + } - function search(_value) + Rectangle + { + height: LogsPaneStyle.generic.layout.headerButtonHeight + anchors.verticalCenter: parent.verticalCenter + color: "transparent" + width: 20 + Button { - filterContent = _value; + id: copyButton + action: copyAction + anchors.fill: parent + anchors.verticalCenter: parent.verticalCenter + height: 25 + style: + ButtonStyle { + background: + Rectangle { + height: LogsPaneStyle.generic.layout.headerButtonHeight + implicitHeight: LogsPaneStyle.generic.layout.headerButtonHeight + color: "transparent" + } + } } - function toogleFilter(_value) - { - var count = roles.length; - for (var i in roles) - { - if (roles[i] === _value) + Image { + id: copyImage + source: copyAction.enabled ? "qrc:/qml/img/copyiconactive.png" : "qrc:/qml/img/copyicon.png" + anchors.centerIn: parent + fillMode: Image.PreserveAspectFit + width: 20 + height: 25 + } + + Action { + id: copyAction + enabled: logsModel.count > 0 + tooltip: qsTr("Copy to Clipboard") + onTriggered: { + var content = ""; + for (var k = 0; k < logsModel.count; k++) { - roles.splice(i, 1); - break; + var log = logsModel.get(k); + content += log.type + "\t" + log.level + "\t" + log.date + "\t" + log.content + "\n"; } + clipboard.text = content; } - if (count === roles.length) - roles.push(_value); - - filterType = regEx(proxyModel.roles); } + } - function regEx(_value) + Rectangle + { + width: 120 + radius: 10 + height: 25 + color: "white" + anchors.verticalCenter: parent.verticalCenter + + Image { - return "(?:" + roles.join('|') + ")"; + id: searchImg + source: "qrc:/qml/img/searchicon.png" + fillMode: Image.PreserveAspectFit + width: 20 + height: 25 + z: 3 } - filterType: "(?:javascript|run|state)" - filterContent: "" - filterSyntax: SortFilterProxyModel.RegExp - filterCaseSensitivity: Qt.CaseInsensitive - } - TableViewColumn - { - role: "date" - title: qsTr("date") - width: LogsPaneStyle.generic.layout.dateWidth - delegate: itemDelegate - } - TableViewColumn - { - role: "type" - title: qsTr("type") - width: LogsPaneStyle.generic.layout.typeWidth - delegate: itemDelegate + DefaultTextField + { + id: searchBox + z: 2 + width: 100 + anchors.left: searchImg.right + anchors.leftMargin: -7 + font.family: LogsPaneStyle.generic.layout.logLabelFont + font.pointSize: Style.absoluteSize(-3) + font.italic: true + text: qsTr(" - Search - ") + onFocusChanged: + { + if (!focus && text === "") + text = qsTr(" - Search - "); + else if (focus && text === qsTr(" - Search - ")) + text = ""; + } + + onTextChanged: { + if (text === qsTr(" - Search - ")) + proxyModel.search(""); + else + proxyModel.search(text); + } + + style: + TextFieldStyle { + background: Rectangle { + radius: 10 + } + } + } } - TableViewColumn + + Rectangle { - role: "content" - title: qsTr("content") - width: LogsPaneStyle.generic.layout.contentWidth - delegate: itemDelegate - } + height: LogsPaneStyle.generic.layout.headerButtonHeight + anchors.verticalCenter: parent.verticalCenter + color: "transparent" + width: 20 + Button + { + id: hideButton + action: hideAction + anchors.fill: parent + anchors.verticalCenter: parent.verticalCenter + height: 25 + style: + ButtonStyle { + background: + Rectangle { + height: LogsPaneStyle.generic.layout.headerButtonHeight + implicitHeight: LogsPaneStyle.generic.layout.headerButtonHeight + color: "transparent" + } + } + } - rowDelegate: Item { - Rectangle { - width: logsTable.width - 4 - height: 17 - color: styleData.alternate ? "transparent" : LogsPaneStyle.generic.layout.logAlternateColor + Image { + id: hideImage + source: "qrc:/qml/img/exit.png" + anchors.centerIn: parent + fillMode: Image.PreserveAspectFit + width: 20 + height: 25 } - } - } - Component { - id: itemDelegate - DefaultLabel { - text: styleData.value; - font.family: LogsPaneStyle.generic.layout.logLabelFont - font.pointSize: Style.absoluteSize(-1) - color: { - if (proxyModel.get(styleData.row).level === "error") - return "red"; - else if (proxyModel.get(styleData.row).level === "warning") - return "orange"; - else - return "#808080"; + Action { + id: hideAction + tooltip: qsTr("Exit") + onTriggered: { + logsPane.parent.toggle(); + } } } } } + } diff --git a/mix/qml/LogsPaneStyle.qml b/mix/qml/LogsPaneStyle.qml index 59b80653a..0bbdfcee4 100644 --- a/mix/qml/LogsPaneStyle.qml +++ b/mix/qml/LogsPaneStyle.qml @@ -11,19 +11,21 @@ QtObject { property QtObject generic: QtObject { property QtObject layout: QtObject { property string backgroundColor: "#f7f7f7" - property string borderColor: "#5391d8" - property int borderWidth: 1 - property int headerHeight: 35 - property int headerButtonSpacing: 5 + property int headerHeight: 30 + property int headerButtonSpacing: 0 property int leftMargin: 10 property int headerButtonHeight: 30 - property string logLabelColor: "#5391d8" + property string logLabelColor: "#4a4a4a" property string logLabelFont: "sans serif" property int headerInputWidth: 200 property int dateWidth: 150 - property int typeWidth: 80 - property int contentWidth: 700 - property string logAlternateColor: "#f0f0f0" + property int typeWidth: 150 + property int contentWidth: 560 + property string logAlternateColor: "#f6f5f6" + property string errorColor: "#fffcd5" + property string buttonSeparatorColor1: "#d3d0d0" + property string buttonSeparatorColor2: "#f2f1f2" + property string buttonSelected: "#dcdcdc" } } } diff --git a/mix/qml/ProjectModel.qml b/mix/qml/ProjectModel.qml index f4b73b601..ec7681f16 100644 --- a/mix/qml/ProjectModel.qml +++ b/mix/qml/ProjectModel.qml @@ -64,6 +64,7 @@ Item { function renameDocument(documentId, newName) { ProjectModelCode.renameDocument(documentId, newName); } function removeDocument(documentId) { ProjectModelCode.removeDocument(documentId); } function getDocument(documentId) { return ProjectModelCode.getDocument(documentId); } + function getDocumentIdByName(documentName) { return ProjectModelCode.getDocumentIdByName(documentName); } function getDocumentIndex(documentId) { return ProjectModelCode.getDocumentIndex(documentId); } function addExistingFiles(paths) { ProjectModelCode.doAddExistingFiles(paths); } function deployProject() { ProjectModelCode.deployProject(false); } diff --git a/mix/qml/StatesComboBox.qml b/mix/qml/StatesComboBox.qml new file mode 100644 index 000000000..bc7a4853d --- /dev/null +++ b/mix/qml/StatesComboBox.qml @@ -0,0 +1,260 @@ +/* + 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 . +*/ +/** @file StatesComboBox.qml + * @author Ali Mashatan ali@ethdev.com + * @date 2015 + * Ethereum IDE client. + */ + +import QtQuick 2.0 +import QtQuick.Controls 1.0 +import QtQuick.Layouts 1.1 +import QtGraphicalEffects 1.0 + +Rectangle { + id: statesComboBox + + width: 200 + height: 23 + + Component.onCompleted: { + var top = dropDownList + while (top.parent) { + top = top.parent + if (top.objectName == "debugPanel") + break + } + var coordinates = dropDownList.mapToItem(top, 0, 0) + //the order is important + dropDownShowdowList.parent = top + dropDownList.parent = top + + dropDownShowdowList.x = coordinates.x + dropDownShowdowList.y = coordinates.y + + dropDownList.x = coordinates.x + dropDownList.y = coordinates.y + } + + signal selectItem(real item) + signal editItem(real item) + signal selectCreate + property int rowHeight: 25 + property variant items + property alias selectedItem: chosenItemText.text + property alias selectedIndex: listView.currentRow + function setSelectedIndex(index) { + listView.currentRow = index + chosenItemText.text = statesComboBox.items.get(index).title + } + + signal comboClicked + + property variant colorItem + property variant colorSelect + + SourceSansProRegular + { + id: regularFont + } + + SourceSansProBold + { + id: boldFont + } + + smooth: true + Rectangle { + id: chosenItem + width: parent.width + height: statesComboBox.height + color: statesComboBox.color + + Text { + id: chosenItemText + anchors.left: parent.left + anchors.leftMargin: 10 + anchors.verticalCenter: parent.verticalCenter + color: statesComboBox.colorItem + text: "" + font.family: regularFont.name + } + + MouseArea { + anchors.fill: parent + onClicked: { + statesComboBox.state = statesComboBox.state === "dropDown" ? "" : "dropDown" + } + } + } + + Rectangle { + id: dropDownShowdowList + width: statesComboBox.width + opacity: 0.3 + height: 0 + clip: true + radius: 4 + anchors.top: chosenItem.top + anchors.margins: 2 + color: "gray" + } + //ToDo: We need scrollbar for items + Rectangle { + id: dropDownList + width: statesComboBox.width + height: 0 + clip: true + radius: 4 + anchors.top: chosenItem.top + anchors.topMargin: 23 + color: statesComboBox.color + + ColumnLayout { + spacing: 2 + TableView { + id: listView + height: 20 + implicitHeight: 0 + width: statesComboBox.width + model: statesComboBox.items + horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff + currentRow: -1 + headerVisible: false + backgroundVisible: false + alternatingRowColors: false + frameVisible: false + + TableViewColumn { + role: "title" + title: "" + width: statesComboBox.width + delegate: mainItemDelegate + } + rowDelegate: Rectangle { + width: statesComboBox.width + height: statesComboBox.rowHeight + } + Component { + id: mainItemDelegate + Rectangle { + id: itemDelegate + width: statesComboBox.width + height: statesComboBox.height + Text { + id: textItemid + text: styleData.value + color: statesComboBox.colorItem + anchors.top: parent.top + anchors.left: parent.left + anchors.leftMargin: 10 + anchors.topMargin: 5 + font.family: regularFont.name + } + Image { + id: imageItemid + height: 20 + width: 20 + anchors.right: parent.right + anchors.top: parent.top + anchors.margins: 5 + visible: false + fillMode: Image.PreserveAspectFit + source: "img/edit_combox.png" + } + + MouseArea { + anchors.fill: parent + hoverEnabled: true + + onEntered: { + imageItemid.visible = true + textItemid.color = statesComboBox.colorSelect + } + onExited: { + imageItemid.visible = false + textItemid.color = statesComboBox.colorItem + } + onClicked: { + if (mouseX > imageItemid.x + && mouseX < imageItemid.x + imageItemid.width + && mouseY > imageItemid.y + && mouseY < imageItemid.y + imageItemid.height) + statesComboBox.editItem(styleData.row) + else { + statesComboBox.state = "" + var prevSelection = chosenItemText.text + chosenItemText.text = styleData.value + listView.currentRow = styleData.row + statesComboBox.selectItem(styleData.row) + } + } + } + } //Item + } //Component + } //Table View + + RowLayout { + anchors.top: listView.bottom + anchors.topMargin: 4 + anchors.left: parent.left + anchors.leftMargin: 10 + Text { + id: createStateText + width: statesComboBox.width + height: statesComboBox.height + font.family: boldFont.name + color: "#808080" + text: qsTr("Create State ...") + font.weight: Font.DemiBold + MouseArea { + anchors.fill: parent + hoverEnabled: true + + onEntered: { + createStateText.color = statesComboBox.colorSelect + } + onExited: { + createStateText.color = statesComboBox.colorItem + } + onClicked: { + statesComboBox.state = "" + statesComboBox.selectCreate() + } + } + } + } + } + } + states: State { + name: "dropDown" + PropertyChanges { + target: dropDownList + height: (statesComboBox.rowHeight * (statesComboBox.items.count + 1)) + } + PropertyChanges { + target: dropDownShowdowList + width: statesComboBox.width + 3 + height: (statesComboBox.rowHeight * (statesComboBox.items.count + 1)) + 3 + } + PropertyChanges { + target: listView + height: 20 + implicitHeight: (statesComboBox.rowHeight * (statesComboBox.items.count)) + } + } +} diff --git a/mix/qml/StatusPane.qml b/mix/qml/StatusPane.qml index 70a4b1d30..6d8042add 100644 --- a/mix/qml/StatusPane.qml +++ b/mix/qml/StatusPane.qml @@ -9,7 +9,7 @@ Rectangle { id: statusHeader objectName: "statusPane" property variant webPreview - + property alias currentStatus: logPane.currentStatus function updateStatus(message) { if (!message) @@ -17,6 +17,7 @@ Rectangle { status.state = ""; status.text = qsTr("Compile successfully."); debugImg.state = "active"; + currentStatus = { "type": "Comp", "date": Qt.formatDateTime(new Date(), "hh:mm:ss"), "content": status.text, "level": "info" } } else { @@ -24,6 +25,7 @@ Rectangle { var errorInfo = ErrorLocationFormater.extractErrorInfo(message, true); status.text = errorInfo.errorLocation + " " + errorInfo.errorDetail; debugImg.state = ""; + currentStatus = { "type": "Comp", "date": Qt.formatDateTime(new Date(), "hh:mm:ss"), "content": status.text, "level": "error" } } debugRunActionIcon.enabled = codeModel.hasContract; } @@ -33,6 +35,7 @@ Rectangle { status.state = ""; status.text = text logPane.push("info", type, text); + currentStatus = { "type": type, "date": Qt.formatDateTime(new Date(), "hh:mm:ss"), "content": text, "level": "info" } } function warningMessage(text, type) @@ -40,13 +43,15 @@ Rectangle { status.state = "warning"; status.text = text logPane.push("warning", type, text); + currentStatus = { "type": type, "date": Qt.formatDateTime(new Date(), "hh:mm:ss"), "content": text, "level": "warning" } } function errorMessage(text, type) { status.state = "error"; - status.text = text + status.text = text; logPane.push("error", type, text); + currentStatus = { "type": type, "date": Qt.formatDateTime(new Date(), "hh:mm:ss"), "content": text, "level": "error" } } Connections { @@ -76,7 +81,7 @@ Rectangle { function format(_message) { var formatted = _message.match(/(?:)/); - if (formatted) + if (!formatted) formatted = _message.match(/(?:)/); if (formatted && formatted.length > 1) formatted = formatted[1]; @@ -90,6 +95,7 @@ Rectangle { return formatted; } } + Connections { target:projectModel onDeploymentStarted: infoMessage(qsTr("Running deployment..."), "Deployment"); @@ -111,32 +117,13 @@ Rectangle { anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter radius: 3 - width: 500 + width: 600 height: 30 color: "#fcfbfc" - states: [ - State { - name: "logsOpened" - PropertyChanges { - target: statusContainer - border.color: "#5391d8" - border.width: 1 - } - }, - State { - name: "logsClosed" - PropertyChanges { - target: statusContainer - border.color: "#5391d8" - border.width: 0 - } - } - ] - Text { anchors.verticalCenter: parent.verticalCenter anchors.horizontalCenter: parent.horizontalCenter - font.pointSize: StatusPaneStyle.general.statusFontSize + font.pointSize: Style.absoluteSize(-1) height: 15 font.family: "sans serif" objectName: "status" @@ -215,40 +202,39 @@ Rectangle { { if (logsContainer.state === "opened") { - statusContainer.state = "logsClosed"; logsContainer.state = "closed" } else { - statusContainer.state = "logsOpened"; logsContainer.state = "opened"; logsContainer.focus = true; forceActiveFocus(); + calCoord(); } } id: logsContainer - width: 1000 - height: 0 - anchors.topMargin: 10 + width: 750 anchors.top: statusContainer.bottom - anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: 4 visible: false - radius: 5 - Component.onCompleted: + radius: 10 + + function calCoord() { var top = logsContainer; while (top.parent) top = top.parent - var coordinates = logsContainer.mapToItem(top, 0, 0) + var coordinates = logsContainer.mapToItem(top, 0, 0); logsContainer.parent = top; - logsContainer.x = coordinates.x - logsContainer.y = coordinates.y + logsContainer.x = status.x + statusContainer.x - LogsPaneStyle.generic.layout.dateWidth - LogsPaneStyle.generic.layout.typeWidth + 70 } + LogsPane { - id: logPane + id: logPane; } + states: [ State { name: "opened"; @@ -257,12 +243,13 @@ Rectangle { State { name: "closed"; PropertyChanges { target: logsContainer; height: 0; visible: false } + PropertyChanges { target: statusContainer; width: 600; height: 30 } } ] transitions: Transition { NumberAnimation { properties: "height"; easing.type: Easing.InOutQuad; duration: 200 } - NumberAnimation { properties: "visible"; easing.type: Easing.InOutQuad; duration: 200 } - } + NumberAnimation { target: logsContainer; properties: "visible"; easing.type: Easing.InOutQuad; duration: 200 } + } } } diff --git a/mix/qml/TransactionLog.qml b/mix/qml/TransactionLog.qml index 43736a89a..5668c6e05 100644 --- a/mix/qml/TransactionLog.qml +++ b/mix/qml/TransactionLog.qml @@ -6,30 +6,16 @@ import QtQuick.Layouts 1.1 import org.ethereum.qml.RecordLogEntry 1.0 Item { - property ListModel fullModel: ListModel{} property ListModel transactionModel: ListModel{} property ListModel callModel: ListModel{} - - Action { - id: addStateAction - text: "Add State" - shortcut: "Ctrl+Alt+T" - enabled: codeModel.hasContract && !clientModel.running; - onTriggered: projectModel.stateListModel.addState(); - } - Action { - id: editStateAction - text: "Edit State" - shortcut: "Ctrl+Alt+T" - enabled: codeModel.hasContract && !clientModel.running && statesCombo.currentIndex >= 0 && projectModel.stateListModel.count > 0; - onTriggered: projectModel.stateListModel.editState(statesCombo.currentIndex); - } + property int selectedStateIndex: statesCombo.selectedIndex ColumnLayout { anchors.fill: parent RowLayout { - + anchors.right: parent.right + anchors.left: parent.left Connections { id: compilationStatus @@ -61,36 +47,24 @@ Item { } } - ComboBox { + StatesComboBox + { id: statesCombo - model: projectModel.stateListModel - width: 150 - editable: false - textRole: "title" - onActivated: { - model.runState(index); - } + items: projectModel.stateListModel + onSelectCreate: projectModel.stateListModel.addState(); + onEditItem: projectModel.stateListModel.editState(item) + colorItem: "#808080" + colorSelect: "#4a90e2" + color: "white" Connections { target: projectModel.stateListModel onStateRun: { - if (statesCombo.currentIndex !== index) - statesCombo.currentIndex = index; + if (statesCombo.selectedIndex !== index) + statesCombo.setSelectedIndex( index ); } } } Button - { - anchors.rightMargin: 9 - anchors.verticalCenter: parent.verticalCenter - action: editStateAction - } - Button - { - anchors.rightMargin: 9 - anchors.verticalCenter: parent.verticalCenter - action: addStateAction - } - Button { anchors.rightMargin: 9 anchors.verticalCenter: parent.verticalCenter @@ -163,16 +137,11 @@ Item { Keys.onPressed: { if ((event.modifiers & Qt.ControlModifier) && event.key === Qt.Key_C && currentRow >=0 && currentRow < logTable.model.count) { var item = logTable.model.get(currentRow); - clipboard.text = item.returned; + appContext.toClipboard(item.returned); } } } - Rectangle { - height: 6 - color: "transparent" - } } - Connections { target: clientModel onStateCleared: { diff --git a/mix/qml/WebPreview.qml b/mix/qml/WebPreview.qml index 0bf31b326..768d188cb 100644 --- a/mix/qml/WebPreview.qml +++ b/mix/qml/WebPreview.qml @@ -156,7 +156,7 @@ Item { if (urlPath === "/") urlPath = "/index.html"; var documentName = urlPath.substr(urlPath.lastIndexOf("/") + 1); - var documentId = projectModel.codeEditor.getDocumentIdByName(documentName); + var documentId = projectModel.getDocumentIdByName(documentName); var content = ""; if (projectModel.codeEditor.isDocumentOpen(documentId)) content = projectModel.codeEditor.getDocumentText(documentId); diff --git a/mix/qml/html/codeeditor.js b/mix/qml/html/codeeditor.js index 5d63a7a83..d61d6e51f 100644 --- a/mix/qml/html/codeeditor.js +++ b/mix/qml/html/codeeditor.js @@ -124,8 +124,6 @@ var executionMark; highlightExecution = function(start, end) { if (executionMark) executionMark.clear(); - if (start === 0 && end + 1 === editor.getValue().length) - return; // Do not hightlight the whole document. if (debugWarning) debugWarning.clear(); executionMark = editor.markText(editor.posFromIndex(start), editor.posFromIndex(end), { className: "CodeMirror-exechighlight" }); diff --git a/mix/qml/img/broom.png b/mix/qml/img/broom.png deleted file mode 100644 index 76a9a0e0c..000000000 Binary files a/mix/qml/img/broom.png and /dev/null differ diff --git a/mix/qml/img/clearicon.png b/mix/qml/img/clearicon.png new file mode 100644 index 000000000..9760ff27b Binary files /dev/null and b/mix/qml/img/clearicon.png differ diff --git a/mix/qml/img/cleariconactive.png b/mix/qml/img/cleariconactive.png new file mode 100644 index 000000000..dfd829d5d Binary files /dev/null and b/mix/qml/img/cleariconactive.png differ diff --git a/mix/qml/img/copyicon.png b/mix/qml/img/copyicon.png new file mode 100644 index 000000000..836f08b0b Binary files /dev/null and b/mix/qml/img/copyicon.png differ diff --git a/mix/qml/img/copyiconactive.png b/mix/qml/img/copyiconactive.png new file mode 100644 index 000000000..387d7f1fa Binary files /dev/null and b/mix/qml/img/copyiconactive.png differ diff --git a/mix/qml/img/edit_combox.png b/mix/qml/img/edit_combox.png new file mode 100644 index 000000000..be3b35942 Binary files /dev/null and b/mix/qml/img/edit_combox.png differ diff --git a/mix/qml/img/pause_button.png b/mix/qml/img/pause_button.png new file mode 100755 index 000000000..e87889551 Binary files /dev/null and b/mix/qml/img/pause_button.png differ diff --git a/mix/qml/img/pause_button2x.png b/mix/qml/img/pause_button2x.png new file mode 100755 index 000000000..6f45b3236 Binary files /dev/null and b/mix/qml/img/pause_button2x.png differ diff --git a/mix/qml/img/play_button.png b/mix/qml/img/play_button.png new file mode 100755 index 000000000..01a5c85cb Binary files /dev/null and b/mix/qml/img/play_button.png differ diff --git a/mix/qml/img/play_button2x.png b/mix/qml/img/play_button2x.png new file mode 100755 index 000000000..24eaa0659 Binary files /dev/null and b/mix/qml/img/play_button2x.png differ diff --git a/mix/qml/img/searchicon.png b/mix/qml/img/searchicon.png new file mode 100644 index 000000000..c10dc9228 Binary files /dev/null and b/mix/qml/img/searchicon.png differ diff --git a/mix/qml/img/stop_button2x.png b/mix/qml/img/stop_button2x.png new file mode 100644 index 000000000..1727b729a Binary files /dev/null and b/mix/qml/img/stop_button2x.png differ diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index 177115f83..25e8dcb77 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -172,7 +172,7 @@ function getDocumentIndex(documentId) for (var i = 0; i < projectListModel.count; i++) if (projectListModel.get(i).documentId === documentId) return i; - console.error("Cant find document " + documentId); + console.error("Can't find document " + documentId); return -1; } @@ -291,6 +291,14 @@ function getDocument(documentId) { return projectListModel.get(i); } +function getDocumentIdByName(fileName) +{ + for (var i = 0; i < projectListModel.count; i++) + if (projectListModel.get(i).fileName === fileName) + return projectListModel.get(i).documentId; + return null; +} + function removeDocument(documentId) { var i = getDocumentIndex(documentId); var document = projectListModel.get(i); diff --git a/mix/res.qrc b/mix/res.qrc index e509bdcc2..0149b96e4 100644 --- a/mix/res.qrc +++ b/mix/res.qrc @@ -17,7 +17,6 @@ qml/fonts/SourceSerifPro-Semibold.ttf qml/img/available_updates.png qml/img/b64.png - qml/img/broom.png qml/img/bugiconactive.png qml/img/bugiconinactive.png qml/img/closedtriangleindicator.png @@ -49,9 +48,20 @@ qml/img/projecticon.png qml/img/run.png qml/img/search_filled.png + qml/img/play_button2x.png + qml/img/play_button.png + qml/img/pause_button2x.png + qml/img/pause_button.png res/mix_256x256x32.png stdc/config.sol stdc/namereg.sol stdc/std.sol + qml/img/edit_combox.png + qml/img/clearicon.png + qml/img/cleariconactive.png + qml/img/copyicon.png + qml/img/copyiconactive.png + qml/img/searchicon.png + qml/img/stop_button2x.png diff --git a/test/SolidityNameAndTypeResolution.cpp b/test/SolidityNameAndTypeResolution.cpp index ddcf36140..531f3bc13 100644 --- a/test/SolidityNameAndTypeResolution.cpp +++ b/test/SolidityNameAndTypeResolution.cpp @@ -460,7 +460,7 @@ BOOST_AUTO_TEST_CASE(function_external_types) uint a; } contract Test { - function boo(uint arg2, bool arg3, bytes8 arg4, bool[2] pairs, uint[] dynamic, C carg) external returns (uint ret) { + function boo(uint arg2, bool arg3, bytes8 arg4, bool[2] pairs, uint[] dynamic, C carg, address[] addresses) external returns (uint ret) { ret = 5; } })"; @@ -471,7 +471,7 @@ BOOST_AUTO_TEST_CASE(function_external_types) auto functions = contract->getDefinedFunctions(); if (functions.empty()) continue; - BOOST_CHECK_EQUAL("boo(uint256,bool,bytes8,bool[2],uint256[],address)", functions[0]->externalSignature()); + BOOST_CHECK_EQUAL("boo(uint256,bool,bytes8,bool[2],uint256[],address,address[])", functions[0]->externalSignature()); } } @@ -503,6 +503,16 @@ BOOST_AUTO_TEST_CASE(function_external_call_not_allowed_conversion) BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); } +// todo delete when implemented +BOOST_AUTO_TEST_CASE(arrays_in_internal_functions) +{ + char const* text = R"( + contract Test { + function foo(address[] addresses) {} + })"; + BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); +} + BOOST_AUTO_TEST_CASE(function_internal_allowed_conversion) { char const* text = R"( diff --git a/test/stMemoryTestFiller.json b/test/stMemoryTestFiller.json index c1754d52f..23f52b657 100644 --- a/test/stMemoryTestFiller.json +++ b/test/stMemoryTestFiller.json @@ -1461,7 +1461,7 @@ } }, - "stackLimitPush32_1024": { + "stackLimitPush32_1023": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1495,7 +1495,7 @@ } }, - "stackLimitPush32_1025": { + "stackLimitPush32_1024": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1529,7 +1529,41 @@ } }, - "stackLimitPush31_1024": { + "stackLimitPush32_1025": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "42949672960", + "currentDifficulty" : "256", + "currentTimestamp" : "1", + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "(asm 1023 0x00 MSTORE JUMPDEST 0x0102030405060708090a0102030405060708090a0102030405060708090a0102 0x01 0x00 MLOAD SUB 0x00 MSTORE 0x00 MLOAD 0x06 JUMPI STOP )", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "429496729600", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "100000", + "to" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "value" : "10", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "stackLimitPush31_1023": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1563,7 +1597,7 @@ } }, - "stackLimitPush31_1025": { + "stackLimitPush31_1024": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1597,7 +1631,41 @@ } }, - "stackLimitGas_1024": { + "stackLimitPush31_1025": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "42949672960", + "currentDifficulty" : "256", + "currentTimestamp" : "1", + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "(asm 1023 0x00 MSTORE JUMPDEST 0x0102030405060708090a0102030405060708090a0102030405060708090a01 0x01 0x00 MLOAD SUB 0x00 MSTORE 0x00 MLOAD 0x06 JUMPI STOP )", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "429496729600", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "100000", + "to" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "value" : "10", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "stackLimitGas_1023": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1631,7 +1699,7 @@ } }, - "stackLimitGas_1025": { + "stackLimitGas_1024": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1665,6 +1733,40 @@ } }, + "stackLimitGas_1025": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "42949672960", + "currentDifficulty" : "256", + "currentTimestamp" : "1", + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "(asm 1023 0x00 MSTORE JUMPDEST GAS 0x01 0x00 MLOAD SUB 0x00 MSTORE 0x00 MLOAD 0x06 JUMPI STOP )", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "429496729600", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "100000", + "to" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "value" : "10", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + "mstroe8_dejavu": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",