Initial commit

This commit is contained in:
cryptonotefoundation 2015-04-29 20:03:08 +03:00
commit 04bc8b699f
116 changed files with 7692 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
.DS_Store
/build
/tags

201
CMakeLists.txt Normal file
View File

@ -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)

4
CryptoNoteWallet.cmake Normal file
View File

@ -0,0 +1,4 @@
set(CN_PROJECT_NAME "")
set(CN_CURRENCY_DISPLAY_NAME "")
set(CN_CURRENCY_TICKER "")

56
src/CommandLineParser.cpp Normal file
View File

@ -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 <QCoreApplication>
#include <common/util.h>
#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);
}
}

35
src/CommandLineParser.h Normal file
View File

@ -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 <QCommandLineParser>
#include <QObject>
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;
};
}

265
src/CryptoNote.cpp Normal file
View File

@ -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<const crypto::hash*>(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<uint8_t> 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<cryptonote::tx_extra_field> extraFields;
std::vector<uint8_t> 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<unsigned char *>(&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<void(std::error_code)>& 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<void(std::error_code)>& 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<cryptonote::core> m_protocolHandler;
nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core>> m_nodeServer;
CryptoNote::InProcessNode m_node;
std::future<bool> 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);
}
}

56
src/CryptoNote.h Normal file
View File

@ -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 <functional>
#include <memory>
#include <string>
#include <system_error>
#include <cryptonote_core/CoreConfig.h>
namespace cryptonote {
class Currency;
}
namespace CryptoNote {
class INode;
class IWallet;
}
namespace WalletGui {
class Node {
public:
virtual ~Node() = 0;
virtual void init(const std::function<void(std::error_code)>& 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);
}

View File

@ -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@";
}

105
src/CurrencyAdapter.cpp Normal file
View File

@ -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);
}
}

35
src/CurrencyAdapter.h Normal file
View File

@ -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 <QString>
#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();
};
}

216
src/NodeAdapter.cpp Normal file
View File

@ -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 <QCoreApplication>
#include <QDateTime>
#include <QDir>
#include <QTimer>
#include <QUrl>
#include <wallet/WalletErrors.h>
#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>("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"

67
src/NodeAdapter.h Normal file
View File

@ -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 <QObject>
#include <QThread>
#include <INode.h>
#include <IWallet.h>
#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);
};
}

225
src/Settings.cpp Normal file
View File

@ -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 <QApplication>
#include <QFile>
#include <QJsonDocument>
#include <QSettings>
#include <QStandardPaths>
#include <QTextCodec>
#include <common/util.h>
#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();
}
}
}

57
src/Settings.h Normal file
View File

@ -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 <QDir>
#include <QJsonObject>
#include <QObject>
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;
};
}

32
src/SignalHandler.cpp Normal file
View File

@ -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 <csignal>
#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();
}
}

31
src/SignalHandler.h Normal file
View File

@ -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 <QObject>
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();
};
}

432
src/WalletAdapter.cpp Normal file
View File

@ -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 <QCoreApplication>
#include <QDateTime>
#include <QLocale>
#include <QVector>
#include <common/util.h>
#include <wallet/WalletErrors.h>
#include <wallet/LegacyKeysImporter.h>
#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<quint64>::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<quint64>::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<CryptoNote::Transfer>& _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<quint64>::max()) {
Q_EMIT walletTransactionCreatedSignal(m_lastWalletTransactionId);
m_lastWalletTransactionId = std::numeric_limits<quint64>::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()));
}
}

103
src/WalletAdapter.h Normal file
View File

@ -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 <QMutex>
#include <QObject>
#include <QTimer>
#include <atomic>
#include <fstream>
#include <IWallet.h>
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<CryptoNote::Transfer>& _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<bool> m_isBackupInProgress;
std::atomic<bool> m_isSynchronized;
std::atomic<quint64> 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();
};
}

1
src/cryptonotewallet.rc Normal file
View File

@ -0,0 +1 @@
IDI_ICON1 ICON "images\cryptonote.ico"

24
src/gui/AboutDialog.cpp Normal file
View File

@ -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() {
}
}

28
src/gui/AboutDialog.h Normal file
View File

@ -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 <QDialog>
namespace Ui {
class AboutDialog;
}
namespace WalletGui {
class AboutDialog : public QDialog {
Q_OBJECT
Q_DISABLE_COPY(AboutDialog)
public:
AboutDialog(QWidget* _parent);
~AboutDialog();
private:
QScopedPointer<Ui::AboutDialog> m_ui;
};
}

View File

@ -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();
}
}

View File

@ -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 <QDialog>
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<Ui::AddressBookDialog> m_ui;
};
}

View File

@ -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 <QApplication>
#include <QClipboard>
#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());
}
}

View File

@ -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 <QFrame>
namespace Ui {
class AddressBookFrame;
}
namespace WalletGui {
class AddressBookFrame : public QFrame {
Q_OBJECT
Q_DISABLE_COPY(AddressBookFrame)
public:
AddressBookFrame(QWidget* _parent);
~AddressBookFrame();
private:
QScopedPointer<Ui::AddressBookFrame> m_ui;
Q_SLOT void addClicked();
Q_SLOT void copyClicked();
Q_SLOT void deleteClicked();
Q_SLOT void currentAddressChanged(const QModelIndex& _index);
};
}

View File

@ -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 <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#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();
}
}
}
}
}

View File

@ -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 <QAbstractItemModel>
#include <QJsonArray>
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);
};
}

46
src/gui/AnimatedLabel.cpp Normal file
View File

@ -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);
}
}
}

35
src/gui/AnimatedLabel.h Normal file
View File

@ -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 <QLabel>
#include <QTimer>
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();
};
}

View File

@ -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);
}
}

View File

@ -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 <QDialog>
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<Ui::ChangePasswordDialog> m_ui;
Q_SLOT void checkPassword(const QString& _password);
};
}

29
src/gui/ExitWidget.cpp Normal file
View File

@ -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 <QMovie>
#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() {
}
}

31
src/gui/ExitWidget.h Normal file
View File

@ -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 <QWidget>
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<Ui::ExitWidget> m_ui;
QMovie* m_clockMovie;
};
}

413
src/gui/MainWindow.cpp Normal file
View File

@ -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 <QCloseEvent>
#include <QFileDialog>
#include <QInputDialog>
#include <QMessageBox>
#include <QSystemTrayIcon>
#include <QTimer>
#include <common/util.h>
#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<AnimatedLabel*>(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<WalletEventType>(_event->type())) {
case WalletEventType::ShowMessage:
showMessage(static_cast<ShowMessageEvent*>(_event)->messageText(), static_cast<ShowMessageEvent*>(_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<AnimatedLabel*>(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<AnimatedLabel*>(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<QAction*> 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<QAction*> 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
}

87
src/gui/MainWindow.h Normal file
View File

@ -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 <QLabel>
#include <QMainWindow>
#include <QSystemTrayIcon>
#include <QTimer>
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<Ui::MainWindow> 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
};
}

30
src/gui/MainWindow.mm Normal file
View File

@ -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 <objc/runtime.h>
#import <Cocoa/Cocoa.h>
#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!");
}
}
}

View File

@ -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();
}
}

View File

@ -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 <QDialog>
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<Ui::NewAddressDialog> m_ui;
};
}

View File

@ -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);
}
}

View File

@ -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 <QDialog>
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<Ui::NewPasswordDialog> m_ui;
Q_SLOT void checkPassword(const QString& _password);
};
}

95
src/gui/OverviewFrame.cpp Normal file
View File

@ -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"

39
src/gui/OverviewFrame.h Normal file
View File

@ -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 <QFrame>
#include <QStyledItemDelegate>
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<Ui::OverviewFrame> m_ui;
QSharedPointer<RecentTransactionsModel> 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();
};
}

View File

@ -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();
}
}

30
src/gui/PasswordDialog.h Normal file
View File

@ -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 <QDialog>
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<Ui::PasswordDialog> m_ui;
};
}

36
src/gui/ReceiveFrame.cpp Normal file
View File

@ -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 <QClipboard>
#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());
}
}

33
src/gui/ReceiveFrame.h Normal file
View File

@ -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 <QFrame>
namespace Ui {
class ReceiveFrame;
}
namespace WalletGui {
class ReceiveFrame : public QFrame {
Q_OBJECT
Q_DISABLE_COPY(ReceiveFrame)
public:
ReceiveFrame(QWidget* _parent);
~ReceiveFrame();
private:
QScopedPointer<Ui::ReceiveFrame> m_ui;
void updateWalletAddress(const QString& _address);
void reset();
Q_SLOT void copyAddress();
};
}

View File

@ -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;
}
}

View File

@ -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 <QSortFilterProxyModel>
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;
};
}

114
src/gui/SendFrame.cpp Normal file
View File

@ -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<TransferFrame*>(_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<CryptoNote::Transfer> 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));
}
}

41
src/gui/SendFrame.h Normal file
View File

@ -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 <QFrame>
#include <IWallet.h>
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<Ui::SendFrame> m_ui;
QList<TransferFrame*> 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();
};
}

View File

@ -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 <QDateTime>
#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;
}
}

View File

@ -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 <QSortFilterProxyModel>
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();
};
}

View File

@ -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 <QDateTime>
#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(
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
"</style></head><body style=\" font-family:'Cantarell'; font-size:11pt; font-weight:400; font-style:normal;\">\n"
"<span style=\" font-weight:600;\">Status: </span>%1</p><br>\n"
"<span style=\" font-weight:600;\">Date: </span>%2</p><br>\n"
"<span style=\" font-weight:600;\">To: </span>%4</p><br>\n"
"<span style=\" font-weight:600;\">Amount: </span>%5</p><br>\n"
"<span style=\" font-weight:600;\">Fee: </span>%6</p><br>\n"
"<span style=\" font-weight:600;\">Transaction hash: </span>%8</p></body></html>") {
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<quint64>();
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<quint64>()) + " " +
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() {
}
}

View File

@ -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 <QDialog>
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<Ui::TransactionDetailsDialog> m_ui;
const QString m_detailsTemplate;
};
}

View File

@ -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 <QFontDatabase>
#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<QLabel*>(_editor)->setText(_index.data().toString());
return;
case TransactionsModel::COLUMN_TYPE:
static_cast<QLabel*>(_editor)->setPixmap(_index.data(TransactionsModel::ROLE_ICON).value<QPixmap>());
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<QAbstractItemModel*>(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"

View File

@ -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 <QDataWidgetMapper>
#include <QFrame>
#include <QModelIndex>
#include <QStyledItemDelegate>
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<Ui::TransactionFrame> m_ui;
QDataWidgetMapper m_dataMapper;
QPersistentModelIndex m_index;
};
}

View File

@ -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 <QFileDialog>
#include <QLabel>
#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<QSortFilterProxyModel*>(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();
}
}

View File

@ -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 <QFrame>
#include <QStyledItemDelegate>
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<Ui::TransactionsFrame> m_ui;
QScopedPointer<TransactionsListModel> m_transactionsModel;
Q_SLOT void exportToCsv();
Q_SLOT void showTransactionDetails(const QModelIndex& _index);
};
}

View File

@ -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;
}
}

View File

@ -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 <QSortFilterProxyModel>
namespace WalletGui {
class TransactionsListModel : public QSortFilterProxyModel {
Q_OBJECT
public:
TransactionsListModel();
~TransactionsListModel();
protected:
bool filterAcceptsColumn(int _sourceColumn, const QModelIndex& _sourceParent) const Q_DECL_OVERRIDE;
};
}

View File

@ -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 <QDateTime>
#include <QFont>
#include <QMetaEnum>
#include <QPixmap>
#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<void(TransactionsModel::*)(CryptoNote::TransactionId)>(&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<int>(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<TransactionType>(_index.data(ROLE_TYPE).value<quint8>());
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<qint64>();
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<qint64>();
return CurrencyAdapter::instance().formatAmount(fee);
}
case COLUMN_HEIGHT:
return QString::number(_index.data(ROLE_HEIGHT).value<quint64>());
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<quint64>();
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<QPixmap>().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<quint8>(TransactionType::MINED);
} else if (!transactionAddress.compare(WalletAdapter::instance().getAddress())) {
return static_cast<quint8>(TransactionType::INOUT);
} else if(_transaction.totalAmount < 0) {
return static_cast<quint8>(TransactionType::OUTPUT);
}
return static_cast<quint8>(TransactionType::INPUT);
}
case ROLE_HASH:
return QByteArray(reinterpret_cast<char*>(&_transaction.hash.front()), _transaction.hash.size());
case ROLE_ADDRESS:
return QString::fromStdString(_transfer.address);
case ROLE_AMOUNT:
return static_cast<qint64>(_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<TransactionType>(_index.data(ROLE_TYPE).value<quint8>());
return getTransactionIcon(transactionType);
}
case ROLE_TRANSACTION_ID:
return QVariant::fromValue(_transactionId);
case ROLE_HEIGHT:
return static_cast<quint64>(_transaction.blockHeight);
case ROLE_FEE:
return static_cast<quint64>(_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();
}
}

View File

@ -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 <QAbstractItemModel>
#include <QSortFilterProxyModel>
#include <IWallet.h>
namespace WalletGui {
typedef QPair<CryptoNote::TransactionId, CryptoNote::TransferId> 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<TransactionTransferId> m_transfers;
QHash<CryptoNote::TransactionId, QPair<quint32, quint32> > 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();
};
}

58
src/gui/TransferFrame.cpp Normal file
View File

@ -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 <QApplication>
#include <QClipboard>
#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());
}
}

38
src/gui/TransferFrame.h Normal file
View File

@ -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 <QFrame>
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<Ui::TransferFrame> m_ui;
Q_SLOT void addressBookClicked();
Q_SLOT void pasteClicked();
};
}

37
src/gui/WalletEvents.h Normal file
View File

@ -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 <QEvent>
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<QEvent::Type>(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;
};
}

102
src/gui/ui/aboutdialog.ui Normal file
View File

@ -0,0 +1,102 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AboutDialog</class>
<widget class="QDialog" name="AboutDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>592</width>
<height>240</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>592</width>
<height>240</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>592</width>
<height>240</height>
</size>
</property>
<property name="windowTitle">
<string>About %1</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0">
<item>
<widget class="QLabel" name="m_aboutLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;CryptoNote coin version %1&lt;/p&gt;&lt;p&gt;CryptoNote coin is the next generation anonymous cryptocurrency based on CryptoNote.&lt;/p&gt;&lt;p&gt;Copyright (c) 2012-2015. CryptoNote Developers&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://opensource.org/licenses/MIT&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;http://opensource.org/licenses/MIT&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://cryptonote.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;https://cryptonote.org/&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="m_closeButton">
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>m_closeButton</sender>
<signal>clicked()</signal>
<receiver>AboutDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>538</x>
<y>285</y>
</hint>
<hint type="destinationlabel">
<x>294</x>
<y>156</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AddressBookDialog</class>
<widget class="QDialog" name="AddressBookDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>747</width>
<height>525</height>
</rect>
</property>
<property name="windowTitle">
<string>Select address</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTreeView" name="m_addressBookView"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="m_okButton">
<property name="text">
<string>Choose</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>m_okButton</sender>
<signal>clicked()</signal>
<receiver>AddressBookDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>694</x>
<y>499</y>
</hint>
<hint type="destinationlabel">
<x>373</x>
<y>262</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_addressBookView</sender>
<signal>doubleClicked(QModelIndex)</signal>
<receiver>AddressBookDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>373</x>
<y>242</y>
</hint>
<hint type="destinationlabel">
<x>373</x>
<y>262</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,142 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AddressBookFrame</class>
<widget class="QFrame" name="AddressBookFrame">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>874</width>
<height>585</height>
</rect>
</property>
<property name="windowTitle">
<string>Frame</string>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTreeView" name="m_addressBookView"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="m_addAddressButton">
<property name="text">
<string>New address</string>
</property>
<property name="icon">
<iconset resource="../../resources.qrc">
<normaloff>:/icons/add</normaloff>:/icons/add</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="m_deleteAddressButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Delete address</string>
</property>
<property name="icon">
<iconset resource="../../resources.qrc">
<normaloff>:/icons/remove</normaloff>:/icons/remove</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="m_copyAddressButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Copy address</string>
</property>
<property name="icon">
<iconset resource="../../resources.qrc">
<normaloff>:/icons/copy</normaloff>:/icons/copy</iconset>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
<resources>
<include location="../../resources.qrc"/>
</resources>
<connections>
<connection>
<sender>m_addAddressButton</sender>
<signal>clicked()</signal>
<receiver>AddressBookFrame</receiver>
<slot>addClicked()</slot>
<hints>
<hint type="sourcelabel">
<x>53</x>
<y>556</y>
</hint>
<hint type="destinationlabel">
<x>436</x>
<y>292</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_deleteAddressButton</sender>
<signal>clicked()</signal>
<receiver>AddressBookFrame</receiver>
<slot>deleteClicked()</slot>
<hints>
<hint type="sourcelabel">
<x>148</x>
<y>556</y>
</hint>
<hint type="destinationlabel">
<x>436</x>
<y>292</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_copyAddressButton</sender>
<signal>clicked()</signal>
<receiver>AddressBookFrame</receiver>
<slot>copyClicked()</slot>
<hints>
<hint type="sourcelabel">
<x>243</x>
<y>556</y>
</hint>
<hint type="destinationlabel">
<x>436</x>
<y>292</y>
</hint>
</hints>
</connection>
</connections>
<slots>
<slot>addClicked()</slot>
<slot>deleteClicked()</slot>
<slot>copyClicked()</slot>
</slots>
</ui>

View File

@ -0,0 +1,207 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ChangePasswordDialog</class>
<widget class="QDialog" name="ChangePasswordDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>338</width>
<height>166</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>338</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>338</width>
<height>16777215</height>
</size>
</property>
<property name="windowTitle">
<string>Change password</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="4" column="1">
<widget class="QPushButton" name="m_okButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Ok</string>
</property>
<property name="default">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="1" colspan="2">
<widget class="QLineEdit" name="m_newPasswordConfirmationEdit">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Old password:</string>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="QLineEdit" name="m_oldPasswordEdit">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="QPushButton" name="m_cancelButton">
<property name="text">
<string>Cancel</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>New password:</string>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QLineEdit" name="m_newPasswordEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Confirm:</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="3">
<widget class="QLabel" name="m_errorLabel">
<property name="styleSheet">
<string notr="true">color: #ff0000; font: 11px;</string>
</property>
<property name="text">
<string>Password not confirmed</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>m_oldPasswordEdit</tabstop>
<tabstop>m_newPasswordEdit</tabstop>
<tabstop>m_newPasswordConfirmationEdit</tabstop>
<tabstop>m_okButton</tabstop>
<tabstop>m_cancelButton</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>m_newPasswordEdit</sender>
<signal>textChanged(QString)</signal>
<receiver>ChangePasswordDialog</receiver>
<slot>checkPassword(QString)</slot>
<hints>
<hint type="sourcelabel">
<x>223</x>
<y>64</y>
</hint>
<hint type="destinationlabel">
<x>168</x>
<y>82</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_newPasswordConfirmationEdit</sender>
<signal>textChanged(QString)</signal>
<receiver>ChangePasswordDialog</receiver>
<slot>checkPassword(QString)</slot>
<hints>
<hint type="sourcelabel">
<x>223</x>
<y>103</y>
</hint>
<hint type="destinationlabel">
<x>168</x>
<y>82</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_okButton</sender>
<signal>clicked()</signal>
<receiver>ChangePasswordDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>169</x>
<y>141</y>
</hint>
<hint type="destinationlabel">
<x>168</x>
<y>82</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_cancelButton</sender>
<signal>clicked()</signal>
<receiver>ChangePasswordDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>277</x>
<y>141</y>
</hint>
<hint type="destinationlabel">
<x>168</x>
<y>82</y>
</hint>
</hints>
</connection>
</connections>
<slots>
<slot>checkPassword(QString)</slot>
</slots>
</ui>

36
src/gui/ui/exitwidget.ui Normal file
View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ExitWidget</class>
<widget class="QWidget" name="ExitWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>385</width>
<height>66</height>
</rect>
</property>
<property name="windowTitle">
<string>Saving data</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,1">
<item>
<widget class="QLabel" name="m_clockLabel">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="m_label">
<property name="text">
<string>%1 wallet is saving data.
Please wait...</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

628
src/gui/ui/mainwindow.ui Normal file
View File

@ -0,0 +1,628 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>920</width>
<height>600</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<property name="windowIcon">
<iconset resource="../../resources.qrc">
<normaloff>:/images/cryptonote</normaloff>:/images/cryptonote</iconset>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="WalletGui::OverviewFrame" name="m_overviewFrame">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
</widget>
</item>
<item>
<widget class="WalletGui::SendFrame" name="m_sendFrame">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
</widget>
</item>
<item>
<widget class="WalletGui::ReceiveFrame" name="m_receiveFrame">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
</widget>
</item>
<item>
<widget class="WalletGui::TransactionsFrame" name="m_transactionsFrame">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
</widget>
</item>
<item>
<widget class="WalletGui::AddressBookFrame" name="m_addressBookFrame">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>920</width>
<height>27</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>File</string>
</property>
<addaction name="m_createWalletAction"/>
<addaction name="m_openWalletAction"/>
<addaction name="m_backupWalletAction"/>
<addaction name="m_exitAction"/>
</widget>
<widget class="QMenu" name="menuSettings">
<property name="title">
<string>Settings</string>
</property>
<addaction name="m_encryptWalletAction"/>
<addaction name="m_changePasswordAction"/>
<addaction name="separator"/>
<addaction name="m_startOnLoginAction"/>
<addaction name="m_minimizeToTrayAction"/>
<addaction name="m_closeToTrayAction"/>
</widget>
<widget class="QMenu" name="menuHelp">
<property name="title">
<string>Help</string>
</property>
<addaction name="m_aboutCryptonoteAction"/>
<addaction name="m_aboutQtAction"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menuSettings"/>
<addaction name="menuHelp"/>
</widget>
<widget class="QToolBar" name="toolBar">
<property name="windowTitle">
<string>toolBar</string>
</property>
<property name="movable">
<bool>false</bool>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextBesideIcon</enum>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
<addaction name="m_overviewAction"/>
<addaction name="m_sendAction"/>
<addaction name="m_receiveAction"/>
<addaction name="m_transactionsAction"/>
<addaction name="m_addressBookAction"/>
</widget>
<widget class="QStatusBar" name="statusBar"/>
<action name="m_overviewAction">
<property name="checkable">
<bool>true</bool>
</property>
<property name="enabled">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="../../resources.qrc">
<normaloff>:/icons/overview</normaloff>:/icons/overview</iconset>
</property>
<property name="text">
<string>Overview</string>
</property>
</action>
<action name="m_sendAction">
<property name="checkable">
<bool>true</bool>
</property>
<property name="enabled">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="../../resources.qrc">
<normaloff>:/icons/send</normaloff>:/icons/send</iconset>
</property>
<property name="text">
<string>Send</string>
</property>
</action>
<action name="m_receiveAction">
<property name="checkable">
<bool>true</bool>
</property>
<property name="enabled">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="../../resources.qrc">
<normaloff>:/icons/receive</normaloff>:/icons/receive</iconset>
</property>
<property name="text">
<string>Receive</string>
</property>
</action>
<action name="m_transactionsAction">
<property name="checkable">
<bool>true</bool>
</property>
<property name="enabled">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="../../resources.qrc">
<normaloff>:/icons/transactions</normaloff>:/icons/transactions</iconset>
</property>
<property name="text">
<string>Transactions</string>
</property>
</action>
<action name="m_exitAction">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Exit</string>
</property>
<property name="shortcut">
<string>Ctrl+Q</string>
</property>
</action>
<action name="m_addressBookAction">
<property name="checkable">
<bool>true</bool>
</property>
<property name="enabled">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="../../resources.qrc">
<normaloff>:/icons/address-book</normaloff>:/icons/address-book</iconset>
</property>
<property name="text">
<string>Address Book</string>
</property>
</action>
<action name="m_createWalletAction">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Create wallet</string>
</property>
</action>
<action name="m_openWalletAction">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Open wallet</string>
</property>
</action>
<action name="m_encryptWalletAction">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Encrypt wallet</string>
</property>
</action>
<action name="m_changePasswordAction">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Change password</string>
</property>
<property name="toolTip">
<string>Change password</string>
</property>
</action>
<action name="m_aboutCryptonoteAction">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>About</string>
</property>
</action>
<action name="m_aboutQtAction">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>About Qt</string>
</property>
</action>
<action name="m_backupWalletAction">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Backup wallet</string>
</property>
</action>
<action name="m_startOnLoginAction">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Start on system login</string>
</property>
</action>
<action name="m_minimizeToTrayAction">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Minimize to tray</string>
</property>
</action>
<action name="m_closeToTrayAction">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Close to tray</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
<class>WalletGui::OverviewFrame</class>
<extends>QFrame</extends>
<header>gui/OverviewFrame.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>WalletGui::SendFrame</class>
<extends>QFrame</extends>
<header>gui/SendFrame.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>WalletGui::ReceiveFrame</class>
<extends>QFrame</extends>
<header>gui/ReceiveFrame.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>WalletGui::TransactionsFrame</class>
<extends>QFrame</extends>
<header>gui/TransactionsFrame.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>WalletGui::AddressBookFrame</class>
<extends>QFrame</extends>
<header>gui/AddressBookFrame.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources>
<include location="../../resources.qrc"/>
</resources>
<connections>
<connection>
<sender>m_overviewAction</sender>
<signal>toggled(bool)</signal>
<receiver>m_overviewFrame</receiver>
<slot>setVisible(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>112</x>
<y>333</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_sendAction</sender>
<signal>toggled(bool)</signal>
<receiver>m_sendFrame</receiver>
<slot>setVisible(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>337</x>
<y>333</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_receiveAction</sender>
<signal>toggled(bool)</signal>
<receiver>m_receiveFrame</receiver>
<slot>setVisible(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>562</x>
<y>333</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_transactionsAction</sender>
<signal>toggled(bool)</signal>
<receiver>m_transactionsFrame</receiver>
<slot>setVisible(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>787</x>
<y>333</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_addressBookAction</sender>
<signal>toggled(bool)</signal>
<receiver>m_addressBookFrame</receiver>
<slot>setVisible(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>809</x>
<y>320</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_createWalletAction</sender>
<signal>triggered()</signal>
<receiver>MainWindow</receiver>
<slot>createWallet()</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>449</x>
<y>299</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_openWalletAction</sender>
<signal>triggered()</signal>
<receiver>MainWindow</receiver>
<slot>openWallet()</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>449</x>
<y>299</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_encryptWalletAction</sender>
<signal>triggered()</signal>
<receiver>MainWindow</receiver>
<slot>encryptWallet()</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>449</x>
<y>299</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_changePasswordAction</sender>
<signal>triggered()</signal>
<receiver>MainWindow</receiver>
<slot>encryptWallet()</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>449</x>
<y>299</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_aboutQtAction</sender>
<signal>triggered()</signal>
<receiver>MainWindow</receiver>
<slot>aboutQt()</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>449</x>
<y>299</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_backupWalletAction</sender>
<signal>triggered()</signal>
<receiver>MainWindow</receiver>
<slot>backupWallet()</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>449</x>
<y>299</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_aboutCryptonoteAction</sender>
<signal>triggered()</signal>
<receiver>MainWindow</receiver>
<slot>about()</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>459</x>
<y>299</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_startOnLoginAction</sender>
<signal>triggered(bool)</signal>
<receiver>MainWindow</receiver>
<slot>setStartOnLogin(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>459</x>
<y>299</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_minimizeToTrayAction</sender>
<signal>triggered(bool)</signal>
<receiver>MainWindow</receiver>
<slot>setMinimizeToTray(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>459</x>
<y>299</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_closeToTrayAction</sender>
<signal>triggered(bool)</signal>
<receiver>MainWindow</receiver>
<slot>setCloseToTray(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>459</x>
<y>299</y>
</hint>
</hints>
</connection>
</connections>
<slots>
<slot>createWallet()</slot>
<slot>openWallet()</slot>
<slot>encryptWallet()</slot>
<slot>aboutQt()</slot>
<slot>backupWallet()</slot>
<slot>about()</slot>
<slot>setStartOnLogin(bool)</slot>
<slot>setMinimizeToTray(bool)</slot>
<slot>setCloseToTray(bool)</slot>
</slots>
</ui>

View File

@ -0,0 +1,133 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>NewAddressDialog</class>
<widget class="QDialog" name="NewAddressDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>590</width>
<height>127</height>
</rect>
</property>
<property name="windowTitle">
<string>New address</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Label:</string>
</property>
</widget>
</item>
<item row="0" column="1" colspan="3">
<widget class="QLineEdit" name="m_labelEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="echoMode">
<enum>QLineEdit::Normal</enum>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Address:</string>
</property>
</widget>
</item>
<item row="1" column="1" colspan="3">
<widget class="QLineEdit" name="m_addressEdit">
<property name="echoMode">
<enum>QLineEdit::Normal</enum>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>338</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="2">
<widget class="QPushButton" name="m_okButton">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Ok</string>
</property>
<property name="default">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QPushButton" name="m_cancelButton">
<property name="text">
<string>Cancel</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>m_okButton</sender>
<signal>clicked()</signal>
<receiver>NewAddressDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>410</x>
<y>102</y>
</hint>
<hint type="destinationlabel">
<x>294</x>
<y>63</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_cancelButton</sender>
<signal>clicked()</signal>
<receiver>NewAddressDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>526</x>
<y>102</y>
</hint>
<hint type="destinationlabel">
<x>294</x>
<y>63</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,180 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>NewPasswordDialog</class>
<widget class="QDialog" name="NewPasswordDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>338</width>
<height>133</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Enter password</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="3" column="1">
<widget class="QPushButton" name="m_okButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Ok</string>
</property>
<property name="default">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QPushButton" name="m_cancelButton">
<property name="text">
<string>Cancel</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Password:</string>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="QLineEdit" name="m_passwordEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QLineEdit" name="m_passwordConfirmationEdit">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Confirm:</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="3">
<widget class="QLabel" name="m_errorLabel">
<property name="styleSheet">
<string notr="true">color: #ff0000; font: 11px;</string>
</property>
<property name="text">
<string>Password not confirmed</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>m_passwordEdit</tabstop>
<tabstop>m_passwordConfirmationEdit</tabstop>
<tabstop>m_okButton</tabstop>
<tabstop>m_cancelButton</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>m_okButton</sender>
<signal>clicked()</signal>
<receiver>NewPasswordDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>147</x>
<y>102</y>
</hint>
<hint type="destinationlabel">
<x>147</x>
<y>63</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_cancelButton</sender>
<signal>clicked()</signal>
<receiver>NewPasswordDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>241</x>
<y>102</y>
</hint>
<hint type="destinationlabel">
<x>147</x>
<y>63</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_passwordEdit</sender>
<signal>textChanged(QString)</signal>
<receiver>NewPasswordDialog</receiver>
<slot>checkPassword(QString)</slot>
<hints>
<hint type="sourcelabel">
<x>206</x>
<y>25</y>
</hint>
<hint type="destinationlabel">
<x>168</x>
<y>64</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_passwordConfirmationEdit</sender>
<signal>textChanged(QString)</signal>
<receiver>NewPasswordDialog</receiver>
<slot>checkPassword(QString)</slot>
<hints>
<hint type="sourcelabel">
<x>206</x>
<y>64</y>
</hint>
<hint type="destinationlabel">
<x>168</x>
<y>64</y>
</hint>
</hints>
</connection>
</connections>
<slots>
<slot>checkPassword(QString)</slot>
</slots>
</ui>

290
src/gui/ui/overviewframe.ui Normal file
View File

@ -0,0 +1,290 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>OverviewFrame</class>
<widget class="QFrame" name="OverviewFrame">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>866</width>
<height>590</height>
</rect>
</property>
<property name="windowTitle">
<string>Frame</string>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QGridLayout" name="gridLayout" columnstretch="40,60">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="horizontalSpacing">
<number>5</number>
</property>
<property name="verticalSpacing">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QFrame" name="m_overviewWalletFrame">
<property name="minimumSize">
<size>
<width>0</width>
<height>160</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>160</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="4" column="1">
<widget class="QLabel" name="m_totalBalanceLabel">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string notr="true">0.00</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="m_actualBalanceLabel">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string notr="true">0.00</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Total:</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="m_tickerLabel1">
<property name="text">
<string notr="true"/>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Wallet</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Unconfirmed:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Balance:</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="m_pendingBalanceLabel">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string notr="true">0.00</string>
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="QLabel" name="m_tickerLabel3">
<property name="text">
<string notr="true"/>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLabel" name="m_tickerLabel2">
<property name="text">
<string notr="true"/>
</property>
</widget>
</item>
<item row="2" column="3">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item row="1" column="0" rowspan="2">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>425</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="1" rowspan="3">
<widget class="QFrame" name="frame_2">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label_8">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Recent transactions</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QTreeView" name="m_recentTransactionsView">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="styleSheet">
<string notr="true">background-color: transparent;</string>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="uniformRowHeights">
<bool>true</bool>
</property>
<property name="itemsExpandable">
<bool>false</bool>
</property>
<property name="headerHidden">
<bool>true</bool>
</property>
<property name="expandsOnDoubleClick">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,131 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PasswordDialog</class>
<widget class="QDialog" name="PasswordDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>338</width>
<height>103</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>338</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>338</width>
<height>16777215</height>
</size>
</property>
<property name="windowTitle">
<string>Enter password</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="1" colspan="2">
<widget class="QLineEdit" name="m_passwordEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QPushButton" name="m_cancelButton">
<property name="text">
<string>Cancel</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Password:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QPushButton" name="m_okButton">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Ok</string>
</property>
<property name="default">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0" colspan="3">
<widget class="QLabel" name="m_errorLabel">
<property name="minimumSize">
<size>
<width>122</width>
<height>0</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">color: #ff0000; font: 11px;</string>
</property>
<property name="text">
<string>Wrong password</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>m_okButton</sender>
<signal>clicked()</signal>
<receiver>PasswordDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>142</x>
<y>84</y>
</hint>
<hint type="destinationlabel">
<x>158</x>
<y>52</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_cancelButton</sender>
<signal>clicked()</signal>
<receiver>PasswordDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>257</x>
<y>84</y>
</hint>
<hint type="destinationlabel">
<x>158</x>
<y>52</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ReceiveFrame</class>
<widget class="QFrame" name="ReceiveFrame">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>846</width>
<height>592</height>
</rect>
</property>
<property name="windowTitle">
<string>Frame</string>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Address:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="m_addressEdit">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="m_copyButton">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../resources.qrc">
<normaloff>:/icons/copy</normaloff>:/icons/copy</iconset>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources>
<include location="../../resources.qrc"/>
</resources>
<connections>
<connection>
<sender>m_copyButton</sender>
<signal>clicked()</signal>
<receiver>ReceiveFrame</receiver>
<slot>copyAddress()</slot>
<hints>
<hint type="sourcelabel">
<x>818</x>
<y>26</y>
</hint>
<hint type="destinationlabel">
<x>422</x>
<y>295</y>
</hint>
</hints>
</connection>
</connections>
<slots>
<slot>copyAddress()</slot>
</slots>
</ui>

320
src/gui/ui/sendframe.ui Normal file
View File

@ -0,0 +1,320 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SendFrame</class>
<widget class="QFrame" name="SendFrame">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>866</width>
<height>590</height>
</rect>
</property>
<property name="windowTitle">
<string>Frame</string>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="m_send_frame_main_layout">
<item>
<widget class="QScrollArea" name="m_transfersScrollarea">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>840</width>
<height>446</height>
</rect>
</property>
<layout class="QVBoxLayout" name="m_send_frame_layout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>445</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<property name="topMargin">
<number>5</number>
</property>
<item row="1" column="1">
<widget class="QSlider" name="m_mixinSlider">
<property name="maximumSize">
<size>
<width>200</width>
<height>16777215</height>
</size>
</property>
<property name="maximum">
<number>10</number>
</property>
<property name="pageStep">
<number>1</number>
</property>
<property name="value">
<number>2</number>
</property>
<property name="tracking">
<bool>false</bool>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBothSides</enum>
</property>
<property name="tickInterval">
<number>1</number>
</property>
</widget>
</item>
<item row="1" column="3">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>298</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>PaymentID:</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLineEdit" name="m_mixinEdit">
<property name="maximumSize">
<size>
<width>30</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string notr="true"/>
</property>
<property name="maxLength">
<number>5</number>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="1" colspan="3">
<widget class="QLineEdit" name="m_paymentIdEdit"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Anonimity level:</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="m_sendButton">
<property name="text">
<string>Send</string>
</property>
<property name="icon">
<iconset resource="../../resources.qrc">
<normaloff>:/icons/send</normaloff>:/icons/send</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="m_clearAllButton">
<property name="text">
<string>Clear All</string>
</property>
<property name="icon">
<iconset resource="../../resources.qrc">
<normaloff>:/icons/remove</normaloff>:/icons/remove</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="m_addRecipientButton">
<property name="text">
<string>Add Recipient</string>
</property>
<property name="icon">
<iconset resource="../../resources.qrc">
<normaloff>:/icons/add</normaloff>:/icons/add</iconset>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>Balance:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="m_balanceLabel">
<property name="text">
<string notr="true">0.00 </string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="m_tickerLabel">
<property name="text">
<string notr="true"/>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<tabstops>
<tabstop>m_paymentIdEdit</tabstop>
<tabstop>m_mixinSlider</tabstop>
<tabstop>m_sendButton</tabstop>
<tabstop>m_clearAllButton</tabstop>
<tabstop>m_addRecipientButton</tabstop>
<tabstop>m_transfersScrollarea</tabstop>
<tabstop>m_mixinEdit</tabstop>
</tabstops>
<resources>
<include location="../../resources.qrc"/>
</resources>
<connections>
<connection>
<sender>m_addRecipientButton</sender>
<signal>clicked()</signal>
<receiver>SendFrame</receiver>
<slot>addRecipientClicked()</slot>
<hints>
<hint type="sourcelabel">
<x>282</x>
<y>561</y>
</hint>
<hint type="destinationlabel">
<x>432</x>
<y>294</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_clearAllButton</sender>
<signal>clicked()</signal>
<receiver>SendFrame</receiver>
<slot>clearAllClicked()</slot>
<hints>
<hint type="sourcelabel">
<x>154</x>
<y>561</y>
</hint>
<hint type="destinationlabel">
<x>432</x>
<y>294</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_sendButton</sender>
<signal>clicked()</signal>
<receiver>SendFrame</receiver>
<slot>sendClicked()</slot>
<hints>
<hint type="sourcelabel">
<x>53</x>
<y>561</y>
</hint>
<hint type="destinationlabel">
<x>432</x>
<y>294</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_mixinSlider</sender>
<signal>valueChanged(int)</signal>
<receiver>SendFrame</receiver>
<slot>mixinValueChanged(int)</slot>
<hints>
<hint type="sourcelabel">
<x>221</x>
<y>520</y>
</hint>
<hint type="destinationlabel">
<x>432</x>
<y>294</y>
</hint>
</hints>
</connection>
</connections>
<slots>
<slot>sendClicked()</slot>
<slot>clearAllClicked()</slot>
<slot>addRecipientClicked()</slot>
<slot>mixinValueChanged(int)</slot>
</slots>
</ui>

View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TransactionDetailsDialog</class>
<widget class="QDialog" name="TransactionDetailsDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>736</width>
<height>357</height>
</rect>
</property>
<property name="windowTitle">
<string>Transaction details</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTextBrowser" name="m_detailsBrowser"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="m_closeButton">
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>m_closeButton</sender>
<signal>clicked()</signal>
<receiver>TransactionDetailsDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>619</x>
<y>331</y>
</hint>
<hint type="destinationlabel">
<x>335</x>
<y>178</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,156 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TransactionFrame</class>
<widget class="QFrame" name="TransactionFrame">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>346</width>
<height>64</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>64</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>540</width>
<height>64</height>
</size>
</property>
<property name="windowTitle">
<string>Frame</string>
</property>
<property name="autoFillBackground">
<bool>true</bool>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="0,0,0">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="m_iconLabel">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,1">
<property name="spacing">
<number>20</number>
</property>
<item>
<widget class="QLabel" name="m_timeLabel">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="m_amountLabel">
<property name="text">
<string>TextLabel</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="m_hashLabel">
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="text">
<string>TextLabel</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="indent">
<number>-1</number>
</property>
<property name="textInteractionFlags">
<set>Qt::NoTextInteraction</set>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,125 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TransactionsFrame</class>
<widget class="QFrame" name="TransactionsFrame">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>830</width>
<height>614</height>
</rect>
</property>
<property name="windowTitle">
<string>Frame</string>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTreeView" name="m_transactionsView">
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustIgnored</enum>
</property>
<property name="editTriggers">
<set>QAbstractItemView::AnyKeyPressed|QAbstractItemView::CurrentChanged|QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked</set>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="uniformRowHeights">
<bool>true</bool>
</property>
<property name="itemsExpandable">
<bool>false</bool>
</property>
<property name="sortingEnabled">
<bool>false</bool>
</property>
<attribute name="headerCascadingSectionResizes">
<bool>true</bool>
</attribute>
<attribute name="headerShowSortIndicator" stdset="0">
<bool>false</bool>
</attribute>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="m_csvButton">
<property name="text">
<string>Export</string>
</property>
<property name="icon">
<iconset resource="../../resources.qrc">
<normaloff>:/icons/export</normaloff>:/icons/export</iconset>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources>
<include location="../../resources.qrc"/>
</resources>
<connections>
<connection>
<sender>m_csvButton</sender>
<signal>clicked()</signal>
<receiver>TransactionsFrame</receiver>
<slot>exportToCsv()</slot>
<hints>
<hint type="sourcelabel">
<x>761</x>
<y>587</y>
</hint>
<hint type="destinationlabel">
<x>414</x>
<y>306</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_transactionsView</sender>
<signal>doubleClicked(QModelIndex)</signal>
<receiver>TransactionsFrame</receiver>
<slot>showTransactionDetails(QModelIndex)</slot>
<hints>
<hint type="sourcelabel">
<x>414</x>
<y>287</y>
</hint>
<hint type="destinationlabel">
<x>414</x>
<y>306</y>
</hint>
</hints>
</connection>
</connections>
<slots>
<slot>exportToCsv()</slot>
<slot>showTransactionDetails(QModelIndex)</slot>
</slots>
</ui>

195
src/gui/ui/transferframe.ui Normal file
View File

@ -0,0 +1,195 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TransferFrame</class>
<widget class="QFrame" name="TransferFrame">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>885</width>
<height>121</height>
</rect>
</property>
<property name="windowTitle">
<string>Frame</string>
</property>
<property name="frameShape">
<enum>QFrame::Box</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>5</number>
</property>
<property name="topMargin">
<number>5</number>
</property>
<property name="rightMargin">
<number>5</number>
</property>
<property name="bottomMargin">
<number>5</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Pay To:</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QToolButton" name="m_addressBookButton">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../resources.qrc">
<normaloff>:/icons/address-book</normaloff>:/icons/address-book</iconset>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QToolButton" name="m_pasteButton">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../resources.qrc">
<normaloff>:/icons/paste</normaloff>:/icons/paste</iconset>
</property>
</widget>
</item>
<item row="1" column="1" colspan="5">
<widget class="QLineEdit" name="m_labelEdit">
<property name="placeholderText">
<string>Enter a label for this address to add it to your address book</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Amount:</string>
</property>
</widget>
</item>
<item row="0" column="5">
<widget class="QToolButton" name="m_removeButton">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../resources.qrc">
<normaloff>:/icons/remove</normaloff>:/icons/remove</iconset>
</property>
</widget>
</item>
<item row="2" column="2" colspan="4">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>558</width>
<height>17</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Label:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="m_amountSpin">
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="suffix">
<string notr="true"/>
</property>
<property name="decimals">
<number>8</number>
</property>
<property name="maximum">
<double>999999999.999999046325684</double>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="QLineEdit" name="m_addressEdit"/>
</item>
</layout>
</widget>
<tabstops>
<tabstop>m_addressEdit</tabstop>
<tabstop>m_labelEdit</tabstop>
<tabstop>m_amountSpin</tabstop>
<tabstop>m_addressBookButton</tabstop>
<tabstop>m_pasteButton</tabstop>
<tabstop>m_removeButton</tabstop>
</tabstops>
<resources>
<include location="../../resources.qrc"/>
</resources>
<connections>
<connection>
<sender>m_removeButton</sender>
<signal>clicked()</signal>
<receiver>TransferFrame</receiver>
<slot>close()</slot>
<hints>
<hint type="sourcelabel">
<x>862</x>
<y>21</y>
</hint>
<hint type="destinationlabel">
<x>442</x>
<y>60</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_addressBookButton</sender>
<signal>clicked()</signal>
<receiver>TransferFrame</receiver>
<slot>addressBookClicked()</slot>
<hints>
<hint type="sourcelabel">
<x>786</x>
<y>21</y>
</hint>
<hint type="destinationlabel">
<x>442</x>
<y>60</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_pasteButton</sender>
<signal>clicked()</signal>
<receiver>TransferFrame</receiver>
<slot>pasteClicked()</slot>
<hints>
<hint type="sourcelabel">
<x>824</x>
<y>21</y>
</hint>
<hint type="destinationlabel">
<x>442</x>
<y>60</y>
</hint>
</hints>
</connection>
</connections>
<slots>
<slot>addressBookClicked()</slot>
<slot>pasteClicked()</slot>
</slots>
</ui>

BIN
src/icons/add.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
src/icons/address-book.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
src/icons/clock1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 864 B

BIN
src/icons/clock2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 863 B

BIN
src/icons/clock3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 856 B

BIN
src/icons/clock4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 869 B

BIN
src/icons/clock5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 858 B

BIN
src/icons/connected.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 762 B

BIN
src/icons/disconnected.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 538 B

BIN
src/icons/editcopy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 600 B

BIN
src/icons/editpaste.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
src/icons/export.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
src/icons/lock_closed.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
src/icons/lock_open.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
src/icons/overview.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

BIN
src/icons/receive.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
src/icons/remove.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 649 B

BIN
src/icons/send.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
src/icons/sync_sprite.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Some files were not shown because too many files have changed in this diff Show More