commit 04bc8b699fe39b9432efae8f6d66ccf6efab9fad
Author: cryptonotefoundation
Date: Wed Apr 29 20:03:08 2015 +0300
Initial commit
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..20a3894
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+.DS_Store
+/build
+/tags
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..15636b1
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,201 @@
+cmake_minimum_required(VERSION 2.8)
+
+include(CryptoNoteWallet.cmake)
+
+project(${CN_PROJECT_NAME})
+
+execute_process(COMMAND git log -1 --pretty=format:%h
+WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+OUTPUT_VARIABLE GIT_REVISION)
+
+set(CRYPTONOTE_LIB cryptonote)
+
+include_directories(${CMAKE_BINARY_DIR}
+ src
+ cryptonote/external
+ cryptonote/include
+ cryptonote/src
+ cryptonote/contrib/epee/include)
+
+find_package(Qt5Gui REQUIRED)
+find_package(Qt5Widgets REQUIRED)
+
+set(Boost_USE_STATIC_LIBS ON)
+if(WIN32)
+ set(Boost_USE_STATIC_RUNTIME OFF)
+else(WIN32)
+ set(Boost_USE_STATIC_RUNTIME ON)
+endif(WIN32)
+
+find_package(Boost 1.55 REQUIRED COMPONENTS date_time filesystem program_options regex serialization system thread chrono)
+if ((${Boost_MAJOR_VERSION} EQUAL 1) AND (${Boost_MINOR_VERSION} EQUAL 54))
+ message(SEND_ERROR "Boost version 1.54 is unsupported, more details are available here http://goo.gl/RrCFmA")
+endif ()
+
+include_directories(${Boost_INCLUDE_DIRS})
+link_directories(${Boost_LIBRARY_DIRS})
+
+set(VERSION "")
+configure_file("cryptonote/src/version.h.in" "version.h")
+configure_file("src/CryptoNoteWalletConfig.h.in" "CryptoNoteWalletConfig.h")
+
+add_definitions(-DGIT_REVISION=\"${GIT_REVISION}\")
+
+set(CMAKE_AUTOMOC ON)
+
+set(CRYPTONOTE_SOURCES
+ cryptonote/contrib/epee/include/misc_log_ex.cpp
+ cryptonote/contrib/epee/include/misc_os_dependent.cpp
+ cryptonote/contrib/epee/include/string_tools.cpp
+ cryptonote/external/miniupnpc/connecthostport.c
+ cryptonote/external/miniupnpc/igd_desc_parse.c
+ cryptonote/external/miniupnpc/minisoap.c
+ cryptonote/external/miniupnpc/miniupnpc.c
+ cryptonote/external/miniupnpc/miniwget.c
+ cryptonote/external/miniupnpc/minixml.c
+ cryptonote/external/miniupnpc/portlistingparse.c
+ cryptonote/external/miniupnpc/receivedata.c
+ cryptonote/external/miniupnpc/upnpcommands.c
+ cryptonote/external/miniupnpc/upnpreplyparse.c
+ cryptonote/src/common/base58.cpp
+ cryptonote/src/common/command_line.cpp
+ cryptonote/src/common/util.cpp
+ cryptonote/src/crypto/blake256.c
+ cryptonote/src/crypto/chacha8.c
+ cryptonote/src/crypto/crypto-ops-data.c
+ cryptonote/src/crypto/crypto-ops.c
+ cryptonote/src/crypto/crypto.cpp
+ cryptonote/src/crypto/groestl.c
+ cryptonote/src/crypto/hash-extra-blake.c
+ cryptonote/src/crypto/hash-extra-groestl.c
+ cryptonote/src/crypto/hash-extra-jh.c
+ cryptonote/src/crypto/hash-extra-skein.c
+ cryptonote/src/crypto/hash.c
+ cryptonote/src/crypto/jh.c
+ cryptonote/src/crypto/keccak.c
+ cryptonote/src/crypto/oaes_lib.c
+ cryptonote/src/crypto/random.c
+ cryptonote/src/crypto/skein.c
+ cryptonote/src/crypto/slow-hash.c
+ cryptonote/src/crypto/slow-hash.cpp
+ cryptonote/src/crypto/tree-hash.c
+ cryptonote/src/cryptonote_core/BlockIndex.cpp
+ cryptonote/src/cryptonote_core/CoreConfig.cpp
+ cryptonote/src/cryptonote_core/Currency.cpp
+ cryptonote/src/cryptonote_core/MinerConfig.cpp
+ cryptonote/src/cryptonote_core/Transaction.cpp
+ cryptonote/src/cryptonote_core/account.cpp
+ cryptonote/src/cryptonote_core/blockchain_storage.cpp
+ cryptonote/src/cryptonote_core/checkpoints.cpp
+ cryptonote/src/cryptonote_core/cryptonote_basic_impl.cpp
+ cryptonote/src/cryptonote_core/cryptonote_core.cpp
+ cryptonote/src/cryptonote_core/cryptonote_format_utils.cpp
+ cryptonote/src/cryptonote_core/cryptonote_serialization.cpp
+ cryptonote/src/cryptonote_core/difficulty.cpp
+ cryptonote/src/cryptonote_core/miner.cpp
+ cryptonote/src/cryptonote_core/tx_pool.cpp
+ cryptonote/src/inprocess_node/InProcessNode.cpp
+ cryptonote/src/inprocess_node/InProcessNodeErrors.cpp
+ cryptonote/src/node_rpc_proxy/NodeErrors.cpp
+ cryptonote/src/node_rpc_proxy/NodeRpcProxy.cpp
+ cryptonote/src/p2p/NetNodeConfig.cpp
+ cryptonote/src/serialization/BinaryInputStreamSerializer.cpp
+ cryptonote/src/serialization/BinaryOutputStreamSerializer.cpp
+ cryptonote/src/transfers/BlockchainSynchronizer.cpp
+ cryptonote/src/transfers/SynchronizationState.cpp
+ cryptonote/src/transfers/TransfersConsumer.cpp
+ cryptonote/src/transfers/TransfersContainer.cpp
+ cryptonote/src/transfers/TransfersSubscription.cpp
+ cryptonote/src/transfers/TransfersSynchronizer.cpp
+ cryptonote/src/wallet/KeysStorage.cpp
+ cryptonote/src/wallet/Wallet.cpp
+ cryptonote/src/wallet/WalletAsyncContextCounter.cpp
+ cryptonote/src/wallet/WalletErrors.cpp
+ cryptonote/src/wallet/WalletSerializer.cpp
+ cryptonote/src/wallet/WalletSerialization.cpp
+ cryptonote/src/wallet/WalletTransactionSender.cpp
+ cryptonote/src/wallet/WalletUnconfirmedTransactions.cpp
+ cryptonote/src/wallet/WalletUserTransactionsCache.cpp
+ cryptonote/src/wallet/LegacyKeysImporter.cpp
+)
+
+file(GLOB_RECURSE SOURCES src/*.cpp)
+file(GLOB_RECURSE HEADERS src/*.h)
+file(GLOB_RECURSE FORMS src/gui/ui/*.ui)
+
+set(QRC src/resources.qrc)
+
+qt5_wrap_ui(UIS ${FORMS})
+qt5_add_resources(RCC ${QRC})
+
+
+if (WIN32)
+ if (NOT MSVC)
+ message(FATAL_ERROR "Only MSVC is supported on this platform")
+ endif ()
+ add_definitions(/D_CRT_SECURE_NO_WARNINGS /D_WIN32_WINNT=0x0600 /DSTATICLIB)
+ include_directories(cryptonote/src/platform/msc)
+
+ set(PLATFORM_DIR Windows)
+ set(BUILD_PLATFORM WIN32)
+ set(BUILD_RESOURCES src/cryptonotewallet.rc)
+ set(QTMAIN Qt5::WinMain)
+
+elseif (UNIX)
+ set(CRYPTONOTE_SOURCES ${CRYPTONOTE_SOURCES} cryptonote/external/miniupnpc/minissdpc.c)
+ if (APPLE)
+ enable_language(ASM)
+ file(GLOB_RECURSE OBJC_SOURCES src/*.mm)
+ set(SOURCES ${SOURCES} ${OBJC_SOURCES})
+ set(PLATFORM_DIR OSX)
+ set(MACOSX_BUNDLE_INFO_STRING "Cryptonote GUI wallet")
+ set(MACOSX_BUNDLE_LONG_VERSION_STRING "${VERSION_VERSION}.${VERSION_MINOR}.${VERSION_PATCH}")
+ set(MACOSX_BUNDLE_BUNDLE_NAME CryptonoteWallet)
+ set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${VERSION_VERSION}.${VERSION_MINOR}.${VERSION_PATCH}")
+ set(MACOSX_BUNDLE_BUNDLE_VERSION "$${VERSION_VERSION}.${VERSION_MINOR}.${VERSION_PATCH}")
+
+ find_package(Qt5PrintSupport REQUIRED)
+
+ include_directories(/usr/include/malloc)
+
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes -std=c++11 -stdlib=libc++")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -maes -D_DARWIN_C_SOURCE")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework Cocoa -framework OpenGL -framework CoreFoundation -framework Carbon -framework IOKit -L/usr/lib")
+
+ set(MACOSX_BUNDLE_ICON_FILE cryptonote.icns)
+ set(APPLICATION_ICON src/images/cryptonote.icns)
+ set_source_files_properties(${APPLICATION_ICON} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
+
+ set(BUILD_PLATFORM MACOSX_BUNDLE)
+ set(BUILD_RESOURCES ${APPLICATION_ICON})
+
+ GET_TARGET_PROPERTY(QT_LIB_DIR "${Qt5Widgets_LIBRARIES}" LOCATION)
+ GET_FILENAME_COMPONENT(QT_LIB_DIR "${QT_LIB_DIR}" PATH)
+ else(APPLE)
+ set(PLATFORM_DIR Linux)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes -std=c++11")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -maes -std=c11")
+ endif (APPLE)
+endif ()
+
+include_directories(cryptonote/src/Platform/${PLATFORM_DIR})
+file(GLOB PLATFORM_SOURCES cryptonote/src/Platform/${PLATFORM_DIR}/System/*)
+set(CRYPTONOTE_SOURCES ${CRYPTONOTE_SOURCES} ${PLATFORM_SOURCES})
+
+add_library(${CRYPTONOTE_LIB} STATIC ${CRYPTONOTE_SOURCES})
+set_target_properties(${CRYPTONOTE_LIB} PROPERTIES COMPILE_DEFINITIONS _GNU_SOURCE)
+target_link_libraries(${CRYPTONOTE_LIB} ${Boost_LIBRARIES})
+
+add_executable(${PROJECT_NAME} ${BUILD_PLATFORM} ${BUILD_RESOURCES} ${SOURCES} ${HEADERS} ${UIS} ${RCC})
+set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_DEFINITIONS _GNU_SOURCE)
+target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES} ${QTMAIN} ${CRYPTONOTE_LIB})
+
+if (APPLE)
+ qt5_use_modules(${PROJECT_NAME} PrintSupport)
+elseif (UNIX)
+ target_link_libraries(${PROJECT_NAME} -lpthread)
+elseif (WIN32)
+ target_link_libraries(${PROJECT_NAME} Imm32 Iphlpapi Winmm)
+endif (APPLE)
+
+qt5_use_modules(${PROJECT_NAME} Widgets Gui)
diff --git a/CryptoNoteWallet.cmake b/CryptoNoteWallet.cmake
new file mode 100644
index 0000000..4af8821
--- /dev/null
+++ b/CryptoNoteWallet.cmake
@@ -0,0 +1,4 @@
+
+set(CN_PROJECT_NAME "")
+set(CN_CURRENCY_DISPLAY_NAME "")
+set(CN_CURRENCY_TICKER "")
diff --git a/src/CommandLineParser.cpp b/src/CommandLineParser.cpp
new file mode 100644
index 0000000..817e314
--- /dev/null
+++ b/src/CommandLineParser.cpp
@@ -0,0 +1,56 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#include
+
+#include
+
+#include "CommandLineParser.h"
+#include "CurrencyAdapter.h"
+
+namespace WalletGui {
+
+CommandLineParser::CommandLineParser() : QObject(), m_parser(), m_help_option(m_parser.addHelpOption()),
+ m_version_option(m_parser.addVersionOption()),
+ m_data_dir_option("data-dir", tr("Specify data directory"), tr("directory"), QString::fromStdString(tools::get_default_data_dir())) {
+ m_parser.setApplicationDescription(QString(tr("%1 wallet")).arg(CurrencyAdapter::instance().getCurrencyDisplayName()));
+ m_parser.addHelpOption();
+ m_parser.addVersionOption();
+ m_parser.addOption(m_data_dir_option);
+}
+
+CommandLineParser::~CommandLineParser() {
+}
+
+bool CommandLineParser::process() {
+#ifdef Q_OS_WIN
+ return m_parser.parse(QCoreApplication::arguments());
+#else
+ m_parser.process(*QCoreApplication::instance());
+ return true;
+#endif
+}
+
+bool CommandLineParser::hasHelpOption() const {
+ return m_parser.isSet(m_help_option);
+}
+
+bool CommandLineParser::hasVersionOption() const {
+ return m_parser.isSet(m_version_option);
+}
+
+QString CommandLineParser::errorText() const {
+ return m_parser.errorText();
+}
+
+QString CommandLineParser::helpText() const {
+ return m_parser.helpText();
+}
+
+QString CommandLineParser::getDataDir() const {
+ return m_parser.value(m_data_dir_option);
+}
+
+}
diff --git a/src/CommandLineParser.h b/src/CommandLineParser.h
new file mode 100644
index 0000000..e6930e2
--- /dev/null
+++ b/src/CommandLineParser.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#pragma once
+
+#include
+#include
+
+namespace WalletGui {
+
+class CommandLineParser : public QObject {
+ Q_OBJECT
+ Q_DISABLE_COPY(CommandLineParser)
+
+public:
+ CommandLineParser();
+ ~CommandLineParser();
+
+ bool process();
+
+ bool hasHelpOption() const;
+ bool hasVersionOption() const;
+ QString errorText() const;
+ QString helpText() const;
+ QString getDataDir() const;
+private:
+ QCommandLineParser m_parser;
+ QCommandLineOption m_help_option;
+ QCommandLineOption m_version_option;
+ QCommandLineOption m_data_dir_option;
+};
+
+}
diff --git a/src/CryptoNote.cpp b/src/CryptoNote.cpp
new file mode 100644
index 0000000..440fb7a
--- /dev/null
+++ b/src/CryptoNote.cpp
@@ -0,0 +1,265 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#include "CryptoNote.h"
+#include "cryptonote_core/cryptonote_basic_impl.h"
+#include "cryptonote_core/cryptonote_format_utils.h"
+#include "cryptonote_core/Currency.h"
+#include "node_rpc_proxy/NodeRpcProxy.h"
+#include "cryptonote_core/CoreConfig.h"
+#include "cryptonote_core/cryptonote_core.h"
+#include "cryptonote_protocol/cryptonote_protocol_handler.h"
+#include "inprocess_node/InProcessNode.h"
+#include "p2p/net_node.h"
+#include "wallet/Wallet.h"
+
+namespace WalletGui {
+
+namespace {
+
+bool parsePaymentId(const std::string& payment_id_str, crypto::hash& payment_id) {
+ cryptonote::blobdata payment_id_data;
+ if (!epee::string_tools::parse_hexstr_to_binbuff(payment_id_str, payment_id_data)) {
+ return false;
+ }
+
+ if (sizeof(crypto::hash) != payment_id_data.size()) {
+ return false;
+ }
+
+ payment_id = *reinterpret_cast(payment_id_data.data());
+ return true;
+}
+
+std::string convertPaymentId(const std::string& paymentIdString) {
+ if (paymentIdString.empty()) {
+ return "";
+ }
+
+ crypto::hash paymentId;
+ if (!parsePaymentId(paymentIdString, paymentId)) {
+ std::stringstream errorStr;
+ errorStr << "Payment id has invalid format: \"" + paymentIdString + "\", expected 64-character string";
+ throw std::runtime_error(errorStr.str());
+ }
+
+ std::vector extra;
+ std::string extra_nonce;
+ cryptonote::set_payment_id_to_tx_extra_nonce(extra_nonce, paymentId);
+ if (!cryptonote::add_extra_nonce_to_tx_extra(extra, extra_nonce)) {
+ std::stringstream errorStr;
+ errorStr << "Something went wrong with payment_id. Please check its format: \"" + paymentIdString + "\", expected 64-character string";
+ throw std::runtime_error(errorStr.str());
+ }
+
+ return std::string(extra.begin(), extra.end());
+}
+
+std::string extractPaymentId(const std::string& extra) {
+ std::vector extraFields;
+ std::vector extraVector;
+ std::copy(extra.begin(), extra.end(), std::back_inserter(extraVector));
+
+ if (!cryptonote::parse_tx_extra(extraVector, extraFields)) {
+ throw std::runtime_error("Can't parse extra");
+ }
+
+ std::string result;
+ cryptonote::tx_extra_nonce extra_nonce;
+ if (cryptonote::find_tx_extra_field_by_type(extraFields, extra_nonce)) {
+ crypto::hash paymentIdHash;
+ if (cryptonote::get_payment_id_from_tx_extra_nonce(extra_nonce.nonce, paymentIdHash)) {
+ unsigned char* buff = reinterpret_cast(&paymentIdHash);
+ for (size_t i = 0; i < sizeof(paymentIdHash); ++i) {
+ result.push_back("0123456789ABCDEF"[buff[i] >> 4]);
+ result.push_back("0123456789ABCDEF"[buff[i] & 15]);
+ }
+ }
+ }
+
+ return result;
+}
+
+
+}
+
+Node::~Node() {
+}
+
+class RpcNode : CryptoNote::INodeObserver, public Node {
+public:
+ RpcNode(const cryptonote::Currency& currency, INodeCallback& callback, const std::string& nodeHost, unsigned short nodePort) :
+ m_callback(callback),
+ m_currency(currency),
+ m_node(nodeHost, nodePort) {
+ m_node.addObserver(this);
+ }
+
+ ~RpcNode() override {
+ }
+
+ void init(const std::function& callback) override {
+ m_node.init(callback);
+ }
+
+ void deinit() override {
+ }
+
+ std::string convertPaymentId(const std::string& paymentIdString) override {
+ return WalletGui::convertPaymentId(paymentIdString);
+ }
+
+ std::string extractPaymentId(const std::string& extra) override {
+ return WalletGui::extractPaymentId(extra);
+ }
+
+ uint64_t getLastKnownBlockHeight() const override {
+ return m_node.getLastKnownBlockHeight();
+ }
+
+ uint64_t getLastLocalBlockHeight() const override {
+ return m_node.getLastLocalBlockHeight();
+ }
+
+ uint64_t getLastLocalBlockTimestamp() const override {
+ return m_node.getLastLocalBlockTimestamp();
+ }
+
+ uint64_t getPeerCount() const override {
+ return m_node.getPeerCount();
+ }
+
+ CryptoNote::IWallet* createWallet() override {
+ return new CryptoNote::Wallet(m_currency, m_node);
+ }
+
+private:
+ INodeCallback& m_callback;
+ const cryptonote::Currency& m_currency;
+ cryptonote::NodeRpcProxy m_node;
+
+ void peerCountUpdated(size_t count) {
+ m_callback.peerCountUpdated(*this, count);
+ }
+
+ void localBlockchainUpdated(uint64_t height) {
+ m_callback.localBlockchainUpdated(*this, height);
+ }
+
+ void lastKnownBlockHeightUpdated(uint64_t height) {
+ m_callback.lastKnownBlockHeightUpdated(*this, height);
+ }
+};
+
+class InprocessNode : CryptoNote::INodeObserver, public Node {
+public:
+ InprocessNode(const cryptonote::Currency& currency, INodeCallback& callback, const cryptonote::CoreConfig& coreConfig) :
+ m_callback(callback),
+ m_currency(currency),
+ m_coreConfig(coreConfig),
+ m_core(m_currency, nullptr),
+ m_protocolHandler(m_core, nullptr),
+ m_nodeServer(m_protocolHandler),
+ m_node(m_core, m_protocolHandler) {
+
+ m_core.set_cryptonote_protocol(&m_protocolHandler);
+ m_protocolHandler.set_p2p_endpoint(&m_nodeServer);
+ cryptonote::checkpoints checkpoints;
+ for (const cryptonote::CheckpointData& checkpoint : cryptonote::CHECKPOINTS) {
+ checkpoints.add_checkpoint(checkpoint.height, checkpoint.blockId);
+ }
+
+ m_core.set_checkpoints(std::move(checkpoints));
+ }
+
+ ~InprocessNode() override {
+
+ }
+
+ void init(const std::function& callback) override {
+ if (!m_core.init(m_coreConfig, cryptonote::MinerConfig(), true)) {
+ callback(make_error_code(cryptonote::error::NOT_INITIALIZED));
+ return;
+ }
+ if (!m_nodeServer.init(nodetool::NetNodeConfig(), false)) {
+ m_core.deinit();
+ callback(make_error_code(cryptonote::error::NOT_INITIALIZED));
+ return;
+ }
+ m_node.init([this, callback](std::error_code ec) {
+ m_node.addObserver(this);
+ callback(ec);
+ });
+ m_nodeServer.run();
+
+ m_nodeServer.deinit();
+ m_core.deinit();
+ m_node.shutdown();
+ }
+
+ void deinit() override {
+ m_nodeServer.send_stop_signal();
+ }
+
+ std::string convertPaymentId(const std::string& paymentIdString) override {
+ return WalletGui::convertPaymentId(paymentIdString);
+ }
+
+ std::string extractPaymentId(const std::string& extra) override {
+ return WalletGui::extractPaymentId(extra);
+ }
+
+ uint64_t getLastKnownBlockHeight() const override {
+ return m_node.getLastKnownBlockHeight();
+ }
+
+ uint64_t getLastLocalBlockHeight() const override {
+ return m_node.getLastLocalBlockHeight();
+ }
+
+ uint64_t getLastLocalBlockTimestamp() const override {
+ return m_node.getLastLocalBlockTimestamp();
+ }
+
+ uint64_t getPeerCount() const override {
+ return m_node.getPeerCount();
+ }
+
+ CryptoNote::IWallet* createWallet() override {
+ return new CryptoNote::Wallet(m_currency, m_node);
+ }
+
+private:
+ INodeCallback& m_callback;
+ const cryptonote::Currency& m_currency;
+ cryptonote::CoreConfig m_coreConfig;
+ cryptonote::core m_core;
+ cryptonote::t_cryptonote_protocol_handler m_protocolHandler;
+ nodetool::node_server> m_nodeServer;
+ CryptoNote::InProcessNode m_node;
+ std::future m_nodeServerFuture;
+
+ void peerCountUpdated(size_t count) {
+ m_callback.peerCountUpdated(*this, count);
+ }
+
+ void localBlockchainUpdated(uint64_t height) {
+ m_callback.localBlockchainUpdated(*this, height);
+ }
+
+ void lastKnownBlockHeightUpdated(uint64_t height) {
+ m_callback.lastKnownBlockHeightUpdated(*this, height);
+ }
+};
+
+Node* createRpcNode(const cryptonote::Currency& currency, INodeCallback& callback, const std::string& nodeHost, unsigned short nodePort) {
+ return new RpcNode(currency, callback, nodeHost, nodePort);
+}
+
+Node* createInprocessNode(const cryptonote::Currency& currency, INodeCallback& callback, const cryptonote::CoreConfig& coreConfig) {
+ return new InprocessNode(currency, callback, coreConfig);
+}
+
+}
diff --git a/src/CryptoNote.h b/src/CryptoNote.h
new file mode 100644
index 0000000..ee3acdc
--- /dev/null
+++ b/src/CryptoNote.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#pragma once
+
+#include
+#include
+#include
+#include
+
+#include
+
+namespace cryptonote {
+
+class Currency;
+
+}
+
+namespace CryptoNote {
+
+class INode;
+class IWallet;
+
+}
+
+namespace WalletGui {
+
+class Node {
+public:
+ virtual ~Node() = 0;
+ virtual void init(const std::function& callback) = 0;
+ virtual void deinit() = 0;
+
+ virtual std::string convertPaymentId(const std::string& paymentIdString) = 0;
+ virtual std::string extractPaymentId(const std::string& extra) = 0;
+ virtual uint64_t getLastKnownBlockHeight() const = 0;
+ virtual uint64_t getLastLocalBlockHeight() const = 0;
+ virtual uint64_t getLastLocalBlockTimestamp() const = 0;
+ virtual uint64_t getPeerCount() const = 0;
+
+ virtual CryptoNote::IWallet* createWallet() = 0;
+};
+
+class INodeCallback {
+public:
+ virtual void peerCountUpdated(Node& node, size_t count) = 0;
+ virtual void localBlockchainUpdated(Node& node, uint64_t height) = 0;
+ virtual void lastKnownBlockHeightUpdated(Node& node, uint64_t height) = 0;
+};
+
+Node* createRpcNode(const cryptonote::Currency& currency, INodeCallback& callback, const std::string& nodeHost, unsigned short nodePort);
+Node* createInprocessNode(const cryptonote::Currency& currency, INodeCallback& callback, const cryptonote::CoreConfig& coreConfig);
+
+}
diff --git a/src/CryptoNoteWalletConfig.h.in b/src/CryptoNoteWalletConfig.h.in
new file mode 100644
index 0000000..6e63995
--- /dev/null
+++ b/src/CryptoNoteWalletConfig.h.in
@@ -0,0 +1,9 @@
+
+#pragma once
+
+namespace WalletGui {
+
+const char WALLET_CURRENCY_DISPLAY_NAME[] = "@CN_CURRENCY_DISPLAY_NAME@";
+const char WALLET_CURRENCY_TICKER[] = "@CN_CURRENCY_TICKER@";
+
+}
diff --git a/src/CurrencyAdapter.cpp b/src/CurrencyAdapter.cpp
new file mode 100644
index 0000000..26d0514
--- /dev/null
+++ b/src/CurrencyAdapter.cpp
@@ -0,0 +1,105 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#include "CurrencyAdapter.h"
+#include "CryptoNoteWalletConfig.h"
+
+namespace WalletGui {
+
+CurrencyAdapter& CurrencyAdapter::instance() {
+ static CurrencyAdapter inst;
+ return inst;
+}
+
+CurrencyAdapter::CurrencyAdapter() : m_currency(cryptonote::CurrencyBuilder().currency()) {
+}
+
+CurrencyAdapter::~CurrencyAdapter() {
+}
+
+const cryptonote::Currency& CurrencyAdapter::getCurrency() {
+ return m_currency;
+}
+
+quintptr CurrencyAdapter::getNumberOfDecimalPlaces() const {
+ return m_currency.numberOfDecimalPlaces();
+}
+
+QString CurrencyAdapter::getCurrencyDisplayName() const {
+ return WALLET_CURRENCY_DISPLAY_NAME;
+}
+
+QString CurrencyAdapter::getCurrencyName() const {
+ return cryptonote::CRYPTONOTE_NAME;
+}
+
+QString CurrencyAdapter::getCurrencyTicker() const {
+ return WALLET_CURRENCY_TICKER;
+}
+
+QString CurrencyAdapter::formatAmount(quint64 _amount) const {
+ QString result = QString::number(_amount);
+ if (result.length() < getNumberOfDecimalPlaces() + 1) {
+ result = result.rightJustified(getNumberOfDecimalPlaces() + 1, '0');
+ }
+
+ quint32 dot_pos = result.length() - getNumberOfDecimalPlaces();
+ for (quint32 pos = result.length() - 1; pos > dot_pos + 1; --pos) {
+ if (result[pos] == '0') {
+ result.remove(pos, 1);
+ } else {
+ break;
+ }
+ }
+
+ result.insert(dot_pos, ".");
+ for (qint32 pos = dot_pos - 3; pos > 0; pos -= 3) {
+ if (result[pos - 1].isDigit()) {
+ result.insert(pos, ',');
+ }
+ }
+
+ return result;
+}
+
+quint64 CurrencyAdapter::parseAmount(const QString& _amountString) const {
+ QString amountString = _amountString.trimmed();
+ amountString.remove(',');
+
+ int pointIndex = amountString.indexOf('.');
+ int fractionSize;
+ if (pointIndex != -1) {
+ fractionSize = amountString.length() - pointIndex - 1;
+ while (getNumberOfDecimalPlaces() < fractionSize && amountString.right(1) == "0") {
+ amountString.remove(amountString.length() - 1, 1);
+ --fractionSize;
+ }
+
+ if (getNumberOfDecimalPlaces() < fractionSize) {
+ return 0;
+ }
+
+ amountString.remove(pointIndex, 1);
+ } else {
+ fractionSize = 0;
+ }
+
+ if (amountString.isEmpty()) {
+ return 0;
+ }
+
+ for (qint32 i = 0; i < getNumberOfDecimalPlaces() - fractionSize; ++i) {
+ amountString.append('0');
+ }
+
+ return amountString.toULongLong();
+}
+
+bool CurrencyAdapter::validateAddress(const QString& _address) const {
+ cryptonote::AccountPublicAddress internalAddress;
+ return m_currency.parseAccountAddressString(_address.toStdString(), internalAddress);
+}
+
+}
diff --git a/src/CurrencyAdapter.h b/src/CurrencyAdapter.h
new file mode 100644
index 0000000..3f9a720
--- /dev/null
+++ b/src/CurrencyAdapter.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#pragma once
+
+#include
+
+#include "cryptonote_core/Currency.h"
+
+namespace WalletGui {
+
+class CurrencyAdapter {
+
+public:
+ static CurrencyAdapter& instance();
+
+ const cryptonote::Currency& getCurrency();
+ QString getCurrencyDisplayName() const;
+ QString getCurrencyName() const;
+ QString getCurrencyTicker() const;
+ quintptr getNumberOfDecimalPlaces() const;
+ QString formatAmount(quint64 _amount) const;
+ quint64 parseAmount(const QString& _amountString) const;
+ bool validateAddress(const QString& _address) const;
+
+private:
+ cryptonote::Currency m_currency;
+
+ CurrencyAdapter();
+ ~CurrencyAdapter();
+};
+
+}
diff --git a/src/NodeAdapter.cpp b/src/NodeAdapter.cpp
new file mode 100644
index 0000000..1f14ab8
--- /dev/null
+++ b/src/NodeAdapter.cpp
@@ -0,0 +1,216 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include "CurrencyAdapter.h"
+#include "NodeAdapter.h"
+#include "Settings.h"
+
+namespace WalletGui {
+
+class InProcessNodeInitializer : public QObject {
+ Q_OBJECT
+ Q_DISABLE_COPY(InProcessNodeInitializer)
+
+Q_SIGNALS:
+ void nodeInitCompletedSignal();
+ void nodeInitFailedSignal(int _errorCode);
+ void nodeDeinitCompletedSignal();
+
+public:
+ InProcessNodeInitializer(QObject* _parent = nullptr) {
+ }
+
+ ~InProcessNodeInitializer() {
+ }
+
+ void start(Node** _node, const cryptonote::Currency* currency, INodeCallback* _callback, const cryptonote::CoreConfig& _coreConfig) {
+ (*_node) = createInprocessNode(*currency, *_callback, _coreConfig);
+ try {
+ (*_node)->init([this](std::error_code _err) {
+ if (_err) {
+ Q_EMIT nodeInitFailedSignal(_err.value());
+ QCoreApplication::processEvents();
+ return;
+ }
+
+ Q_EMIT nodeInitCompletedSignal();
+ QCoreApplication::processEvents();
+ });
+ } catch (std::runtime_error& err) {
+ Q_EMIT nodeInitFailedSignal(cryptonote::error::INTERNAL_WALLET_ERROR);
+ QCoreApplication::processEvents();
+ return;
+ }
+
+ delete *_node;
+ *_node = nullptr;
+ Q_EMIT nodeDeinitCompletedSignal();
+ }
+
+ void stop(Node** _node) {
+ Q_CHECK_PTR(*_node);
+ (*_node)->deinit();
+ }
+};
+
+NodeAdapter& NodeAdapter::instance() {
+ static NodeAdapter inst;
+ return inst;
+}
+
+NodeAdapter::NodeAdapter() : QObject(), m_node(nullptr), m_nodeInitializerThread(), m_nodeInitializer(new InProcessNodeInitializer) {
+ m_nodeInitializer->moveToThread(&m_nodeInitializerThread);
+
+ qRegisterMetaType("cryptonote::CoreConfig");
+
+ connect(m_nodeInitializer, &InProcessNodeInitializer::nodeInitCompletedSignal, this, &NodeAdapter::nodeInitCompletedSignal, Qt::QueuedConnection);
+ connect(this, &NodeAdapter::initNodeSignal, m_nodeInitializer, &InProcessNodeInitializer::start, Qt::QueuedConnection);
+ connect(this, &NodeAdapter::deinitNodeSignal, m_nodeInitializer, &InProcessNodeInitializer::stop, Qt::QueuedConnection);
+
+ QString logFileName = QCoreApplication::applicationName() + ".log";
+ epee::log_space::log_singletone::add_logger(LOGGER_FILE, logFileName.toLocal8Bit(),
+ Settings::instance().getDataDir().absolutePath().toLocal8Bit());
+}
+
+NodeAdapter::~NodeAdapter() {
+}
+
+quintptr NodeAdapter::getPeerCount() const {
+ Q_ASSERT(m_node != nullptr);
+ return m_node->getPeerCount();
+}
+
+std::string NodeAdapter::convertPaymentId(const QString& _paymentIdString) const {
+ Q_CHECK_PTR(m_node);
+ try {
+ return m_node->convertPaymentId(_paymentIdString.toStdString());
+ } catch (std::runtime_error& err) {
+ }
+ return std::string();
+}
+
+QString NodeAdapter::extractPaymentId(const std::string& _extra) const {
+ Q_CHECK_PTR(m_node);
+ return QString::fromStdString(m_node->extractPaymentId(_extra));
+}
+
+CryptoNote::IWallet* NodeAdapter::createWallet() const {
+ Q_CHECK_PTR(m_node);
+ return m_node->createWallet();
+}
+
+bool NodeAdapter::init() {
+ Q_ASSERT(m_node == nullptr);
+ // TODO Insert the right URL for the local daemon
+ QUrl localNodeUrl = QUrl::fromUserInput("");
+
+ m_node = createRpcNode(CurrencyAdapter::instance().getCurrency(), *this, localNodeUrl.host().toStdString(), localNodeUrl.port());
+
+ QTimer initTimer;
+ initTimer.setInterval(3000);
+ initTimer.setSingleShot(true);
+ initTimer.start();
+ m_node->init([this](std::error_code _err) {
+ Q_UNUSED(_err);
+ });
+ QEventLoop waitLoop;
+ connect(&initTimer, &QTimer::timeout, &waitLoop, &QEventLoop::quit);
+ connect(this, &NodeAdapter::peerCountUpdatedSignal, &waitLoop, &QEventLoop::quit);
+ connect(this, &NodeAdapter::localBlockchainUpdatedSignal, &waitLoop, &QEventLoop::quit);
+ waitLoop.exec();
+ if (initTimer.isActive()) {
+ initTimer.stop();
+ Q_EMIT nodeInitCompletedSignal();
+ return true;
+ }
+
+ delete m_node;
+ m_node = nullptr;
+ return initInProcessNode();
+}
+
+quint64 NodeAdapter::getLastKnownBlockHeight() const {
+ Q_CHECK_PTR(m_node);
+ return m_node->getLastKnownBlockHeight();
+}
+
+quint64 NodeAdapter::getLastLocalBlockHeight() const {
+ Q_CHECK_PTR(m_node);
+ return m_node->getLastLocalBlockHeight();
+}
+
+QDateTime NodeAdapter::getLastLocalBlockTimestamp() const {
+ Q_CHECK_PTR(m_node);
+ return QDateTime::fromTime_t(m_node->getLastLocalBlockTimestamp(), Qt::UTC);
+}
+
+void NodeAdapter::peerCountUpdated(Node& _node, size_t _count) {
+ Q_UNUSED(_node);
+ Q_EMIT peerCountUpdatedSignal(_count);
+}
+
+void NodeAdapter::localBlockchainUpdated(Node& _node, uint64_t _height) {
+ Q_UNUSED(_node);
+ Q_EMIT localBlockchainUpdatedSignal(_height);
+}
+
+void NodeAdapter::lastKnownBlockHeightUpdated(Node& _node, uint64_t _height) {
+ Q_UNUSED(_node);
+ Q_EMIT lastKnownBlockHeightUpdatedSignal(_height);
+}
+
+bool NodeAdapter::initInProcessNode() {
+ Q_ASSERT(m_node == nullptr);
+ m_nodeInitializerThread.start();
+ cryptonote::CoreConfig coreConfig = makeCoreConfig();
+ Q_EMIT initNodeSignal(&m_node, &CurrencyAdapter::instance().getCurrency(), this, coreConfig);
+ QEventLoop waitLoop;
+ connect(m_nodeInitializer, &InProcessNodeInitializer::nodeInitCompletedSignal, &waitLoop, &QEventLoop::quit);
+ connect(m_nodeInitializer, &InProcessNodeInitializer::nodeInitFailedSignal, &waitLoop, &QEventLoop::exit);
+ if (waitLoop.exec() != 0) {
+ return false;
+ }
+
+ Q_EMIT localBlockchainUpdatedSignal(getLastLocalBlockHeight());
+ Q_EMIT lastKnownBlockHeightUpdatedSignal(getLastKnownBlockHeight());
+ return true;
+}
+
+void NodeAdapter::deinit() {
+ if (m_node != nullptr) {
+ if (m_nodeInitializerThread.isRunning()) {
+ m_nodeInitializer->stop(&m_node);
+ QEventLoop waitLoop;
+ connect(m_nodeInitializer, &InProcessNodeInitializer::nodeDeinitCompletedSignal, &waitLoop, &QEventLoop::quit, Qt::QueuedConnection);
+ waitLoop.exec();
+ m_nodeInitializerThread.quit();
+ m_nodeInitializerThread.wait();
+ } else {
+ delete m_node;
+ m_node = nullptr;
+ }
+ }
+}
+
+cryptonote::CoreConfig NodeAdapter::makeCoreConfig() const {
+ cryptonote::CoreConfig config;
+ boost::program_options::variables_map options;
+ boost::any dataDir = Settings::instance().getDataDir().absolutePath().toStdString();
+ options.insert(std::make_pair("data-dir", boost::program_options::variable_value(dataDir, false)));
+ config.init(options);
+ return config;
+}
+
+}
+
+#include "NodeAdapter.moc"
diff --git a/src/NodeAdapter.h b/src/NodeAdapter.h
new file mode 100644
index 0000000..18467a4
--- /dev/null
+++ b/src/NodeAdapter.h
@@ -0,0 +1,67 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#pragma once
+
+#include
+#include
+
+#include
+#include
+
+#include "CryptoNote.h"
+
+namespace cryptonote {
+
+class Currency;
+
+}
+
+namespace WalletGui {
+
+class InProcessNodeInitializer;
+
+class NodeAdapter : public QObject, public INodeCallback {
+ Q_OBJECT
+ Q_DISABLE_COPY(NodeAdapter)
+
+public:
+ static NodeAdapter& instance();
+
+ quintptr getPeerCount() const;
+ std::string convertPaymentId(const QString& _payment_id_string) const;
+ QString extractPaymentId(const std::string& _extra) const;
+ CryptoNote::IWallet* createWallet() const;
+
+ bool init();
+ void deinit();
+ quint64 getLastKnownBlockHeight() const;
+ quint64 getLastLocalBlockHeight() const;
+ QDateTime getLastLocalBlockTimestamp() const;
+ void peerCountUpdated(Node& _node, size_t _count) Q_DECL_OVERRIDE;
+ void localBlockchainUpdated(Node& _node, uint64_t _height) Q_DECL_OVERRIDE;
+ void lastKnownBlockHeightUpdated(Node& _node, uint64_t _height) Q_DECL_OVERRIDE;
+
+private:
+ Node* m_node;
+ QThread m_nodeInitializerThread;
+ InProcessNodeInitializer* m_nodeInitializer;
+
+ NodeAdapter();
+ ~NodeAdapter();
+
+ bool initInProcessNode();
+ cryptonote::CoreConfig makeCoreConfig() const;
+
+Q_SIGNALS:
+ void localBlockchainUpdatedSignal(quint64 _height);
+ void lastKnownBlockHeightUpdatedSignal(quint64 _height);
+ void nodeInitCompletedSignal();
+ void peerCountUpdatedSignal(quintptr _count);
+ void initNodeSignal(Node** _node, const cryptonote::Currency* currency, INodeCallback* _callback, const cryptonote::CoreConfig& _core_config);
+ void deinitNodeSignal(Node** _node);
+};
+
+}
diff --git a/src/Settings.cpp b/src/Settings.cpp
new file mode 100644
index 0000000..547047b
--- /dev/null
+++ b/src/Settings.cpp
@@ -0,0 +1,225 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include "CommandLineParser.h"
+#include "CurrencyAdapter.h"
+#include "Settings.h"
+
+namespace WalletGui {
+
+Settings& Settings::instance() {
+ static Settings inst;
+ return inst;
+}
+
+Settings::Settings() : QObject(), m_cmdLineParser(nullptr) {
+}
+
+Settings::~Settings() {
+}
+
+void Settings::setCommandLineParser(CommandLineParser* _cmdLineParser) {
+ Q_CHECK_PTR(_cmdLineParser);
+ m_cmdLineParser = _cmdLineParser;
+}
+
+void Settings::load() {
+ QFile cfgFile(getDataDir().absoluteFilePath(QCoreApplication::applicationName() + ".cfg"));
+ if (cfgFile.open(QIODevice::ReadOnly)) {
+ m_settings = QJsonDocument::fromJson(cfgFile.readAll()).object();
+ cfgFile.close();
+ if (!m_settings.contains("walletFile")) {
+ m_addressBookFile = getDataDir().absoluteFilePath(QCoreApplication::applicationName() + ".addressbook");
+ } else {
+ m_addressBookFile = m_settings.value("walletFile").toString();
+ m_addressBookFile.replace(m_addressBookFile.lastIndexOf(".wallet"), 7, ".addressbook");
+ }
+ } else {
+ m_addressBookFile = getDataDir().absoluteFilePath(QCoreApplication::applicationName() + ".addressbook");
+ }
+}
+
+QDir Settings::getDataDir() const {
+ Q_CHECK_PTR(m_cmdLineParser);
+ return QDir(m_cmdLineParser->getDataDir());
+}
+
+QString Settings::getWalletFile() const {
+ return m_settings.contains("walletFile") ? m_settings.value("walletFile").toString() :
+ getDataDir().absoluteFilePath(QCoreApplication::applicationName() + ".wallet");
+}
+
+QString Settings::getAddressBookFile() const {
+ return m_addressBookFile;
+}
+
+bool Settings::isEncrypted() const {
+ return m_settings.contains("encrypted") ? m_settings.value("encrypted").toBool() : false;
+}
+
+QString Settings::getVersion() const {
+ return GIT_REVISION;
+}
+
+bool Settings::isStartOnLoginEnabled() const {
+ bool res = false;
+#ifdef Q_OS_MAC
+ QDir autorunDir = QDir::home();
+ if (!autorunDir.cd("Library") || !autorunDir.cd("LaunchAgents")) {
+ return false;
+ }
+
+ QString autorunFilePath = autorunDir.absoluteFilePath(QCoreApplication::applicationName() + ".plist");
+ if (!QFile::exists(autorunFilePath)) {
+ return false;
+ }
+
+ QSettings autorunSettings(autorunFilePath, QSettings::NativeFormat);
+ res = autorunSettings.value("RunAtLoad", false).toBool();
+#elif defined(Q_OS_LINUX)
+ QString configPath = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation);
+ if (configPath.isEmpty()) {
+ return false;
+ }
+
+ QDir autorunDir(configPath);
+ if (!autorunDir.cd("autostart")) {
+ return false;
+ }
+
+ QString autorunFilePath = autorunDir.absoluteFilePath(QCoreApplication::applicationName() + ".desktop");
+ res = QFile::exists(autorunFilePath);
+#elif defined(Q_OS_WIN)
+ QSettings autorunSettings("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run", QSettings::NativeFormat);
+ QString keyName = QString("%1Wallet").arg(CurrencyAdapter::instance().getCurrencyDisplayName());
+ res = autorunSettings.contains(keyName) &&
+ !QDir::fromNativeSeparators(autorunSettings.value(keyName).toString()).compare(QApplication::applicationFilePath());
+#endif
+ return res;
+}
+
+#ifdef Q_OS_WIN
+bool Settings::isMinimizeToTrayEnabled() const {
+ return m_settings.contains("minimizeToTray") ? m_settings.value("minimizeToTray").toBool() : false;
+}
+
+bool Settings::isCloseToTrayEnabled() const {
+ return m_settings.contains("closeToTray") ? m_settings.value("closeToTray").toBool() : false;
+}
+#endif
+
+void Settings::setWalletFile(const QString& _file) {
+ if (_file.endsWith(".wallet") || _file.endsWith(".keys")) {
+ m_settings.insert("walletFile", _file);
+ } else {
+ m_settings.insert("walletFile", _file + ".wallet");
+ }
+
+ saveSettings();
+ m_addressBookFile = m_settings.value("walletFile").toString();
+ m_addressBookFile.replace(m_addressBookFile.lastIndexOf(".wallet"), 7, ".addressbook");
+}
+
+void Settings::setEncrypted(bool _encrypted) {
+ if (isEncrypted() != _encrypted) {
+ m_settings.insert("encrypted", _encrypted);
+ saveSettings();
+ }
+}
+
+void Settings::setCurrentTheme(const QString& _theme) {
+}
+
+void Settings::setStartOnLoginEnabled(bool _enable) {
+#ifdef Q_OS_MAC
+ QDir autorunDir = QDir::home();
+ if (!autorunDir.cd("Library") || !autorunDir.cd("LaunchAgents")) {
+ return;
+ }
+
+ QString autorunFilePath = autorunDir.absoluteFilePath(QCoreApplication::applicationName() + ".plist");
+ QSettings autorunSettings(autorunFilePath, QSettings::NativeFormat);
+ autorunSettings.setValue("Label", "org." + QCoreApplication::applicationName());
+ autorunSettings.setValue("Program", QApplication::applicationFilePath());
+ autorunSettings.setValue("RunAtLoad", _enable);
+ autorunSettings.setValue("ProcessType", "InterActive");
+#elif defined(Q_OS_LINUX)
+ QString configPath = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation);
+ if (configPath.isEmpty()) {
+ return;
+ }
+
+ QDir autorunDir(configPath);
+ if(!autorunDir.exists("autostart")) {
+ autorunDir.mkdir("autostart");
+ }
+
+ if (!autorunDir.cd("autostart")) {
+ return;
+ }
+
+ QString autorunFilePath = autorunDir.absoluteFilePath(QCoreApplication::applicationName() + ".desktop");
+ QFile autorunFile(autorunFilePath);
+ if (!autorunFile.open(QFile::WriteOnly | QFile::Truncate)) {
+ return;
+ }
+
+ if (_enable) {
+ autorunFile.write("[Desktop Entry]\n");
+ autorunFile.write("Type=Application\n");
+ autorunFile.write(QString("Name=%1 Wallet\n").arg(CurrencyAdapter::instance().getCurrencyDisplayName()).toLocal8Bit());
+ autorunFile.write(QString("Exec=%1\n").arg(QApplication::applicationFilePath()).toLocal8Bit());
+ autorunFile.write("Terminal=false\n");
+ autorunFile.write("Hidden=false\n");
+ autorunFile.close();
+ } else {
+ QFile::remove(autorunFilePath);
+ }
+#elif defined(Q_OS_WIN)
+ QSettings autorunSettings("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run", QSettings::NativeFormat);
+ QString keyName = QString("%1Wallet").arg(CurrencyAdapter::instance().getCurrencyDisplayName());
+ if (_enable) {
+ autorunSettings.setValue(keyName, QDir::toNativeSeparators(QApplication::applicationFilePath()));
+ } else {
+ autorunSettings.remove(keyName);
+ }
+#endif
+}
+
+#ifdef Q_OS_WIN
+void Settings::setMinimizeToTrayEnabled(bool _enable) {
+ if (isMinimizeToTrayEnabled() != _enable) {
+ m_settings.insert("minimizeToTray", _enable);
+ saveSettings();
+ }
+}
+
+void Settings::setCloseToTrayEnabled(bool _enable) {
+ if (isCloseToTrayEnabled() != _enable) {
+ m_settings.insert("closeToTray", _enable);
+ saveSettings();
+ }
+}
+#endif
+
+void Settings::saveSettings() const {
+ QFile cfgFile(getDataDir().absoluteFilePath(QCoreApplication::applicationName() + ".cfg"));
+ if (cfgFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
+ QJsonDocument cfg_doc(m_settings);
+ cfgFile.write(cfg_doc.toJson());
+ cfgFile.close();
+ }
+}
+
+}
diff --git a/src/Settings.h b/src/Settings.h
new file mode 100644
index 0000000..20ffe4d
--- /dev/null
+++ b/src/Settings.h
@@ -0,0 +1,57 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#pragma once
+
+#include
+#include
+#include
+
+namespace WalletGui {
+
+class CommandLineParser;
+
+class Settings : public QObject {
+ Q_OBJECT
+ Q_DISABLE_COPY(Settings)
+
+public:
+ static Settings& instance();
+
+ void setCommandLineParser(CommandLineParser* _cmd_line_parser);
+ void load();
+
+ QDir getDataDir() const;
+ QString getWalletFile() const;
+ QString getAddressBookFile() const;
+ bool isEncrypted() const;
+ QString getVersion() const;
+ bool isStartOnLoginEnabled() const;
+#ifdef Q_OS_WIN
+ bool isMinimizeToTrayEnabled() const;
+ bool isCloseToTrayEnabled() const;
+#endif
+
+ void setWalletFile(const QString& _file);
+ void setEncrypted(bool _encrypted);
+ void setCurrentTheme(const QString& _theme);
+ void setStartOnLoginEnabled(bool _enable);
+#ifdef Q_OS_WIN
+ void setMinimizeToTrayEnabled(bool _enable);
+ void setCloseToTrayEnabled(bool _enable);
+#endif
+
+private:
+ QJsonObject m_settings;
+ QString m_addressBookFile;
+ CommandLineParser* m_cmdLineParser;
+
+ Settings();
+ ~Settings();
+
+ void saveSettings() const;
+};
+
+}
diff --git a/src/SignalHandler.cpp b/src/SignalHandler.cpp
new file mode 100644
index 0000000..445250f
--- /dev/null
+++ b/src/SignalHandler.cpp
@@ -0,0 +1,32 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#include
+
+#include "SignalHandler.h"
+
+namespace WalletGui {
+
+SignalHandler& SignalHandler::instance() {
+ static SignalHandler inst;
+ return inst;
+}
+
+SignalHandler::SignalHandler() : QObject() {
+}
+
+SignalHandler::~SignalHandler() {
+}
+
+void SignalHandler::init() {
+ std::signal(SIGINT, SignalHandler::sigHandler);
+ std::signal(SIGTERM, SignalHandler::sigHandler);
+}
+
+void SignalHandler::sigHandler(int _signal) {
+ Q_EMIT SignalHandler::instance().quitSignal();
+}
+
+}
diff --git a/src/SignalHandler.h b/src/SignalHandler.h
new file mode 100644
index 0000000..fac3966
--- /dev/null
+++ b/src/SignalHandler.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#pragma once
+
+#include
+
+namespace WalletGui {
+
+class SignalHandler : public QObject {
+ Q_OBJECT
+ Q_DISABLE_COPY(SignalHandler)
+
+public:
+ static SignalHandler& instance();
+
+ void init();
+
+private:
+ SignalHandler();
+ ~SignalHandler();
+
+ static void sigHandler(int _signal);
+
+Q_SIGNALS:
+ void quitSignal();
+};
+
+}
diff --git a/src/WalletAdapter.cpp b/src/WalletAdapter.cpp
new file mode 100644
index 0000000..436e2cd
--- /dev/null
+++ b/src/WalletAdapter.cpp
@@ -0,0 +1,432 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include "NodeAdapter.h"
+#include "Settings.h"
+#include "WalletAdapter.h"
+
+namespace WalletGui {
+
+const quint32 MSECS_IN_HOUR = 60 * 60 * 1000;
+const quint32 MSECS_IN_MINUTE = 60 * 1000;
+
+const quint32 LAST_BLOCK_INFO_UPDATING_INTERVAL = 1 * MSECS_IN_MINUTE;
+const quint32 LAST_BLOCK_INFO_WARNING_INTERVAL = 1 * MSECS_IN_HOUR;
+
+WalletAdapter& WalletAdapter::instance() {
+ static WalletAdapter inst;
+ return inst;
+}
+
+WalletAdapter::WalletAdapter() : QObject(), m_wallet(nullptr), m_mutex(), m_isBackupInProgress(false),
+ m_isSynchronized(false), m_newTransactionsNotificationTimer(),
+ m_lastWalletTransactionId(std::numeric_limits::max()) {
+ connect(this, &WalletAdapter::walletInitCompletedSignal, this, &WalletAdapter::onWalletInitCompleted, Qt::QueuedConnection);
+ connect(this, &WalletAdapter::walletSendTransactionCompletedSignal, this, &WalletAdapter::onWalletSendTransactionCompleted, Qt::QueuedConnection);
+ connect(this, &WalletAdapter::updateBlockStatusTextSignal, this, &WalletAdapter::updateBlockStatusText, Qt::QueuedConnection);
+ connect(this, &WalletAdapter::updateBlockStatusTextWithDelaySignal, this, &WalletAdapter::updateBlockStatusTextWithDelay, Qt::QueuedConnection);
+ connect(&m_newTransactionsNotificationTimer, &QTimer::timeout, this, &WalletAdapter::notifyAboutLastTransaction);
+ connect(this, &WalletAdapter::walletSynchronizationProgressUpdatedSignal, this, [&]() {
+ if (!m_newTransactionsNotificationTimer.isActive()) {
+ m_newTransactionsNotificationTimer.start();
+ }
+ }, Qt::QueuedConnection);
+
+ connect(this, &WalletAdapter::walletSynchronizationCompletedSignal, this, [&]() {
+ m_newTransactionsNotificationTimer.stop();
+ notifyAboutLastTransaction();
+ }, Qt::QueuedConnection);
+
+ m_newTransactionsNotificationTimer.setInterval(500);
+}
+
+WalletAdapter::~WalletAdapter() {
+}
+
+QString WalletAdapter::getAddress() const {
+ try {
+ return m_wallet == nullptr ? QString() : QString::fromStdString(m_wallet->getAddress());
+ } catch (std::system_error&) {
+ return QString();
+ }
+}
+
+quint64 WalletAdapter::getActualBalance() const {
+ try {
+ return m_wallet == nullptr ? 0 : m_wallet->actualBalance();
+ } catch (std::system_error&) {
+ return 0;
+ }
+}
+
+quint64 WalletAdapter::getPendingBalance() const {
+ try {
+ return m_wallet == nullptr ? 0 : m_wallet->pendingBalance();
+ } catch (std::system_error&) {
+ return 0;
+ }
+}
+
+void WalletAdapter::open(const QString& _password) {
+ Q_ASSERT(m_wallet == nullptr);
+ Settings::instance().setEncrypted(!_password.isEmpty());
+ Q_EMIT walletStateChangedSignal(tr("Opening wallet"));
+
+ m_wallet = NodeAdapter::instance().createWallet();
+ m_wallet->addObserver(this);
+
+ if (QFile::exists(Settings::instance().getWalletFile())) {
+ if (Settings::instance().getWalletFile().endsWith(".keys")) {
+ if(!importLegacyWallet(_password)) {
+ return;
+ }
+ }
+
+ if (openFile(Settings::instance().getWalletFile(), true)) {
+ try {
+ m_wallet->initAndLoad(m_file, _password.toStdString());
+ } catch (std::system_error&) {
+ closeFile();
+ delete m_wallet;
+ m_wallet = nullptr;
+ }
+ }
+ } else {
+ Settings::instance().setEncrypted(false);
+ try {
+ m_wallet->initAndGenerate("");
+ } catch (std::system_error&) {
+ delete m_wallet;
+ m_wallet = nullptr;
+ }
+ }
+}
+
+bool WalletAdapter::isOpen() const {
+ return m_wallet != nullptr;
+}
+
+bool WalletAdapter::importLegacyWallet(const QString &_password) {
+ QString fileName = Settings::instance().getWalletFile();
+ Settings::instance().setEncrypted(!_password.isEmpty());
+ try {
+ fileName.replace(fileName.lastIndexOf(".keys"), 5, ".wallet");
+ if (!openFile(fileName, false)) {
+ delete m_wallet;
+ m_wallet = nullptr;
+ return false;
+ }
+
+ cryptonote::importLegacyKeys(Settings::instance().getWalletFile().toStdString(), _password.toStdString(), m_file);
+ closeFile();
+ Settings::instance().setWalletFile(fileName);
+ return true;
+ } catch (std::system_error& _err) {
+ closeFile();
+ if (_err.code().value() == cryptonote::error::WRONG_PASSWORD) {
+ Settings::instance().setEncrypted(true);
+ Q_EMIT openWalletWithPasswordSignal(!_password.isEmpty());
+ }
+ } catch (std::runtime_error& _err) {
+ closeFile();
+ }
+
+ delete m_wallet;
+ m_wallet = nullptr;
+ return false;
+}
+
+void WalletAdapter::close() {
+ Q_CHECK_PTR(m_wallet);
+ save(true, true);
+ lock();
+ m_wallet->removeObserver(this);
+ m_isSynchronized = false;
+ m_newTransactionsNotificationTimer.stop();
+ m_lastWalletTransactionId = std::numeric_limits::max();
+ Q_EMIT walletCloseCompletedSignal();
+ QCoreApplication::processEvents();
+ delete m_wallet;
+ m_wallet = nullptr;
+ unlock();
+}
+
+bool WalletAdapter::save(bool _details, bool _cache) {
+ return save(Settings::instance().getWalletFile() + ".temp", _details, _cache);
+}
+
+bool WalletAdapter::save(const QString& _file, bool _details, bool _cache) {
+ Q_CHECK_PTR(m_wallet);
+ if (openFile(_file, false)) {
+ try {
+ m_wallet->save(m_file, _details, _cache);
+ } catch (std::system_error&) {
+ closeFile();
+ return false;
+ }
+ Q_EMIT walletStateChangedSignal(tr("Saving data"));
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+void WalletAdapter::backup(const QString& _file) {
+ if (save(_file.endsWith(".wallet") ? _file : _file + ".wallet", true, false)) {
+ m_isBackupInProgress = true;
+ }
+}
+
+quint64 WalletAdapter::getTransactionCount() const {
+ Q_CHECK_PTR(m_wallet);
+ try {
+ return m_wallet->getTransactionCount();
+ } catch (std::system_error&) {
+ }
+
+ return 0;
+}
+
+quint64 WalletAdapter::getTransferCount() const {
+ Q_CHECK_PTR(m_wallet);
+ try {
+ return m_wallet->getTransferCount();
+ } catch (std::system_error&) {
+ }
+
+ return 0;
+}
+
+bool WalletAdapter::getTransaction(CryptoNote::TransactionId& _id, CryptoNote::TransactionInfo& _transaction) {
+ Q_CHECK_PTR(m_wallet);
+ try {
+ return m_wallet->getTransaction(_id, _transaction);
+ } catch (std::system_error&) {
+ }
+
+ return false;
+}
+
+bool WalletAdapter::getTransfer(CryptoNote::TransferId& _id, CryptoNote::Transfer& _transfer) {
+ Q_CHECK_PTR(m_wallet);
+ try {
+ return m_wallet->getTransfer(_id, _transfer);
+ } catch (std::system_error&) {
+ }
+
+ return false;
+}
+
+void WalletAdapter::sendTransaction(const QVector& _transfers, quint64 _fee, const QString& _paymentId, quint64 _mixin) {
+ Q_CHECK_PTR(m_wallet);
+ try {
+ lock();
+ m_wallet->sendTransaction(_transfers.toStdVector(), _fee, NodeAdapter::instance().convertPaymentId(_paymentId), _mixin, 0);
+ Q_EMIT walletStateChangedSignal(tr("Sending transaction"));
+ } catch (std::system_error&) {
+ unlock();
+ }
+}
+
+bool WalletAdapter::changePassword(const QString& _oldPassword, const QString& _newPassword) {
+ Q_CHECK_PTR(m_wallet);
+ try {
+ if (m_wallet->changePassword(_oldPassword.toStdString(), _newPassword.toStdString()).value() == cryptonote::error::WRONG_PASSWORD) {
+ return false;
+ }
+ } catch (std::system_error&) {
+ return false;
+ }
+
+ Settings::instance().setEncrypted(!_newPassword.isEmpty());
+ return save(true, true);
+}
+
+void WalletAdapter::setWalletFile(const QString& _path) {
+ Q_ASSERT(m_wallet == nullptr);
+ Settings::instance().setWalletFile(_path);
+}
+
+void WalletAdapter::initCompleted(std::error_code _error) {
+ if (m_file.is_open()) {
+ closeFile();
+ }
+
+ Q_EMIT walletInitCompletedSignal(_error.value(), QString::fromStdString(_error.message()));
+}
+
+void WalletAdapter::onWalletInitCompleted(int _error, const QString& _errorText) {
+ switch(_error) {
+ case 0: {
+ Q_EMIT walletActualBalanceUpdatedSignal(m_wallet->actualBalance());
+ Q_EMIT walletPendingBalanceUpdatedSignal(m_wallet->pendingBalance());
+ Q_EMIT updateWalletAddressSignal(QString::fromStdString(m_wallet->getAddress()));
+ Q_EMIT reloadWalletTransactionsSignal();
+ Q_EMIT walletStateChangedSignal(tr("Ready"));
+ QTimer::singleShot(5000, this, SLOT(updateBlockStatusText()));
+ if (!QFile::exists(Settings::instance().getWalletFile())) {
+ save(true, true);
+ }
+
+ break;
+ }
+ case cryptonote::error::WRONG_PASSWORD:
+ Q_EMIT openWalletWithPasswordSignal(Settings::instance().isEncrypted());
+ Settings::instance().setEncrypted(true);
+ delete m_wallet;
+ m_wallet = nullptr;
+ break;
+ default: {
+ delete m_wallet;
+ m_wallet = nullptr;
+ break;
+ }
+ }
+}
+
+void WalletAdapter::saveCompleted(std::error_code _error) {
+ if (!_error && !m_isBackupInProgress) {
+ closeFile();
+ renameFile(Settings::instance().getWalletFile() + ".temp", Settings::instance().getWalletFile());
+ Q_EMIT walletStateChangedSignal(tr("Ready"));
+ Q_EMIT updateBlockStatusTextWithDelaySignal();
+ } else if (m_isBackupInProgress) {
+ m_isBackupInProgress = false;
+ closeFile();
+ } else {
+ closeFile();
+ }
+
+ Q_EMIT walletSaveCompletedSignal(_error.value(), QString::fromStdString(_error.message()));
+}
+
+void WalletAdapter::synchronizationProgressUpdated(uint64_t _current, uint64_t _total) {
+ m_isSynchronized = false;
+ Q_EMIT walletStateChangedSignal(QString("%1 %2/%3").arg(tr("Synchronizing")).arg(_current).arg(_total));
+ Q_EMIT walletSynchronizationProgressUpdatedSignal(_current, _total);
+}
+
+void WalletAdapter::synchronizationCompleted(std::error_code _error) {
+ if (!_error) {
+ m_isSynchronized = true;
+ Q_EMIT updateBlockStatusTextSignal();
+ Q_EMIT walletSynchronizationCompletedSignal(_error.value(), QString::fromStdString(_error.message()));
+ }
+}
+
+void WalletAdapter::actualBalanceUpdated(uint64_t _actual_balance) {
+ Q_EMIT walletActualBalanceUpdatedSignal(_actual_balance);
+}
+
+void WalletAdapter::pendingBalanceUpdated(uint64_t _pending_balance) {
+ Q_EMIT walletPendingBalanceUpdatedSignal(_pending_balance);
+}
+
+void WalletAdapter::externalTransactionCreated(CryptoNote::TransactionId _transactionId) {
+ if (!m_isSynchronized) {
+ m_lastWalletTransactionId = _transactionId;
+ } else {
+ Q_EMIT walletTransactionCreatedSignal(_transactionId);
+ }
+}
+
+void WalletAdapter::sendTransactionCompleted(CryptoNote::TransactionId _transaction_id, std::error_code _error) {
+ unlock();
+ Q_EMIT walletSendTransactionCompletedSignal(_transaction_id, _error.value(), QString::fromStdString(_error.message()));
+ Q_EMIT updateBlockStatusTextWithDelaySignal();
+}
+
+void WalletAdapter::onWalletSendTransactionCompleted(CryptoNote::TransactionId _transactionId, int _error, const QString& _errorText) {
+ if (_error) {
+ return;
+ }
+
+ CryptoNote::TransactionInfo transaction;
+ if (!this->getTransaction(_transactionId, transaction)) {
+ return;
+ }
+
+ if (transaction.transferCount == 0) {
+ return;
+ }
+
+ Q_EMIT walletTransactionCreatedSignal(_transactionId);
+
+ save(true, true);
+}
+
+void WalletAdapter::transactionUpdated(CryptoNote::TransactionId _transactionId) {
+ Q_EMIT walletTransactionUpdatedSignal(_transactionId);
+}
+
+void WalletAdapter::lock() {
+ m_mutex.lock();
+}
+
+void WalletAdapter::unlock() {
+ m_mutex.unlock();
+}
+
+bool WalletAdapter::openFile(const QString& _file, bool _readOnly) {
+ lock();
+ m_file.open(_file.toStdString(), std::ios::binary | (_readOnly ? std::ios::in : (std::ios::out | std::ios::trunc)));
+ if (!m_file.is_open()) {
+ unlock();
+ }
+
+ return m_file.is_open();
+}
+
+void WalletAdapter::closeFile() {
+ m_file.close();
+ unlock();
+}
+
+void WalletAdapter::notifyAboutLastTransaction() {
+ if (m_lastWalletTransactionId != std::numeric_limits::max()) {
+ Q_EMIT walletTransactionCreatedSignal(m_lastWalletTransactionId);
+ m_lastWalletTransactionId = std::numeric_limits::max();
+ }
+}
+
+void WalletAdapter::renameFile(const QString& _oldName, const QString& _newName) {
+ Q_ASSERT(QFile::exists(_oldName));
+ QFile::remove(_newName);
+ QFile::rename(_oldName, _newName);
+}
+
+void WalletAdapter::updateBlockStatusText() {
+ if (m_wallet == nullptr) {
+ return;
+ }
+
+ const QDateTime currentTime = QDateTime::currentDateTimeUtc();
+ const QDateTime blockTime = NodeAdapter::instance().getLastLocalBlockTimestamp();
+ quint64 blockAge = blockTime.msecsTo(currentTime);
+ const QString warningString = blockTime.msecsTo(currentTime) < LAST_BLOCK_INFO_WARNING_INTERVAL ? "" :
+ QString(" Warning: last block was received %1 hours %2 minutes ago").arg(blockAge / MSECS_IN_HOUR).arg(blockAge % MSECS_IN_HOUR / MSECS_IN_MINUTE);
+ Q_EMIT walletStateChangedSignal(QString(tr("Wallet synchronized. Height: %1 | Time (UTC): %2%3")).
+ arg(NodeAdapter::instance().getLastLocalBlockHeight()).
+ arg(QLocale(QLocale::English).toString(blockTime, "dd MMM yyyy, HH:mm:ss")).
+ arg(warningString));
+
+ QTimer::singleShot(LAST_BLOCK_INFO_UPDATING_INTERVAL, this, SLOT(updateBlockStatusText()));
+}
+
+void WalletAdapter::updateBlockStatusTextWithDelay() {
+ QTimer::singleShot(5000, this, SLOT(updateBlockStatusText()));
+}
+
+}
diff --git a/src/WalletAdapter.h b/src/WalletAdapter.h
new file mode 100644
index 0000000..615f819
--- /dev/null
+++ b/src/WalletAdapter.h
@@ -0,0 +1,103 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#pragma once
+
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+
+namespace WalletGui {
+
+class WalletAdapter : public QObject, public CryptoNote::IWalletObserver {
+ Q_OBJECT
+ Q_DISABLE_COPY(WalletAdapter)
+
+public:
+ static WalletAdapter& instance();
+
+ void open(const QString& _password);
+ void close();
+ bool save(bool _details, bool _cache);
+ void backup(const QString& _file);
+
+ QString getAddress() const;
+ quint64 getActualBalance() const;
+ quint64 getPendingBalance() const;
+ quint64 getTransactionCount() const;
+ quint64 getTransferCount() const;
+ bool getTransaction(CryptoNote::TransactionId& _id, CryptoNote::TransactionInfo& _transaction);
+ bool getTransfer(CryptoNote::TransferId& _id, CryptoNote::Transfer& _transfer);
+ bool isOpen() const;
+ void sendTransaction(const QVector& _transfers, quint64 _fee, const QString& _payment_id, quint64 _mixin);
+ bool changePassword(const QString& _old_pass, const QString& _new_pass);
+ void setWalletFile(const QString& _path);
+
+ void initCompleted(std::error_code _result) Q_DECL_OVERRIDE;
+ void saveCompleted(std::error_code _result) Q_DECL_OVERRIDE;
+ void synchronizationProgressUpdated(uint64_t _current, uint64_t _total) Q_DECL_OVERRIDE;
+ void synchronizationCompleted(std::error_code _error) Q_DECL_OVERRIDE;
+ void actualBalanceUpdated(uint64_t _actual_balance) Q_DECL_OVERRIDE;
+ void pendingBalanceUpdated(uint64_t _pending_balance) Q_DECL_OVERRIDE;
+ void externalTransactionCreated(CryptoNote::TransactionId _transaction_id) Q_DECL_OVERRIDE;
+ void sendTransactionCompleted(CryptoNote::TransactionId _transaction_id, std::error_code _result) Q_DECL_OVERRIDE;
+ void transactionUpdated(CryptoNote::TransactionId _transaction_id) Q_DECL_OVERRIDE;
+
+private:
+ std::fstream m_file;
+ CryptoNote::IWallet* m_wallet;
+ QMutex m_mutex;
+ std::atomic m_isBackupInProgress;
+ std::atomic m_isSynchronized;
+ std::atomic m_lastWalletTransactionId;
+ QTimer m_newTransactionsNotificationTimer;
+
+ WalletAdapter();
+ ~WalletAdapter();
+
+ void onWalletInitCompleted(int _error, const QString& _error_text);
+ void onWalletSendTransactionCompleted(CryptoNote::TransactionId _transaction_id, int _error, const QString& _error_text);
+
+ bool importLegacyWallet(const QString &_password);
+ bool save(const QString& _file, bool _details, bool _cache);
+ void lock();
+ void unlock();
+ bool openFile(const QString& _file, bool _read_only);
+ void closeFile();
+ void notifyAboutLastTransaction();
+
+ static void renameFile(const QString& _old_name, const QString& _new_name);
+ Q_SLOT void updateBlockStatusText();
+ Q_SLOT void updateBlockStatusTextWithDelay();
+
+Q_SIGNALS:
+ void walletInitCompletedSignal(int _error, const QString& _error_text);
+ void walletCloseCompletedSignal();
+ void walletSaveCompletedSignal(int _error, const QString& _error_text);
+ void walletSynchronizationProgressUpdatedSignal(quint64 _current, quint64 _total);
+ void walletSynchronizationCompletedSignal(int _error, const QString& _error_text);
+ void walletActualBalanceUpdatedSignal(quint64 _actual_balance);
+ void walletPendingBalanceUpdatedSignal(quint64 _pending_balance);
+ void walletTransactionCreatedSignal(CryptoNote::TransactionId _transaction_id);
+ void walletSendTransactionCompletedSignal(CryptoNote::TransactionId _transaction_id, int _error, const QString& _error_text);
+ void walletTransactionUpdatedSignal(CryptoNote::TransactionId _transaction_id);
+ void walletStateChangedSignal(const QString &_state_text);
+
+ void openWalletWithPasswordSignal(bool _error);
+ void changeWalletPasswordSignal();
+ void updateWalletAddressSignal(const QString& _address);
+ void reloadWalletTransactionsSignal();
+ void updateBlockStatusTextSignal();
+ void updateBlockStatusTextWithDelaySignal();
+};
+
+
+
+}
diff --git a/src/cryptonotewallet.rc b/src/cryptonotewallet.rc
new file mode 100644
index 0000000..a790366
--- /dev/null
+++ b/src/cryptonotewallet.rc
@@ -0,0 +1 @@
+IDI_ICON1 ICON "images\cryptonote.ico"
diff --git a/src/gui/AboutDialog.cpp b/src/gui/AboutDialog.cpp
new file mode 100644
index 0000000..1e3418e
--- /dev/null
+++ b/src/gui/AboutDialog.cpp
@@ -0,0 +1,24 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#include "AboutDialog.h"
+#include "CurrencyAdapter.h"
+#include "Settings.h"
+
+#include "ui_aboutdialog.h"
+
+namespace WalletGui {
+
+AboutDialog::AboutDialog(QWidget* _parent) : QDialog(_parent), m_ui(new Ui::AboutDialog) {
+ m_ui->setupUi(this);
+ setWindowTitle(QString(tr("About %1 Wallet")).arg(CurrencyAdapter::instance().getCurrencyDisplayName()));
+ QString aboutText = m_ui->m_aboutLabel->text();
+ m_ui->m_aboutLabel->setText(aboutText.arg(GIT_REVISION));
+}
+
+AboutDialog::~AboutDialog() {
+}
+
+}
diff --git a/src/gui/AboutDialog.h b/src/gui/AboutDialog.h
new file mode 100644
index 0000000..fdb9775
--- /dev/null
+++ b/src/gui/AboutDialog.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#pragma once
+
+#include
+
+namespace Ui {
+class AboutDialog;
+}
+
+namespace WalletGui {
+
+class AboutDialog : public QDialog {
+ Q_OBJECT
+ Q_DISABLE_COPY(AboutDialog)
+
+public:
+ AboutDialog(QWidget* _parent);
+ ~AboutDialog();
+
+private:
+ QScopedPointer m_ui;
+};
+
+}
diff --git a/src/gui/AddressBookDialog.cpp b/src/gui/AddressBookDialog.cpp
new file mode 100644
index 0000000..71c66b3
--- /dev/null
+++ b/src/gui/AddressBookDialog.cpp
@@ -0,0 +1,28 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#include "AddressBookDialog.h"
+#include "AddressBookModel.h"
+
+#include "ui_addressbookdialog.h"
+
+namespace WalletGui {
+
+AddressBookDialog::AddressBookDialog(QWidget* _parent) : QDialog(_parent), m_ui(new Ui::AddressBookDialog) {
+ m_ui->setupUi(this);
+ m_ui->m_addressBookView->setModel(&AddressBookModel::instance());
+ if (AddressBookModel::instance().rowCount() > 0) {
+ m_ui->m_addressBookView->setCurrentIndex(AddressBookModel::instance().index(0, 0));
+ }
+}
+
+AddressBookDialog::~AddressBookDialog() {
+}
+
+QString AddressBookDialog::getAddress() const {
+ return m_ui->m_addressBookView->currentIndex().data(AddressBookModel::ROLE_ADDRESS).toString();
+}
+
+}
diff --git a/src/gui/AddressBookDialog.h b/src/gui/AddressBookDialog.h
new file mode 100644
index 0000000..d9aba9f
--- /dev/null
+++ b/src/gui/AddressBookDialog.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#pragma once
+
+#include
+
+namespace Ui {
+class AddressBookDialog;
+}
+
+namespace WalletGui {
+
+class AddressBookDialog : public QDialog {
+ Q_OBJECT
+ Q_DISABLE_COPY(AddressBookDialog)
+
+public:
+ AddressBookDialog(QWidget* _parent);
+ ~AddressBookDialog();
+
+ QString getAddress() const;
+
+private:
+ QScopedPointer m_ui;
+};
+
+}
diff --git a/src/gui/AddressBookFrame.cpp b/src/gui/AddressBookFrame.cpp
new file mode 100644
index 0000000..ca612aa
--- /dev/null
+++ b/src/gui/AddressBookFrame.cpp
@@ -0,0 +1,58 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#include
+#include
+
+#include "CurrencyAdapter.h"
+#include "AddressBookModel.h"
+#include "AddressBookFrame.h"
+#include "MainWindow.h"
+#include "NewAddressDialog.h"
+#include "WalletEvents.h"
+
+#include "ui_addressbookframe.h"
+
+namespace WalletGui {
+
+AddressBookFrame::AddressBookFrame(QWidget* _parent) : QFrame(_parent), m_ui(new Ui::AddressBookFrame) {
+ m_ui->setupUi(this);
+ m_ui->m_addressBookView->setModel(&AddressBookModel::instance());
+
+ connect(m_ui->m_addressBookView->selectionModel(), &QItemSelectionModel::currentChanged, this, &AddressBookFrame::currentAddressChanged);
+}
+
+AddressBookFrame::~AddressBookFrame() {
+}
+
+void AddressBookFrame::addClicked() {
+ NewAddressDialog dlg(&MainWindow::instance());
+ if (dlg.exec() == QDialog::Accepted) {
+ QString label = dlg.getLabel();
+ QString address = dlg.getAddress();
+ if (!CurrencyAdapter::instance().validateAddress(address)) {
+ QCoreApplication::postEvent(&MainWindow::instance(), new ShowMessageEvent(tr("Invalid address"), QtCriticalMsg));
+ return;
+ }
+
+ AddressBookModel::instance().addAddress(label, address);
+ }
+}
+
+void AddressBookFrame::copyClicked() {
+ QApplication::clipboard()->setText(m_ui->m_addressBookView->currentIndex().data(AddressBookModel::ROLE_ADDRESS).toString());
+}
+
+void AddressBookFrame::deleteClicked() {
+ int row = m_ui->m_addressBookView->currentIndex().row();
+ AddressBookModel::instance().removeAddress(row);
+}
+
+void AddressBookFrame::currentAddressChanged(const QModelIndex& _index) {
+ m_ui->m_copyAddressButton->setEnabled(_index.isValid());
+ m_ui->m_deleteAddressButton->setEnabled(_index.isValid());
+}
+
+}
diff --git a/src/gui/AddressBookFrame.h b/src/gui/AddressBookFrame.h
new file mode 100644
index 0000000..444d733
--- /dev/null
+++ b/src/gui/AddressBookFrame.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#pragma once
+
+#include
+
+namespace Ui {
+class AddressBookFrame;
+}
+
+namespace WalletGui {
+
+class AddressBookFrame : public QFrame {
+ Q_OBJECT
+ Q_DISABLE_COPY(AddressBookFrame)
+
+public:
+ AddressBookFrame(QWidget* _parent);
+ ~AddressBookFrame();
+
+private:
+ QScopedPointer m_ui;
+
+ Q_SLOT void addClicked();
+ Q_SLOT void copyClicked();
+ Q_SLOT void deleteClicked();
+ Q_SLOT void currentAddressChanged(const QModelIndex& _index);
+};
+
+}
diff --git a/src/gui/AddressBookModel.cpp b/src/gui/AddressBookModel.cpp
new file mode 100644
index 0000000..7f9d457
--- /dev/null
+++ b/src/gui/AddressBookModel.cpp
@@ -0,0 +1,155 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#include
+#include
+#include
+
+#include "WalletAdapter.h"
+#include "AddressBookModel.h"
+#include "Settings.h"
+
+namespace WalletGui {
+
+AddressBookModel& AddressBookModel::instance() {
+ static AddressBookModel inst;
+ return inst;
+}
+
+AddressBookModel::AddressBookModel() : QAbstractItemModel() {
+ connect(&WalletAdapter::instance(), &WalletAdapter::walletInitCompletedSignal, this, &AddressBookModel::walletInitCompleted, Qt::QueuedConnection);
+ connect(&WalletAdapter::instance(), &WalletAdapter::walletCloseCompletedSignal, this, &AddressBookModel::reset, Qt::QueuedConnection);
+}
+
+AddressBookModel::~AddressBookModel() {
+}
+
+int AddressBookModel::columnCount(const QModelIndex& _parent) const {
+ return 2;
+}
+
+QVariant AddressBookModel::data(const QModelIndex& _index, int _role) const {
+ if (!_index.isValid()) {
+ return QVariant();
+ }
+
+ QJsonObject address = m_addressBook.at(_index.row()).toObject();
+
+ switch (_role) {
+ case Qt::DisplayRole:
+ switch (_index.column()) {
+ case COLUMN_LABEL:
+ return _index.data(ROLE_LABEL);
+ case COLUMN_ADDRESS:
+ return _index.data(ROLE_ADDRESS);
+ default:
+ return QVariant();
+ }
+
+ case ROLE_LABEL:
+ return address.value("label");
+ case ROLE_ADDRESS:
+ return address.value("address");
+ default:
+ return QVariant();
+ }
+
+ return QVariant();
+}
+
+Qt::ItemFlags AddressBookModel::flags(const QModelIndex& _index) const {
+ return (Qt::ItemIsEnabled | Qt::ItemNeverHasChildren | Qt::ItemIsSelectable);
+}
+
+QVariant AddressBookModel::headerData(int _section, Qt::Orientation _orientation, int _role) const {
+ if (_orientation != Qt::Horizontal || _role != Qt::DisplayRole) {
+ return QVariant();
+ }
+
+ switch (_section) {
+ case COLUMN_LABEL:
+ return tr("Label");
+ case COLUMN_ADDRESS:
+ return tr("Address");
+ }
+
+ return QVariant();
+}
+
+QModelIndex AddressBookModel::index(int _row, int _column, const QModelIndex& _parent) const {
+ if (_parent.isValid()) {
+ return QModelIndex();
+ }
+
+ return createIndex(_row, _column, _row);
+}
+
+QModelIndex AddressBookModel::parent(const QModelIndex& _index) const {
+ return QModelIndex();
+}
+
+int AddressBookModel::rowCount(const QModelIndex& _parent) const {
+ return m_addressBook.size();
+}
+
+void AddressBookModel::addAddress(const QString& _label, const QString& _address) {
+ beginInsertRows(QModelIndex(), m_addressBook.size(), m_addressBook.size());
+ QJsonObject newAddress;
+ newAddress.insert("label", _label);
+ newAddress.insert("address", _address);
+ m_addressBook.append(newAddress);
+ endInsertRows();
+ saveAddressBook();
+}
+
+void AddressBookModel::removeAddress(quint32 _row) {
+ if (_row > m_addressBook.size() - 1) {
+ return;
+ }
+
+ beginRemoveRows(QModelIndex(), _row, _row);
+ m_addressBook.removeAt(_row);
+ endRemoveRows();
+ saveAddressBook();
+}
+
+void AddressBookModel::reset() {
+ beginResetModel();
+ while (!m_addressBook.empty()) {
+ m_addressBook.removeFirst();
+ }
+
+ endResetModel();
+}
+
+void AddressBookModel::saveAddressBook() {
+ QFile addressBookFile(Settings::instance().getAddressBookFile());
+ if (addressBookFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
+ QByteArray file_content = QJsonDocument(m_addressBook).toJson(QJsonDocument::Compact);
+ addressBookFile.write(file_content);
+ addressBookFile.close();
+ }
+}
+
+void AddressBookModel::walletInitCompleted(int _error, const QString& _error_text) {
+ if (!_error) {
+ QFile addressBookFile(Settings::instance().getAddressBookFile());
+ if (addressBookFile.open(QIODevice::ReadOnly)) {
+ QByteArray file_content = addressBookFile.readAll();
+ QJsonDocument doc = QJsonDocument::fromJson(file_content);
+ if (!doc.isNull()) {
+ m_addressBook = doc.array();
+ }
+
+ addressBookFile.close();
+ if (!m_addressBook.isEmpty()) {
+ beginInsertRows(QModelIndex(), 0, m_addressBook.size() - 1);
+ endInsertRows();
+ }
+ }
+ }
+}
+
+}
diff --git a/src/gui/AddressBookModel.h b/src/gui/AddressBookModel.h
new file mode 100644
index 0000000..a07a3ab
--- /dev/null
+++ b/src/gui/AddressBookModel.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#pragma once
+
+#include
+#include
+
+namespace WalletGui {
+
+class AddressBookModel : public QAbstractItemModel
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(AddressBookModel)
+
+public:
+ enum Columns {COLUMN_LABEL = 0, COLUMN_ADDRESS};
+ enum Roles { ROLE_LABEL = Qt::UserRole, ROLE_ADDRESS };
+
+ static AddressBookModel& instance();
+ int columnCount(const QModelIndex& _parent = QModelIndex()) const Q_DECL_OVERRIDE;
+ QVariant data(const QModelIndex& _index, int _role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
+ Qt::ItemFlags flags(const QModelIndex& _index) const Q_DECL_OVERRIDE;
+ QVariant headerData(int _section, Qt::Orientation _orientation, int _role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
+ QModelIndex index(int _row, int _column, const QModelIndex& _parent = QModelIndex()) const Q_DECL_OVERRIDE;
+ QModelIndex parent(const QModelIndex& _index) const Q_DECL_OVERRIDE;
+ int rowCount(const QModelIndex& _parent = QModelIndex()) const Q_DECL_OVERRIDE;
+
+ void addAddress(const QString& _label, const QString& _address);
+ void removeAddress(quint32 _row);
+
+private:
+ QJsonArray m_addressBook;
+
+ AddressBookModel();
+ ~AddressBookModel();
+
+ void reset();
+ void saveAddressBook();
+ void walletInitCompleted(int _error, const QString& _error_text);
+};
+
+}
diff --git a/src/gui/AnimatedLabel.cpp b/src/gui/AnimatedLabel.cpp
new file mode 100644
index 0000000..88b919f
--- /dev/null
+++ b/src/gui/AnimatedLabel.cpp
@@ -0,0 +1,46 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#include "AnimatedLabel.h"
+
+namespace WalletGui {
+
+AnimatedLabel::AnimatedLabel(QWidget* _parent) : QLabel(_parent), m_spriteVerticalSpace(0) {
+ connect(&m_animationTimer, &QTimer::timeout, this, &AnimatedLabel::timeout);
+}
+
+AnimatedLabel::~AnimatedLabel() {
+}
+
+void AnimatedLabel::setSprite(const QPixmap& _spritePixmap, const QSize& _frameSize, quint32 _verticalSpace, quint32 _frequency) {
+ m_spritePixmap = _spritePixmap;
+ m_spriteFrameSize = _frameSize;
+ m_spriteVerticalSpace = _verticalSpace;
+ m_animationTimer.setInterval(1000 / _frequency);
+ m_frameRect.setTopLeft(QPoint(0, 0));
+ m_frameRect.setBottomRight(m_frameRect.topLeft() += QPoint(_frameSize.width(), _frameSize.height()));
+}
+
+void AnimatedLabel::startAnimation() {
+ if (m_animationTimer.isActive()) {
+ return;
+ }
+
+ m_animationTimer.start();
+}
+
+void AnimatedLabel::stopAnimation() {
+ m_animationTimer.stop();
+}
+
+void AnimatedLabel::timeout() {
+ setPixmap(m_spritePixmap.copy(m_frameRect));
+ m_frameRect.translate(QPoint(0, m_spriteVerticalSpace + m_spriteFrameSize.height()));
+ if (m_frameRect.bottom() >= m_spritePixmap.height()) {
+ m_frameRect.moveTop(0);
+ }
+}
+
+}
diff --git a/src/gui/AnimatedLabel.h b/src/gui/AnimatedLabel.h
new file mode 100644
index 0000000..42bd642
--- /dev/null
+++ b/src/gui/AnimatedLabel.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#pragma once
+
+#include
+#include
+
+namespace WalletGui {
+
+class AnimatedLabel : public QLabel {
+ Q_OBJECT
+ Q_DISABLE_COPY(AnimatedLabel)
+
+public:
+ AnimatedLabel(QWidget* _parent);
+ ~AnimatedLabel();
+
+ void setSprite(const QPixmap& _sprite_pixmap, const QSize& _frame_size, quint32 _vertical_space, quint32 _frequency);
+ void startAnimation();
+ void stopAnimation();
+
+private:
+ QPixmap m_spritePixmap;
+ QSize m_spriteFrameSize;
+ quint32 m_spriteVerticalSpace;
+ QTimer m_animationTimer;
+ QRect m_frameRect;
+
+ void timeout();
+};
+
+}
diff --git a/src/gui/ChangePasswordDialog.cpp b/src/gui/ChangePasswordDialog.cpp
new file mode 100644
index 0000000..a4267e0
--- /dev/null
+++ b/src/gui/ChangePasswordDialog.cpp
@@ -0,0 +1,36 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#include "ChangePasswordDialog.h"
+
+#include "ui_changepassworddialog.h"
+
+namespace WalletGui {
+
+ChangePasswordDialog::ChangePasswordDialog(QWidget* _parent) : QDialog(_parent), m_ui(new Ui::ChangePasswordDialog) {
+ m_ui->setupUi(this);
+ m_ui->m_errorLabel->setText("");
+}
+
+ChangePasswordDialog::~ChangePasswordDialog() {
+}
+
+QString ChangePasswordDialog::getNewPassword() const {
+ return m_ui->m_newPasswordEdit->text();
+}
+
+QString ChangePasswordDialog::getOldPassword() const {
+ return m_ui->m_oldPasswordEdit->text();
+}
+
+void ChangePasswordDialog::checkPassword(const QString& _password) {
+ bool passwordIsConfirmed = !(m_ui->m_newPasswordEdit->text().trimmed().isEmpty() ||
+ m_ui->m_newPasswordConfirmationEdit->text().trimmed().isEmpty() ||
+ m_ui->m_newPasswordEdit->text().compare(m_ui->m_newPasswordConfirmationEdit->text()));
+ m_ui->m_errorLabel->setText(passwordIsConfirmed ? "" : tr("Password not confirmed"));
+ m_ui->m_okButton->setEnabled(passwordIsConfirmed);
+}
+
+}
diff --git a/src/gui/ChangePasswordDialog.h b/src/gui/ChangePasswordDialog.h
new file mode 100644
index 0000000..8e83d41
--- /dev/null
+++ b/src/gui/ChangePasswordDialog.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#pragma once
+
+#include
+
+namespace Ui {
+class ChangePasswordDialog;
+}
+
+namespace WalletGui {
+
+class ChangePasswordDialog : public QDialog {
+ Q_OBJECT
+ Q_DISABLE_COPY(ChangePasswordDialog)
+
+public:
+ ChangePasswordDialog(QWidget* _parent);
+ ~ChangePasswordDialog();
+
+ QString getNewPassword() const;
+ QString getOldPassword() const;
+
+private:
+ QScopedPointer m_ui;
+
+ Q_SLOT void checkPassword(const QString& _password);
+};
+
+}
diff --git a/src/gui/ExitWidget.cpp b/src/gui/ExitWidget.cpp
new file mode 100644
index 0000000..6395905
--- /dev/null
+++ b/src/gui/ExitWidget.cpp
@@ -0,0 +1,29 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#include
+
+#include "CurrencyAdapter.h"
+#include "ExitWidget.h"
+
+#include "ui_exitwidget.h"
+
+namespace WalletGui {
+
+ExitWidget::ExitWidget(QWidget* _parent) : QWidget(_parent, Qt::Window), m_ui(new Ui::ExitWidget),
+ m_clockMovie(new QMovie(this)) {
+ m_ui->setupUi(this);
+ QString text = m_ui->m_label->text();
+ m_ui->m_label->setText(text.arg(CurrencyAdapter::instance().getCurrencyDisplayName()));
+ m_clockMovie->setFileName(":images/clock");
+ m_clockMovie->setScaledSize(QSize(48, 48));
+ m_ui->m_clockLabel->setMovie(m_clockMovie);
+ m_clockMovie->start();
+}
+
+ExitWidget::~ExitWidget() {
+}
+
+}
diff --git a/src/gui/ExitWidget.h b/src/gui/ExitWidget.h
new file mode 100644
index 0000000..dbe75b2
--- /dev/null
+++ b/src/gui/ExitWidget.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#pragma once
+
+#include
+
+class QMovie;
+
+namespace Ui {
+class ExitWidget;
+}
+
+namespace WalletGui {
+
+class ExitWidget : public QWidget {
+ Q_OBJECT
+ Q_DISABLE_COPY(ExitWidget)
+
+public:
+ ExitWidget(QWidget* _parent);
+ ~ExitWidget();
+
+private:
+ QScopedPointer m_ui;
+ QMovie* m_clockMovie;
+};
+
+}
diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp
new file mode 100644
index 0000000..0bbb18f
--- /dev/null
+++ b/src/gui/MainWindow.cpp
@@ -0,0 +1,413 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include "AboutDialog.h"
+#include "AnimatedLabel.h"
+#include "ChangePasswordDialog.h"
+#include "CurrencyAdapter.h"
+#include "ExitWidget.h"
+#include "MainWindow.h"
+#include "NewPasswordDialog.h"
+#include "NodeAdapter.h"
+#include "PasswordDialog.h"
+#include "Settings.h"
+#include "WalletAdapter.h"
+#include "WalletEvents.h"
+
+#include "ui_mainwindow.h"
+
+namespace WalletGui {
+
+MainWindow* MainWindow::m_instance = nullptr;
+
+MainWindow& MainWindow::instance() {
+ if (m_instance == nullptr) {
+ m_instance = new MainWindow;
+ }
+
+ return *m_instance;
+}
+
+MainWindow::MainWindow() : QMainWindow(), m_ui(new Ui::MainWindow), m_trayIcon(nullptr), m_tabActionGroup(new QActionGroup(this)),
+ m_isAboutToQuit(false) {
+ m_ui->setupUi(this);
+ m_connectionStateIconLabel = new QLabel(this);
+ m_encryptionStateIconLabel = new QLabel(this);
+ m_synchronizationStateIconLabel = new AnimatedLabel(this);
+
+ connectToSignals();
+ initUi();
+
+ walletClosed();
+}
+
+MainWindow::~MainWindow() {
+}
+
+void MainWindow::connectToSignals() {
+ connect(&WalletAdapter::instance(), &WalletAdapter::openWalletWithPasswordSignal, this, &MainWindow::askForWalletPassword, Qt::QueuedConnection);
+ connect(&WalletAdapter::instance(), &WalletAdapter::changeWalletPasswordSignal, this, &MainWindow::encryptWallet, Qt::QueuedConnection);
+ connect(&WalletAdapter::instance(), &WalletAdapter::walletSynchronizationProgressUpdatedSignal,
+ this, &MainWindow::walletSynchronizationInProgress, Qt::QueuedConnection);
+ connect(&WalletAdapter::instance(), &WalletAdapter::walletSynchronizationCompletedSignal, this, &MainWindow::walletSynchronized
+ , Qt::QueuedConnection);
+ connect(&WalletAdapter::instance(), &WalletAdapter::walletStateChangedSignal, this, &MainWindow::setStatusBarText);
+ connect(&WalletAdapter::instance(), &WalletAdapter::walletInitCompletedSignal, this, &MainWindow::walletOpened);
+ connect(&WalletAdapter::instance(), &WalletAdapter::walletCloseCompletedSignal, this, &MainWindow::walletClosed);
+ connect(&NodeAdapter::instance(), &NodeAdapter::peerCountUpdatedSignal, this, &MainWindow::peerCountUpdated, Qt::QueuedConnection);
+ connect(m_ui->m_exitAction, &QAction::triggered, qApp, &QApplication::quit);
+}
+
+void MainWindow::initUi() {
+ setWindowTitle(QString("%1 Wallet %2").arg(CurrencyAdapter::instance().getCurrencyDisplayName()).arg(Settings::instance().getVersion()));
+#ifdef Q_OS_WIN32
+ if (QSystemTrayIcon::isSystemTrayAvailable()) {
+ m_trayIcon = new QSystemTrayIcon(QPixmap(":images/cryptonote"), this);
+ connect(m_trayIcon, &QSystemTrayIcon::activated, this, &MainWindow::trayActivated);
+ }
+#endif
+ m_ui->m_aboutCryptonoteAction->setText(QString(tr("About %1 Wallet")).arg(CurrencyAdapter::instance().getCurrencyDisplayName()));
+
+ m_ui->m_overviewFrame->hide();
+ m_ui->m_sendFrame->hide();
+ m_ui->m_receiveFrame->hide();
+ m_ui->m_transactionsFrame->hide();
+ m_ui->m_addressBookFrame->hide();
+
+ m_tabActionGroup->addAction(m_ui->m_overviewAction);
+ m_tabActionGroup->addAction(m_ui->m_sendAction);
+ m_tabActionGroup->addAction(m_ui->m_receiveAction);
+ m_tabActionGroup->addAction(m_ui->m_transactionsAction);
+ m_tabActionGroup->addAction(m_ui->m_addressBookAction);
+
+ m_ui->m_overviewAction->toggle();
+ encryptedFlagChanged(false);
+ statusBar()->addPermanentWidget(m_connectionStateIconLabel);
+ statusBar()->addPermanentWidget(m_encryptionStateIconLabel);
+ statusBar()->addPermanentWidget(m_synchronizationStateIconLabel);
+ qobject_cast(m_synchronizationStateIconLabel)->setSprite(QPixmap(":icons/sync_sprite"), QSize(16, 16), 5, 24);
+ m_connectionStateIconLabel->setPixmap(QPixmap(":icons/disconnected").scaled(16, 16, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
+
+#ifdef Q_OS_MAC
+ installDockHandler();
+#endif
+
+#ifndef Q_OS_WIN
+ m_ui->m_minimizeToTrayAction->deleteLater();
+ m_ui->m_closeToTrayAction->deleteLater();
+#endif
+}
+
+#ifdef Q_OS_WIN
+void MainWindow::minimizeToTray(bool _on) {
+ if (_on) {
+ hide();
+ m_trayIcon->show();
+ } else {
+ showNormal();
+ activateWindow();
+ m_trayIcon->hide();
+ }
+}
+#endif
+
+void MainWindow::scrollToTransaction(const QModelIndex& _index) {
+ m_ui->m_transactionsAction->setChecked(true);
+ m_ui->m_transactionsFrame->scrollToTransaction(_index);
+}
+
+void MainWindow::quit() {
+ if (!m_isAboutToQuit) {
+ ExitWidget* exitWidget = new ExitWidget(nullptr);
+ exitWidget->show();
+ m_isAboutToQuit = true;
+ close();
+ }
+}
+
+#ifdef Q_OS_MAC
+void MainWindow::restoreFromDock() {
+ if (m_isAboutToQuit) {
+ return;
+ }
+
+ showNormal();
+}
+#endif
+
+void MainWindow::closeEvent(QCloseEvent* _event) {
+#ifdef Q_OS_WIN
+ if (m_isAboutToQuit) {
+ QMainWindow::closeEvent(_event);
+ return;
+ } else if (Settings::instance().isCloseToTrayEnabled()) {
+ minimizeToTray(true);
+ _event->ignore();
+ } else {
+ QApplication::quit();
+ return;
+ }
+#elif defined(Q_OS_LINUX)
+ if (!m_isAboutToQuit) {
+ QApplication::quit();
+ return;
+ }
+#endif
+ QMainWindow::closeEvent(_event);
+
+}
+
+#ifdef Q_OS_WIN
+void MainWindow::changeEvent(QEvent* _event) {
+ QMainWindow::changeEvent(_event);
+ if (!QSystemTrayIcon::isSystemTrayAvailable()) {
+ QMainWindow::changeEvent(_event);
+ return;
+ }
+
+ switch (_event->type()) {
+ case QEvent::WindowStateChange:
+ if(Settings::instance().isMinimizeToTrayEnabled()) {
+ minimizeToTray(isMinimized());
+ }
+ break;
+ default:
+ break;
+ }
+
+ QMainWindow::changeEvent(_event);
+}
+#endif
+
+bool MainWindow::event(QEvent* _event) {
+ switch (static_cast(_event->type())) {
+ case WalletEventType::ShowMessage:
+ showMessage(static_cast(_event)->messageText(), static_cast(_event)->messageType());
+ return true;
+ }
+
+ return QMainWindow::event(_event);
+}
+
+void MainWindow::createWallet() {
+ QString filePath = QFileDialog::getSaveFileName(this, tr("New wallet file"),
+ #ifdef Q_OS_WIN
+ QApplication::applicationDirPath(),
+ #else
+ QDir::homePath(),
+ #endif
+ tr("Wallets (*.wallet)")
+ );
+
+ if (!filePath.isEmpty() && !filePath.endsWith(".wallet")) {
+ filePath.append(".wallet");
+ }
+
+ if (!filePath.isEmpty() && !QFile::exists(filePath)) {
+ if (WalletAdapter::instance().isOpen()) {
+ WalletAdapter::instance().close();
+ }
+
+ WalletAdapter::instance().setWalletFile(filePath);
+ WalletAdapter::instance().open("");
+ }
+}
+
+void MainWindow::openWallet() {
+ QString filePath = QFileDialog::getOpenFileName(this, tr("Open .wallet/.keys file"),
+#ifdef Q_OS_WIN
+ QApplication::applicationDirPath(),
+#else
+ QDir::homePath(),
+#endif
+ tr("Wallet (*.wallet *.keys)"));
+
+ if (!filePath.isEmpty()) {
+ if (WalletAdapter::instance().isOpen()) {
+ WalletAdapter::instance().close();
+ }
+
+ WalletAdapter::instance().setWalletFile(filePath);
+ WalletAdapter::instance().open("");
+ }
+}
+
+void MainWindow::backupWallet() {
+ QString filePath = QFileDialog::getSaveFileName(this, tr("Backup wallet to..."),
+ #ifdef Q_OS_WIN
+ QApplication::applicationDirPath(),
+ #else
+ QDir::homePath(),
+ #endif
+ tr("Wallets (*.wallet)")
+ );
+ if (!filePath.isEmpty() && !filePath.endsWith(".wallet")) {
+ filePath.append(".wallet");
+ }
+
+ if (!filePath.isEmpty() && !QFile::exists(filePath)) {
+ WalletAdapter::instance().backup(filePath);
+ }
+}
+
+void MainWindow::encryptWallet() {
+ if (Settings::instance().isEncrypted()) {
+ bool error = false;
+ do {
+ ChangePasswordDialog dlg(this);
+ if (dlg.exec() == QDialog::Rejected) {
+ return;
+ }
+
+ QString oldPassword = dlg.getOldPassword();
+ QString newPassword = dlg.getNewPassword();
+ error = !WalletAdapter::instance().changePassword(oldPassword, newPassword);
+ } while (error);
+ } else {
+ NewPasswordDialog dlg(this);
+ if (dlg.exec() == QDialog::Accepted) {
+ QString password = dlg.getPassword();
+ if (password.isEmpty()) {
+ return;
+ }
+
+ encryptedFlagChanged(WalletAdapter::instance().changePassword("", password));
+ }
+ }
+}
+
+void MainWindow::aboutQt() {
+ QMessageBox::aboutQt(this);
+}
+
+void MainWindow::setStartOnLogin(bool _on) {
+ Settings::instance().setStartOnLoginEnabled(_on);
+ m_ui->m_startOnLoginAction->setChecked(Settings::instance().isStartOnLoginEnabled());
+}
+
+void MainWindow::setMinimizeToTray(bool _on) {
+#ifdef Q_OS_WIN
+ Settings::instance().setMinimizeToTrayEnabled(_on);
+#endif
+}
+
+void MainWindow::setCloseToTray(bool _on) {
+#ifdef Q_OS_WIN
+ Settings::instance().setCloseToTrayEnabled(_on);
+#endif
+}
+
+void MainWindow::about() {
+ AboutDialog dlg(this);
+ dlg.exec();
+}
+
+void MainWindow::setStatusBarText(const QString& _text) {
+ statusBar()->showMessage(_text);
+}
+
+void MainWindow::showMessage(const QString& _text, QtMsgType _type) {
+ switch (_type) {
+ case QtCriticalMsg:
+ QMessageBox::critical(this, tr("Wallet error"), _text);
+ break;
+ case QtDebugMsg:
+ QMessageBox::information(this, tr("Wallet"), _text);
+ break;
+ default:
+ break;
+ }
+}
+
+void MainWindow::askForWalletPassword(bool _error) {
+ PasswordDialog dlg(_error, this);
+ if (dlg.exec() == QDialog::Accepted) {
+ QString password = dlg.getPassword();
+ WalletAdapter::instance().open(password);
+ }
+}
+
+void MainWindow::encryptedFlagChanged(bool _encrypted) {
+ m_ui->m_encryptWalletAction->setEnabled(!_encrypted);
+ m_ui->m_changePasswordAction->setEnabled(_encrypted);
+ QString encryptionIconPath = _encrypted ? ":icons/encrypted" : ":icons/decrypted";
+ QPixmap encryptionIcon = QPixmap(encryptionIconPath).scaled(16, 16, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+ m_encryptionStateIconLabel->setPixmap(encryptionIcon);
+ QString encryptionLabelTooltip = _encrypted ? tr("Encrypted") : tr("Not encrypted");
+ m_encryptionStateIconLabel->setToolTip(encryptionLabelTooltip);
+}
+
+void MainWindow::peerCountUpdated(quint64 _peerCount) {
+ QString connectionIconPath = _peerCount > 0 ? ":icons/connected" : ":icons/disconnected";
+ QPixmap connectionIcon = QPixmap(connectionIconPath).scaled(16, 16, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+ m_connectionStateIconLabel->setPixmap(connectionIcon);
+ m_connectionStateIconLabel->setToolTip(QString(tr("%1 peers").arg(_peerCount)));
+}
+
+void MainWindow::walletSynchronizationInProgress() {
+ qobject_cast(m_synchronizationStateIconLabel)->startAnimation();
+ m_synchronizationStateIconLabel->setToolTip(tr("Synchronization in progress"));
+}
+
+void MainWindow::walletSynchronized(int _error, const QString& _error_text) {
+ QPixmap syncIcon = QPixmap(":icons/synced").scaled(16, 16, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+ qobject_cast(m_synchronizationStateIconLabel)->stopAnimation();
+ m_synchronizationStateIconLabel->setPixmap(syncIcon);
+ QString syncLabelTooltip = _error > 0 ? tr("Not synchronized") : tr("Synchronized");
+ m_synchronizationStateIconLabel->setToolTip(syncLabelTooltip);
+}
+
+void MainWindow::walletOpened(bool _error, const QString& _error_text) {
+ if (!_error) {
+ m_encryptionStateIconLabel->show();
+ m_synchronizationStateIconLabel->show();
+ m_ui->m_backupWalletAction->setEnabled(true);
+ encryptedFlagChanged(Settings::instance().isEncrypted());
+
+ QList tabActions = m_tabActionGroup->actions();
+ Q_FOREACH(auto action, tabActions) {
+ action->setEnabled(true);
+ }
+
+ m_ui->m_overviewAction->trigger();
+ m_ui->m_overviewFrame->show();
+ } else {
+ walletClosed();
+ }
+}
+
+void MainWindow::walletClosed() {
+ m_ui->m_backupWalletAction->setEnabled(false);
+ m_ui->m_encryptWalletAction->setEnabled(false);
+ m_ui->m_changePasswordAction->setEnabled(false);
+ m_ui->m_overviewFrame->hide();
+ m_ui->m_sendFrame->hide();
+ m_ui->m_transactionsFrame->hide();
+ m_ui->m_addressBookFrame->hide();
+ m_encryptionStateIconLabel->hide();
+ m_synchronizationStateIconLabel->hide();
+ QList tabActions = m_tabActionGroup->actions();
+ Q_FOREACH(auto action, tabActions) {
+ action->setEnabled(false);
+ }
+}
+
+#ifdef Q_OS_WIN
+void MainWindow::trayActivated(QSystemTrayIcon::ActivationReason _reason) {
+ showNormal();
+ m_trayIcon->hide();
+}
+#endif
+
+}
diff --git a/src/gui/MainWindow.h b/src/gui/MainWindow.h
new file mode 100644
index 0000000..0ae5574
--- /dev/null
+++ b/src/gui/MainWindow.h
@@ -0,0 +1,87 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#pragma once
+
+#include
+#include
+#include
+#include
+
+class QActionGroup;
+
+namespace Ui {
+class MainWindow;
+}
+
+namespace WalletGui {
+
+class MainWindow : public QMainWindow {
+ Q_OBJECT
+ Q_DISABLE_COPY(MainWindow)
+
+public:
+ static MainWindow& instance();
+ void scrollToTransaction(const QModelIndex& _index);
+ void quit();
+
+protected:
+ void closeEvent(QCloseEvent* _event) Q_DECL_OVERRIDE;
+ bool event(QEvent* _event) Q_DECL_OVERRIDE;
+
+private:
+ QScopedPointer m_ui;
+ QLabel* m_connectionStateIconLabel;
+ QLabel* m_encryptionStateIconLabel;
+ QLabel* m_synchronizationStateIconLabel;
+ QSystemTrayIcon* m_trayIcon;
+ QActionGroup* m_tabActionGroup;
+ bool m_isAboutToQuit;
+
+ static MainWindow* m_instance;
+
+ MainWindow();
+ ~MainWindow();
+
+ void connectToSignals();
+ void initUi();
+
+ void minimizeToTray(bool _on);
+ void setStatusBarText(const QString& _text);
+ void showMessage(const QString& _text, QtMsgType _type);
+ void askForWalletPassword(bool _error);
+ void encryptedFlagChanged(bool _encrypted);
+ void peerCountUpdated(quint64 _peer_count);
+ void walletSynchronizationInProgress();
+ void walletSynchronized(int _error, const QString& _error_text);
+ void walletOpened(bool _error, const QString& _error_text);
+ void walletClosed();
+
+ Q_SLOT void createWallet();
+ Q_SLOT void openWallet();
+ Q_SLOT void backupWallet();
+ Q_SLOT void encryptWallet();
+ Q_SLOT void aboutQt();
+ Q_SLOT void about();
+ Q_SLOT void setStartOnLogin(bool _on);
+ Q_SLOT void setMinimizeToTray(bool _on);
+ Q_SLOT void setCloseToTray(bool _on);
+
+#ifdef Q_OS_MAC
+public:
+ void restoreFromDock();
+
+private:
+ void installDockHandler();
+#elif defined(Q_OS_WIN)
+protected:
+ void changeEvent(QEvent* _event) Q_DECL_OVERRIDE;
+
+private:
+ void trayActivated(QSystemTrayIcon::ActivationReason _reason);
+#endif
+};
+
+}
diff --git a/src/gui/MainWindow.mm b/src/gui/MainWindow.mm
new file mode 100644
index 0000000..146ff6e
--- /dev/null
+++ b/src/gui/MainWindow.mm
@@ -0,0 +1,30 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#import
+#import
+
+#include "mainwindow.h"
+
+namespace WalletGui {
+
+namespace {
+
+void dockClickHandler(id self, SEL _cmd) {
+ Q_UNUSED(self)
+ Q_UNUSED(_cmd)
+ MainWindow::instance().restoreFromDock();
+}
+
+}
+
+void MainWindow::installDockHandler() {
+ Class cls = [[[NSApplication sharedApplication] delegate] class];
+ if (!class_replaceMethod(cls, @selector(applicationShouldHandleReopen:hasVisibleWindows:), (IMP) dockClickHandler, "v@:")) {
+ NSLog(@"MainWindow::installDockHandler() : class_addMethod failed!");
+ }
+}
+
+}
diff --git a/src/gui/NewAddressDialog.cpp b/src/gui/NewAddressDialog.cpp
new file mode 100644
index 0000000..084d5cb
--- /dev/null
+++ b/src/gui/NewAddressDialog.cpp
@@ -0,0 +1,28 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#include "NewAddressDialog.h"
+
+#include "ui_newaddressdialog.h"
+
+namespace WalletGui {
+
+NewAddressDialog::NewAddressDialog(QWidget* _parent) : QDialog(_parent), m_ui(new Ui::NewAddressDialog) {
+ m_ui->setupUi(this);
+}
+
+NewAddressDialog::~NewAddressDialog() {
+}
+
+QString NewAddressDialog::getAddress() const {
+ return m_ui->m_addressEdit->text();
+}
+
+
+QString NewAddressDialog::getLabel() const {
+ return m_ui->m_labelEdit->text();
+}
+
+}
diff --git a/src/gui/NewAddressDialog.h b/src/gui/NewAddressDialog.h
new file mode 100644
index 0000000..152c377
--- /dev/null
+++ b/src/gui/NewAddressDialog.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#pragma once
+
+#include
+
+namespace Ui {
+class NewAddressDialog;
+}
+
+namespace WalletGui {
+
+class NewAddressDialog : public QDialog {
+ Q_OBJECT
+ Q_DISABLE_COPY(NewAddressDialog)
+
+public:
+ NewAddressDialog(QWidget* _parent);
+ ~NewAddressDialog();
+
+ QString getAddress() const;
+ QString getLabel() const;
+
+private:
+ QScopedPointer m_ui;
+};
+
+}
diff --git a/src/gui/NewPasswordDialog.cpp b/src/gui/NewPasswordDialog.cpp
new file mode 100644
index 0000000..f169301
--- /dev/null
+++ b/src/gui/NewPasswordDialog.cpp
@@ -0,0 +1,32 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#include "NewPasswordDialog.h"
+
+#include "ui_newpassworddialog.h"
+
+namespace WalletGui {
+
+NewPasswordDialog::NewPasswordDialog(QWidget* _parent) : QDialog(_parent), m_ui(new Ui::NewPasswordDialog) {
+ m_ui->setupUi(this);
+ m_ui->m_errorLabel->setText("");
+}
+
+NewPasswordDialog::~NewPasswordDialog() {
+}
+
+QString NewPasswordDialog::getPassword() const {
+ return m_ui->m_passwordEdit->text();
+}
+
+void NewPasswordDialog::checkPassword(const QString& _password) {
+ bool passwordIsConfirmed = !(m_ui->m_passwordEdit->text().trimmed().isEmpty() ||
+ m_ui->m_passwordConfirmationEdit->text().trimmed().isEmpty() ||
+ m_ui->m_passwordEdit->text().compare(m_ui->m_passwordConfirmationEdit->text()));
+ m_ui->m_errorLabel->setText(passwordIsConfirmed ? "" : tr("Password not confirmed"));
+ m_ui->m_okButton->setEnabled(passwordIsConfirmed);
+}
+
+}
diff --git a/src/gui/NewPasswordDialog.h b/src/gui/NewPasswordDialog.h
new file mode 100644
index 0000000..f84e907
--- /dev/null
+++ b/src/gui/NewPasswordDialog.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#pragma once
+
+#include
+
+namespace Ui {
+class NewPasswordDialog;
+}
+
+namespace WalletGui {
+
+class NewPasswordDialog : public QDialog {
+ Q_OBJECT
+ Q_DISABLE_COPY(NewPasswordDialog)
+
+public:
+ NewPasswordDialog(QWidget* _parent);
+ ~NewPasswordDialog();
+
+ QString getPassword() const;
+
+private:
+ QScopedPointer m_ui;
+
+ Q_SLOT void checkPassword(const QString& _password);
+};
+
+}
diff --git a/src/gui/OverviewFrame.cpp b/src/gui/OverviewFrame.cpp
new file mode 100644
index 0000000..0141677
--- /dev/null
+++ b/src/gui/OverviewFrame.cpp
@@ -0,0 +1,95 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#include "CurrencyAdapter.h"
+#include "OverviewFrame.h"
+#include "TransactionFrame.h"
+#include "RecentTransactionsModel.h"
+#include "WalletAdapter.h"
+
+#include "ui_overviewframe.h"
+
+namespace WalletGui {
+
+class RecentTransactionsDelegate : public QStyledItemDelegate {
+ Q_OBJECT
+
+public:
+ RecentTransactionsDelegate(QObject* _parent) : QStyledItemDelegate(_parent) {
+ }
+
+ ~RecentTransactionsDelegate() {
+ }
+
+ QWidget* createEditor(QWidget* _parent, const QStyleOptionViewItem& _option, const QModelIndex& _index) const Q_DECL_OVERRIDE {
+ if (!_index.isValid()) {
+ return nullptr;
+ }
+
+ return new TransactionFrame(_index, _parent);
+ }
+
+ QSize sizeHint(const QStyleOptionViewItem& _option, const QModelIndex& _index) const Q_DECL_OVERRIDE {
+ return QSize(346, 64);
+ }
+};
+
+OverviewFrame::OverviewFrame(QWidget* _parent) : QFrame(_parent), m_ui(new Ui::OverviewFrame), m_transactionModel(new RecentTransactionsModel) {
+ m_ui->setupUi(this);
+ connect(&WalletAdapter::instance(), &WalletAdapter::walletActualBalanceUpdatedSignal, this, &OverviewFrame::updateActualBalance,
+ Qt::QueuedConnection);
+ connect(&WalletAdapter::instance(), &WalletAdapter::walletPendingBalanceUpdatedSignal, this, &OverviewFrame::updatePendingBalance,
+ Qt::QueuedConnection);
+ connect(&WalletAdapter::instance(), &WalletAdapter::walletCloseCompletedSignal, this, &OverviewFrame::reset,
+ Qt::QueuedConnection);
+ connect(m_transactionModel.data(), &QAbstractItemModel::rowsInserted, this, &OverviewFrame::transactionsInserted);
+ connect(m_transactionModel.data(), &QAbstractItemModel::layoutChanged, this, &OverviewFrame::layoutChanged);
+
+ m_ui->m_tickerLabel1->setText(CurrencyAdapter::instance().getCurrencyTicker().toUpper());
+ m_ui->m_tickerLabel2->setText(CurrencyAdapter::instance().getCurrencyTicker().toUpper());
+ m_ui->m_tickerLabel3->setText(CurrencyAdapter::instance().getCurrencyTicker().toUpper());
+
+ m_ui->m_recentTransactionsView->setItemDelegate(new RecentTransactionsDelegate(this));
+ m_ui->m_recentTransactionsView->setModel(m_transactionModel.data());
+ reset();
+}
+
+OverviewFrame::~OverviewFrame() {
+}
+
+void OverviewFrame::transactionsInserted(const QModelIndex& _parent, int _first, int _last) {
+ for (quint32 i = _first; i <= _last; ++i) {
+ QModelIndex recentModelIndex = m_transactionModel->index(i, 0);
+ m_ui->m_recentTransactionsView->openPersistentEditor(recentModelIndex);
+ }
+}
+
+void OverviewFrame::layoutChanged() {
+ for (quint32 i = 0; i <= m_transactionModel->rowCount(); ++i) {
+ QModelIndex recent_index = m_transactionModel->index(i, 0);
+ m_ui->m_recentTransactionsView->openPersistentEditor(recent_index);
+ }
+}
+
+void OverviewFrame::updateActualBalance(quint64 _balance) {
+ m_ui->m_actualBalanceLabel->setText(CurrencyAdapter::instance().formatAmount(_balance));
+ quint64 pendingBalance = WalletAdapter::instance().getPendingBalance();
+ m_ui->m_totalBalanceLabel->setText(CurrencyAdapter::instance().formatAmount(_balance + pendingBalance));
+}
+
+void OverviewFrame::updatePendingBalance(quint64 _balance) {
+ m_ui->m_pendingBalanceLabel->setText(CurrencyAdapter::instance().formatAmount(_balance));
+ quint64 actualBalance = WalletAdapter::instance().getActualBalance();
+ m_ui->m_totalBalanceLabel->setText(CurrencyAdapter::instance().formatAmount(_balance + actualBalance));
+}
+
+void OverviewFrame::reset() {
+ updateActualBalance(0);
+ updatePendingBalance(0);
+}
+
+}
+
+#include "OverviewFrame.moc"
diff --git a/src/gui/OverviewFrame.h b/src/gui/OverviewFrame.h
new file mode 100644
index 0000000..e44456b
--- /dev/null
+++ b/src/gui/OverviewFrame.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#pragma once
+
+#include
+#include
+
+namespace Ui {
+class OverviewFrame;
+}
+
+namespace WalletGui {
+
+class RecentTransactionsModel;
+
+class OverviewFrame : public QFrame {
+ Q_OBJECT
+ Q_DISABLE_COPY(OverviewFrame)
+
+public:
+ OverviewFrame(QWidget* _parent);
+ ~OverviewFrame();
+
+private:
+ QScopedPointer m_ui;
+ QSharedPointer m_transactionModel;
+
+ void transactionsInserted(const QModelIndex& _parent, int _first, int _last);
+ void transactionsRemoved(const QModelIndex& _parent, int _first, int _last);
+ void layoutChanged();
+ void updateActualBalance(quint64 _balance);
+ void updatePendingBalance(quint64 _balance);
+ void reset();
+};
+
+}
diff --git a/src/gui/PasswordDialog.cpp b/src/gui/PasswordDialog.cpp
new file mode 100644
index 0000000..bd1d982
--- /dev/null
+++ b/src/gui/PasswordDialog.cpp
@@ -0,0 +1,28 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#include "PasswordDialog.h"
+
+#include "ui_passworddialog.h"
+
+namespace WalletGui {
+
+PasswordDialog::PasswordDialog(bool _error, QWidget* _parent) : QDialog(_parent), m_ui(new Ui::PasswordDialog) {
+ m_ui->setupUi(this);
+ if (!_error) {
+ m_ui->m_errorLabel->hide();
+ }
+
+ adjustSize();
+}
+
+PasswordDialog::~PasswordDialog() {
+}
+
+QString PasswordDialog::getPassword() const {
+ return m_ui->m_passwordEdit->text();
+}
+
+}
diff --git a/src/gui/PasswordDialog.h b/src/gui/PasswordDialog.h
new file mode 100644
index 0000000..ee2c68c
--- /dev/null
+++ b/src/gui/PasswordDialog.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#pragma once
+
+#include
+
+namespace Ui {
+class PasswordDialog;
+}
+
+namespace WalletGui {
+
+class PasswordDialog : public QDialog {
+ Q_OBJECT
+ Q_DISABLE_COPY(PasswordDialog)
+
+public:
+ PasswordDialog(bool _error, QWidget* _parent);
+ ~PasswordDialog();
+
+ QString getPassword() const;
+
+private:
+ QScopedPointer m_ui;
+};
+
+}
diff --git a/src/gui/ReceiveFrame.cpp b/src/gui/ReceiveFrame.cpp
new file mode 100644
index 0000000..b167cca
--- /dev/null
+++ b/src/gui/ReceiveFrame.cpp
@@ -0,0 +1,36 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#include
+
+#include "ReceiveFrame.h"
+#include "WalletAdapter.h"
+
+#include "ui_receiveframe.h"
+
+namespace WalletGui {
+
+ReceiveFrame::ReceiveFrame(QWidget* _parent) : QFrame(_parent), m_ui(new Ui::ReceiveFrame) {
+ m_ui->setupUi(this);
+ connect(&WalletAdapter::instance(), &WalletAdapter::updateWalletAddressSignal, this, &ReceiveFrame::updateWalletAddress);
+ connect(&WalletAdapter::instance(), &WalletAdapter::walletCloseCompletedSignal, this, &ReceiveFrame::reset);
+}
+
+ReceiveFrame::~ReceiveFrame() {
+}
+
+void ReceiveFrame::updateWalletAddress(const QString& _address) {
+ m_ui->m_addressEdit->setText(_address);
+}
+
+void ReceiveFrame::reset() {
+ m_ui->m_addressEdit->clear();
+}
+
+void ReceiveFrame::copyAddress() {
+ QApplication::clipboard()->setText(m_ui->m_addressEdit->text());
+}
+
+}
diff --git a/src/gui/ReceiveFrame.h b/src/gui/ReceiveFrame.h
new file mode 100644
index 0000000..c407acf
--- /dev/null
+++ b/src/gui/ReceiveFrame.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#pragma once
+
+#include
+
+namespace Ui {
+class ReceiveFrame;
+}
+
+namespace WalletGui {
+
+class ReceiveFrame : public QFrame {
+ Q_OBJECT
+ Q_DISABLE_COPY(ReceiveFrame)
+
+public:
+ ReceiveFrame(QWidget* _parent);
+ ~ReceiveFrame();
+
+private:
+ QScopedPointer m_ui;
+
+ void updateWalletAddress(const QString& _address);
+ void reset();
+
+ Q_SLOT void copyAddress();
+};
+
+}
diff --git a/src/gui/RecentTransactionsModel.cpp b/src/gui/RecentTransactionsModel.cpp
new file mode 100644
index 0000000..1a0992c
--- /dev/null
+++ b/src/gui/RecentTransactionsModel.cpp
@@ -0,0 +1,37 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#include "RecentTransactionsModel.h"
+#include "SortedTransactionsModel.h"
+
+namespace WalletGui {
+
+RecentTransactionsModel::RecentTransactionsModel() : QSortFilterProxyModel() {
+ setSourceModel(&SortedTransactionsModel::instance());
+ setDynamicSortFilter(true);
+ connect(sourceModel(), &QAbstractItemModel::rowsInserted, this, &RecentTransactionsModel::invalidateFilter);
+}
+
+RecentTransactionsModel::~RecentTransactionsModel() {
+}
+
+int RecentTransactionsModel::columnCount(const QModelIndex& _parent) const {
+ return 1;
+}
+
+QVariant RecentTransactionsModel::data(const QModelIndex& _index, int _role) const {
+ if(_role == Qt::DecorationRole) {
+ return QVariant();
+ }
+
+ return QSortFilterProxyModel::data(_index, _role);
+}
+
+bool RecentTransactionsModel::filterAcceptsRow(int _sourceRow, const QModelIndex& _sourceParent) const {
+ return _sourceRow < 6;
+}
+
+
+}
diff --git a/src/gui/RecentTransactionsModel.h b/src/gui/RecentTransactionsModel.h
new file mode 100644
index 0000000..7a86cca
--- /dev/null
+++ b/src/gui/RecentTransactionsModel.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#pragma once
+
+#include
+
+namespace WalletGui {
+
+class RecentTransactionsModel : public QSortFilterProxyModel {
+ Q_OBJECT
+ Q_DISABLE_COPY(RecentTransactionsModel)
+
+public:
+ RecentTransactionsModel();
+ ~RecentTransactionsModel();
+
+ int columnCount(const QModelIndex& _parent = QModelIndex()) const Q_DECL_OVERRIDE;
+ QVariant data(const QModelIndex& _index, int _role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
+ bool filterAcceptsRow(int _source_row, const QModelIndex& _source_parent) const Q_DECL_OVERRIDE;
+};
+
+}
diff --git a/src/gui/SendFrame.cpp b/src/gui/SendFrame.cpp
new file mode 100644
index 0000000..9ac69ad
--- /dev/null
+++ b/src/gui/SendFrame.cpp
@@ -0,0 +1,114 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#include "AddressBookModel.h"
+#include "CurrencyAdapter.h"
+#include "MainWindow.h"
+#include "NodeAdapter.h"
+#include "SendFrame.h"
+#include "TransferFrame.h"
+#include "WalletAdapter.h"
+#include "WalletEvents.h"
+
+#include "ui_sendframe.h"
+
+namespace WalletGui {
+
+const quint64 MINIMAL_FEE = 1000000;
+
+SendFrame::SendFrame(QWidget* _parent) : QFrame(_parent), m_ui(new Ui::SendFrame) {
+ m_ui->setupUi(this);
+ clearAllClicked();
+ mixinValueChanged(m_ui->m_mixinSlider->value());
+
+ connect(&WalletAdapter::instance(), &WalletAdapter::walletSendTransactionCompletedSignal, this, &SendFrame::sendTransactionCompleted,
+ Qt::QueuedConnection);
+ connect(&WalletAdapter::instance(), &WalletAdapter::walletActualBalanceUpdatedSignal, this, &SendFrame::walletActualBalanceUpdated,
+ Qt::QueuedConnection);
+
+ m_ui->m_tickerLabel->setText(CurrencyAdapter::instance().getCurrencyTicker().toUpper());
+}
+
+SendFrame::~SendFrame() {
+}
+
+void SendFrame::addRecipientClicked() {
+ TransferFrame* newTransfer = new TransferFrame(m_ui->m_transfersScrollarea);
+ m_ui->m_send_frame_layout->insertWidget(m_transfers.size(), newTransfer);
+ m_transfers.append(newTransfer);
+ if (m_transfers.size() == 1) {
+ newTransfer->disableRemoveButton(true);
+ } else {
+ m_transfers[0]->disableRemoveButton(false);
+ }
+
+ connect(newTransfer, &TransferFrame::destroyed, [this](QObject* _obj) {
+ m_transfers.removeOne(static_cast(_obj));
+ if (m_transfers.size() == 1) {
+ m_transfers[0]->disableRemoveButton(true);
+ }
+ });
+}
+
+void SendFrame::clearAllClicked() {
+ Q_FOREACH (TransferFrame* transfer, m_transfers) {
+ transfer->close();
+ }
+
+ m_transfers.clear();
+ addRecipientClicked();
+ m_ui->m_paymentIdEdit->clear();
+ m_ui->m_mixinSlider->setValue(2);
+}
+
+void SendFrame::sendClicked() {
+ QVector walletTransfers;
+ Q_FOREACH (TransferFrame * transfer, m_transfers) {
+ QString address = transfer->getAddress();
+ if (!CurrencyAdapter::instance().validateAddress(address)) {
+ QCoreApplication::postEvent(
+ &MainWindow::instance(),
+ new ShowMessageEvent(tr("Invalid recipient address"), QtCriticalMsg));
+ return;
+ }
+
+ CryptoNote::Transfer walletTransfer;
+ walletTransfer.address = address.toStdString();
+ uint64_t amount = CurrencyAdapter::instance().parseAmount(transfer->getAmountString());
+ walletTransfer.amount = amount;
+ walletTransfers.push_back(walletTransfer);
+ QString label = transfer->getLabel();
+ if (!label.isEmpty()) {
+ AddressBookModel::instance().addAddress(label, address);
+ }
+ }
+
+ quint64 fee = MINIMAL_FEE;
+ if (fee < MINIMAL_FEE) {
+ QCoreApplication::postEvent(&MainWindow::instance(), new ShowMessageEvent(tr("Minimum allowed fee is 0.01"), QtCriticalMsg));
+ return;
+ }
+
+ if (WalletAdapter::instance().isOpen()) {
+ WalletAdapter::instance().sendTransaction(walletTransfers, fee, m_ui->m_paymentIdEdit->text(), m_ui->m_mixinSlider->value());
+ }
+}
+
+void SendFrame::mixinValueChanged(int _value) {
+ m_ui->m_mixinEdit->setText(QString::number(_value));
+}
+
+void SendFrame::sendTransactionCompleted(CryptoNote::TransactionId _id, bool _result, const QString& _errorText) {
+ Q_UNUSED(_id);
+ Q_UNUSED(_result);
+ Q_UNUSED(_errorText);
+ clearAllClicked();
+}
+
+void SendFrame::walletActualBalanceUpdated(quint64 _balance) {
+ m_ui->m_balanceLabel->setText(CurrencyAdapter::instance().formatAmount(_balance));
+}
+
+}
diff --git a/src/gui/SendFrame.h b/src/gui/SendFrame.h
new file mode 100644
index 0000000..eceac98
--- /dev/null
+++ b/src/gui/SendFrame.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#pragma once
+
+#include
+
+#include
+
+namespace Ui {
+ class SendFrame;
+}
+
+namespace WalletGui {
+
+class TransferFrame;
+
+class SendFrame : public QFrame {
+ Q_OBJECT
+ Q_DISABLE_COPY(SendFrame)
+
+public:
+ SendFrame(QWidget* _parent);
+ ~SendFrame();
+
+private:
+ QScopedPointer m_ui;
+ QList m_transfers;
+
+ void sendTransactionCompleted(CryptoNote::TransactionId _id, bool _result, const QString& _error_text);
+ void walletActualBalanceUpdated(quint64 _balance);
+
+ Q_SLOT void addRecipientClicked();
+ Q_SLOT void clearAllClicked();
+ Q_SLOT void mixinValueChanged(int _value);
+ Q_SLOT void sendClicked();
+};
+
+}
diff --git a/src/gui/SortedTransactionsModel.cpp b/src/gui/SortedTransactionsModel.cpp
new file mode 100644
index 0000000..47fe856
--- /dev/null
+++ b/src/gui/SortedTransactionsModel.cpp
@@ -0,0 +1,45 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#include
+
+#include "SortedTransactionsModel.h"
+#include "TransactionsModel.h"
+
+namespace WalletGui {
+
+SortedTransactionsModel& SortedTransactionsModel::instance() {
+ static SortedTransactionsModel inst;
+ return inst;
+}
+
+SortedTransactionsModel::SortedTransactionsModel() : QSortFilterProxyModel() {
+ setSourceModel(&TransactionsModel::instance());
+ setDynamicSortFilter(true);
+ sort(TransactionsModel::COLUMN_DATE, Qt::DescendingOrder);
+}
+
+SortedTransactionsModel::~SortedTransactionsModel() {
+}
+
+bool SortedTransactionsModel::lessThan(const QModelIndex& _left, const QModelIndex& _right) const {
+ QDateTime leftDate = _left.data(TransactionsModel::ROLE_DATE).toDateTime();
+ QDateTime rightDate = _right.data(TransactionsModel::ROLE_DATE).toDateTime();
+ if((rightDate.isNull() || !rightDate.isValid()) && (leftDate.isNull() || !leftDate.isValid())) {
+ return _left.row() < _right.row();
+ }
+
+ if(leftDate.isNull() || !leftDate.isValid()) {
+ return false;
+ }
+
+ if(rightDate.isNull() || !rightDate.isValid()) {
+ return true;
+ }
+
+ return leftDate < rightDate;
+}
+
+}
diff --git a/src/gui/SortedTransactionsModel.h b/src/gui/SortedTransactionsModel.h
new file mode 100644
index 0000000..bd46883
--- /dev/null
+++ b/src/gui/SortedTransactionsModel.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#pragma once
+
+#include
+
+namespace WalletGui {
+
+class SortedTransactionsModel : public QSortFilterProxyModel {
+ Q_OBJECT
+ Q_DISABLE_COPY(SortedTransactionsModel)
+
+public:
+ static SortedTransactionsModel& instance();
+
+protected:
+ bool lessThan(const QModelIndex& _left, const QModelIndex& _right) const Q_DECL_OVERRIDE;
+
+private:
+ SortedTransactionsModel();
+ ~SortedTransactionsModel();
+};
+
+
+
+}
diff --git a/src/gui/TransactionDetailsDialog.cpp b/src/gui/TransactionDetailsDialog.cpp
new file mode 100644
index 0000000..e3c3313
--- /dev/null
+++ b/src/gui/TransactionDetailsDialog.cpp
@@ -0,0 +1,46 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#include
+
+#include "CurrencyAdapter.h"
+#include "TransactionDetailsDialog.h"
+#include "TransactionsModel.h"
+
+#include "ui_transactiondetailsdialog.h"
+
+namespace WalletGui {
+
+TransactionDetailsDialog::TransactionDetailsDialog(const QModelIndex& _index, QWidget* _parent) : QDialog(_parent),
+ m_ui(new Ui::TransactionDetailsDialog), m_detailsTemplate(
+ "\n"
+ "Status: %1
\n"
+ "Date: %2
\n"
+ "To: %4
\n"
+ "Amount: %5
\n"
+ "Fee: %6
\n"
+ "Transaction hash: %8") {
+ m_ui->setupUi(this);
+
+ QModelIndex index = TransactionsModel::instance().index(_index.data(TransactionsModel::ROLE_ROW).toInt(),
+ _index.data(TransactionsModel::ROLE_ROW).toInt());
+
+ quint64 numberOfConfirmations = index.data(TransactionsModel::ROLE_NUMBER_OF_CONFIRMATIONS).value();
+ QString amountText = index.sibling(index.row(), TransactionsModel::COLUMN_AMOUNT).data().toString() + " " +
+ CurrencyAdapter::instance().getCurrencyTicker().toUpper();
+ QString feeText = CurrencyAdapter::instance().formatAmount(index.data(TransactionsModel::ROLE_FEE).value()) + " " +
+ CurrencyAdapter::instance().getCurrencyTicker().toUpper();
+
+ m_ui->m_detailsBrowser->setHtml(m_detailsTemplate.arg(QString("%1 confirmations").arg(numberOfConfirmations)).
+ arg(index.sibling(index.row(), TransactionsModel::COLUMN_DATE).data().toString()).arg(index.sibling(index.row(),
+ TransactionsModel::COLUMN_ADDRESS).data().toString()).arg(amountText).arg(feeText).
+ arg(index.sibling(index.row(), TransactionsModel::COLUMN_HASH).data().toString()));
+}
+
+TransactionDetailsDialog::~TransactionDetailsDialog() {
+}
+
+}
diff --git a/src/gui/TransactionDetailsDialog.h b/src/gui/TransactionDetailsDialog.h
new file mode 100644
index 0000000..0d116bb
--- /dev/null
+++ b/src/gui/TransactionDetailsDialog.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#pragma once
+
+#include
+
+namespace Ui {
+class TransactionDetailsDialog;
+}
+
+namespace WalletGui {
+
+class TransactionDetailsDialog : public QDialog {
+ Q_OBJECT
+ Q_DISABLE_COPY(TransactionDetailsDialog)
+
+public:
+ TransactionDetailsDialog(const QModelIndex &_index, QWidget* _parent);
+ ~TransactionDetailsDialog();
+
+private:
+ QScopedPointer m_ui;
+ const QString m_detailsTemplate;
+};
+
+}
diff --git a/src/gui/TransactionFrame.cpp b/src/gui/TransactionFrame.cpp
new file mode 100644
index 0000000..3cf53ed
--- /dev/null
+++ b/src/gui/TransactionFrame.cpp
@@ -0,0 +1,68 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#include
+
+#include "MainWindow.h"
+#include "TransactionFrame.h"
+#include "TransactionsModel.h"
+
+#include "ui_transactionframe.h"
+
+namespace WalletGui {
+
+class RecentTransactionDelegate : public QStyledItemDelegate {
+ Q_OBJECT
+
+public:
+ RecentTransactionDelegate(QObject* _parent) : QStyledItemDelegate(_parent) {
+
+ }
+
+ ~RecentTransactionDelegate() {
+ }
+
+ void setEditorData(QWidget* _editor, const QModelIndex& _index) const Q_DECL_OVERRIDE {
+ switch(_index.column()) {
+ case TransactionsModel::COLUMN_AMOUNT:
+ case TransactionsModel::COLUMN_HASH:
+ case TransactionsModel::COLUMN_DATE:
+ static_cast(_editor)->setText(_index.data().toString());
+ return;
+ case TransactionsModel::COLUMN_TYPE:
+ static_cast(_editor)->setPixmap(_index.data(TransactionsModel::ROLE_ICON).value());
+ return;
+ default:
+ return;
+ }
+ }
+};
+
+TransactionFrame::TransactionFrame(const QModelIndex& _index, QWidget* _parent) : QFrame(_parent),
+ m_ui(new Ui::TransactionFrame), m_dataMapper(this), m_index(_index) {
+ m_ui->setupUi(this);
+ QFont font = QFontDatabase::systemFont(QFontDatabase::FixedFont);
+ font.setPixelSize(11);
+ m_ui->m_hashLabel->setFont(font);
+
+ m_dataMapper.setModel(const_cast(m_index.model()));
+ m_dataMapper.setItemDelegate(new RecentTransactionDelegate(this));
+ m_dataMapper.addMapping(m_ui->m_iconLabel, TransactionsModel::COLUMN_TYPE);
+ m_dataMapper.addMapping(m_ui->m_amountLabel, TransactionsModel::COLUMN_AMOUNT);
+ m_dataMapper.addMapping(m_ui->m_timeLabel, TransactionsModel::COLUMN_DATE);
+ m_dataMapper.addMapping(m_ui->m_hashLabel, TransactionsModel::COLUMN_HASH);
+ m_dataMapper.setCurrentModelIndex(m_index);
+}
+
+TransactionFrame::~TransactionFrame() {
+}
+
+void TransactionFrame::mousePressEvent(QMouseEvent* _event) {
+ MainWindow::instance().scrollToTransaction(TransactionsModel::instance().index(m_index.data(TransactionsModel::ROLE_ROW).toInt(), 0));
+}
+
+}
+
+#include "TransactionFrame.moc"
diff --git a/src/gui/TransactionFrame.h b/src/gui/TransactionFrame.h
new file mode 100644
index 0000000..ba5a971
--- /dev/null
+++ b/src/gui/TransactionFrame.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#pragma once
+
+#include
+#include
+#include
+#include
+
+namespace Ui {
+class TransactionFrame;
+}
+
+namespace WalletGui {
+
+class TransactionFrame : public QFrame {
+ Q_OBJECT
+ Q_DISABLE_COPY(TransactionFrame)
+
+public:
+ TransactionFrame(const QModelIndex &_index, QWidget* _parent);
+ ~TransactionFrame();
+
+protected:
+ void mousePressEvent(QMouseEvent* _event) Q_DECL_OVERRIDE;
+
+private:
+ QScopedPointer m_ui;
+ QDataWidgetMapper m_dataMapper;
+ QPersistentModelIndex m_index;
+};
+
+}
diff --git a/src/gui/TransactionsFrame.cpp b/src/gui/TransactionsFrame.cpp
new file mode 100644
index 0000000..97a533d
--- /dev/null
+++ b/src/gui/TransactionsFrame.cpp
@@ -0,0 +1,62 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#include
+#include
+
+#include "MainWindow.h"
+#include "SortedTransactionsModel.h"
+#include "TransactionsFrame.h"
+#include "TransactionDetailsDialog.h"
+#include "TransactionsListModel.h"
+#include "TransactionsModel.h"
+
+#include "ui_transactionsframe.h"
+
+namespace WalletGui {
+
+TransactionsFrame::TransactionsFrame(QWidget* _parent) : QFrame(_parent), m_ui(new Ui::TransactionsFrame),
+ m_transactionsModel(new TransactionsListModel) {
+ m_ui->setupUi(this);
+ m_ui->m_transactionsView->setModel(m_transactionsModel.data());
+ m_ui->m_transactionsView->header()->setSectionResizeMode(TransactionsModel::COLUMN_STATE, QHeaderView::Fixed);
+ m_ui->m_transactionsView->header()->resizeSection(TransactionsModel::COLUMN_STATE, 25);
+ m_ui->m_transactionsView->header()->resizeSection(TransactionsModel::COLUMN_DATE, 140);
+ m_ui->m_transactionsView->header()->resizeSection(TransactionsModel::COLUMN_ADDRESS, 400);
+}
+
+TransactionsFrame::~TransactionsFrame() {
+}
+
+void TransactionsFrame::scrollToTransaction(const QModelIndex& _index) {
+ QModelIndex sortedModelIndex = SortedTransactionsModel::instance().mapFromSource(_index);
+ QModelIndex index = static_cast(m_ui->m_transactionsView->model())->mapFromSource(sortedModelIndex);
+ m_ui->m_transactionsView->scrollTo(index);
+ m_ui->m_transactionsView->setFocus();
+ m_ui->m_transactionsView->setCurrentIndex(index);
+}
+
+void TransactionsFrame::exportToCsv() {
+ QString file = QFileDialog::getSaveFileName(&MainWindow::instance(), tr("Select CSV file"), QDir::homePath(), "CSV (*.csv)");
+ if (!file.isEmpty()) {
+ QByteArray csv = TransactionsModel::instance().toCsv();
+ QFile f(file);
+ if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
+ f.write(csv);
+ f.close();
+ }
+ }
+}
+
+void TransactionsFrame::showTransactionDetails(const QModelIndex& _index) {
+ if (!_index.isValid()) {
+ return;
+ }
+
+ TransactionDetailsDialog dlg(_index, &MainWindow::instance());
+ dlg.exec();
+}
+
+}
diff --git a/src/gui/TransactionsFrame.h b/src/gui/TransactionsFrame.h
new file mode 100644
index 0000000..7bbbddd
--- /dev/null
+++ b/src/gui/TransactionsFrame.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#pragma once
+
+#include
+#include
+
+namespace Ui {
+class TransactionsFrame;
+}
+
+namespace WalletGui {
+
+class TransactionsListModel;
+
+class TransactionsFrame : public QFrame {
+ Q_OBJECT
+ Q_DISABLE_COPY(TransactionsFrame)
+
+public:
+ TransactionsFrame(QWidget* _parent);
+ ~TransactionsFrame();
+
+ void scrollToTransaction(const QModelIndex& _index);
+
+private:
+ QScopedPointer m_ui;
+ QScopedPointer m_transactionsModel;
+
+ Q_SLOT void exportToCsv();
+ Q_SLOT void showTransactionDetails(const QModelIndex& _index);
+};
+
+}
diff --git a/src/gui/TransactionsListModel.cpp b/src/gui/TransactionsListModel.cpp
new file mode 100644
index 0000000..1921a17
--- /dev/null
+++ b/src/gui/TransactionsListModel.cpp
@@ -0,0 +1,25 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#include "SortedTransactionsModel.h"
+#include "TransactionsListModel.h"
+#include "TransactionsModel.h"
+
+namespace WalletGui {
+
+TransactionsListModel::TransactionsListModel() : QSortFilterProxyModel() {
+ setSourceModel(&SortedTransactionsModel::instance());
+}
+
+TransactionsListModel::~TransactionsListModel() {
+}
+
+bool TransactionsListModel::filterAcceptsColumn(int _sourceColumn, const QModelIndex& _sourceParent) const {
+ quint32 column = sourceModel()->headerData(_sourceColumn, Qt::Horizontal, TransactionsModel::ROLE_COLUMN).toUInt();
+ return column != TransactionsModel::COLUMN_HASH && column != TransactionsModel::COLUMN_FEE && column != TransactionsModel::COLUMN_HEIGHT &&
+ column != TransactionsModel::COLUMN_TYPE;
+}
+
+}
diff --git a/src/gui/TransactionsListModel.h b/src/gui/TransactionsListModel.h
new file mode 100644
index 0000000..ead5f02
--- /dev/null
+++ b/src/gui/TransactionsListModel.h
@@ -0,0 +1,23 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#pragma once
+
+#include
+
+namespace WalletGui {
+
+class TransactionsListModel : public QSortFilterProxyModel {
+ Q_OBJECT
+
+public:
+ TransactionsListModel();
+ ~TransactionsListModel();
+
+protected:
+ bool filterAcceptsColumn(int _sourceColumn, const QModelIndex& _sourceParent) const Q_DECL_OVERRIDE;
+};
+
+}
diff --git a/src/gui/TransactionsModel.cpp b/src/gui/TransactionsModel.cpp
new file mode 100644
index 0000000..a0dc94e
--- /dev/null
+++ b/src/gui/TransactionsModel.cpp
@@ -0,0 +1,394 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#include
+#include
+#include
+#include
+
+#include "CurrencyAdapter.h"
+#include "NodeAdapter.h"
+#include "TransactionsModel.h"
+#include "WalletAdapter.h"
+
+namespace WalletGui {
+
+enum class TransactionType : quint8 {MINED, INPUT, OUTPUT, INOUT};
+
+const int TRANSACTIONS_MODEL_COLUMN_COUNT =
+ TransactionsModel::staticMetaObject.enumerator(TransactionsModel::staticMetaObject.indexOfEnumerator("Columns")).keyCount();
+
+namespace {
+
+QPixmap getTransactionIcon(TransactionType _transactionType) {
+ switch (_transactionType) {
+ case TransactionType::MINED:
+ return QPixmap(":icons/tx-mined");
+ case TransactionType::INPUT:
+ return QPixmap(":icons/tx-input");
+ case TransactionType::OUTPUT:
+ return QPixmap(":icons/tx-output");
+ case TransactionType::INOUT:
+ return QPixmap(":icons/tx-inout");
+ default:
+ break;
+ }
+
+ return QPixmap();
+}
+
+}
+
+TransactionsModel& TransactionsModel::instance() {
+ static TransactionsModel inst;
+ return inst;
+}
+
+TransactionsModel::TransactionsModel() : QAbstractItemModel() {
+ connect(&WalletAdapter::instance(), &WalletAdapter::reloadWalletTransactionsSignal, this, &TransactionsModel::reloadWalletTransactions,
+ Qt::QueuedConnection);
+ connect(&WalletAdapter::instance(), &WalletAdapter::walletTransactionCreatedSignal, this,
+ static_cast(&TransactionsModel::appendTransaction), Qt::QueuedConnection);
+ connect(&WalletAdapter::instance(), &WalletAdapter::walletTransactionUpdatedSignal, this, &TransactionsModel::updateWalletTransaction,
+ Qt::QueuedConnection);
+ connect(&NodeAdapter::instance(), &NodeAdapter::localBlockchainUpdatedSignal, this, &TransactionsModel::localBlockchainUpdated,
+ Qt::QueuedConnection);
+ connect(&WalletAdapter::instance(), &WalletAdapter::walletCloseCompletedSignal, this, &TransactionsModel::reset,
+ Qt::QueuedConnection);
+}
+
+TransactionsModel::~TransactionsModel() {
+}
+
+Qt::ItemFlags TransactionsModel::flags(const QModelIndex& _index) const {
+ Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemNeverHasChildren | Qt::ItemIsSelectable;
+ if(_index.column() == COLUMN_HASH) {
+ flags |= Qt::ItemIsEditable;
+ }
+
+ return flags;
+}
+
+int TransactionsModel::columnCount(const QModelIndex& _parent) const {
+ return TRANSACTIONS_MODEL_COLUMN_COUNT;
+}
+
+int TransactionsModel::rowCount(const QModelIndex& _parent) const {
+ return m_transfers.size();
+}
+
+QVariant TransactionsModel::headerData(int _section, Qt::Orientation _orientation, int _role) const {
+ if(_orientation != Qt::Horizontal) {
+ return QVariant();
+ }
+
+ switch(_role) {
+ case Qt::DisplayRole:
+ switch(_section) {
+ case COLUMN_STATE:
+ return QVariant();
+ case COLUMN_DATE:
+ return tr("Date");
+ case COLUMN_TYPE:
+ return tr("Type");
+ case COLUMN_HASH:
+ return tr("Hash");
+ case COLUMN_ADDRESS:
+ return tr("Address");
+ case COLUMN_AMOUNT:
+ return tr("Amount");
+ case COLUMN_PAYMENT_ID:
+ return tr("PaymentID");
+ default:
+ break;
+ }
+
+ case Qt::TextAlignmentRole:
+ if (_section == COLUMN_AMOUNT) {
+ return static_cast(Qt::AlignRight | Qt::AlignVCenter);
+ }
+
+ return QVariant();
+
+ case ROLE_COLUMN:
+ return _section;
+ }
+
+ return QVariant();
+}
+
+QVariant TransactionsModel::data(const QModelIndex& _index, int _role) const {
+ if(!_index.isValid()) {
+ return QVariant();
+ }
+
+ CryptoNote::TransactionInfo transaction;
+ CryptoNote::Transfer transfer;
+ CryptoNote::TransactionId transactionId = m_transfers.value(_index.row()).first;
+ CryptoNote::TransferId transferId = m_transfers.value(_index.row()).second;
+
+ if(!WalletAdapter::instance().getTransaction(transactionId, transaction) ||
+ (m_transfers.value(_index.row()).second != CryptoNote::INVALID_TRANSFER_ID &&
+ !WalletAdapter::instance().getTransfer(transferId, transfer))) {
+ return QVariant();
+ }
+
+ switch(_role) {
+ case Qt::DisplayRole:
+ case Qt::EditRole:
+ return getDisplayRole(_index);
+
+ case Qt::DecorationRole:
+ return getDecorationRole(_index);
+
+ case Qt::TextAlignmentRole:
+ return getAlignmentRole(_index);
+
+ default:
+ return getUserRole(_index, _role, transactionId, transaction, transferId, transfer);
+ }
+
+ return QVariant();
+}
+
+QModelIndex TransactionsModel::index(int _row, int _column, const QModelIndex& _parent) const {
+ if(_parent.isValid()) {
+ return QModelIndex();
+ }
+
+ return createIndex(_row, _column, _row);
+}
+
+QModelIndex TransactionsModel::parent(const QModelIndex& _index) const {
+ return QModelIndex();
+}
+
+QByteArray TransactionsModel::toCsv() const {
+ QByteArray res;
+ res.append("\"State\",\"Date\",\"Amount\",\"Fee\",\"Hash\",\"Height\",\"Address\",\"Payment ID\"\n");
+ for (quint32 row = 0; row < rowCount(); ++row) {
+ QModelIndex ind = index(row, 0);
+ res.append("\"").append(ind.data().toString().toUtf8()).append("\",");
+ res.append("\"").append(ind.sibling(row, COLUMN_DATE).data().toString().toUtf8()).append("\",");
+ res.append("\"").append(ind.sibling(row, COLUMN_AMOUNT).data().toString().toUtf8()).append("\",");
+ res.append("\"").append(ind.sibling(row, COLUMN_FEE).data().toString().toUtf8()).append("\",");
+ res.append("\"").append(ind.sibling(row, COLUMN_HASH).data().toString().toUtf8()).append("\",");
+ res.append("\"").append(ind.sibling(row, COLUMN_HEIGHT).data().toString().toUtf8()).append("\",");
+ res.append("\"").append(ind.sibling(row, COLUMN_ADDRESS).data().toString().toUtf8()).append("\",");
+ res.append("\"").append(ind.sibling(row, COLUMN_PAYMENT_ID).data().toString().toUtf8()).append("\"\n");
+ }
+
+ return res;
+}
+
+QVariant TransactionsModel::getDisplayRole(const QModelIndex& _index) const {
+ switch(_index.column()) {
+ case COLUMN_DATE: {
+ QDateTime date = _index.data(ROLE_DATE).toDateTime();
+ return (date.isNull() || !date.isValid() ? "-" : date.toString("dd-MM-yy HH:mm"));
+ }
+
+ case COLUMN_HASH:
+ return _index.data(ROLE_HASH).toByteArray().toHex().toUpper();
+
+ case COLUMN_ADDRESS: {
+ TransactionType transactionType = static_cast(_index.data(ROLE_TYPE).value());
+ QString transactionAddress = _index.data(ROLE_ADDRESS).toString();
+ if (transactionType == TransactionType::INPUT || transactionType == TransactionType::MINED ||
+ transactionType == TransactionType::INOUT) {
+ return QString(tr("me (%1)").arg(WalletAdapter::instance().getAddress()));
+ } else if (transactionAddress.isEmpty()) {
+ return tr("(n/a)");
+ }
+
+ return transactionAddress;
+ }
+
+ case COLUMN_AMOUNT: {
+ qint64 amount = _index.data(ROLE_AMOUNT).value();
+ QString amountStr = CurrencyAdapter::instance().formatAmount(qAbs(amount));
+ return (amount < 0 ? "-" + amountStr : amountStr);
+ }
+
+ case COLUMN_PAYMENT_ID:
+ return _index.data(ROLE_PAYMENT_ID);
+
+ case COLUMN_FEE: {
+ qint64 fee = _index.data(ROLE_FEE).value();
+ return CurrencyAdapter::instance().formatAmount(fee);
+ }
+
+ case COLUMN_HEIGHT:
+ return QString::number(_index.data(ROLE_HEIGHT).value());
+
+ default:
+ break;
+ }
+
+ return QVariant();
+}
+
+QVariant TransactionsModel::getDecorationRole(const QModelIndex& _index) const {
+ if(_index.column() == COLUMN_STATE) {
+ quint64 numberOfConfirmations = _index.data(ROLE_NUMBER_OF_CONFIRMATIONS).value();
+ if(numberOfConfirmations == 0) {
+ return QPixmap(":icons/unconfirmed");
+ } else if(numberOfConfirmations < 2) {
+ return QPixmap(":icons/clock1");
+ } else if(numberOfConfirmations < 4) {
+ return QPixmap(":icons/clock2");
+ } else if(numberOfConfirmations < 6) {
+ return QPixmap(":icons/clock3");
+ } else if(numberOfConfirmations < 8) {
+ return QPixmap(":icons/clock4");
+ } else if(numberOfConfirmations < 10) {
+ return QPixmap(":icons/clock5");
+ } else {
+ return QPixmap(":icons/transaction");
+ }
+ } else if (_index.column() == COLUMN_ADDRESS) {
+ return _index.data(ROLE_ICON).value().scaled(20, 20, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+ }
+
+ return QVariant();
+}
+
+QVariant TransactionsModel::getAlignmentRole(const QModelIndex& _index) const {
+ return headerData(_index.column(), Qt::Horizontal, Qt::TextAlignmentRole);
+}
+
+QVariant TransactionsModel::getUserRole(const QModelIndex& _index, int _role, CryptoNote::TransactionId _transactionId,
+ CryptoNote::TransactionInfo& _transaction, CryptoNote::TransferId _transferId, CryptoNote::Transfer& _transfer) const {
+ switch(_role) {
+ case ROLE_DATE:
+ return (_transaction.timestamp > 0 ? QDateTime::fromTime_t(_transaction.timestamp) : QDateTime());
+
+ case ROLE_TYPE: {
+ QString transactionAddress = _index.data(ROLE_ADDRESS).toString();
+ if(_transaction.isCoinbase) {
+ return static_cast(TransactionType::MINED);
+ } else if (!transactionAddress.compare(WalletAdapter::instance().getAddress())) {
+ return static_cast(TransactionType::INOUT);
+ } else if(_transaction.totalAmount < 0) {
+ return static_cast(TransactionType::OUTPUT);
+ }
+
+ return static_cast(TransactionType::INPUT);
+ }
+
+ case ROLE_HASH:
+ return QByteArray(reinterpret_cast(&_transaction.hash.front()), _transaction.hash.size());
+
+ case ROLE_ADDRESS:
+ return QString::fromStdString(_transfer.address);
+
+ case ROLE_AMOUNT:
+ return static_cast(_transferId == CryptoNote::INVALID_TRANSFER_ID ? _transaction.totalAmount : -_transfer.amount);
+
+ case ROLE_PAYMENT_ID:
+ return NodeAdapter::instance().extractPaymentId(_transaction.extra);
+
+ case ROLE_ICON: {
+ TransactionType transactionType = static_cast(_index.data(ROLE_TYPE).value());
+ return getTransactionIcon(transactionType);
+ }
+
+ case ROLE_TRANSACTION_ID:
+ return QVariant::fromValue(_transactionId);
+
+ case ROLE_HEIGHT:
+ return static_cast(_transaction.blockHeight);
+
+ case ROLE_FEE:
+ return static_cast(_transaction.fee);
+
+ case ROLE_NUMBER_OF_CONFIRMATIONS:
+ return (_transaction.blockHeight == CryptoNote::UNCONFIRMED_TRANSACTION_HEIGHT ? 0 :
+ NodeAdapter::instance().getLastKnownBlockHeight() - _transaction.blockHeight + 1);
+
+ case ROLE_COLUMN:
+ return headerData(_index.column(), Qt::Horizontal, ROLE_COLUMN);
+
+ case ROLE_ROW:
+ return _index.row();
+ }
+
+ return QVariant();
+}
+
+void TransactionsModel::reloadWalletTransactions() {
+ beginResetModel();
+ m_transfers.clear();
+ m_transactionRow.clear();
+ endResetModel();
+
+ quint32 row_count = 0;
+ for (CryptoNote::TransactionId transactionId = 0; transactionId < WalletAdapter::instance().getTransactionCount(); ++transactionId) {
+ appendTransaction(transactionId, row_count);
+ }
+
+ if (row_count > 0) {
+ beginInsertRows(QModelIndex(), 0, row_count - 1);
+ endInsertRows();
+ }
+}
+
+void TransactionsModel::appendTransaction(CryptoNote::TransactionId _transactionId, quint32& _insertedRowCount) {
+ CryptoNote::TransactionInfo transaction;
+ if (!WalletAdapter::instance().getTransaction(_transactionId, transaction)) {
+ return;
+ }
+
+ if (transaction.transferCount) {
+ m_transactionRow[_transactionId] = qMakePair(m_transfers.size(), transaction.transferCount);
+ for (CryptoNote::TransferId transfer_id = transaction.firstTransferId;
+ transfer_id < transaction.firstTransferId + transaction.transferCount; ++transfer_id) {
+ m_transfers.append(TransactionTransferId(_transactionId, transfer_id));
+ ++_insertedRowCount;
+ }
+ } else {
+ m_transfers.append(TransactionTransferId(_transactionId, CryptoNote::INVALID_TRANSFER_ID));
+ m_transactionRow[_transactionId] = qMakePair(m_transfers.size() - 1, 1);
+ ++_insertedRowCount;
+ }
+}
+
+void TransactionsModel::appendTransaction(CryptoNote::TransactionId _transactionId) {
+ if (m_transactionRow.contains(_transactionId)) {
+ return;
+ }
+
+ quint32 oldRowCount = rowCount();
+ quint32 insertedRowCount = 0;
+ for (quint64 transactionId = m_transactionRow.size(); transactionId <= _transactionId; ++transactionId) {
+ appendTransaction(transactionId, insertedRowCount);
+ }
+
+ if (insertedRowCount > 0) {
+ beginInsertRows(QModelIndex(), oldRowCount, oldRowCount + insertedRowCount - 1);
+ endInsertRows();
+ }
+}
+
+void TransactionsModel::updateWalletTransaction(CryptoNote::TransactionId _id) {
+ quint32 firstRow = m_transactionRow.value(_id).first;
+ quint32 lastRow = firstRow + m_transactionRow.value(_id).second - 1;
+ Q_EMIT dataChanged(index(firstRow, COLUMN_DATE), index(lastRow, COLUMN_DATE));
+}
+
+void TransactionsModel::localBlockchainUpdated(quint64 _height) {
+ if(rowCount() > 0) {
+ Q_EMIT dataChanged(index(0, COLUMN_STATE), index(rowCount() - 1, COLUMN_STATE));
+ }
+}
+
+void TransactionsModel::reset() {
+ beginResetModel();
+ m_transfers.clear();
+ m_transactionRow.clear();
+ endResetModel();
+}
+
+}
diff --git a/src/gui/TransactionsModel.h b/src/gui/TransactionsModel.h
new file mode 100644
index 0000000..883e9ea
--- /dev/null
+++ b/src/gui/TransactionsModel.h
@@ -0,0 +1,67 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#pragma once
+
+#include
+#include
+
+#include
+
+namespace WalletGui {
+
+typedef QPair TransactionTransferId;
+
+class TransactionsModel : public QAbstractItemModel {
+ Q_OBJECT
+ Q_ENUMS(Columns)
+ Q_ENUMS(Roles)
+
+public:
+ enum Columns{
+ COLUMN_STATE = 0, COLUMN_DATE, COLUMN_AMOUNT, COLUMN_ADDRESS, COLUMN_PAYMENT_ID, COLUMN_HASH, COLUMN_FEE,
+ COLUMN_HEIGHT, COLUMN_TYPE
+ };
+
+ enum Roles{
+ ROLE_DATE = Qt::UserRole, ROLE_TYPE, ROLE_HASH, ROLE_ADDRESS, ROLE_AMOUNT, ROLE_PAYMENT_ID, ROLE_ICON,
+ ROLE_TRANSACTION_ID, ROLE_HEIGHT, ROLE_FEE, ROLE_NUMBER_OF_CONFIRMATIONS, ROLE_COLUMN, ROLE_ROW
+ };
+
+ static TransactionsModel& instance();
+
+ Qt::ItemFlags flags(const QModelIndex& _index) const Q_DECL_OVERRIDE;
+ int columnCount(const QModelIndex& _parent = QModelIndex()) const Q_DECL_OVERRIDE;
+ int rowCount(const QModelIndex& _parent = QModelIndex()) const Q_DECL_OVERRIDE;
+
+ QVariant headerData(int _section, Qt::Orientation _orientation, int _role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
+ QVariant data(const QModelIndex& _index, int _role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
+ QModelIndex index(int _row, int _column, const QModelIndex& _parent = QModelIndex()) const Q_DECL_OVERRIDE;
+ QModelIndex parent(const QModelIndex& _index) const Q_DECL_OVERRIDE;
+
+ QByteArray toCsv() const;
+
+private:
+ QVector m_transfers;
+ QHash > m_transactionRow;
+
+ TransactionsModel();
+ ~TransactionsModel();
+
+ QVariant getDisplayRole(const QModelIndex& _index) const;
+ QVariant getDecorationRole(const QModelIndex& _index) const;
+ QVariant getAlignmentRole(const QModelIndex& _index) const;
+ QVariant getUserRole(const QModelIndex& _index, int _role, CryptoNote::TransactionId _transactionId, CryptoNote::TransactionInfo& _transaction,
+ CryptoNote::TransferId _transferId, CryptoNote::Transfer& _transfer) const;
+
+ void reloadWalletTransactions();
+ void appendTransaction(CryptoNote::TransactionId _id, quint32& _row_count);
+ void appendTransaction(CryptoNote::TransactionId _id);
+ void updateWalletTransaction(CryptoNote::TransactionId _id);
+ void localBlockchainUpdated(quint64 _height);
+ void reset();
+};
+
+}
diff --git a/src/gui/TransferFrame.cpp b/src/gui/TransferFrame.cpp
new file mode 100644
index 0000000..a19dc24
--- /dev/null
+++ b/src/gui/TransferFrame.cpp
@@ -0,0 +1,58 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#include
+#include
+
+#include "AddressBookDialog.h"
+#include "MainWindow.h"
+#include "CurrencyAdapter.h"
+#include "TransferFrame.h"
+
+#include "ui_transferframe.h"
+
+namespace WalletGui {
+
+TransferFrame::TransferFrame(QWidget* _parent) : QFrame(_parent), m_ui(new Ui::TransferFrame) {
+ m_ui->setupUi(this);
+ setAttribute(Qt::WA_DeleteOnClose);
+ m_ui->m_amountSpin->setSuffix(" " + CurrencyAdapter::instance().getCurrencyTicker().toUpper());
+}
+
+TransferFrame::~TransferFrame() {
+}
+
+QString TransferFrame::getAddress() const {
+ return m_ui->m_addressEdit->text().trimmed();
+}
+
+QString TransferFrame::getLabel() const {
+ return m_ui->m_labelEdit->text().trimmed();
+}
+
+qreal TransferFrame::getAmount() const {
+ return m_ui->m_amountSpin->value();
+}
+
+QString TransferFrame::getAmountString() const {
+ return m_ui->m_amountSpin->cleanText();
+}
+
+void TransferFrame::disableRemoveButton(bool _disable) {
+ m_ui->m_removeButton->setDisabled(_disable);
+}
+
+void TransferFrame::addressBookClicked() {
+ AddressBookDialog dlg(&MainWindow::instance());
+ if(dlg.exec() == QDialog::Accepted) {
+ m_ui->m_addressEdit->setText(dlg.getAddress());
+ }
+}
+
+void TransferFrame::pasteClicked() {
+ m_ui->m_addressEdit->setText(QApplication::clipboard()->text());
+}
+
+}
diff --git a/src/gui/TransferFrame.h b/src/gui/TransferFrame.h
new file mode 100644
index 0000000..e6bee51
--- /dev/null
+++ b/src/gui/TransferFrame.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#pragma once
+
+#include
+
+namespace Ui {
+class TransferFrame;
+}
+
+namespace WalletGui {
+
+class TransferFrame : public QFrame {
+ Q_OBJECT
+ Q_DISABLE_COPY(TransferFrame)
+
+public:
+ TransferFrame(QWidget* _parent);
+ ~TransferFrame();
+
+ QString getAddress() const;
+ QString getLabel() const;
+ qreal getAmount() const;
+ QString getAmountString() const;
+
+ void disableRemoveButton(bool _disable);
+
+private:
+ QScopedPointer m_ui;
+
+ Q_SLOT void addressBookClicked();
+ Q_SLOT void pasteClicked();
+};
+
+}
diff --git a/src/gui/WalletEvents.h b/src/gui/WalletEvents.h
new file mode 100644
index 0000000..4e55a78
--- /dev/null
+++ b/src/gui/WalletEvents.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#pragma once
+
+#include
+
+namespace WalletGui
+{
+ enum class WalletEventType : quint32 {
+ ShowMessage = QEvent::User
+ };
+
+ class ShowMessageEvent : public QEvent {
+ Q_DISABLE_COPY(ShowMessageEvent)
+
+ public:
+ ShowMessageEvent(const QString &_messageText, QtMsgType _messageType) : QEvent(static_cast(WalletEventType::ShowMessage)),
+ m_messageText(_messageText), m_messgaeType(_messageType) {
+ }
+
+ QString messageText() const {
+ return m_messageText;
+ }
+
+ QtMsgType messageType() const {
+ return m_messgaeType;
+ }
+
+ private:
+ QString m_messageText;
+ QtMsgType m_messgaeType;
+ };
+
+}
diff --git a/src/gui/ui/aboutdialog.ui b/src/gui/ui/aboutdialog.ui
new file mode 100644
index 0000000..ffc592f
--- /dev/null
+++ b/src/gui/ui/aboutdialog.ui
@@ -0,0 +1,102 @@
+
+
+ AboutDialog
+
+
+
+ 0
+ 0
+ 592
+ 240
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 592
+ 240
+
+
+
+
+ 592
+ 240
+
+
+
+ About %1
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ <html><head/><body><p>CryptoNote coin version %1</p><p>CryptoNote coin is the next generation anonymous cryptocurrency based on CryptoNote.</p><p>Copyright (c) 2012-2015. CryptoNote Developers</p><p><a href="http://opensource.org/licenses/MIT"><span style=" text-decoration: underline; color:#0000ff;">http://opensource.org/licenses/MIT</span></a></p><p><a href="https://cryptonote.org/"><span style=" text-decoration: underline; color:#0000ff;">https://cryptonote.org/</span></a></p></body></html>
+
+
+ Qt::RichText
+
+
+ true
+
+
+ true
+
+
+
+ -
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Close
+
+
+
+
+
+
+
+
+
+
+ m_closeButton
+ clicked()
+ AboutDialog
+ accept()
+
+
+ 538
+ 285
+
+
+ 294
+ 156
+
+
+
+
+
diff --git a/src/gui/ui/addressbookdialog.ui b/src/gui/ui/addressbookdialog.ui
new file mode 100644
index 0000000..45f41ff
--- /dev/null
+++ b/src/gui/ui/addressbookdialog.ui
@@ -0,0 +1,81 @@
+
+
+ AddressBookDialog
+
+
+
+ 0
+ 0
+ 747
+ 525
+
+
+
+ Select address
+
+
+ -
+
+
+ -
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Choose
+
+
+
+
+
+
+
+
+
+
+ m_okButton
+ clicked()
+ AddressBookDialog
+ accept()
+
+
+ 694
+ 499
+
+
+ 373
+ 262
+
+
+
+
+ m_addressBookView
+ doubleClicked(QModelIndex)
+ AddressBookDialog
+ accept()
+
+
+ 373
+ 242
+
+
+ 373
+ 262
+
+
+
+
+
diff --git a/src/gui/ui/addressbookframe.ui b/src/gui/ui/addressbookframe.ui
new file mode 100644
index 0000000..43438f9
--- /dev/null
+++ b/src/gui/ui/addressbookframe.ui
@@ -0,0 +1,142 @@
+
+
+ AddressBookFrame
+
+
+
+ 0
+ 0
+ 874
+ 585
+
+
+
+ Frame
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+ -
+
+
+ -
+
+
-
+
+
+ New address
+
+
+
+ :/icons/add:/icons/add
+
+
+
+ -
+
+
+ false
+
+
+ Delete address
+
+
+
+ :/icons/remove:/icons/remove
+
+
+
+ -
+
+
+ false
+
+
+ Copy address
+
+
+
+ :/icons/copy:/icons/copy
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+
+
+
+
+
+
+ m_addAddressButton
+ clicked()
+ AddressBookFrame
+ addClicked()
+
+
+ 53
+ 556
+
+
+ 436
+ 292
+
+
+
+
+ m_deleteAddressButton
+ clicked()
+ AddressBookFrame
+ deleteClicked()
+
+
+ 148
+ 556
+
+
+ 436
+ 292
+
+
+
+
+ m_copyAddressButton
+ clicked()
+ AddressBookFrame
+ copyClicked()
+
+
+ 243
+ 556
+
+
+ 436
+ 292
+
+
+
+
+
+ addClicked()
+ deleteClicked()
+ copyClicked()
+
+
diff --git a/src/gui/ui/changepassworddialog.ui b/src/gui/ui/changepassworddialog.ui
new file mode 100644
index 0000000..79526c7
--- /dev/null
+++ b/src/gui/ui/changepassworddialog.ui
@@ -0,0 +1,207 @@
+
+
+ ChangePasswordDialog
+
+
+
+ 0
+ 0
+ 338
+ 166
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 338
+ 0
+
+
+
+
+ 338
+ 16777215
+
+
+
+ Change password
+
+
+ -
+
+
+ false
+
+
+ Ok
+
+
+ true
+
+
+
+ -
+
+
+ QLineEdit::Password
+
+
+
+ -
+
+
+ Old password:
+
+
+
+ -
+
+
+ QLineEdit::Password
+
+
+
+ -
+
+
+ Cancel
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ New password:
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ QLineEdit::Password
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Confirm:
+
+
+
+ -
+
+
+ color: #ff0000; font: 11px;
+
+
+ Password not confirmed
+
+
+ Qt::AlignCenter
+
+
+
+
+
+
+ m_oldPasswordEdit
+ m_newPasswordEdit
+ m_newPasswordConfirmationEdit
+ m_okButton
+ m_cancelButton
+
+
+
+
+ m_newPasswordEdit
+ textChanged(QString)
+ ChangePasswordDialog
+ checkPassword(QString)
+
+
+ 223
+ 64
+
+
+ 168
+ 82
+
+
+
+
+ m_newPasswordConfirmationEdit
+ textChanged(QString)
+ ChangePasswordDialog
+ checkPassword(QString)
+
+
+ 223
+ 103
+
+
+ 168
+ 82
+
+
+
+
+ m_okButton
+ clicked()
+ ChangePasswordDialog
+ accept()
+
+
+ 169
+ 141
+
+
+ 168
+ 82
+
+
+
+
+ m_cancelButton
+ clicked()
+ ChangePasswordDialog
+ reject()
+
+
+ 277
+ 141
+
+
+ 168
+ 82
+
+
+
+
+
+ checkPassword(QString)
+
+
diff --git a/src/gui/ui/exitwidget.ui b/src/gui/ui/exitwidget.ui
new file mode 100644
index 0000000..7aa24bc
--- /dev/null
+++ b/src/gui/ui/exitwidget.ui
@@ -0,0 +1,36 @@
+
+
+ ExitWidget
+
+
+
+ 0
+ 0
+ 385
+ 66
+
+
+
+ Saving data
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+ %1 wallet is saving data.
+Please wait...
+
+
+
+
+
+
+
+
diff --git a/src/gui/ui/mainwindow.ui b/src/gui/ui/mainwindow.ui
new file mode 100644
index 0000000..6dd6806
--- /dev/null
+++ b/src/gui/ui/mainwindow.ui
@@ -0,0 +1,628 @@
+
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 920
+ 600
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 16777215
+ 16777215
+
+
+
+ MainWindow
+
+
+
+ :/images/cryptonote:/images/cryptonote
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+ QFrame::NoFrame
+
+
+ QFrame::Raised
+
+
+
+ -
+
+
+ QFrame::NoFrame
+
+
+ QFrame::Raised
+
+
+
+ -
+
+
+ QFrame::NoFrame
+
+
+ QFrame::Raised
+
+
+
+ -
+
+
+ QFrame::NoFrame
+
+
+ QFrame::Raised
+
+
+
+ -
+
+
+ QFrame::NoFrame
+
+
+ QFrame::Raised
+
+
+
+
+
+
+
+
+ toolBar
+
+
+ false
+
+
+ Qt::ToolButtonTextBesideIcon
+
+
+ TopToolBarArea
+
+
+ false
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+ true
+
+
+
+ :/icons/overview:/icons/overview
+
+
+ Overview
+
+
+
+
+ true
+
+
+ true
+
+
+
+ :/icons/send:/icons/send
+
+
+ Send
+
+
+
+
+ true
+
+
+ true
+
+
+
+ :/icons/receive:/icons/receive
+
+
+ Receive
+
+
+
+
+ true
+
+
+ true
+
+
+
+ :/icons/transactions:/icons/transactions
+
+
+ Transactions
+
+
+
+
+ true
+
+
+ Exit
+
+
+ Ctrl+Q
+
+
+
+
+ true
+
+
+ true
+
+
+
+ :/icons/address-book:/icons/address-book
+
+
+ Address Book
+
+
+
+
+ true
+
+
+ Create wallet
+
+
+
+
+ true
+
+
+ Open wallet
+
+
+
+
+ true
+
+
+ Encrypt wallet
+
+
+
+
+ true
+
+
+ Change password
+
+
+ Change password
+
+
+
+
+ true
+
+
+ About
+
+
+
+
+ true
+
+
+ About Qt
+
+
+
+
+ true
+
+
+ Backup wallet
+
+
+
+
+ true
+
+
+ Start on system login
+
+
+
+
+ true
+
+
+ Minimize to tray
+
+
+
+
+ true
+
+
+ Close to tray
+
+
+
+
+
+ WalletGui::OverviewFrame
+ QFrame
+
+ 1
+
+
+ WalletGui::SendFrame
+ QFrame
+
+ 1
+
+
+ WalletGui::ReceiveFrame
+ QFrame
+
+ 1
+
+
+ WalletGui::TransactionsFrame
+ QFrame
+
+ 1
+
+
+ WalletGui::AddressBookFrame
+ QFrame
+
+ 1
+
+
+
+
+
+
+
+ m_overviewAction
+ toggled(bool)
+ m_overviewFrame
+ setVisible(bool)
+
+
+ -1
+ -1
+
+
+ 112
+ 333
+
+
+
+
+ m_sendAction
+ toggled(bool)
+ m_sendFrame
+ setVisible(bool)
+
+
+ -1
+ -1
+
+
+ 337
+ 333
+
+
+
+
+ m_receiveAction
+ toggled(bool)
+ m_receiveFrame
+ setVisible(bool)
+
+
+ -1
+ -1
+
+
+ 562
+ 333
+
+
+
+
+ m_transactionsAction
+ toggled(bool)
+ m_transactionsFrame
+ setVisible(bool)
+
+
+ -1
+ -1
+
+
+ 787
+ 333
+
+
+
+
+ m_addressBookAction
+ toggled(bool)
+ m_addressBookFrame
+ setVisible(bool)
+
+
+ -1
+ -1
+
+
+ 809
+ 320
+
+
+
+
+ m_createWalletAction
+ triggered()
+ MainWindow
+ createWallet()
+
+
+ -1
+ -1
+
+
+ 449
+ 299
+
+
+
+
+ m_openWalletAction
+ triggered()
+ MainWindow
+ openWallet()
+
+
+ -1
+ -1
+
+
+ 449
+ 299
+
+
+
+
+ m_encryptWalletAction
+ triggered()
+ MainWindow
+ encryptWallet()
+
+
+ -1
+ -1
+
+
+ 449
+ 299
+
+
+
+
+ m_changePasswordAction
+ triggered()
+ MainWindow
+ encryptWallet()
+
+
+ -1
+ -1
+
+
+ 449
+ 299
+
+
+
+
+ m_aboutQtAction
+ triggered()
+ MainWindow
+ aboutQt()
+
+
+ -1
+ -1
+
+
+ 449
+ 299
+
+
+
+
+ m_backupWalletAction
+ triggered()
+ MainWindow
+ backupWallet()
+
+
+ -1
+ -1
+
+
+ 449
+ 299
+
+
+
+
+ m_aboutCryptonoteAction
+ triggered()
+ MainWindow
+ about()
+
+
+ -1
+ -1
+
+
+ 459
+ 299
+
+
+
+
+ m_startOnLoginAction
+ triggered(bool)
+ MainWindow
+ setStartOnLogin(bool)
+
+
+ -1
+ -1
+
+
+ 459
+ 299
+
+
+
+
+ m_minimizeToTrayAction
+ triggered(bool)
+ MainWindow
+ setMinimizeToTray(bool)
+
+
+ -1
+ -1
+
+
+ 459
+ 299
+
+
+
+
+ m_closeToTrayAction
+ triggered(bool)
+ MainWindow
+ setCloseToTray(bool)
+
+
+ -1
+ -1
+
+
+ 459
+ 299
+
+
+
+
+
+ createWallet()
+ openWallet()
+ encryptWallet()
+ aboutQt()
+ backupWallet()
+ about()
+ setStartOnLogin(bool)
+ setMinimizeToTray(bool)
+ setCloseToTray(bool)
+
+
diff --git a/src/gui/ui/newaddressdialog.ui b/src/gui/ui/newaddressdialog.ui
new file mode 100644
index 0000000..758eef1
--- /dev/null
+++ b/src/gui/ui/newaddressdialog.ui
@@ -0,0 +1,133 @@
+
+
+ NewAddressDialog
+
+
+
+ 0
+ 0
+ 590
+ 127
+
+
+
+ New address
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Label:
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ QLineEdit::Normal
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Address:
+
+
+
+ -
+
+
+ QLineEdit::Normal
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 338
+ 20
+
+
+
+
+ -
+
+
+ true
+
+
+ Ok
+
+
+ true
+
+
+
+ -
+
+
+ Cancel
+
+
+
+
+
+
+
+
+ m_okButton
+ clicked()
+ NewAddressDialog
+ accept()
+
+
+ 410
+ 102
+
+
+ 294
+ 63
+
+
+
+
+ m_cancelButton
+ clicked()
+ NewAddressDialog
+ reject()
+
+
+ 526
+ 102
+
+
+ 294
+ 63
+
+
+
+
+
diff --git a/src/gui/ui/newpassworddialog.ui b/src/gui/ui/newpassworddialog.ui
new file mode 100644
index 0000000..14badb2
--- /dev/null
+++ b/src/gui/ui/newpassworddialog.ui
@@ -0,0 +1,180 @@
+
+
+ NewPasswordDialog
+
+
+
+ 0
+ 0
+ 338
+ 133
+
+
+
+
+ 0
+ 0
+
+
+
+ Enter password
+
+
+ -
+
+
+ false
+
+
+ Ok
+
+
+ true
+
+
+
+ -
+
+
+ Cancel
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Password:
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ QLineEdit::Password
+
+
+
+ -
+
+
+ QLineEdit::Password
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Confirm:
+
+
+
+ -
+
+
+ color: #ff0000; font: 11px;
+
+
+ Password not confirmed
+
+
+ Qt::AlignCenter
+
+
+
+
+
+
+ m_passwordEdit
+ m_passwordConfirmationEdit
+ m_okButton
+ m_cancelButton
+
+
+
+
+ m_okButton
+ clicked()
+ NewPasswordDialog
+ accept()
+
+
+ 147
+ 102
+
+
+ 147
+ 63
+
+
+
+
+ m_cancelButton
+ clicked()
+ NewPasswordDialog
+ reject()
+
+
+ 241
+ 102
+
+
+ 147
+ 63
+
+
+
+
+ m_passwordEdit
+ textChanged(QString)
+ NewPasswordDialog
+ checkPassword(QString)
+
+
+ 206
+ 25
+
+
+ 168
+ 64
+
+
+
+
+ m_passwordConfirmationEdit
+ textChanged(QString)
+ NewPasswordDialog
+ checkPassword(QString)
+
+
+ 206
+ 64
+
+
+ 168
+ 64
+
+
+
+
+
+ checkPassword(QString)
+
+
diff --git a/src/gui/ui/overviewframe.ui b/src/gui/ui/overviewframe.ui
new file mode 100644
index 0000000..7b5b99f
--- /dev/null
+++ b/src/gui/ui/overviewframe.ui
@@ -0,0 +1,290 @@
+
+
+ OverviewFrame
+
+
+
+ 0
+ 0
+ 866
+ 590
+
+
+
+ Frame
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+
+ QLayout::SetDefaultConstraint
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 5
+
+
+ 0
+
+ -
+
+
+
+ 0
+ 160
+
+
+
+
+ 16777215
+ 160
+
+
+
+ QFrame::NoFrame
+
+
+ QFrame::Raised
+
+
+
-
+
+
+
+ 75
+ true
+
+
+
+ 0.00
+
+
+
+ -
+
+
+
+ 75
+ true
+
+
+
+ 0.00
+
+
+
+ -
+
+
+ Total:
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+ 75
+ true
+
+
+
+ Wallet
+
+
+
+ -
+
+
+ Unconfirmed:
+
+
+
+ -
+
+
+ Balance:
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+
+ 75
+ true
+
+
+
+ 0.00
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+ QSizePolicy::Expanding
+
+
+
+ 20
+ 425
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 16777215
+ 16777215
+
+
+
+ QFrame::NoFrame
+
+
+ QFrame::Raised
+
+
+
-
+
+
-
+
+
+
+ 75
+ true
+
+
+
+ Recent transactions
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+ -
+
+
+ Qt::NoFocus
+
+
+ background-color: transparent;
+
+
+ QFrame::NoFrame
+
+
+ QAbstractItemView::NoEditTriggers
+
+
+ QAbstractItemView::NoSelection
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/gui/ui/passworddialog.ui b/src/gui/ui/passworddialog.ui
new file mode 100644
index 0000000..4a65b8d
--- /dev/null
+++ b/src/gui/ui/passworddialog.ui
@@ -0,0 +1,131 @@
+
+
+ PasswordDialog
+
+
+
+ 0
+ 0
+ 338
+ 103
+
+
+
+
+ 338
+ 0
+
+
+
+
+ 338
+ 16777215
+
+
+
+ Enter password
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ QLineEdit::Password
+
+
+
+ -
+
+
+ Cancel
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Password:
+
+
+
+ -
+
+
+ true
+
+
+ Ok
+
+
+ true
+
+
+
+ -
+
+
+
+ 122
+ 0
+
+
+
+ color: #ff0000; font: 11px;
+
+
+ Wrong password
+
+
+ Qt::AlignCenter
+
+
+
+
+
+
+
+
+ m_okButton
+ clicked()
+ PasswordDialog
+ accept()
+
+
+ 142
+ 84
+
+
+ 158
+ 52
+
+
+
+
+ m_cancelButton
+ clicked()
+ PasswordDialog
+ reject()
+
+
+ 257
+ 84
+
+
+ 158
+ 52
+
+
+
+
+
diff --git a/src/gui/ui/receiveframe.ui b/src/gui/ui/receiveframe.ui
new file mode 100644
index 0000000..8071d82
--- /dev/null
+++ b/src/gui/ui/receiveframe.ui
@@ -0,0 +1,91 @@
+
+
+ ReceiveFrame
+
+
+
+ 0
+ 0
+ 846
+ 592
+
+
+
+ Frame
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+ -
+
+
-
+
+
+ Address:
+
+
+
+ -
+
+
+ true
+
+
+
+ -
+
+
+ ...
+
+
+
+ :/icons/copy:/icons/copy
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+
+
+
+
+ m_copyButton
+ clicked()
+ ReceiveFrame
+ copyAddress()
+
+
+ 818
+ 26
+
+
+ 422
+ 295
+
+
+
+
+
+ copyAddress()
+
+
diff --git a/src/gui/ui/sendframe.ui b/src/gui/ui/sendframe.ui
new file mode 100644
index 0000000..69040c6
--- /dev/null
+++ b/src/gui/ui/sendframe.ui
@@ -0,0 +1,320 @@
+
+
+ SendFrame
+
+
+
+ 0
+ 0
+ 866
+ 590
+
+
+
+ Frame
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+ -
+
+
+ QFrame::NoFrame
+
+
+ true
+
+
+
+
+ 0
+ 0
+ 840
+ 446
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 445
+
+
+
+
+
+
+
+
+ -
+
+
+ 5
+
+
-
+
+
+
+ 200
+ 16777215
+
+
+
+ 10
+
+
+ 1
+
+
+ 2
+
+
+ false
+
+
+ Qt::Horizontal
+
+
+ QSlider::TicksBothSides
+
+
+ 1
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Expanding
+
+
+
+ 298
+ 20
+
+
+
+
+ -
+
+
+ PaymentID:
+
+
+
+ -
+
+
+
+ 30
+ 16777215
+
+
+
+
+
+
+ 5
+
+
+ Qt::AlignCenter
+
+
+ true
+
+
+
+ -
+
+
+ -
+
+
+ Anonimity level:
+
+
+
+
+
+ -
+
+
-
+
+
+ Send
+
+
+
+ :/icons/send:/icons/send
+
+
+
+ -
+
+
+ Clear All
+
+
+
+ :/icons/remove:/icons/remove
+
+
+
+ -
+
+
+ Add Recipient
+
+
+
+ :/icons/add:/icons/add
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Balance:
+
+
+
+ -
+
+
+ 0.00
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+ m_paymentIdEdit
+ m_mixinSlider
+ m_sendButton
+ m_clearAllButton
+ m_addRecipientButton
+ m_transfersScrollarea
+ m_mixinEdit
+
+
+
+
+
+
+ m_addRecipientButton
+ clicked()
+ SendFrame
+ addRecipientClicked()
+
+
+ 282
+ 561
+
+
+ 432
+ 294
+
+
+
+
+ m_clearAllButton
+ clicked()
+ SendFrame
+ clearAllClicked()
+
+
+ 154
+ 561
+
+
+ 432
+ 294
+
+
+
+
+ m_sendButton
+ clicked()
+ SendFrame
+ sendClicked()
+
+
+ 53
+ 561
+
+
+ 432
+ 294
+
+
+
+
+ m_mixinSlider
+ valueChanged(int)
+ SendFrame
+ mixinValueChanged(int)
+
+
+ 221
+ 520
+
+
+ 432
+ 294
+
+
+
+
+
+ sendClicked()
+ clearAllClicked()
+ addRecipientClicked()
+ mixinValueChanged(int)
+
+
diff --git a/src/gui/ui/transactiondetailsdialog.ui b/src/gui/ui/transactiondetailsdialog.ui
new file mode 100644
index 0000000..4b324e1
--- /dev/null
+++ b/src/gui/ui/transactiondetailsdialog.ui
@@ -0,0 +1,65 @@
+
+
+ TransactionDetailsDialog
+
+
+
+ 0
+ 0
+ 736
+ 357
+
+
+
+ Transaction details
+
+
+ -
+
+
+ -
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Close
+
+
+
+
+
+
+
+
+
+
+ m_closeButton
+ clicked()
+ TransactionDetailsDialog
+ accept()
+
+
+ 619
+ 331
+
+
+ 335
+ 178
+
+
+
+
+
diff --git a/src/gui/ui/transactionframe.ui b/src/gui/ui/transactionframe.ui
new file mode 100644
index 0000000..f5d70a6
--- /dev/null
+++ b/src/gui/ui/transactionframe.ui
@@ -0,0 +1,156 @@
+
+
+ TransactionFrame
+
+
+
+ 0
+ 0
+ 346
+ 64
+
+
+
+
+ 0
+ 64
+
+
+
+
+ 540
+ 64
+
+
+
+ Frame
+
+
+ true
+
+
+ QFrame::NoFrame
+
+
+ QFrame::Raised
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+
+
+
+
+ -
+
+
+ 0
+
+
-
+
+
+ Qt::Vertical
+
+
+ QSizePolicy::Fixed
+
+
+
+ 20
+ 10
+
+
+
+
+ -
+
+
+ 20
+
+
-
+
+
+ TextLabel
+
+
+
+ -
+
+
+ TextLabel
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+
+
+ -
+
+
+
+
+
+ TextLabel
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+ -1
+
+
+ Qt::NoTextInteraction
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+ QSizePolicy::Fixed
+
+
+
+ 20
+ 10
+
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+
+
diff --git a/src/gui/ui/transactionsframe.ui b/src/gui/ui/transactionsframe.ui
new file mode 100644
index 0000000..e4868c4
--- /dev/null
+++ b/src/gui/ui/transactionsframe.ui
@@ -0,0 +1,125 @@
+
+
+ TransactionsFrame
+
+
+
+ 0
+ 0
+ 830
+ 614
+
+
+
+ Frame
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+ -
+
+
+ QAbstractScrollArea::AdjustIgnored
+
+
+ QAbstractItemView::AnyKeyPressed|QAbstractItemView::CurrentChanged|QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+
+ -
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Export
+
+
+
+ :/icons/export:/icons/export
+
+
+
+
+
+
+
+
+
+
+
+
+ m_csvButton
+ clicked()
+ TransactionsFrame
+ exportToCsv()
+
+
+ 761
+ 587
+
+
+ 414
+ 306
+
+
+
+
+ m_transactionsView
+ doubleClicked(QModelIndex)
+ TransactionsFrame
+ showTransactionDetails(QModelIndex)
+
+
+ 414
+ 287
+
+
+ 414
+ 306
+
+
+
+
+
+ exportToCsv()
+ showTransactionDetails(QModelIndex)
+
+
diff --git a/src/gui/ui/transferframe.ui b/src/gui/ui/transferframe.ui
new file mode 100644
index 0000000..c68ec8a
--- /dev/null
+++ b/src/gui/ui/transferframe.ui
@@ -0,0 +1,195 @@
+
+
+ TransferFrame
+
+
+
+ 0
+ 0
+ 885
+ 121
+
+
+
+ Frame
+
+
+ QFrame::Box
+
+
+ QFrame::Sunken
+
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
+ -
+
+
+ Pay To:
+
+
+
+ -
+
+
+ ...
+
+
+
+ :/icons/address-book:/icons/address-book
+
+
+
+ -
+
+
+ ...
+
+
+
+ :/icons/paste:/icons/paste
+
+
+
+ -
+
+
+ Enter a label for this address to add it to your address book
+
+
+
+ -
+
+
+ Amount:
+
+
+
+ -
+
+
+ ...
+
+
+
+ :/icons/remove:/icons/remove
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 558
+ 17
+
+
+
+
+ -
+
+
+ Label:
+
+
+
+ -
+
+
+ Qt::LeftToRight
+
+
+
+
+
+ 8
+
+
+ 999999999.999999046325684
+
+
+
+ -
+
+
+
+
+
+ m_addressEdit
+ m_labelEdit
+ m_amountSpin
+ m_addressBookButton
+ m_pasteButton
+ m_removeButton
+
+
+
+
+
+
+ m_removeButton
+ clicked()
+ TransferFrame
+ close()
+
+
+ 862
+ 21
+
+
+ 442
+ 60
+
+
+
+
+ m_addressBookButton
+ clicked()
+ TransferFrame
+ addressBookClicked()
+
+
+ 786
+ 21
+
+
+ 442
+ 60
+
+
+
+
+ m_pasteButton
+ clicked()
+ TransferFrame
+ pasteClicked()
+
+
+ 824
+ 21
+
+
+ 442
+ 60
+
+
+
+
+
+ addressBookClicked()
+ pasteClicked()
+
+
diff --git a/src/icons/add.png b/src/icons/add.png
new file mode 100644
index 0000000..ea53fc3
Binary files /dev/null and b/src/icons/add.png differ
diff --git a/src/icons/address-book.png b/src/icons/address-book.png
new file mode 100644
index 0000000..33a2d91
Binary files /dev/null and b/src/icons/address-book.png differ
diff --git a/src/icons/clock1.png b/src/icons/clock1.png
new file mode 100644
index 0000000..9f0aa5d
Binary files /dev/null and b/src/icons/clock1.png differ
diff --git a/src/icons/clock2.png b/src/icons/clock2.png
new file mode 100644
index 0000000..bad00cc
Binary files /dev/null and b/src/icons/clock2.png differ
diff --git a/src/icons/clock3.png b/src/icons/clock3.png
new file mode 100644
index 0000000..7314d53
Binary files /dev/null and b/src/icons/clock3.png differ
diff --git a/src/icons/clock4.png b/src/icons/clock4.png
new file mode 100644
index 0000000..07f5bfa
Binary files /dev/null and b/src/icons/clock4.png differ
diff --git a/src/icons/clock5.png b/src/icons/clock5.png
new file mode 100644
index 0000000..27e9630
Binary files /dev/null and b/src/icons/clock5.png differ
diff --git a/src/icons/connected.png b/src/icons/connected.png
new file mode 100644
index 0000000..df42ee2
Binary files /dev/null and b/src/icons/connected.png differ
diff --git a/src/icons/disconnected.png b/src/icons/disconnected.png
new file mode 100644
index 0000000..dca1059
Binary files /dev/null and b/src/icons/disconnected.png differ
diff --git a/src/icons/editcopy.png b/src/icons/editcopy.png
new file mode 100644
index 0000000..7807c59
Binary files /dev/null and b/src/icons/editcopy.png differ
diff --git a/src/icons/editpaste.png b/src/icons/editpaste.png
new file mode 100644
index 0000000..e217e30
Binary files /dev/null and b/src/icons/editpaste.png differ
diff --git a/src/icons/export.png b/src/icons/export.png
new file mode 100644
index 0000000..5c1f519
Binary files /dev/null and b/src/icons/export.png differ
diff --git a/src/icons/lock_closed.png b/src/icons/lock_closed.png
new file mode 100644
index 0000000..6de207d
Binary files /dev/null and b/src/icons/lock_closed.png differ
diff --git a/src/icons/lock_open.png b/src/icons/lock_open.png
new file mode 100644
index 0000000..23ce324
Binary files /dev/null and b/src/icons/lock_open.png differ
diff --git a/src/icons/overview.png b/src/icons/overview.png
new file mode 100644
index 0000000..a274f0c
Binary files /dev/null and b/src/icons/overview.png differ
diff --git a/src/icons/receive.png b/src/icons/receive.png
new file mode 100644
index 0000000..8ed337c
Binary files /dev/null and b/src/icons/receive.png differ
diff --git a/src/icons/remove.png b/src/icons/remove.png
new file mode 100644
index 0000000..224d2c2
Binary files /dev/null and b/src/icons/remove.png differ
diff --git a/src/icons/send.png b/src/icons/send.png
new file mode 100644
index 0000000..43c3d79
Binary files /dev/null and b/src/icons/send.png differ
diff --git a/src/icons/sync_sprite.png b/src/icons/sync_sprite.png
new file mode 100644
index 0000000..d9c9ce0
Binary files /dev/null and b/src/icons/sync_sprite.png differ
diff --git a/src/icons/synced.png b/src/icons/synced.png
new file mode 100644
index 0000000..9fad384
Binary files /dev/null and b/src/icons/synced.png differ
diff --git a/src/icons/transaction.png b/src/icons/transaction.png
new file mode 100644
index 0000000..8a804b0
Binary files /dev/null and b/src/icons/transaction.png differ
diff --git a/src/icons/transactions.png b/src/icons/transactions.png
new file mode 100644
index 0000000..ac955c7
Binary files /dev/null and b/src/icons/transactions.png differ
diff --git a/src/icons/tx_inout.png b/src/icons/tx_inout.png
new file mode 100644
index 0000000..5f092f9
Binary files /dev/null and b/src/icons/tx_inout.png differ
diff --git a/src/icons/tx_input.png b/src/icons/tx_input.png
new file mode 100644
index 0000000..a2d324e
Binary files /dev/null and b/src/icons/tx_input.png differ
diff --git a/src/icons/tx_mined.png b/src/icons/tx_mined.png
new file mode 100644
index 0000000..a7acc6c
Binary files /dev/null and b/src/icons/tx_mined.png differ
diff --git a/src/icons/tx_output.png b/src/icons/tx_output.png
new file mode 100644
index 0000000..a7c5ebf
Binary files /dev/null and b/src/icons/tx_output.png differ
diff --git a/src/icons/unconfirmed.png b/src/icons/unconfirmed.png
new file mode 100644
index 0000000..cfe1a1c
Binary files /dev/null and b/src/icons/unconfirmed.png differ
diff --git a/src/images/clock.gif b/src/images/clock.gif
new file mode 100644
index 0000000..31b6c2c
Binary files /dev/null and b/src/images/clock.gif differ
diff --git a/src/images/cryptonote.icns b/src/images/cryptonote.icns
new file mode 100644
index 0000000..1f82a07
Binary files /dev/null and b/src/images/cryptonote.icns differ
diff --git a/src/images/cryptonote.ico b/src/images/cryptonote.ico
new file mode 100644
index 0000000..8b6a715
Binary files /dev/null and b/src/images/cryptonote.ico differ
diff --git a/src/images/cryptonote.png b/src/images/cryptonote.png
new file mode 100644
index 0000000..cace7ed
Binary files /dev/null and b/src/images/cryptonote.png differ
diff --git a/src/images/splash.png b/src/images/splash.png
new file mode 100644
index 0000000..4fa4aaf
Binary files /dev/null and b/src/images/splash.png differ
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..bf49ad9
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,94 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "CommandLineParser.h"
+#include "CurrencyAdapter.h"
+#include "NodeAdapter.h"
+#include "Settings.h"
+#include "SignalHandler.h"
+#include "WalletAdapter.h"
+
+#include "gui/MainWindow.h"
+
+#define DEBUG 1
+
+using namespace WalletGui;
+
+int main(int argc, char* argv[]) {
+ QApplication app(argc, argv);
+ app.setApplicationName(CurrencyAdapter::instance().getCurrencyName() + "wallet");
+ app.setApplicationVersion(Settings::instance().getVersion());
+ app.setQuitOnLastWindowClosed(false);
+
+#ifndef Q_OS_MAC
+ QApplication::setStyle(QStyleFactory::create("Fusion"));
+#endif
+
+ CommandLineParser cmdLineParser;
+ Settings::instance().setCommandLineParser(&cmdLineParser);
+ bool cmdLineParseResult = cmdLineParser.process();
+ Settings::instance().load();
+
+#ifdef Q_OS_WIN
+ if(!cmdLineParseResult) {
+ QMessageBox::critical(nullptr, QObject::tr("Error"), cmdLineParser.errorText());
+ return app.exec();
+ } else if (cmdLineParser.hasHelpOption()) {
+ QMessageBox::information(nullptr, QObject::tr("Help"), cmdLineParser.helpText());
+ return app.exec();
+ }
+#endif
+
+ QString dataDirPath = Settings::instance().getDataDir().absolutePath();
+ if (!QDir().exists(dataDirPath)) {
+ QDir().mkpath(dataDirPath);
+ }
+
+ QLockFile lockFile(Settings::instance().getDataDir().absoluteFilePath(QApplication::applicationName() + ".lock"));
+ if (!lockFile.tryLock()) {
+ QMessageBox::warning(nullptr, QObject::tr("Fail"), QString("%1 wallet already running").arg(CurrencyAdapter::instance().getCurrencyDisplayName()));
+ return 0;
+ }
+
+ QLocale::setDefault(QLocale::c());
+
+ SignalHandler::instance().init();
+ QObject::connect(&SignalHandler::instance(), &SignalHandler::quitSignal, &app, &QApplication::quit);
+
+ QSplashScreen* splash = new QSplashScreen(QPixmap(":images/splash"), Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint);
+ if (!splash->isVisible()) {
+ splash->show();
+ }
+
+ splash->showMessage(QObject::tr("Loading blockchain..."), Qt::AlignLeft | Qt::AlignBottom, Qt::white);
+ app.processEvents();
+ qRegisterMetaType("CryptoNote::TransactionId");
+ qRegisterMetaType("quintptr");
+ if (!NodeAdapter::instance().init()) {
+ return 0;
+ }
+
+ splash->finish(&MainWindow::instance());
+ MainWindow::instance().show();
+ WalletAdapter::instance().open("");
+ QObject::connect(QApplication::instance(), &QApplication::aboutToQuit, []() {
+ MainWindow::instance().quit();
+ if (WalletAdapter::instance().isOpen()) {
+ WalletAdapter::instance().close();
+ }
+
+ NodeAdapter::instance().deinit();
+ });
+
+ return app.exec();
+}
diff --git a/src/miniupnpcstrings.h b/src/miniupnpcstrings.h
new file mode 100644
index 0000000..4a4765b
--- /dev/null
+++ b/src/miniupnpcstrings.h
@@ -0,0 +1,11 @@
+// Copyright (c) 2011-2015 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef MINIUPNPCSTRINGS_H_INCLUDED
+#define MINIUPNPCSTRINGS_H_INCLUDED
+
+#define OS_STRING "Windows"
+#define MINIUPNPC_VERSION_STRING "1.9"
+
+#endif
diff --git a/src/resources.qrc b/src/resources.qrc
new file mode 100644
index 0000000..e973685
--- /dev/null
+++ b/src/resources.qrc
@@ -0,0 +1,36 @@
+
+
+ icons/sync_sprite.png
+ icons/synced.png
+ icons/lock_closed.png
+ icons/lock_open.png
+ icons/tx_mined.png
+ icons/editcopy.png
+ icons/add.png
+ icons/tx_input.png
+ icons/tx_output.png
+ icons/address-book.png
+ icons/editpaste.png
+ icons/remove.png
+ icons/receive.png
+ icons/transactions.png
+ icons/send.png
+ icons/overview.png
+ icons/clock1.png
+ icons/clock2.png
+ icons/clock3.png
+ icons/clock4.png
+ icons/clock5.png
+ icons/transaction.png
+ icons/connected.png
+ icons/disconnected.png
+ icons/export.png
+ icons/tx_inout.png
+ icons/unconfirmed.png
+
+
+ images/splash.png
+ images/cryptonote.png
+ images/clock.gif
+
+