From ab1b288fa7994db5f036e93d5f8ba73372017c40 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Sun, 6 May 2012 19:40:58 +0200 Subject: [PATCH] Convert UI interface to boost::signals2. - Signals now go directly from the core to WalletModel/ClientModel. - WalletModel subscribes to signals on CWallet: Prepares for multi-wallet support, by no longer assuming an implicit global wallet. - Gets rid of noui.cpp, the few lines that were left are merged into init.cpp - Rename wxXXX message flags to MF_XXX, to make them UI indifferent. - ThreadSafeMessageBox no longer returns the value `4` which was never used, converted to void. --- src/bitcoinrpc.cpp | 16 ++--- src/init.cpp | 39 +++++++++--- src/keystore.cpp | 5 +- src/keystore.h | 6 ++ src/main.cpp | 14 ++--- src/makefile.linux-mingw | 3 +- src/makefile.mingw | 3 +- src/makefile.osx | 3 +- src/makefile.unix | 3 +- src/net.cpp | 2 +- src/noui.cpp | 59 ------------------ src/qt/bitcoin.cpp | 84 +++++--------------------- src/qt/clientmodel.cpp | 45 ++++++++++++++ src/qt/clientmodel.h | 3 + src/qt/qtipcserver.cpp | 4 +- src/qt/walletmodel.cpp | 49 ++++++++++++++- src/qt/walletmodel.h | 3 + src/ui_interface.h | 127 ++++++++++++++++++++++----------------- src/util.cpp | 2 +- src/wallet.cpp | 4 +- src/wallet.h | 11 ++++ 21 files changed, 263 insertions(+), 222 deletions(-) delete mode 100644 src/noui.cpp diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 334425a9a..cc4d85cbb 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -435,7 +435,7 @@ Value stop(const Array& params, bool fHelp) "stop\n" "Stop Bitcoin server."); // Shutdown will take long enough that the response should get back - QueueShutdown(); + uiInterface.QueueShutdown(); return "Bitcoin server stopping"; } @@ -1928,7 +1928,7 @@ Value encryptwallet(const Array& params, bool fHelp) // BDB seems to have a bad habit of writing old data into // slack space in .dat files; that is bad if the old data is // unencrypted private keys. So: - QueueShutdown(); + uiInterface.QueueShutdown(); return "wallet encrypted; Bitcoin server stopping, restart to run with encrypted wallet"; } @@ -2620,7 +2620,7 @@ void ThreadRPCServer2(void* parg) strWhatAmI = strprintf(_("To use the %s option"), "\"-server\""); else if (mapArgs.count("-daemon")) strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\""); - ThreadSafeMessageBox(strprintf( + uiInterface.ThreadSafeMessageBox(strprintf( _("%s, you must set a rpcpassword in the configuration file:\n %s\n" "It is recommended you use the following random password:\n" "rpcuser=bitcoinrpc\n" @@ -2630,8 +2630,8 @@ void ThreadRPCServer2(void* parg) strWhatAmI.c_str(), GetConfigFile().string().c_str(), EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()), - _("Error"), wxOK | wxMODAL); - QueueShutdown(); + _("Error"), MF_OK | MF_MODAL); + uiInterface.QueueShutdown(); return; } @@ -2650,9 +2650,9 @@ void ThreadRPCServer2(void* parg) } catch(boost::system::system_error &e) { - ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()), - _("Error"), wxOK | wxMODAL); - QueueShutdown(); + uiInterface.ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()), + _("Error"), MF_OK | MF_MODAL); + uiInterface.QueueShutdown(); return; } diff --git a/src/init.cpp b/src/init.cpp index 47b6f9232..096f28964 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -22,6 +22,7 @@ using namespace std; using namespace boost; CWallet* pwalletMain; +CClientUIInterface uiInterface; ////////////////////////////////////////////////////////////////////////////// // @@ -90,9 +91,33 @@ void HandleSIGTERM(int) // Start // #if !defined(QT_GUI) +static int noui_ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style) +{ + printf("%s: %s\n", caption.c_str(), message.c_str()); + fprintf(stderr, "%s: %s\n", caption.c_str(), message.c_str()); + return 4; +} + +static bool noui_ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption) +{ + return true; +} + +static void noui_QueueShutdown() +{ + // Without UI, Shutdown can simply be started in a new thread + CreateThread(Shutdown, NULL); +} + int main(int argc, char* argv[]) { bool fRet = false; + + // Connect bitcoind signal handlers + uiInterface.ThreadSafeMessageBox.connect(noui_ThreadSafeMessageBox); + uiInterface.ThreadSafeAskFee.connect(noui_ThreadSafeAskFee); + uiInterface.QueueShutdown.connect(noui_QueueShutdown); + fRet = AppInit(argc, argv); if (fRet && fDaemon) @@ -160,13 +185,13 @@ bool AppInit(int argc, char* argv[]) bool static InitError(const std::string &str) { - ThreadSafeMessageBox(str, _("Bitcoin"), wxOK | wxMODAL); + uiInterface.ThreadSafeMessageBox(str, _("Bitcoin"), MF_OK|MF_MODAL); return false; } bool static InitWarning(const std::string &str) { - ThreadSafeMessageBox(str, _("Bitcoin"), wxOK | wxICON_EXCLAMATION | wxMODAL); + uiInterface.ThreadSafeMessageBox(str, _("Bitcoin"), MF_OK | MF_ICON_EXCLAMATION | MF_MODAL); return true; } @@ -367,7 +392,7 @@ bool AppInit2() fprintf(stdout, "Bitcoin server starting\n"); int64 nStart; - InitMessage(_("Loading addresses...")); + uiInterface.InitMessage(_("Loading addresses...")); printf("Loading addresses...\n"); nStart = GetTimeMillis(); @@ -380,7 +405,7 @@ bool AppInit2() printf("Loaded %i addresses from peers.dat %"PRI64d"ms\n", addrman.size(), GetTimeMillis() - nStart); - InitMessage(_("Loading block index...")); + uiInterface.InitMessage(_("Loading block index...")); printf("Loading block index...\n"); nStart = GetTimeMillis(); if (!LoadBlockIndex()) @@ -406,7 +431,7 @@ bool AppInit2() } } - InitMessage(_("Loading wallet...")); + uiInterface.InitMessage(_("Loading wallet...")); printf("Loading wallet...\n"); nStart = GetTimeMillis(); bool fFirstRun; @@ -474,14 +499,14 @@ bool AppInit2() } if (pindexBest != pindexRescan) { - InitMessage(_("Rescanning...")); + uiInterface.InitMessage(_("Rescanning...")); printf("Rescanning last %i blocks (from block %i)...\n", pindexBest->nHeight - pindexRescan->nHeight, pindexRescan->nHeight); nStart = GetTimeMillis(); pwalletMain->ScanForWalletTransactions(pindexRescan, true); printf(" rescan %15"PRI64d"ms\n", GetTimeMillis() - nStart); } - InitMessage(_("Done loading")); + uiInterface.InitMessage(_("Done loading")); printf("Done loading\n"); //// debug print diff --git a/src/keystore.cpp b/src/keystore.cpp index 55fba4c37..bdeae3013 100644 --- a/src/keystore.cpp +++ b/src/keystore.cpp @@ -5,7 +5,6 @@ #include "keystore.h" #include "script.h" -#include "ui_interface.h" bool CKeyStore::GetPubKey(const CBitcoinAddress &address, std::vector &vchPubKeyOut) const { @@ -84,7 +83,7 @@ bool CCryptoKeyStore::Lock() vMasterKey.clear(); } - NotifyKeyStoreStatusChanged(this); + NotifyStatusChanged(this); return true; } @@ -114,7 +113,7 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn) } vMasterKey = vMasterKeyIn; } - NotifyKeyStoreStatusChanged(this); + NotifyStatusChanged(this); return true; } diff --git a/src/keystore.h b/src/keystore.h index dd7110db5..6b5d01cfa 100644 --- a/src/keystore.h +++ b/src/keystore.h @@ -8,6 +8,7 @@ #include "crypter.h" #include "sync.h" #include "base58.h" +#include class CScript; @@ -174,6 +175,11 @@ public: mi++; } } + + /* Wallet status (encrypted, locked) changed. + * Note: Called without locks held. + */ + boost::signals2::signal NotifyStatusChanged; }; #endif diff --git a/src/main.cpp b/src/main.cpp index 7e7a0badf..8410b9af4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -946,7 +946,7 @@ void static InvalidChainFound(CBlockIndex* pindexNew) { bnBestInvalidWork = pindexNew->bnChainWork; CTxDB().WriteBestInvalidWork(bnBestInvalidWork); - NotifyBlocksChanged(); + uiInterface.NotifyBlocksChanged(); } printf("InvalidChainFound: invalid block=%s height=%d work=%s\n", pindexNew->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->nHeight, pindexNew->bnChainWork.ToString().c_str()); printf("InvalidChainFound: current best=%s height=%d work=%s\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainWork.ToString().c_str()); @@ -1647,7 +1647,7 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos) hashPrevBestCoinBase = vtx[0].GetHash(); } - NotifyBlocksChanged(); + uiInterface.NotifyBlocksChanged(); return true; } @@ -1858,8 +1858,8 @@ bool CheckDiskSpace(uint64 nAdditionalBytes) string strMessage = _("Warning: Disk space is low"); strMiscWarning = strMessage; printf("*** %s\n", strMessage.c_str()); - ThreadSafeMessageBox(strMessage, "Bitcoin", wxOK | wxICON_EXCLAMATION | wxMODAL); - QueueShutdown(); + uiInterface.ThreadSafeMessageBox(strMessage, "Bitcoin", MF_OK | MF_ICON_EXCLAMATION | MF_MODAL); + uiInterface.QueueShutdown(); return false; } return true; @@ -2204,13 +2204,13 @@ bool CAlert::ProcessAlert() if (Cancels(alert)) { printf("cancelling alert %d\n", alert.nID); - NotifyAlertChanged((*mi).first, CT_DELETED); + uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED); mapAlerts.erase(mi++); } else if (!alert.IsInEffect()) { printf("expiring alert %d\n", alert.nID); - NotifyAlertChanged((*mi).first, CT_DELETED); + uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED); mapAlerts.erase(mi++); } else @@ -2232,7 +2232,7 @@ bool CAlert::ProcessAlert() mapAlerts.insert(make_pair(GetHash(), *this)); // Notify UI if it applies to me if(AppliesToMe()) - NotifyAlertChanged(GetHash(), CT_NEW); + uiInterface.NotifyAlertChanged(GetHash(), CT_NEW); } printf("accepted alert %d, AppliesToMe()=%d\n", nID, AppliesToMe()); diff --git a/src/makefile.linux-mingw b/src/makefile.linux-mingw index 61b38a663..1e9dd687f 100644 --- a/src/makefile.linux-mingw +++ b/src/makefile.linux-mingw @@ -64,8 +64,7 @@ OBJS= \ obj/sync.o \ obj/util.o \ obj/wallet.o \ - obj/walletdb.o \ - obj/noui.o + obj/walletdb.o all: bitcoind.exe diff --git a/src/makefile.mingw b/src/makefile.mingw index 47bf8d530..fdd4f4635 100644 --- a/src/makefile.mingw +++ b/src/makefile.mingw @@ -61,8 +61,7 @@ OBJS= \ obj/sync.o \ obj/util.o \ obj/wallet.o \ - obj/walletdb.o \ - obj/noui.o + obj/walletdb.o all: bitcoind.exe diff --git a/src/makefile.osx b/src/makefile.osx index 227756f27..d6433a698 100644 --- a/src/makefile.osx +++ b/src/makefile.osx @@ -88,8 +88,7 @@ OBJS= \ obj/sync.o \ obj/util.o \ obj/wallet.o \ - obj/walletdb.o \ - obj/noui.o + obj/walletdb.o ifdef USE_UPNP DEFS += -DUSE_UPNP=$(USE_UPNP) diff --git a/src/makefile.unix b/src/makefile.unix index 04e17866e..ec6609f99 100644 --- a/src/makefile.unix +++ b/src/makefile.unix @@ -108,8 +108,7 @@ OBJS= \ obj/sync.o \ obj/util.o \ obj/wallet.o \ - obj/walletdb.o \ - obj/noui.o + obj/walletdb.o all: bitcoind diff --git a/src/net.cpp b/src/net.cpp index 32875b0f0..8eff9cbe7 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -705,7 +705,7 @@ void ThreadSocketHandler2(void* parg) if (vNodes.size() != nPrevNodeCount) { nPrevNodeCount = vNodes.size(); - NotifyNumConnectionsChanged(vNodes.size()); + uiInterface.NotifyNumConnectionsChanged(vNodes.size()); } diff --git a/src/noui.cpp b/src/noui.cpp deleted file mode 100644 index c7b74bea7..000000000 --- a/src/noui.cpp +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2012 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying -// file license.txt or http://www.opensource.org/licenses/mit-license.php. -#include "ui_interface.h" - -#include -#include "init.h" - -int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style) -{ - printf("%s: %s\n", caption.c_str(), message.c_str()); - fprintf(stderr, "%s: %s\n", caption.c_str(), message.c_str()); - return 4; -} - -bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption) -{ - return true; -} - -void InitMessage(const std::string &message) -{ -} - -std::string _(const char* psz) -{ - return psz; -} - -void QueueShutdown() -{ - // Without UI, Shutdown can simply be started in a new thread - CreateThread(Shutdown, NULL); -} - -void NotifyBlocksChanged() -{ -} - -void NotifyKeyStoreStatusChanged(CBasicKeyStore *wallet) -{ -} - -void NotifyAddressBookChanged(CWallet *wallet, const std::string &address, const std::string &label, EntryStatus status) -{ -} - -void NotifyTransactionChanged(CWallet *wallet, const uint256 &hashTx, EntryStatus status) -{ -} - -void NotifyNumConnectionsChanged(int newNumConnections) -{ -} - -void NotifyAlertChanged(const uint256 &hash, EntryStatus status) -{ -} diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index a50443021..c5592b28d 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -36,15 +36,13 @@ Q_IMPORT_PLUGIN(qtaccessiblewidgets) // Need a global reference for the notifications to find the GUI static BitcoinGUI *guiref; static QSplashScreen *splashref; -static WalletModel *walletmodel; -static ClientModel *clientmodel; -int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style) +static void ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style) { // Message from network thread if(guiref) { - bool modal = (style & wxMODAL); + bool modal = (style & MF_MODAL); // in case of modal message, use blocking connection to wait for user to click OK QMetaObject::invokeMethod(guiref, "error", modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection, @@ -57,10 +55,9 @@ int ThreadSafeMessageBox(const std::string& message, const std::string& caption, printf("%s: %s\n", caption.c_str(), message.c_str()); fprintf(stderr, "%s: %s\n", caption.c_str(), message.c_str()); } - return 4; } -bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption) +static bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption) { if(!guiref) return false; @@ -75,7 +72,7 @@ bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption) return payFee; } -void ThreadSafeHandleURI(const std::string& strURI) +static void ThreadSafeHandleURI(const std::string& strURI) { if(!guiref) return; @@ -84,7 +81,7 @@ void ThreadSafeHandleURI(const std::string& strURI) Q_ARG(QString, QString::fromStdString(strURI))); } -void InitMessage(const std::string &message) +static void InitMessage(const std::string &message) { if(splashref) { @@ -93,7 +90,7 @@ void InitMessage(const std::string &message) } } -void QueueShutdown() +static void QueueShutdown() { QMetaObject::invokeMethod(QCoreApplication::instance(), "quit", Qt::QueuedConnection); } @@ -101,66 +98,11 @@ void QueueShutdown() /* Translate string to current locale using Qt. */ -std::string _(const char* psz) +static std::string Translate(const char* psz) { return QCoreApplication::translate("bitcoin-core", psz).toStdString(); } -void NotifyBlocksChanged() -{ - // This notification is too frequent. Don't trigger a signal. - // Don't remove it, though, as it might be useful later. -} - -void NotifyKeyStoreStatusChanged(CBasicKeyStore *wallet) -{ - // This currently ignores the wallet argument. When multiple wallet support is implemented, this - // parameter should be mapped to a specific WalletModel for that wallet. - OutputDebugStringF("NotifyKeyStoreStatusChanged\n"); - if(walletmodel) - QMetaObject::invokeMethod(walletmodel, "updateStatus", Qt::QueuedConnection); -} - -void NotifyAddressBookChanged(CWallet *wallet, const std::string &address, const std::string &label, ChangeType status) -{ - // This currently ignores the wallet argument. When multiple wallet support is implemented, this - // parameter should be mapped to a specific WalletModel for that wallet. - OutputDebugStringF("NotifyAddressBookChanged %s %s status=%i\n", address.c_str(), label.c_str(), status); - if(walletmodel) - QMetaObject::invokeMethod(walletmodel, "updateAddressBook", Qt::QueuedConnection, - Q_ARG(QString, QString::fromStdString(address)), - Q_ARG(QString, QString::fromStdString(label)), - Q_ARG(int, status)); -} - -void NotifyTransactionChanged(CWallet *wallet, const uint256 &hash, ChangeType status) -{ - // This currently ignores the wallet argument. When multiple wallet support is implemented, this - // parameter should be mapped to a specific WalletModel for that wallet. - OutputDebugStringF("NotifyTransactionChanged %s status=%i\n", hash.GetHex().c_str(), status); - if(walletmodel) - QMetaObject::invokeMethod(walletmodel, "updateTransaction", Qt::QueuedConnection, - Q_ARG(QString, QString::fromStdString(hash.GetHex())), - Q_ARG(int, status)); -} - -void NotifyNumConnectionsChanged(int newNumConnections) -{ - // Too noisy: OutputDebugStringF("NotifyNumConnectionsChanged %i\n", newNumConnections); - if(clientmodel) - QMetaObject::invokeMethod(clientmodel, "updateNumConnections", Qt::QueuedConnection, - Q_ARG(int, newNumConnections)); -} - -void NotifyAlertChanged(const uint256 &hash, ChangeType status) -{ - OutputDebugStringF("NotifyAlertChanged %s status=%i\n", hash.GetHex().c_str(), status); - if(clientmodel) - QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection, - Q_ARG(QString, QString::fromStdString(hash.GetHex())), - Q_ARG(int, status)); -} - /* Handle runaway exceptions. Shows a message box with the problem and quits the program. */ static void handleRunawayException(std::exception *e) @@ -307,6 +249,14 @@ int main(int argc, char *argv[]) if (translator.load(lang_territory, ":/translations/")) app.installTranslator(&translator); + // Subscribe to global signals from core + uiInterface.ThreadSafeMessageBox.connect(ThreadSafeMessageBox); + uiInterface.ThreadSafeAskFee.connect(ThreadSafeAskFee); + uiInterface.ThreadSafeHandleURI.connect(ThreadSafeHandleURI); + uiInterface.InitMessage.connect(InitMessage); + uiInterface.QueueShutdown.connect(QueueShutdown); + uiInterface.Translate.connect(Translate); + // Show help message immediately after parsing command-line options (for "-lang") and setting locale, // but before showing splash screen. if (mapArgs.count("-?") || mapArgs.count("--help")) @@ -348,9 +298,7 @@ int main(int argc, char *argv[]) splash.finish(&window); ClientModel clientModel(&optionsModel); - clientmodel = &clientModel; WalletModel walletModel(pwalletMain, &optionsModel); - walletmodel = &walletModel; window.setClientModel(&clientModel); window.setWalletModel(&walletModel); @@ -392,8 +340,6 @@ int main(int argc, char *argv[]) window.setClientModel(0); window.setWalletModel(0); guiref = 0; - clientmodel = 0; - walletmodel = 0; } Shutdown(NULL); } diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 1914ef90b..64fd2a945 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -22,6 +22,13 @@ ClientModel::ClientModel(OptionsModel *optionsModel, QObject *parent) : pollTimer->setInterval(MODEL_UPDATE_DELAY); pollTimer->start(); connect(pollTimer, SIGNAL(timeout()), this, SLOT(updateTimer())); + + subscribeToCoreSignals(); +} + +ClientModel::~ClientModel() +{ + unsubscribeFromCoreSignals(); } int ClientModel::getNumConnections() const @@ -127,3 +134,41 @@ QDateTime ClientModel::formatClientStartupTime() const { return QDateTime::fromTime_t(nClientStartupTime); } + +// Handlers for core signals +static void NotifyBlocksChanged(ClientModel *clientmodel) +{ + // This notification is too frequent. Don't trigger a signal. + // Don't remove it, though, as it might be useful later. +} + +static void NotifyNumConnectionsChanged(ClientModel *clientmodel, int newNumConnections) +{ + // Too noisy: OutputDebugStringF("NotifyNumConnectionsChanged %i\n", newNumConnections); + QMetaObject::invokeMethod(clientmodel, "updateNumConnections", Qt::QueuedConnection, + Q_ARG(int, newNumConnections)); +} + +static void NotifyAlertChanged(ClientModel *clientmodel, const uint256 &hash, ChangeType status) +{ + OutputDebugStringF("NotifyAlertChanged %s status=%i\n", hash.GetHex().c_str(), status); + QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection, + Q_ARG(QString, QString::fromStdString(hash.GetHex())), + Q_ARG(int, status)); +} + +void ClientModel::subscribeToCoreSignals() +{ + // Connect signals to client + uiInterface.NotifyBlocksChanged.connect(boost::bind(NotifyBlocksChanged, this)); + uiInterface.NotifyNumConnectionsChanged.connect(boost::bind(NotifyNumConnectionsChanged, this, _1)); + uiInterface.NotifyAlertChanged.connect(boost::bind(NotifyAlertChanged, this, _1, _2)); +} + +void ClientModel::unsubscribeFromCoreSignals() +{ + // Disconnect signals from client + uiInterface.NotifyBlocksChanged.disconnect(boost::bind(NotifyBlocksChanged, this)); + uiInterface.NotifyNumConnectionsChanged.disconnect(boost::bind(NotifyNumConnectionsChanged, this, _1)); + uiInterface.NotifyAlertChanged.disconnect(boost::bind(NotifyAlertChanged, this, _1, _2)); +} diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index bf2cd84a1..0349c389c 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -19,6 +19,7 @@ class ClientModel : public QObject Q_OBJECT public: explicit ClientModel(OptionsModel *optionsModel, QObject *parent = 0); + ~ClientModel(); OptionsModel *getOptionsModel(); @@ -52,6 +53,8 @@ private: QTimer *pollTimer; + void subscribeToCoreSignals(); + void unsubscribeFromCoreSignals(); signals: void numConnectionsChanged(int count); void numBlocksChanged(int count, int countOfPeers); diff --git a/src/qt/qtipcserver.cpp b/src/qt/qtipcserver.cpp index 06ada5aac..3d7d90e90 100644 --- a/src/qt/qtipcserver.cpp +++ b/src/qt/qtipcserver.cpp @@ -31,7 +31,7 @@ void ipcThread(void* parg) ptime d = boost::posix_time::microsec_clock::universal_time() + millisec(100); if(mq->timed_receive(&strBuf, sizeof(strBuf), nSize, nPriority, d)) { - ThreadSafeHandleURI(std::string(strBuf, nSize)); + uiInterface.ThreadSafeHandleURI(std::string(strBuf, nSize)); Sleep(1000); } if (fShutdown) @@ -69,7 +69,7 @@ void ipcInit() ptime d = boost::posix_time::microsec_clock::universal_time() + millisec(1); if(mq->timed_receive(&strBuf, sizeof(strBuf), nSize, nPriority, d)) { - ThreadSafeHandleURI(std::string(strBuf, nSize)); + uiInterface.ThreadSafeHandleURI(std::string(strBuf, nSize)); } else break; diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 4e082a8ab..1a9700ef0 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -18,6 +18,13 @@ WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *p { addressTableModel = new AddressTableModel(wallet, this); transactionTableModel = new TransactionTableModel(wallet, this); + + subscribeToCoreSignals(); +} + +WalletModel::~WalletModel() +{ + unsubscribeFromCoreSignals(); } qint64 WalletModel::getBalance() const @@ -147,7 +154,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(const QListNotifyStatusChanged.connect(boost::bind(&NotifyKeyStoreStatusChanged, this, _1)); + wallet->NotifyAddressBookChanged.connect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4)); + wallet->NotifyTransactionChanged.connect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3)); +} + +void WalletModel::unsubscribeFromCoreSignals() +{ + // Disconnect signals from wallet + wallet->NotifyStatusChanged.disconnect(boost::bind(&NotifyKeyStoreStatusChanged, this, _1)); + wallet->NotifyAddressBookChanged.disconnect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4)); + wallet->NotifyTransactionChanged.disconnect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3)); +} + // WalletModel::UnlockContext implementation WalletModel::UnlockContext WalletModel::requestUnlock() { diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 8250794f2..c413ed243 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -24,6 +24,7 @@ class WalletModel : public QObject Q_OBJECT public: explicit WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *parent = 0); + ~WalletModel(); enum StatusCode // Returned by sendCoins { @@ -118,6 +119,8 @@ private: qint64 cachedNumTransactions; EncryptionStatus cachedEncryptionStatus; + void subscribeToCoreSignals(); + void unsubscribeFromCoreSignals(); signals: // Signal that balance in wallet changed void balanceChanged(qint64 balance, qint64 unconfirmedBalance); diff --git a/src/ui_interface.h b/src/ui_interface.h index c1ed265a0..954a78100 100644 --- a/src/ui_interface.h +++ b/src/ui_interface.h @@ -6,40 +6,47 @@ #include #include "util.h" // for int64 +#include +#include class CBasicKeyStore; class CWallet; class uint256; -#define wxYES 0x00000002 -#define wxOK 0x00000004 -#define wxNO 0x00000008 -#define wxYES_NO (wxYES|wxNO) -#define wxCANCEL 0x00000010 -#define wxAPPLY 0x00000020 -#define wxCLOSE 0x00000040 -#define wxOK_DEFAULT 0x00000000 -#define wxYES_DEFAULT 0x00000000 -#define wxNO_DEFAULT 0x00000080 -#define wxCANCEL_DEFAULT 0x80000000 -#define wxICON_EXCLAMATION 0x00000100 -#define wxICON_HAND 0x00000200 -#define wxICON_WARNING wxICON_EXCLAMATION -#define wxICON_ERROR wxICON_HAND -#define wxICON_QUESTION 0x00000400 -#define wxICON_INFORMATION 0x00000800 -#define wxICON_STOP wxICON_HAND -#define wxICON_ASTERISK wxICON_INFORMATION -#define wxICON_MASK (0x00000100|0x00000200|0x00000400|0x00000800) -#define wxFORWARD 0x00001000 -#define wxBACKWARD 0x00002000 -#define wxRESET 0x00004000 -#define wxHELP 0x00008000 -#define wxMORE 0x00010000 -#define wxSETUP 0x00020000 -// Force blocking, modal message box dialog (not just notification) -#define wxMODAL 0x00040000 +/** Flags for CClientUIInterface::ThreadSafeMessageBox */ +enum MessageBoxFlags +{ + MF_YES = 0x00000002, + MF_OK = 0x00000004, + MF_NO = 0x00000008, + MF_YES_NO = (MF_YES|MF_NO), + MF_CANCEL = 0x00000010, + MF_APPLY = 0x00000020, + MF_CLOSE = 0x00000040, + MF_OK_DEFAULT = 0x00000000, + MF_YES_DEFAULT = 0x00000000, + MF_NO_DEFAULT = 0x00000080, + MF_CANCEL_DEFAULT = 0x80000000, + MF_ICON_EXCLAMATION = 0x00000100, + MF_ICON_HAND = 0x00000200, + MF_ICON_WARNING = MF_ICON_EXCLAMATION, + MF_ICON_ERROR = MF_ICON_HAND, + MF_ICON_QUESTION = 0x00000400, + MF_ICON_INFORMATION = 0x00000800, + MF_ICON_STOP = MF_ICON_HAND, + MF_ICON_ASTERISK = MF_ICON_INFORMATION, + MF_ICON_MASK = (0x00000100|0x00000200|0x00000400|0x00000800), + MF_FORWARD = 0x00001000, + MF_BACKWARD = 0x00002000, + MF_RESET = 0x00004000, + MF_HELP = 0x00008000, + MF_MORE = 0x00010000, + MF_SETUP = 0x00020000, +// Force blocking, modal message box dialog (not just OS notification) + MF_MODAL = 0x00040000 +}; +/** General change type (added, updated, removed). */ enum ChangeType { CT_NEW, @@ -47,39 +54,51 @@ enum ChangeType CT_DELETED }; -/* These UI communication functions are implemented in bitcoin.cpp (for ui) and noui.cpp (no ui) */ +/** Signals for UI communication. */ +class CClientUIInterface +{ +public: + /** Show message box. */ + boost::signals2::signal ThreadSafeMessageBox; -extern int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style=wxOK); -extern bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption); -extern void ThreadSafeHandleURI(const std::string& strURI); -extern void QueueShutdown(); -extern void InitMessage(const std::string &message); -extern std::string _(const char* psz); + /** Ask the user whether he want to pay a fee or not. */ + boost::signals2::signal > ThreadSafeAskFee; -/* Block chain changed. */ -extern void NotifyBlocksChanged(); + /** Handle an URL passed on the command line. */ + boost::signals2::signal ThreadSafeHandleURI; -/* Wallet status (encrypted, locked) changed. - * Note: Called without locks held. - */ -extern void NotifyKeyStoreStatusChanged(CBasicKeyStore *wallet); + /** Progress message during initialization. */ + boost::signals2::signal InitMessage; -/* Address book entry changed. - * Note: called with lock cs_wallet held. - */ -extern void NotifyAddressBookChanged(CWallet *wallet, const std::string &address, const std::string &label, ChangeType status); + /** Initiate client shutdown. */ + boost::signals2::signal QueueShutdown; -/* Wallet transaction added, removed or updated. - * Note: called with lock cs_wallet held. - */ -extern void NotifyTransactionChanged(CWallet *wallet, const uint256 &hashTx, ChangeType status); + /** Translate a message to the native language of the user. */ + boost::signals2::signal Translate; -/* Number of connections changed. */ -extern void NotifyNumConnectionsChanged(int newNumConnections); + /** Block chain changed. */ + boost::signals2::signal NotifyBlocksChanged; -/* New, updated or cancelled alert. - * Note: called with lock cs_mapAlerts held. + /** Number of network connections changed. */ + boost::signals2::signal NotifyNumConnectionsChanged; + + /** + * New, updated or cancelled alert. + * @note called with lock cs_mapAlerts held. + */ + boost::signals2::signal NotifyAlertChanged; +}; + +extern CClientUIInterface uiInterface; + +/** + * Translation function: Call Translate signal on UI interface, which returns a boost::optional result. + * If no translation slot is registered, nothing is returned, and simply return the input. */ -extern void NotifyAlertChanged(const uint256 &hash, ChangeType status); +inline std::string _(const char* psz) +{ + boost::optional rv = uiInterface.Translate(psz); + return rv ? (*rv) : psz; +} #endif diff --git a/src/util.cpp b/src/util.cpp index c778e51e3..a9b65ed94 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -1000,7 +1000,7 @@ void AddTimeData(const CNetAddr& ip, int64 nTime) string strMessage = _("Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly."); strMiscWarning = strMessage; printf("*** %s\n", strMessage.c_str()); - ThreadSafeMessageBox(strMessage+" ", string("Bitcoin"), wxOK | wxICON_EXCLAMATION); + uiInterface.ThreadSafeMessageBox(strMessage+" ", string("Bitcoin"), MF_OK | MF_ICON_EXCLAMATION); } } } diff --git a/src/wallet.cpp b/src/wallet.cpp index 132f68bee..92ad8c0f1 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -276,7 +276,7 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) CDB::Rewrite(strWalletFile); } - NotifyKeyStoreStatusChanged(this); + NotifyStatusChanged(this); return true; } @@ -1229,7 +1229,7 @@ string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, return strError; } - if (fAskFee && !ThreadSafeAskFee(nFeeRequired, _("Sending..."))) + if (fAskFee && !uiInterface.ThreadSafeAskFee(nFeeRequired, _("Sending..."))) return "ABORTED"; if (!CommitTransaction(wtxNew, reservekey)) diff --git a/src/wallet.h b/src/wallet.h index f84e6a329..b3b2e4f46 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -9,6 +9,7 @@ #include "key.h" #include "keystore.h" #include "script.h" +#include "ui_interface.h" class CWalletTx; class CReserveKey; @@ -261,6 +262,16 @@ public: // get the current wallet format (the oldest client version guaranteed to understand this wallet) int GetVersion() { return nWalletVersion; } + + /** Address book entry changed. + * @note called with lock cs_wallet held. + */ + boost::signals2::signal NotifyAddressBookChanged; + + /** Wallet transaction added, removed or updated. + * @note called with lock cs_wallet held. + */ + boost::signals2::signal NotifyTransactionChanged; }; /** A key allocated from the key pool. */