From 04bc8b699fe39b9432efae8f6d66ccf6efab9fad Mon Sep 17 00:00:00 2001 From: cryptonotefoundation Date: Wed, 29 Apr 2015 20:03:08 +0300 Subject: [PATCH] Initial commit --- .gitignore | 3 + CMakeLists.txt | 201 ++++++++ CryptoNoteWallet.cmake | 4 + src/CommandLineParser.cpp | 56 +++ src/CommandLineParser.h | 35 ++ src/CryptoNote.cpp | 265 +++++++++++ src/CryptoNote.h | 56 +++ src/CryptoNoteWalletConfig.h.in | 9 + src/CurrencyAdapter.cpp | 105 +++++ src/CurrencyAdapter.h | 35 ++ src/NodeAdapter.cpp | 216 +++++++++ src/NodeAdapter.h | 67 +++ src/Settings.cpp | 225 +++++++++ src/Settings.h | 57 +++ src/SignalHandler.cpp | 32 ++ src/SignalHandler.h | 31 ++ src/WalletAdapter.cpp | 432 +++++++++++++++++ src/WalletAdapter.h | 103 ++++ src/cryptonotewallet.rc | 1 + src/gui/AboutDialog.cpp | 24 + src/gui/AboutDialog.h | 28 ++ src/gui/AddressBookDialog.cpp | 28 ++ src/gui/AddressBookDialog.h | 30 ++ src/gui/AddressBookFrame.cpp | 58 +++ src/gui/AddressBookFrame.h | 33 ++ src/gui/AddressBookModel.cpp | 155 ++++++ src/gui/AddressBookModel.h | 45 ++ src/gui/AnimatedLabel.cpp | 46 ++ src/gui/AnimatedLabel.h | 35 ++ src/gui/ChangePasswordDialog.cpp | 36 ++ src/gui/ChangePasswordDialog.h | 33 ++ src/gui/ExitWidget.cpp | 29 ++ src/gui/ExitWidget.h | 31 ++ src/gui/MainWindow.cpp | 413 ++++++++++++++++ src/gui/MainWindow.h | 87 ++++ src/gui/MainWindow.mm | 30 ++ src/gui/NewAddressDialog.cpp | 28 ++ src/gui/NewAddressDialog.h | 31 ++ src/gui/NewPasswordDialog.cpp | 32 ++ src/gui/NewPasswordDialog.h | 32 ++ src/gui/OverviewFrame.cpp | 95 ++++ src/gui/OverviewFrame.h | 39 ++ src/gui/PasswordDialog.cpp | 28 ++ src/gui/PasswordDialog.h | 30 ++ src/gui/ReceiveFrame.cpp | 36 ++ src/gui/ReceiveFrame.h | 33 ++ src/gui/RecentTransactionsModel.cpp | 37 ++ src/gui/RecentTransactionsModel.h | 25 + src/gui/SendFrame.cpp | 114 +++++ src/gui/SendFrame.h | 41 ++ src/gui/SortedTransactionsModel.cpp | 45 ++ src/gui/SortedTransactionsModel.h | 29 ++ src/gui/TransactionDetailsDialog.cpp | 46 ++ src/gui/TransactionDetailsDialog.h | 29 ++ src/gui/TransactionFrame.cpp | 68 +++ src/gui/TransactionFrame.h | 36 ++ src/gui/TransactionsFrame.cpp | 62 +++ src/gui/TransactionsFrame.h | 37 ++ src/gui/TransactionsListModel.cpp | 25 + src/gui/TransactionsListModel.h | 23 + src/gui/TransactionsModel.cpp | 394 ++++++++++++++++ src/gui/TransactionsModel.h | 67 +++ src/gui/TransferFrame.cpp | 58 +++ src/gui/TransferFrame.h | 38 ++ src/gui/WalletEvents.h | 37 ++ src/gui/ui/aboutdialog.ui | 102 ++++ src/gui/ui/addressbookdialog.ui | 81 ++++ src/gui/ui/addressbookframe.ui | 142 ++++++ src/gui/ui/changepassworddialog.ui | 207 ++++++++ src/gui/ui/exitwidget.ui | 36 ++ src/gui/ui/mainwindow.ui | 628 +++++++++++++++++++++++++ src/gui/ui/newaddressdialog.ui | 133 ++++++ src/gui/ui/newpassworddialog.ui | 180 +++++++ src/gui/ui/overviewframe.ui | 290 ++++++++++++ src/gui/ui/passworddialog.ui | 131 ++++++ src/gui/ui/receiveframe.ui | 91 ++++ src/gui/ui/sendframe.ui | 320 +++++++++++++ src/gui/ui/transactiondetailsdialog.ui | 65 +++ src/gui/ui/transactionframe.ui | 156 ++++++ src/gui/ui/transactionsframe.ui | 125 +++++ src/gui/ui/transferframe.ui | 195 ++++++++ src/icons/add.png | Bin 0 -> 1112 bytes src/icons/address-book.png | Bin 0 -> 1690 bytes src/icons/clock1.png | Bin 0 -> 864 bytes src/icons/clock2.png | Bin 0 -> 863 bytes src/icons/clock3.png | Bin 0 -> 856 bytes src/icons/clock4.png | Bin 0 -> 869 bytes src/icons/clock5.png | Bin 0 -> 858 bytes src/icons/connected.png | Bin 0 -> 762 bytes src/icons/disconnected.png | Bin 0 -> 538 bytes src/icons/editcopy.png | Bin 0 -> 600 bytes src/icons/editpaste.png | Bin 0 -> 1135 bytes src/icons/export.png | Bin 0 -> 1931 bytes src/icons/lock_closed.png | Bin 0 -> 1401 bytes src/icons/lock_open.png | Bin 0 -> 1359 bytes src/icons/overview.png | Bin 0 -> 6327 bytes src/icons/receive.png | Bin 0 -> 1331 bytes src/icons/remove.png | Bin 0 -> 649 bytes src/icons/send.png | Bin 0 -> 1345 bytes src/icons/sync_sprite.png | Bin 0 -> 43485 bytes src/icons/synced.png | Bin 0 -> 560 bytes src/icons/transaction.png | Bin 0 -> 211 bytes src/icons/transactions.png | Bin 0 -> 1343 bytes src/icons/tx_inout.png | Bin 0 -> 2442 bytes src/icons/tx_input.png | Bin 0 -> 1114 bytes src/icons/tx_mined.png | Bin 0 -> 1458 bytes src/icons/tx_output.png | Bin 0 -> 1107 bytes src/icons/unconfirmed.png | Bin 0 -> 291 bytes src/images/clock.gif | Bin 0 -> 44663 bytes src/images/cryptonote.icns | Bin 0 -> 199156 bytes src/images/cryptonote.ico | Bin 0 -> 370070 bytes src/images/cryptonote.png | Bin 0 -> 3961 bytes src/images/splash.png | Bin 0 -> 7955 bytes src/main.cpp | 94 ++++ src/miniupnpcstrings.h | 11 + src/resources.qrc | 36 ++ 116 files changed, 7692 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 CryptoNoteWallet.cmake create mode 100644 src/CommandLineParser.cpp create mode 100644 src/CommandLineParser.h create mode 100644 src/CryptoNote.cpp create mode 100644 src/CryptoNote.h create mode 100644 src/CryptoNoteWalletConfig.h.in create mode 100644 src/CurrencyAdapter.cpp create mode 100644 src/CurrencyAdapter.h create mode 100644 src/NodeAdapter.cpp create mode 100644 src/NodeAdapter.h create mode 100644 src/Settings.cpp create mode 100644 src/Settings.h create mode 100644 src/SignalHandler.cpp create mode 100644 src/SignalHandler.h create mode 100644 src/WalletAdapter.cpp create mode 100644 src/WalletAdapter.h create mode 100644 src/cryptonotewallet.rc create mode 100644 src/gui/AboutDialog.cpp create mode 100644 src/gui/AboutDialog.h create mode 100644 src/gui/AddressBookDialog.cpp create mode 100644 src/gui/AddressBookDialog.h create mode 100644 src/gui/AddressBookFrame.cpp create mode 100644 src/gui/AddressBookFrame.h create mode 100644 src/gui/AddressBookModel.cpp create mode 100644 src/gui/AddressBookModel.h create mode 100644 src/gui/AnimatedLabel.cpp create mode 100644 src/gui/AnimatedLabel.h create mode 100644 src/gui/ChangePasswordDialog.cpp create mode 100644 src/gui/ChangePasswordDialog.h create mode 100644 src/gui/ExitWidget.cpp create mode 100644 src/gui/ExitWidget.h create mode 100644 src/gui/MainWindow.cpp create mode 100644 src/gui/MainWindow.h create mode 100644 src/gui/MainWindow.mm create mode 100644 src/gui/NewAddressDialog.cpp create mode 100644 src/gui/NewAddressDialog.h create mode 100644 src/gui/NewPasswordDialog.cpp create mode 100644 src/gui/NewPasswordDialog.h create mode 100644 src/gui/OverviewFrame.cpp create mode 100644 src/gui/OverviewFrame.h create mode 100644 src/gui/PasswordDialog.cpp create mode 100644 src/gui/PasswordDialog.h create mode 100644 src/gui/ReceiveFrame.cpp create mode 100644 src/gui/ReceiveFrame.h create mode 100644 src/gui/RecentTransactionsModel.cpp create mode 100644 src/gui/RecentTransactionsModel.h create mode 100644 src/gui/SendFrame.cpp create mode 100644 src/gui/SendFrame.h create mode 100644 src/gui/SortedTransactionsModel.cpp create mode 100644 src/gui/SortedTransactionsModel.h create mode 100644 src/gui/TransactionDetailsDialog.cpp create mode 100644 src/gui/TransactionDetailsDialog.h create mode 100644 src/gui/TransactionFrame.cpp create mode 100644 src/gui/TransactionFrame.h create mode 100644 src/gui/TransactionsFrame.cpp create mode 100644 src/gui/TransactionsFrame.h create mode 100644 src/gui/TransactionsListModel.cpp create mode 100644 src/gui/TransactionsListModel.h create mode 100644 src/gui/TransactionsModel.cpp create mode 100644 src/gui/TransactionsModel.h create mode 100644 src/gui/TransferFrame.cpp create mode 100644 src/gui/TransferFrame.h create mode 100644 src/gui/WalletEvents.h create mode 100644 src/gui/ui/aboutdialog.ui create mode 100644 src/gui/ui/addressbookdialog.ui create mode 100644 src/gui/ui/addressbookframe.ui create mode 100644 src/gui/ui/changepassworddialog.ui create mode 100644 src/gui/ui/exitwidget.ui create mode 100644 src/gui/ui/mainwindow.ui create mode 100644 src/gui/ui/newaddressdialog.ui create mode 100644 src/gui/ui/newpassworddialog.ui create mode 100644 src/gui/ui/overviewframe.ui create mode 100644 src/gui/ui/passworddialog.ui create mode 100644 src/gui/ui/receiveframe.ui create mode 100644 src/gui/ui/sendframe.ui create mode 100644 src/gui/ui/transactiondetailsdialog.ui create mode 100644 src/gui/ui/transactionframe.ui create mode 100644 src/gui/ui/transactionsframe.ui create mode 100644 src/gui/ui/transferframe.ui create mode 100644 src/icons/add.png create mode 100644 src/icons/address-book.png create mode 100644 src/icons/clock1.png create mode 100644 src/icons/clock2.png create mode 100644 src/icons/clock3.png create mode 100644 src/icons/clock4.png create mode 100644 src/icons/clock5.png create mode 100644 src/icons/connected.png create mode 100644 src/icons/disconnected.png create mode 100644 src/icons/editcopy.png create mode 100644 src/icons/editpaste.png create mode 100644 src/icons/export.png create mode 100644 src/icons/lock_closed.png create mode 100644 src/icons/lock_open.png create mode 100644 src/icons/overview.png create mode 100644 src/icons/receive.png create mode 100644 src/icons/remove.png create mode 100644 src/icons/send.png create mode 100644 src/icons/sync_sprite.png create mode 100644 src/icons/synced.png create mode 100644 src/icons/transaction.png create mode 100644 src/icons/transactions.png create mode 100644 src/icons/tx_inout.png create mode 100644 src/icons/tx_input.png create mode 100644 src/icons/tx_mined.png create mode 100644 src/icons/tx_output.png create mode 100644 src/icons/unconfirmed.png create mode 100644 src/images/clock.gif create mode 100644 src/images/cryptonote.icns create mode 100644 src/images/cryptonote.ico create mode 100644 src/images/cryptonote.png create mode 100644 src/images/splash.png create mode 100644 src/main.cpp create mode 100644 src/miniupnpcstrings.h create mode 100644 src/resources.qrc 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 + + + + + + + + + 0 + 0 + 920 + 27 + + + + + File + + + + + + + + + Settings + + + + + + + + + + + Help + + + + + + + + + + + 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 +
gui/OverviewFrame.h
+ 1 +
+ + WalletGui::SendFrame + QFrame +
gui/SendFrame.h
+ 1 +
+ + WalletGui::ReceiveFrame + QFrame +
gui/ReceiveFrame.h
+ 1 +
+ + WalletGui::TransactionsFrame + QFrame +
gui/TransactionsFrame.h
+ 1 +
+ + WalletGui::AddressBookFrame + QFrame +
gui/AddressBookFrame.h
+ 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 0000000000000000000000000000000000000000..ea53fc3493dde873101127e3e9f37edfdad968c7 GIT binary patch literal 1112 zcmV-e1gHCnP)#Jvax;q&S5d;hob*B=^PIvC(Ha|eYUog1SRZMp3Dhi@|NfZS%*&36G zfeb{%7(xaW<4nkC_w;;K-Fqw!WpNpr`GD!uoIa=S=6&va?(Ht&0Fi&5o<-zMQ4vva z!QpU{kxEKNqKT}HN8bP!*k`2dGt$qJ?wONse6aA+!m-@t1eAcMvaCN+cX+Nn`2Lj( zm(G0+{Bo!O2**x6acZU`9V#_RJSJ|>UaaTD{D}_m%%KA)5HzqIwj1$4McLL$8=O$l z#$f^o;Da}Tir4{@w{chvVLAY)0Ynb?*7_L8tDhEtPy=Wg%AIF`Ac4}x;SExB8Y2i0 zf~WLlBpy|1s;>Z<27pj`PvZbV>Rzi@+^UUWY7Tg>rQbHIAa)B52GIE^f1zLW zK7RG-*N!QwN+4hziW0Q`po9>T`C>jVeTBy)P1=N`F%10(=Jb7>yekR>06~Hk)D}T1 zS$F@)+cNuM=gW()Up({N(dX>|d9_{OHQ=q9L|Z4#zY#YFt~~yZYirlgL?NNBK%!PP z{eMl-3c8nzuhLA@BPR#XQiZb4MyLU?d#|>JB|9MEUjeDOHTsF0t2Yq`ASj9e?YA^* z2&4**L5i|-*EFJ$BMm@2@u-f&8dq1YusB|9b}l9#Ls&105J3Q`R;t^6+r)S7+WN+o zb{vuT^48znczm73;UbkQA;APNi3t#`16DyHMb)lWW3vectG*SkS}=2j--dU&v2vYz z<9j9=?^yZgd0?H0S(PqsehG<66 zLI9A8!u7v?;Pmm+RE_=XA&?2y#}E=jK#E$+>eea~;@}V>z%CFHtp!M>;%fLeyePT! zbdUD|?B!2nSBL;ImJ+An1aXQwsT0HjiJ(q#BR8Uys{%0pPVZ$EeX3EKY&RU2IXUm< zV7~s?J`qCjH;nb6(D!H?YM6cgVu@q*<47rlc_pjhpiT}xf@6X(aU@I zO+Q_LPFmQk8xZEQIdh|iupH-W!U4i@fNv1*_soSFifI9?P_pH4 zB$AN2w9PCr7`nCi@^E<*SYn@XAiJJi=%00od#gwbSGyp2l1q_xT>UJatm6`w$elm$ eTmsIs&-f1xl@eeay)1+P0000r!I2aoic|aMG}NlzRW0Ov;r_i@@3 z9`}C5L}c0^+ip&>GU%AuS#pbhBycZj?VMNsl&$~^AD%2D^n`+~nZpG5#V8#l$K_vp zfQ143&bO;a0ni()yq7C8S6I=6-E(Pv@xUizU4P45>`Q7WxKX0kdboXnpSmFFfl`P(xMeuS1h?EL>{ zxSQja(07kk8t$5*q02~3tC|M6nwCyA^7|n=MTjA_1&!X!uVT`e|C>)(74-=&-+St$ z0JuKfp4*3gXNJSt)f+bcUC}gTqO^0Ik{T5ijVh{IG&Cr*GNS+ssgMtiW3oc#l_o-?GVpd@)+sRY!ros1Z+?2V z=kJaLytJ=j&j-ckGWk7plUe{K#-V@MNPD*$d5?~|Ru$#-qkP_G;(CXL6FIj?&THi3 zS}SL7=}4{CkyfjvyxoL∨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 literal 0 HcmV?d00001 diff --git a/src/icons/clock3.png b/src/icons/clock3.png new file mode 100644 index 0000000000000000000000000000000000000000..7314d5302b7e31564d4ffbe95b85863b8ee2a697 GIT binary patch literal 856 zcmV-e1E>6nP)N^kZBk2{(pnK}35_k_Q>A%}FDgNxG~&DZ=#vCQeT{_1mqwt1 zRw^JMLJNYG(6T0Lh-#xvZ|25IHkMUe?2Row9x!Z7?5h}Z{fzdb!YeLR;*uD*0If2t#!C!Oiykhe~)vdT(n z!~F1D_}6;bT-b?Q1kC;d*5u^mg_DCFm!B1G%0-jPcHm1%pO?@sd^Ss4bmt!O{T)BP zzL@%8W@hFKz&HTAoliWUp6Qd06Z>U0m7=G&mwW%*g#nwxeGdO^`t;hGw~ods6$PI+ z#>VD=Ik7u)F0H=Ko2-M1X-lWcWHN+7z~f4ppt^yrHhH;!3qin*dCka?hI61(Uuia* z?ZWfC;TH~iLvgLf>iRmdQfO#tty&{$JO)(TDQ0gi2$j+K`DxD&5j@ zWt-`1OT7E>JfB@z0u!>`2>I~KfSm1vtUW>^Y@Ad=N4w&gTmn|ay;8_# zEn;;W>P z9>;M#ZZG`K(!&)Z;c$C7K#Q2-gOE?IHNcL!eA7!Fl&p(|LZL1IcFuV5=VJLiRr^C@ z8@dJ#;r1QC*A|z4tg}{?oIhijdOyRZpSqIo3hqac#$} ziEydME^i+GifXmS(wgAgTi(k3lDW8-tN|>Z!szH|dp4ULQA!PEQu>UPk*N8}-0s4v i)#{C6u~-8Pd-xx;e71%+z|EKd0000 literal 0 HcmV?d00001 diff --git a/src/icons/clock4.png b/src/icons/clock4.png new file mode 100644 index 0000000000000000000000000000000000000000..07f5bfab5f2161ae1a65fe3ce3fc66f83271636b GIT binary patch literal 869 zcmV-r1DgDaP)C%v8`aWLO_%nD24_Sf#%nO{wj$1TTqE8 z!GM4Wst5vtq*k#0PRW`SVx!VLY`VdA^VrwjJA3Exc^9>WoZ)Z=_|7@Z2V-L&CMPHD za5#M2^Sm_Y=A^IWx+?GMf)L^cfClz}?Y&P=Pj|PqtFMzs;{&0VI9h`-9PYe}a&-e6 zg-yD8P5ic5pb>xWCIA8e>wojq)YM2%PjD&SnHV@^S%`B9T`NEo4PyRD@C3`fWm4Ja zYd6Nm#x4P14+5Ia$yDoS4|ChrP7%f8eR!gV+kY(K-sYb$`W}jZm%$qbubq*B!84VQ zhKGlb`-I(mb6Z${)4}5b(lxZS1VLm&2p6TDEz}(ii-nNvb7A1(`i}-LW^4AseES!x zE8=M@8jWUpo;Yw!*Gt&ATYyvw#sE?(R4NsSMhRe55Obi7i)cq3v9<=zy|UBGIX`PD zr82q^VZ=DXkq)S)S!sAu!f{+k&w=sH#9Z)zi}VQ>PQ8JyEG@~~jJ<-x#&04 z04UfY1wezCht)L!V|gek3)QNbw*kz97oaGC_0<(T)mK95nH2yEMDkx{zWQti#N0J&VQ|Eq7uJ;%ICHFb_=W?rDHvx8IGsC6v{ld0`Saa$Yps_m<|y5FyXeDD`qimZ*~;oGe9nHM`&V}XKpI@e1>(BXZ160yUT3Sodce8!;=EcFkn$3I74Er!NG}Iajh0ZFa v(t&`?C?$Dw+s%cQ%jKW)`FsTc;XnKXzVg5yGnYgS00000NkvXXu0mjfgBzRe literal 0 HcmV?d00001 diff --git a/src/icons/clock5.png b/src/icons/clock5.png new file mode 100644 index 0000000000000000000000000000000000000000..27e9630eb5a0ddd3484ef0f998ab292351db550a GIT binary patch literal 858 zcmV-g1Eu_lP)| zP_3d+M2LcIC4xy4Vrm{XG&N03LNm^E9+|oKJnp?tAQ0(y_<#fd2j|Cec#5&HF(;8o z3@D}gEhjoBrHrI!<{I~T-}h$#$sq_15!r0^bWb}c<^AABiM93=TLlHqrEHS^|!U_8}E|~ zdl&8kckTT*x20o~neNna*YR;&8^^W@qmcFWhq!GO5=Rxy=?VcJOFtWWUaeYdf4Hxe zcD?IXDwP^c_vOzz$L_JYwTae-FaoU%l}d%0ETO43tRX`Wx3x~PRr2Cn#a`RCha6+f zVDea9IH@XKgJ8L3f}J$s-hKuizLF>*2+#zM&+(UiDpg6>semAe_gj&zUx{}pyn2Y8 zl!VU~v7TQeMWT4RaIPH@29~;7?!5CwUMu;Drdq00I(O$)}B!U1iM3Dgu;ei1f zBNW>Yd=v`PWbw_V?yD9sTUaLw?SSQ5g57@tGzu*=N~i-RvY|q9f7a)(nL69c7RH!) zt57IRuik!UsjfhUhR`u6(U8L<8mEV12q`5!m^W8^#C^XZ#R8V**E>2HRS1o|XH(pq~-E?{W zi@5RpkfQ@3ZD$O174YLkot-VksiBB>KW*l>Y<80D`9&9v+UzVzD7(OuumTpfTF^s^RQ@ kVC8c8r@6Vg3J`I?f2Tvd>e!g&_5c6?07*qoM6N<$f*i+_SpWb4 literal 0 HcmV?d00001 diff --git a/src/icons/connected.png b/src/icons/connected.png new file mode 100644 index 0000000000000000000000000000000000000000..df42ee29a7c9bb98df378fdebb49cbe4913ca0d0 GIT binary patch literal 762 zcmVm9(N{w3br+xqd8y3uF=hr=PIQmHjLIr(vFYU;tYBVcFC z;^JaRr_<5RW)sH7#+Zg$tyY-HWd7(d!3Y~08`S>({*OwfLe9?4NW0x8*=&|z3g%iU z6#BcnyHD}i(FE)3>$iD#5&*$T=u4@4$uaLKl!P?rI+-x>y^m@HiEEWUK4l5VgQ=kew07xOTNCCM|9+L0F56Nb;vC-)6 z{QP`76bk*qS)tWxLGC1XN;Rl)jG9DdkutI{5DyLd{k|JFzD?7#rrYfr!{PA7@$vCj s+=o8r%3Yvn35hb|C2|UX)s27W-`poo-ZgGR)c^nh07*qoM6N<$f__O?!T!+~yOY1@YgTcxSV?SIRH2un8&CYBdENHx=7W1U)0s!d1?RL{F%buU?EgwB! z4!`>L2Ug{|4phbAa5&X$Hla``NDtm6&)1yGG3LAXm~Pb!6mc*ZOcjeo5Cj2uo`+m6 z_Z|oYrd@MGH|+69`gC1mQ87?rr%I&~h@uGbcpU2WI<(C=j*}kmX1U#YGSRgJzu&); z&*!0BE<+}h`AiUvMxk1*LVG+CiM*(tfpQCtM&l}xNYrq5qSNU}Hk&03!w?h`Ns*(k0wY9a~+~n@<@#^aC{QLdu>+jy(<+r!DM>YSXQ^z`jcz*Ehz#-{0Zn948Dyh;GVctl&gSk+`W7rVw3Jk_*7R^>imXspCR4#$*H3-1CSALjNLx$rzIj zVAS`>{udfVV@x*SR)e(`yH^PP223`9Bj{-GGQ(s8^aXQ5gU35eE`XwRe_{7Mf%^wc z#tOZRF-~<1h0PNt=K$*4JY#YWj@so`z258F`$v&%K&#wh`T6zz^NYzAu#zo+$qm3t mt^q6A0#I8WU^31EEo*-TJ~w5qT=Sp+0000`b~`h literal 0 HcmV?d00001 diff --git a/src/icons/editpaste.png b/src/icons/editpaste.png new file mode 100644 index 0000000000000000000000000000000000000000..e217e308ea43cbe2bd4ca3c41415f76968972625 GIT binary patch literal 1135 zcmV-#1d#iQP)N~63&n+f`K9+L|Q13AO@%tEVWdcP%agi z5r()5ihzKqN(#b>DGny2g1Xpk*KO~g=XrkJllt(1dAIXj#ho!&&ic^jr{Ze{P z9k6?CWZ=vuIlZe@UVC=NGAohRL~Q1V%xZpO0iv%|aviPyVr0Z;czDDq<+4u{4q^A& zG|j!A%+w|djoAf2Ax$8@xg&v)$tpyFC7;vu^7(C zPkWAhK95DjMzAvaK7&$*N16?p-oDkxj(w49Z-0Ibplwnb7@L663Ol?|xQ8SnVu#;~ zMr*^IIV~%@x=wYiUAuBEFr1W#1?-I#6}by2g$Q-AA`2HjWM$e89XiSS^{c8RVgV!R z4TuqlG%?DcO@KHUXf5RPITkN&u`+G@_n%f ztOSb|&1PVr)V62Or)=8v^1l*EfvO{rQUEq7=#1MDOrAWEo}Qm<6O|ad($qA)4R{*} zv$dXLGUP)!L0e%(1d$W-5fFhFjUad~Impqv_rqMJ>5o<}Bwm8jZREihDuD0KW9>brU>r3nIs zG0EZFT2ln1SOz1wptIEt7$bzCszlr2@h9~>JJd@I2N6;l2t#7r8;A$TLu-8Eghcug zjPX$%57)ZZP*NpQ8z>HGrc5%ppd)3g#*(brMWUvFHu6Ky>B&nUZz++_3H2yW2N9CD z+gYOK5uCj`{8FF_2X72dYr}yV3maLK{N(NuwHx^M{IzS9tOK?H_s0L1!aGafTnFBo zxB+L0^h>CKBH$-}#imjyOdAx5hdE26G!UbKvQ7O*Y@;uNWy})k0`8!c0R*TgVOQ^t z24wsKS{r(M|K!r8f%vyzGFsc!)c7}{ukRYS`3I)+^&>B+!BGGJ002ovPDHLkV1l2; B97X^D literal 0 HcmV?d00001 diff --git a/src/icons/export.png b/src/icons/export.png new file mode 100644 index 0000000000000000000000000000000000000000..5c1f51905428a5516438333f4ba59a42b6ba1696 GIT binary patch literal 1931 zcmV;62Xy#}P)#wsP7;z-1&IPssO`2@)pl!JZRl3VmPyK5RI7B%E>T3Ywl#eLt7@R=mPK_} zrDX!xQH3Q7Ei@5AO5`LbCr92Sk;uz=d(LxhhRmE!M#9c+KlL|r&HX%|uIu{W_dL(d z&z>OeK$lluwDz9)?2L(9dmZ<@V(!b2a^ExZ*!HN7W{k9uy&$b+lwE49s? ztgWss`m***Eh}2CK5stp-I?Cjxf&3(#vB;BT`xo)GoNm;$Lz}lvmaLeThcodc`ll9 z7dr4xRu5K|JQ%#?Z^IwG7?V6ipH{Bc^t>6GVV|z4xlJW|^vvu2JTpO**k>i#ojfxJIYO zX-xK5J(K>N2A+LZPo_Sj$J3uu@Y*6 zJ-k)8a)zWV)l{Zv(wbByCgtnHoh5p6{bpI`g{kkZzG}a#yCRZ0Ds*F8vAmfW-%N8p zUaz7`slqMoJmt}xWqYOa^{O1#)72AtaW@=oM}}+ZZzNBuu3i30BNnB}rvOWLuUEUo z`xP=PT)_z;YW2ta)NgW(=B-+-8x@t3B)_Sf%v@zt>aowHJ(IMeEq~>1INlS(pAatP ze=SvRSNw{-I-Kd%k14rUs&khzbpCRN^70(2z2TN5nUXwy$?cQ;l1^UnD`EalDgQ4j zj_p*{2|9Bpc1Q8`^^r&^A4u*4O5U|uf8Kmmcfv3wuU~Q-lFKL6*2yPn(nmQuzHh1Y zRh-^y$&x#M2Wnhwa5{m^L*NN!aBnx+x%t$1xh{c4O`SPSC$A z6P|4QMijK8DZaReh`n8~nKN5RwyjdxMosx}yAGUpt0ATtXzmF#SGh|nu9ga`q%uQ# zWnr!kZJi@+cuvz>@P3mMc(sb^l5+Nz<+>o}dk79^$o*yPKT}Kq5MTldv_^o>Pn`mj zF}yG?wj1jX_kl;-GqHcmDJ>zg$xpG%%Ql-6$oe;ULWt>8MYhdBwHE-?&{!bAZ-V!x zc|f&Z=-&&Pca7nnXIs;6bocw>LYUNK0Mo*$oC0iqM+TIa(>fYDggQ8$=?3bJ8D@@{2RJ_Bww-tS5JZ`l$hQXWM8p! z-3=B?V9$;E6Ynzvrh)c>cefix#kMCYbuh-mt$4kcH6a9=HyS{Ynw8B(pYsQ(t|l_t zpkt_=V;Qvs0cQPv*EbI|{_%4l2yP$rXb z&bqH=fzL;)Hg0-^<#6+(zRNHnjsw@`5F894&B0nHuLYcCa6HY;#-w6aEzYFS z?t^aa7&@foz(?S>jot|bJ2Ot3K58<+j3nj(Ck3`_3d$iU=%#L(g|>j;I(Y#{DWsgK zW&P$t-uobfx27Ip@r+~+tlk7^n~7_;jU9{fXccuYU0-a?%dM@6G{wRQ%kk=M9i^Q4 zQpQV)pSDErZz@&3TRM?r>hFiE^!8e(M$I~>L8A}p*Tc4GMC>P;HF>^1U+|XBZ2p7F zQYJ_luS(gkOSx0()K^C?V4(@-wXhtVxx2&jEgzi;uD0MS zhR{&J0!9rO<=`s7gQOz%0y)`lsQGQ!_Ujq4Vg4&)CWP(u)z6x;H!VLp=naPa;lWTU9qFe)q-RE&QjiS6#!|rtH zQW0d9!sSZHsf7Zdh5%S;0xRr3wW)GJmjU7J!rPpqI^Roaj-R3{UYs_c+mYuj&MP+Z zoYiJlA!J^=Wn`;2s^b4ae|Ta{5WC~=ZFYJDY<&#g?F=I$;2{e{@;~zP=RdG*GViZC RnzjG{002ovPDHLkV1oU{ux$VU literal 0 HcmV?d00001 diff --git a/src/icons/lock_closed.png b/src/icons/lock_closed.png new file mode 100644 index 0000000000000000000000000000000000000000..6de207db7db063f910892e66845bf3f109c9be79 GIT binary patch literal 1401 zcmV-<1%~>GP)Acx%bY@&hF0cvg)R2iiVMyiJ!GWqJc(cX`+&lsbuOx2$?3KC;=T-eo_W~VahfgfiE?%el*JLg>f z>j?g0=FC|ViA2iZ8Zlz{tYO23JZGD(=cf@px(v(EhI#m^*jbwEFrC<06J#O5@+H2Qtm?7ue@856# zQc86SgbW0n=bw0D$lCh)7e|gAJDT(7&!-O^IyN0R#Xrsb`O8H^!-ie^_aE0gcmAYT ztoZo)qD8AF8uYbz@dqOt8aAJ4Y&@wiT=-3I*|P2U^5q*s2F3K71qUHZr^A;^yJ=36&rAt40)(q}Ed-j^%yZ5NKa^+9+OcDw-oAa0HlOz! z6k`T#YivBBo0?km`t@IYV^EAkKdGpwnCLhGqR}W)$^-NhDOID{k_~2y+ErCmFWtG* z<^UdrgGG@netWeeg!Qx#f>^98qp>a+6eBF_YAhCO11K*Kj}$`J8vGfDBFWkjA*Cu; zN@3Q7B+yMi(M~w&nQK8HOdA!bDK?{Ufv;YzaV(^Lz2{7@)1IQ;j7KVKtKqSefl=ngEw!gJ3GfWrM>d&TRT^YB+&D(d{=+oyJ&wHE4B2i_J>bUjWx65VgOW-b z^pRfxA^agR$QoWxjx@YDW;Fv(^5Lh~nX)!P{rVK|Y-}gda;^8;Z0r%;;3YwbJQjr_ z)472v0WuECkOnEp+~vgK+w3?7)xZGY$8)gnU=rdF{GtWOBpQ*YKmh^DFQEDimkIxK z4_zIai2pDL_-niqa1#_R5CfS4O&*6rkr}^$XC#eu?`m1hm{i8BLrE^TfdHn~!s`+Pr@Y~#s1*L!?fWUB1_fyT2{?~D*u-6PK9A(0kWW6(2r7}vL(I?v;a#3 zY0y3l?E;2K!-FIjTXF>k0>4}aVgkYeC<{X95oH1bHfWtEe;Wc=^bQsoz$aW#DH0dr zTyBACa&Fy(wu>5^fM243fK&Rr09*Kjz24!Z!O222PV!fmX-|RUfB-TQ(!Xoy0)~aa z)AkdxFO~(`0U=A-1%PcsxD3idzMwDg zHwD2daTf?7Y!SAh(lYGF#DWSN%M!LhANh|Ul}yGmoi%kK>lw7iV~MaeULry=ekI-S zE@+Q-Y;4@#{7G4Pd8JlLQ7{5c=@CL$S@&l4?(O!k`M>24(#9V>1QEN`00000NkvXX Hu0mjf+o_Kp literal 0 HcmV?d00001 diff --git a/src/icons/lock_open.png b/src/icons/lock_open.png new file mode 100644 index 0000000000000000000000000000000000000000..23ce3243aa2e0b81298e819114fed166cf8f9d57 GIT binary patch literal 1359 zcmV-V1+e;wP)7ym$B4oV%;FQdCroNRgZ@mCBS-2g;m^=4^!qh6Uh%0nuMk6quo)5E5w! z0<0`V0jf+iM`@-maj4+XrRt{BZTH^y-uK@3oYN}@nDgFtHyqIiJ{-<_xt#C&JkNPU zjF5(g*Q>NvD-(&zMS;_W5KeFJy-RoQbRWs*z3+kRi~zw1Shj54vdNPteYAM-!rGde z@x)?rLLrBIK1X-=Ee;<(eDU<@6Q2NkM?Jvu@>96EH60|)lM2W+J@IFyFQ#tpM(&z||+;>Gplot-^&baZgyL~FXO?T^;> z_O{ExJ|RRX77oX$t*ymzoLAc0&z>|!T@GX@1tnO$dZRODO!*JZ&Ffyhd)K40vx8Ho zj{llU^=&prT~ta3s0s0S`DgX@jVtTw>KHpV&Xz47pSyD9(gNTfkHX58Z#8b+y36d} zf6VOI(PEmK-u`{Xisr`xdC(=7<&aslXwf@?45gq1Yu9et zSyh#2Qi`1Cr9~>0Tm}3_5t7MUQ)bL~{!DZ8hDsqc+qZvu6j=C3L)g^x?i0RJ(r90U zF~A*$Kq>d@jT<+wpE`9i`}XbeT3dg58u*+4iu(Gcn|ANsZ!TWEWwvem(kxi;^1?v= z%@CuEGTi9z?*||nje&3~7=qCcpy|zPi4%@voCp~c_C^$7XJbvo&-t^3AO>iPgDJ9) zkoPWlm*)6g?cDrpEZ+5Vyb$fEeKvY0<$5?W6gmqehaAFPYsP>6+)L9pS0th#tu!F8 z2&=GrGw8Wpg#alO+8DGl2qAE!z(|K|I!oKJ^Lv5yLssC)iPdk+ZI}}xRt+i#CLibz zUbPQW0|rbE^nE?Zmw|S`*b8GbO8|&Zs@y!N5X$u1DUH%Idv z314HkAfvOWs1TY{2jRquCMWI?y6iuL^03id*>~AFlU~Ip_4k()*0&ysbq&QN7 zc0j0M-U3HLH1g0ympz(gq2b*EA%r7h4pfY?afy_|3FH9_Taa2m| zG5F~U+|-3^$r-ra)$_r@FV4IljmO6rtu;jv7>17!LgsT<^Ea>G-pT)se*mfny+@Xr R#&07~M;lBZ;x|o|( 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 pM>wwIOV-qr?^OfqIL&E#$iGq+DUN!abJ-8 zG#_n~d+#|iW*8#Cv|u&C`0ZKx&3VNbscQaQOU2HVMF!@#-^& zbEhURUdY7ITu6h*q88tKpF%7b*WT=Ad(S{~iLM8c>J_P#GU158BmeK!T1WlOhPi1vgG)snCey*8pJYoxKdMs0DK-St%xjI>m* z9%6#LiM|E`5IY@!f2Pjb*{khP|Fp{H(lXs2J0w6#iX(y;7^SozK%n1DVi3wE00$}G z7Z#bCo<_Bo*6+1xeBPk3@rBmL2Fd@I`ujohBM4W6u|6I6McWeKsw)0y;>2e@?RJf zBo)Aq38V&zfS8d;AOR8tCqi~>Cerl6ya3#(p1CGwX91FdNdcGwwuZc!0p9N??mY0C j!`TGhaO4>=V#J6)NhJ@SnNAkS00000NkvXXu0mjf%u*jv literal 0 HcmV?d00001 diff --git a/src/icons/send.png b/src/icons/send.png new file mode 100644 index 0000000000000000000000000000000000000000..43c3d7922c15e1e4962264322228746d54162413 GIT binary patch literal 1345 zcmV-H1-|-;P)Nr3^29?oeI`6Gvz+ z8POr?ywEdVbFqLT@JUdiUM|VeO!b!b{G}4@g81KpBAq5QsAgeTzZ@&q0hK z8w+)NeHvR7_l`>FUmUQa_C^L(7WbPoYx`@7s1o3XoCB!D44V7cIL2RI&Z&&XRSM-e zC;+7Zh3i1*Dx%XdXor+i>^$OesMY16u?Zu};K@hF(yuH}-GATa+9;cZKy|J!VK(#} zOcWDmVvIFc*3ky(sEz_-6d4VkUDH~lBcWFTG`D*^_o2&umm03A6sFuYoFo=+#`OAy zQC1p&4Y>qB>jYN`^?OdR=A#z!(>{LS4DiB^Ab5U&HMjWWrF?>v zLT3SiAOz)jtlZ<^Ifk1D3lB~o#l{UkRBYX{e+Dq~tO1M&#t2~WEddFhSd5|zI;zpX zn=1eiK>>bty>ze%lS7nVo0)?wnshH>Wu zKwaHlK=10t4hRlHo@)plgKu#yzDn?vvN(8Xj8?=-Apio#5=C&w#SW84xZtH(zwt-b z)P3EC7rc;L0D;za&CR1rxO`Z#HC8yDi{mJZgKM$1V`t`XKEdvTS&9^7w175D9_uru z3c_@XZ99Hq>a$&L$>JdYfOG+Li%}b9#uxrEUJpUly-@uYg#09V%rM7(r(Zy$b>! zpE{EK08U3Szn;u8a-f|XU&wVsQyu0TH|^)1d*0<}Q+o}0;bVVs-T(9%-9$#;fHujQ z)#S`)l#odV^e#!?UBC8LD*A*>Ti!q_c}K}#G{M4I=wU-*1MK|l zfb4HLEKLWGNOZbYc6{6@qiruhFmE>{)t6exfu0BW_|rx?*4!+|jvbe|wVz0@flFiZ z7p$hVrtDvD$@?ll3KtxrwEA`n-KG1wV9C{`wkw|g%vLEIxgw_b z!nKswR$Ax@itcLYvhxwv(W-mlsd+fgD?rS-s{i#HiY29}8D+p600000NkvXXu0mjf DT@;2) literal 0 HcmV?d00001 diff --git a/src/icons/sync_sprite.png b/src/icons/sync_sprite.png new file mode 100644 index 0000000000000000000000000000000000000000..d9c9ce0e41b6913950953db53c89456115f1aa03 GIT binary patch literal 43485 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 GgZ=}*B<$h< literal 0 HcmV?d00001 diff --git a/src/icons/synced.png b/src/icons/synced.png new file mode 100644 index 0000000000000000000000000000000000000000..9fad3847681ff1f54091598f4d2b47cf65098d82 GIT binary patch literal 560 zcmV-00?+-4P)#w8=EuO*D51z%D*Fp^WMwFp$da3*_HEjW$p4rAXa4uxVey}#LZl9^NNa|{%cKh~|3z9J`De!e z;^T4uxbw80=uNTwI^%K9|1&=){y+G==6}jz@Be&x2HUx_GSuoRZR@1qh z{}+EP{9kr9=Ks=X75`6sp89{sr<(t{C;b0Q=38D6Nidbc8OXwsHXb%pod0co*ZKeG z=V||UyzctH{!QioqB8;iW%C{GOU2l#;Eg4@5HEJcbeBC<=cE6xeo^y(@r&I5CFcVF zYZSS^mJM|`B`TdL`34ob&hq*{>1D+Kl1o1Sb&I_}EBOYx6P?hsyd#AT(n23Z9kKs! yS>yjx#VtCH%yON-fI|L z9sV$#ZLnRUCMBn^uQ|oR*z#nV*(65BClUhOzO|YUE-Y7NU~n^=Y0W1h7!7nKgQu&X J%Q~loCIG2tN|XQq literal 0 HcmV?d00001 diff --git a/src/icons/transactions.png b/src/icons/transactions.png new file mode 100644 index 0000000000000000000000000000000000000000..ac955c7291d8e113bb6399264711857782f5813b GIT binary patch literal 1343 zcmV-F1;F}=P)8ff$fQ=%$rvKHt6{cjn~I9fo`FZdgDB)L9PaoSl2m`Of{GGjI6M zi^|M1&yF^F-OeFdtrnC--5M}lEl(MNK?c3wPfdrsEVqQIP^r^M& z>9ySK3f4jDzzSFksepAsgP(@A+_T=gd~Csy*;KMM62-NPKlAllZ$BRaw3?OX#J!v7 zjZaYPW=WG=qQu7J5rDP9#^Sj+02wY@DLyL+4C{BIYxN310^ppsoleS+!1dpOkWhkk zQY`L5Vw>6EdyT#XVDa6crVjLmh-eo9D6JW!iuXVGo~7$cpv(NOE&{NU^VmD(XSD)n zs;rw@<7-9$D8sdzmYr*_@#4NItP`Y^K$U{O+2x3WYNB}eqszQ^ZirGQ0zl9VQ(^3` z5oYfh;~x=mpcIqiebR4${1*_Vvo5s`fHY0%_j`asL`af^dc95%thMxdy?plK_=yyJ z=fv-LbhJTgEmlks0NP-kioAXP*%!S2#+%DUJ&^hNE$rL(96>mD?mWki9rwUi2T<&a zZnw+s-H+YUN0HE&qVp6eMJgcxCMGA?wd)aIAWc&?Y*U3jv12F37+~ejgF(c3 ze=ry_H8q{l060;gR1SdFSWywc#*Ncn|4b$)$Jx7g4}V3R^Xe&+bbum^saAOkG^v9c zx0CWtGwz*}z_klSU5J+zL@d?{&1xlE7r-R>FQ771a=XF+f>H_~T4VfLQ1Qh?A}E|Q zSUVsBgCYf}gj5uvKAld7D_1U~l=ewltrp|s4tq)VZQ>ZA!a+2cxaK zAy9zQmIMk533rEpfc|KdMW?_f3vojn%d??rLfoqA}dq1-<9Hxwp zuA$%Uq5vy^HY=M@!Yge|e9*Bg=AU_47vN04@ zZn%}*4uZALpAXK(-RAskJ@6m=<>xKpYFQp%D@OrFW1WB|O2%pIc8?zL3AHxVY9@dp z?lORhQ{bHUgY99RjZLVvDfNKFqnHa9e&EcRPpMQAhQlH2*RNyy_U#^oF$tG0UE=iV zPkfJv5NE$Q5dawlgTa8A+08sSe;?umC!mTyMh5GMa`ECKCr^Gzqfz%K*!=w5EdUSu z#KvfT`Q=wmo%+}VTzU4Z^6!JsQLT>f(AN9oB?GNjX~Mwy)~$1#II)0I%JXQ9@w;$N z{8-M+Y~t9l!;$CQNf>yyxdsfBgmDA~VGPSn7(Yw3TJ;(QAswXH(2%B@P_I=(!F=HY z0MEIz+5da}A&6kKg7QIx&HyZRdUS3qF|+~%l{gZfKmX^#>`UN1vw>ehoD1tjUxTM_ z(C>pZ$_J6s?RJf?zN_)%YZp8igm^moLFdS2i4#krI z$;jMwh4UvwP?AF(?cI$?5W=j&A7~uy_o{IiB$|jyL)+bs4M7M5A}AXh=TM`YGGv62 zT{%z2?XLYkAOC23>$=|cdu_MQY_FubZ@;zsBku5%- z@9C8*SH9l>zg6)hz~JEEg|6#fFCy0gmmc+?L=FN^TWg0@bto7NzIoKjnn3_bCX?41 zV{QjJk5&L4*$xa@Yc~ah!L2~UCNM_`uw}~@|K#N4jjGxYe7I2sH3|`VTU8$i9t;Em zf2!ACc_%0n6BEP01@$^US`_-6uLG9=AFtQnVXwhdD)kAD7D@zA)yrpL_m-+|7LmuZ+3fGTySv}>VpJIJzFqiiFHIX78ag|d z%Uumz4O|6$z+)^QnMK@3P!vFbPkPAzzP0w#!C-JZ4IGRBY}>Z&t^ND=|7~Dk;2}WL z>GTc2FRR&=HrsGGe7~xu9LIUdYql}arJ7I?_NBNz<6LW3VZ6bjADWHOtLF~9BU z>1iqW-{i$sRSiIYfB$(vzlc2D+uOU+YuN@sM3#8Wzs;*-udH3W_AFz}3*@W*BER4N zd4ND5FbeFhW-lTJz;)fb$=B#pR5cw6g}&yc{GtG-dyMxLkNG^&*Vnf+m&?7Rs--_b zf64XMYCcr;KcP_QeBj2C+ddI_C=?3aUCrJASZh5AAR-N`0k_?D+X`##^W@(IrDZJZ z>+9E92B!#|EhBGWGXc&-5=a&Z3q`G2jJ&kLbYsK*$y z2{^S3E(`<$14Y9^ z&wukY#a@@mWFD&|f~YF#bozI|HC1BY83+Wtc9s9ur>c+%(d1=g=$Kkm5?AV0C06_H3}&dA8fBOG534{(j^x`X}w{cR?ZNcezL zs#%E0c(pv`jEsz2DI&+~6#FXIb-PS=cehKS?ahR$dKoGohT}L-8e^`f^6ROoh{)}+ zSnM~&CUC?cq5?Io|3C1+18G&g1{kfy{%D}8;b=7aBRDh;s49S}o>6Ooj^jLUt-XT$ zqDUq7sOlBg+C{lsZsFwQLEO1@-bXD!h<#G$H zwTp}~=c?+9(>;cWe9Lhhr+8yd;o&kOGUG#tNC)|8b4@eBfq{WPuUWHZxzFc&0$5y@ ze2$206p%;6AN zo(D)I674_|IEO>Od>e2v&;_go{NZr;qpJFIj;tN7h};;BMyFj_noSeHTHA=7U;x&w zTbFYj=VsssWl3+gx3@nB(9+U!3vljCezMuDx~{vQBX_xSz?Y-Z=p!@P7u%ZGYTb|; zP()QV7K`1Xs(l>lTpuZ(74Wk4J~1(&@pycXi2R}Cc2-2b7>mUot!7_r0=v8f+^8l{ zj^jAd!X`&nM1D0DoG~5MY}?w}EP%DPXg3LTN2Aflyp(MKvf1owUNWm{wFy(rIF9pc zYwhxAG&&5BNF?T~>Q&Y3#>dAMVD8+x3E(|d4aQ=zjb6*0+8$4*)BAv`iUa>p)ugIE z77PYo_F7Oio_+S&Ihjo6V}+9^oxtTxvtm@r=;&zMO*h?i5Ma%kH5bI=@xRZe+$jN4 zsnjzf^4VF&{cj*?j7d&ROuSsa6EqXGK5!`_a+gj_1MGV0=(9Mqw@<2 zpNoq_YgMK6y1~3ruY;)}r|Y^q>vh%yo~qZulmNyUPj7eNh=f$N zeD2;Xo)MAgjvYH5Z{)GsY9~b{olajVBCAz(CHYy|u|k2Zs=5(Ku3o*mA=`50%<8Q0 z#*G`70G}&}aTyIbY+c3}@Pdd8ipZu_t5!|7gw`--eOS6kB9WNu_xl&SuDb+SQaEF< z7-$Dhqw?M#s9H4=%$seZqIUN)PZ2Vkuo zJ#gT_XmQ+ryl~V6_?Tr~#;{X5v07*qo IM6N<$f*YKb@Bjb+ literal 0 HcmV?d00001 diff --git a/src/icons/tx_input.png b/src/icons/tx_input.png new file mode 100644 index 0000000000000000000000000000000000000000..a2d324ee34ace4ce3ad4e5c7ae2f9eb6b27ff7a3 GIT binary patch literal 1114 zcmV-g1f~0lP)0(_^6zj0e_#OL@XyhOy;My9MU1`JOmymBLa)rFq3hCLveu)A?p|2ZTurdydJ3jIl>3 zhFc<<@B+5;X1pQ%_G~f%J&HiTw)HPhss6aNgwn)EMAs`$qcjtFjjfU;eEdE7G!-}A zGbw%1NtrLBQbzM*&q+zK=Y?-%be5cmv>zjHa9rtv{gjkoK6{7BG;)}dfpg|#H|VoE zm`p1Jc1bD1;~}fi>)WS^}q&3k)g(hiC?@73_?$z$6=I z5jMs~*{{h3zE!5rA&HOd~zW5klV-OMT@4{q)@Iz)PUl^Z`vy`o50_J2(z%|{h zX6b_B7@5*FSGci6U$iM=~Ptsi;Zw0$1kYKGBYFngUTA3Mvr;B4GHG4WM)DUZt$ww)Z{lU03uU`uwx>o+rQe?z|u8 z-d=a@b4|&L+u$*ySJ*%fjH+q(pTUiRDB5rowbdO=1Abn67A3}TZgW-9svq(;99YJ= z>|*#L4RFol9Cowsh$^H9Q-s^x31h+rUr$Omb`|qGoWah2^Z~1JQK1c59{N6$UF>1( zN1o~z_F_b3k0kKap0=V1uZ8}eP24sf3&mw?5 zAKlbad>Z+|U^HP0iq>)_J0rA^@nNh3MR`$cvbmh$Q{xZ-gYi|_4K2%YFF34q&3IEK zOcO1s`H(wiRSs7$Onqu5Z9-wCX)NWe7?IgrJHOr{6@>h4Iq` zdk9t3G2CtuI?9gB z5b;Y{6~=YG;TC<18Rx05?J6iO&KB{7Oj{Fq)ruvecL|fgV9Kn;(2Kp zYQc*||1wsJ(h}mmg*l=ln)fyy2W9;-|5fF%yTu7UhP$GzpECt7qZ#)l0XO#U4hHFn|_|@s@_} zmF~ewYY1v#2tOG?3;rSvyWCYPf;mDatYLg?Nk&RTl}p;O_nJHXVAO&wDpFI?WWhJk z=qoOIyPRWt%5ui8&7I^U*vah9>!76jA&Sm42>K~^MY`ohzofmGMJE)^2#Mcwz=Ub;FHeNYZWphQq z7@FwRKh$?=4liPSU(r>%j%*!TKkutMVEY=L#-1R?+Zo5>d_i@HdTXy2YVk_fXsbG7 zw~vL>fGkXjw@=&#`y@P0kVEgP>|wU945*X6yPhmVi#CcX4pUz5ENJZYTVIEyssPf zXz&Hm4_}#V;}* z+o-)}NUhg6P8kDRi1**A4r%Z^rEYJYD>be&G^7Q1)gQlW@cSxniRbiOkIyyEb9mHl z>fMjyGF~0BRJPPLzLVXkGoG-4R|9ZT#^Z!=Oc9SB>Ht{OMS3cM*%*v78gs20WIKay z*KT2eM#nMIBluHi)cpJO+jtr*s-DK`@QfQR&sMp<)@S-oyX=i$}tsE~P2p09NrI%K9roAG5QEP@7-W2gij9yX&^uaL;eobq~ zIdZN2Kn>6s)S&3ZA;0-nD|sn*OhS)}W1#2EU8B#cJEZ0ZE>#v0z*~vp&1lAdLypuv zPtfM(dUD(RwLtyo>z3M6HGKi$#f)yKt~UCl{IRBs@(6?cn*Q(4-yYI)TdB!mD*ylh M07*qoM6N<$f;~pXivR!s literal 0 HcmV?d00001 diff --git a/src/icons/tx_output.png b/src/icons/tx_output.png new file mode 100644 index 0000000000000000000000000000000000000000..a7c5ebf56b0e41285e95bbe35f653f4bb4db6cde GIT binary patch literal 1107 zcmV-Z1g!gsP)Xc;a{Vda5p8_%t`aUek^t+!V@QX+-;OTwwuq#CX0jIY%Mjl{F;)l%wfL4DLL$& z-%|44P6VZIpcEoqjbONjQi#lR2tpivkW!HLA&A(Glz{!g@41_Yc$yL{e*$`E7E>-- zCtF!>W^zhwlvjqc8Y5n%KgmotwPx+V|M}{N&^xwJvUEtV=N(=-dKDkZN4S~4W?jJQ zApZqBC>foIT_;YimoYv-v3eItYLz<`7o*2ftUf~s9Gc|>wg3%dRF^sty$#v1hGNx( zP`J+;DF&zwN|K#+A4WE2KE-MdLg8lX1U9%=C-*P^HHF!K%>8&fwb zdQ?fO*R1CUHrY4Uwi1NmPfHu=Pr68Qr>c`mQZ+aB$A$Qgbpq`O$*(Yr`7BrHm3-CA z^@iXqHCxFA#nYC+R%-!!k$3L$v?a8-r8uJmz;I+bhMYWcRieDxaUuz)pVRX}B$4{r z^P8T3!FKGyM4U6-F>~&Gs}nu=lXU_gAt%voNBb3bN0(ia6M(azX>$pH4h%xN${Yvk!f`~<@9ZZai8eK%2lrT)&x7cL z#zX)a+!f91_5#ec2#FKf&IE;jaxV>E*;)!j?^lWQ(?=gfIy+-sSuueWa~})%EIBYWmaBdy&a3qFCL7Q23O!m5RDisr`4U8rV!N#i|~m=+%_; zymBD=sgh);qIV%1-fSm`7Z0$L(o5|K!px-~rZ8I}NzQ7fSx0tnTr-UlOoqCBLhrTo8&0_9g7bRf7 zv&GEytB_w_e}96$Pp@PP_w%=m7gL=)!msoeF7;<|G%gLV+^=dL+dS5*OkUytFN%ta Z{st&W#y17AgX;hQ002ovPDHLkV1oC_4k-Wt literal 0 HcmV?d00001 diff --git a/src/icons/unconfirmed.png b/src/icons/unconfirmed.png new file mode 100644 index 0000000000000000000000000000000000000000..cfe1a1c8b8fe5d66d4a29e4b5f3cfdd6294064c5 GIT binary patch literal 291 zcmV+;0o?wHP)O(_NB$rAU;Bzd z2Hh0l@>{8AWIPx&%o~^gJMiDLhk*k{9%!U6&;`sueNq{Z_xz99!@vuZLRYBM{$u-p zt0JJ28L&B3G5hhB|7mv_#Ifrajk&zxf59s@4WLpifYmf><^RgBY`Q>;umWD+Z7cqJ zY-QkKzybI|4lnudIu96jkIfWK3kDWk3OMZB!mpWUAv}l?+##1{{CC@g+YLOP pn@hgiPh#N2rGSxvk3kYOvH=}`LP{({BNzYx002ovPDHLkV1m2zdgA~9 literal 0 HcmV?d00001 diff --git a/src/images/clock.gif b/src/images/clock.gif new file mode 100644 index 0000000000000000000000000000000000000000..31b6c2c752f0512bb67469b8a062302db1e9046e GIT binary patch literal 44663 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

m|955OOey~({$bM3X+8~CD)$s@4CNuOs73$ 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 literal 0 HcmV?d00001 diff --git a/src/images/cryptonote.icns b/src/images/cryptonote.icns new file mode 100644 index 0000000000000000000000000000000000000000..1f82a0781b629a6e0a11022336bce3adaea29801 GIT binary patch literal 199156 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�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 literal 0 HcmV?d00001 diff --git a/src/images/cryptonote.ico b/src/images/cryptonote.ico new file mode 100644 index 0000000000000000000000000000000000000000..8b6a715129489eea75a2c88a5640c5d3101ec0f9 GIT binary patch literal 370070 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Ʈzl{09Jfp`b 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 literal 0 HcmV?d00001 diff --git a/src/images/cryptonote.png b/src/images/cryptonote.png new file mode 100644 index 0000000000000000000000000000000000000000..cace7edd95e5efb2cf4cb1e2b22c8d5b0a08a072 GIT binary patch literal 3961 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 literal 0 HcmV?d00001 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 + +