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.
This commit is contained in:
Wladimir J. van der Laan 2012-05-06 19:40:58 +02:00
parent fe4a655042
commit ab1b288fa7
21 changed files with 267 additions and 226 deletions

View File

@ -435,7 +435,7 @@ Value stop(const Array& params, bool fHelp)
"stop\n" "stop\n"
"Stop Bitcoin server."); "Stop Bitcoin server.");
// Shutdown will take long enough that the response should get back // Shutdown will take long enough that the response should get back
QueueShutdown(); uiInterface.QueueShutdown();
return "Bitcoin server stopping"; 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 // 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 // slack space in .dat files; that is bad if the old data is
// unencrypted private keys. So: // unencrypted private keys. So:
QueueShutdown(); uiInterface.QueueShutdown();
return "wallet encrypted; Bitcoin server stopping, restart to run with encrypted wallet"; 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\""); strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
else if (mapArgs.count("-daemon")) else if (mapArgs.count("-daemon"))
strWhatAmI = strprintf(_("To use the %s option"), "\"-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" _("%s, you must set a rpcpassword in the configuration file:\n %s\n"
"It is recommended you use the following random password:\n" "It is recommended you use the following random password:\n"
"rpcuser=bitcoinrpc\n" "rpcuser=bitcoinrpc\n"
@ -2630,8 +2630,8 @@ void ThreadRPCServer2(void* parg)
strWhatAmI.c_str(), strWhatAmI.c_str(),
GetConfigFile().string().c_str(), GetConfigFile().string().c_str(),
EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()), EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
_("Error"), wxOK | wxMODAL); _("Error"), MF_OK | MF_MODAL);
QueueShutdown(); uiInterface.QueueShutdown();
return; return;
} }
@ -2650,9 +2650,9 @@ void ThreadRPCServer2(void* parg)
} }
catch(boost::system::system_error &e) 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()), uiInterface.ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
_("Error"), wxOK | wxMODAL); _("Error"), MF_OK | MF_MODAL);
QueueShutdown(); uiInterface.QueueShutdown();
return; return;
} }

View File

@ -22,6 +22,7 @@ using namespace std;
using namespace boost; using namespace boost;
CWallet* pwalletMain; CWallet* pwalletMain;
CClientUIInterface uiInterface;
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
@ -90,9 +91,33 @@ void HandleSIGTERM(int)
// Start // Start
// //
#if !defined(QT_GUI) #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[]) int main(int argc, char* argv[])
{ {
bool fRet = false; 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); fRet = AppInit(argc, argv);
if (fRet && fDaemon) if (fRet && fDaemon)
@ -160,13 +185,13 @@ bool AppInit(int argc, char* argv[])
bool static InitError(const std::string &str) bool static InitError(const std::string &str)
{ {
ThreadSafeMessageBox(str, _("Bitcoin"), wxOK | wxMODAL); uiInterface.ThreadSafeMessageBox(str, _("Bitcoin"), MF_OK|MF_MODAL);
return false; return false;
} }
bool static InitWarning(const std::string &str) 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; return true;
} }
@ -367,7 +392,7 @@ bool AppInit2()
fprintf(stdout, "Bitcoin server starting\n"); fprintf(stdout, "Bitcoin server starting\n");
int64 nStart; int64 nStart;
InitMessage(_("Loading addresses...")); uiInterface.InitMessage(_("Loading addresses..."));
printf("Loading addresses...\n"); printf("Loading addresses...\n");
nStart = GetTimeMillis(); nStart = GetTimeMillis();
@ -380,7 +405,7 @@ bool AppInit2()
printf("Loaded %i addresses from peers.dat %"PRI64d"ms\n", printf("Loaded %i addresses from peers.dat %"PRI64d"ms\n",
addrman.size(), GetTimeMillis() - nStart); addrman.size(), GetTimeMillis() - nStart);
InitMessage(_("Loading block index...")); uiInterface.InitMessage(_("Loading block index..."));
printf("Loading block index...\n"); printf("Loading block index...\n");
nStart = GetTimeMillis(); nStart = GetTimeMillis();
if (!LoadBlockIndex()) if (!LoadBlockIndex())
@ -406,7 +431,7 @@ bool AppInit2()
} }
} }
InitMessage(_("Loading wallet...")); uiInterface.InitMessage(_("Loading wallet..."));
printf("Loading wallet...\n"); printf("Loading wallet...\n");
nStart = GetTimeMillis(); nStart = GetTimeMillis();
bool fFirstRun; bool fFirstRun;
@ -474,14 +499,14 @@ bool AppInit2()
} }
if (pindexBest != pindexRescan) if (pindexBest != pindexRescan)
{ {
InitMessage(_("Rescanning...")); uiInterface.InitMessage(_("Rescanning..."));
printf("Rescanning last %i blocks (from block %i)...\n", pindexBest->nHeight - pindexRescan->nHeight, pindexRescan->nHeight); printf("Rescanning last %i blocks (from block %i)...\n", pindexBest->nHeight - pindexRescan->nHeight, pindexRescan->nHeight);
nStart = GetTimeMillis(); nStart = GetTimeMillis();
pwalletMain->ScanForWalletTransactions(pindexRescan, true); pwalletMain->ScanForWalletTransactions(pindexRescan, true);
printf(" rescan %15"PRI64d"ms\n", GetTimeMillis() - nStart); printf(" rescan %15"PRI64d"ms\n", GetTimeMillis() - nStart);
} }
InitMessage(_("Done loading")); uiInterface.InitMessage(_("Done loading"));
printf("Done loading\n"); printf("Done loading\n");
//// debug print //// debug print

View File

@ -5,7 +5,6 @@
#include "keystore.h" #include "keystore.h"
#include "script.h" #include "script.h"
#include "ui_interface.h"
bool CKeyStore::GetPubKey(const CBitcoinAddress &address, std::vector<unsigned char> &vchPubKeyOut) const bool CKeyStore::GetPubKey(const CBitcoinAddress &address, std::vector<unsigned char> &vchPubKeyOut) const
{ {
@ -84,7 +83,7 @@ bool CCryptoKeyStore::Lock()
vMasterKey.clear(); vMasterKey.clear();
} }
NotifyKeyStoreStatusChanged(this); NotifyStatusChanged(this);
return true; return true;
} }
@ -114,7 +113,7 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
} }
vMasterKey = vMasterKeyIn; vMasterKey = vMasterKeyIn;
} }
NotifyKeyStoreStatusChanged(this); NotifyStatusChanged(this);
return true; return true;
} }

View File

@ -8,6 +8,7 @@
#include "crypter.h" #include "crypter.h"
#include "sync.h" #include "sync.h"
#include "base58.h" #include "base58.h"
#include <boost/signals2/signal.hpp>
class CScript; class CScript;
@ -174,6 +175,11 @@ public:
mi++; mi++;
} }
} }
/* Wallet status (encrypted, locked) changed.
* Note: Called without locks held.
*/
boost::signals2::signal<void (CCryptoKeyStore* wallet)> NotifyStatusChanged;
}; };
#endif #endif

View File

@ -946,7 +946,7 @@ void static InvalidChainFound(CBlockIndex* pindexNew)
{ {
bnBestInvalidWork = pindexNew->bnChainWork; bnBestInvalidWork = pindexNew->bnChainWork;
CTxDB().WriteBestInvalidWork(bnBestInvalidWork); 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: 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()); 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(); hashPrevBestCoinBase = vtx[0].GetHash();
} }
NotifyBlocksChanged(); uiInterface.NotifyBlocksChanged();
return true; return true;
} }
@ -1858,8 +1858,8 @@ bool CheckDiskSpace(uint64 nAdditionalBytes)
string strMessage = _("Warning: Disk space is low"); string strMessage = _("Warning: Disk space is low");
strMiscWarning = strMessage; strMiscWarning = strMessage;
printf("*** %s\n", strMessage.c_str()); printf("*** %s\n", strMessage.c_str());
ThreadSafeMessageBox(strMessage, "Bitcoin", wxOK | wxICON_EXCLAMATION | wxMODAL); uiInterface.ThreadSafeMessageBox(strMessage, "Bitcoin", MF_OK | MF_ICON_EXCLAMATION | MF_MODAL);
QueueShutdown(); uiInterface.QueueShutdown();
return false; return false;
} }
return true; return true;
@ -2204,13 +2204,13 @@ bool CAlert::ProcessAlert()
if (Cancels(alert)) if (Cancels(alert))
{ {
printf("cancelling alert %d\n", alert.nID); printf("cancelling alert %d\n", alert.nID);
NotifyAlertChanged((*mi).first, CT_DELETED); uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED);
mapAlerts.erase(mi++); mapAlerts.erase(mi++);
} }
else if (!alert.IsInEffect()) else if (!alert.IsInEffect())
{ {
printf("expiring alert %d\n", alert.nID); printf("expiring alert %d\n", alert.nID);
NotifyAlertChanged((*mi).first, CT_DELETED); uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED);
mapAlerts.erase(mi++); mapAlerts.erase(mi++);
} }
else else
@ -2232,7 +2232,7 @@ bool CAlert::ProcessAlert()
mapAlerts.insert(make_pair(GetHash(), *this)); mapAlerts.insert(make_pair(GetHash(), *this));
// Notify UI if it applies to me // Notify UI if it applies to me
if(AppliesToMe()) if(AppliesToMe())
NotifyAlertChanged(GetHash(), CT_NEW); uiInterface.NotifyAlertChanged(GetHash(), CT_NEW);
} }
printf("accepted alert %d, AppliesToMe()=%d\n", nID, AppliesToMe()); printf("accepted alert %d, AppliesToMe()=%d\n", nID, AppliesToMe());

View File

@ -64,8 +64,7 @@ OBJS= \
obj/sync.o \ obj/sync.o \
obj/util.o \ obj/util.o \
obj/wallet.o \ obj/wallet.o \
obj/walletdb.o \ obj/walletdb.o
obj/noui.o
all: bitcoind.exe all: bitcoind.exe

View File

@ -61,8 +61,7 @@ OBJS= \
obj/sync.o \ obj/sync.o \
obj/util.o \ obj/util.o \
obj/wallet.o \ obj/wallet.o \
obj/walletdb.o \ obj/walletdb.o
obj/noui.o
all: bitcoind.exe all: bitcoind.exe

View File

@ -88,8 +88,7 @@ OBJS= \
obj/sync.o \ obj/sync.o \
obj/util.o \ obj/util.o \
obj/wallet.o \ obj/wallet.o \
obj/walletdb.o \ obj/walletdb.o
obj/noui.o
ifdef USE_UPNP ifdef USE_UPNP
DEFS += -DUSE_UPNP=$(USE_UPNP) DEFS += -DUSE_UPNP=$(USE_UPNP)

View File

@ -108,8 +108,7 @@ OBJS= \
obj/sync.o \ obj/sync.o \
obj/util.o \ obj/util.o \
obj/wallet.o \ obj/wallet.o \
obj/walletdb.o \ obj/walletdb.o
obj/noui.o
all: bitcoind all: bitcoind

View File

@ -705,7 +705,7 @@ void ThreadSocketHandler2(void* parg)
if (vNodes.size() != nPrevNodeCount) if (vNodes.size() != nPrevNodeCount)
{ {
nPrevNodeCount = vNodes.size(); nPrevNodeCount = vNodes.size();
NotifyNumConnectionsChanged(vNodes.size()); uiInterface.NotifyNumConnectionsChanged(vNodes.size());
} }

View File

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

View File

@ -36,15 +36,13 @@ Q_IMPORT_PLUGIN(qtaccessiblewidgets)
// Need a global reference for the notifications to find the GUI // Need a global reference for the notifications to find the GUI
static BitcoinGUI *guiref; static BitcoinGUI *guiref;
static QSplashScreen *splashref; 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 // Message from network thread
if(guiref) 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 // in case of modal message, use blocking connection to wait for user to click OK
QMetaObject::invokeMethod(guiref, "error", QMetaObject::invokeMethod(guiref, "error",
modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection, 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()); printf("%s: %s\n", caption.c_str(), message.c_str());
fprintf(stderr, "%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) if(!guiref)
return false; return false;
@ -75,7 +72,7 @@ bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption)
return payFee; return payFee;
} }
void ThreadSafeHandleURI(const std::string& strURI) static void ThreadSafeHandleURI(const std::string& strURI)
{ {
if(!guiref) if(!guiref)
return; return;
@ -84,7 +81,7 @@ void ThreadSafeHandleURI(const std::string& strURI)
Q_ARG(QString, QString::fromStdString(strURI))); Q_ARG(QString, QString::fromStdString(strURI)));
} }
void InitMessage(const std::string &message) static void InitMessage(const std::string &message)
{ {
if(splashref) if(splashref)
{ {
@ -93,7 +90,7 @@ void InitMessage(const std::string &message)
} }
} }
void QueueShutdown() static void QueueShutdown()
{ {
QMetaObject::invokeMethod(QCoreApplication::instance(), "quit", Qt::QueuedConnection); QMetaObject::invokeMethod(QCoreApplication::instance(), "quit", Qt::QueuedConnection);
} }
@ -101,66 +98,11 @@ void QueueShutdown()
/* /*
Translate string to current locale using Qt. 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(); 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. /* Handle runaway exceptions. Shows a message box with the problem and quits the program.
*/ */
static void handleRunawayException(std::exception *e) static void handleRunawayException(std::exception *e)
@ -307,6 +249,14 @@ int main(int argc, char *argv[])
if (translator.load(lang_territory, ":/translations/")) if (translator.load(lang_territory, ":/translations/"))
app.installTranslator(&translator); 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, // Show help message immediately after parsing command-line options (for "-lang") and setting locale,
// but before showing splash screen. // but before showing splash screen.
if (mapArgs.count("-?") || mapArgs.count("--help")) if (mapArgs.count("-?") || mapArgs.count("--help"))
@ -348,9 +298,7 @@ int main(int argc, char *argv[])
splash.finish(&window); splash.finish(&window);
ClientModel clientModel(&optionsModel); ClientModel clientModel(&optionsModel);
clientmodel = &clientModel;
WalletModel walletModel(pwalletMain, &optionsModel); WalletModel walletModel(pwalletMain, &optionsModel);
walletmodel = &walletModel;
window.setClientModel(&clientModel); window.setClientModel(&clientModel);
window.setWalletModel(&walletModel); window.setWalletModel(&walletModel);
@ -392,8 +340,6 @@ int main(int argc, char *argv[])
window.setClientModel(0); window.setClientModel(0);
window.setWalletModel(0); window.setWalletModel(0);
guiref = 0; guiref = 0;
clientmodel = 0;
walletmodel = 0;
} }
Shutdown(NULL); Shutdown(NULL);
} }

View File

@ -22,6 +22,13 @@ ClientModel::ClientModel(OptionsModel *optionsModel, QObject *parent) :
pollTimer->setInterval(MODEL_UPDATE_DELAY); pollTimer->setInterval(MODEL_UPDATE_DELAY);
pollTimer->start(); pollTimer->start();
connect(pollTimer, SIGNAL(timeout()), this, SLOT(updateTimer())); connect(pollTimer, SIGNAL(timeout()), this, SLOT(updateTimer()));
subscribeToCoreSignals();
}
ClientModel::~ClientModel()
{
unsubscribeFromCoreSignals();
} }
int ClientModel::getNumConnections() const int ClientModel::getNumConnections() const
@ -127,3 +134,41 @@ QDateTime ClientModel::formatClientStartupTime() const
{ {
return QDateTime::fromTime_t(nClientStartupTime); 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));
}

View File

@ -19,6 +19,7 @@ class ClientModel : public QObject
Q_OBJECT Q_OBJECT
public: public:
explicit ClientModel(OptionsModel *optionsModel, QObject *parent = 0); explicit ClientModel(OptionsModel *optionsModel, QObject *parent = 0);
~ClientModel();
OptionsModel *getOptionsModel(); OptionsModel *getOptionsModel();
@ -52,6 +53,8 @@ private:
QTimer *pollTimer; QTimer *pollTimer;
void subscribeToCoreSignals();
void unsubscribeFromCoreSignals();
signals: signals:
void numConnectionsChanged(int count); void numConnectionsChanged(int count);
void numBlocksChanged(int count, int countOfPeers); void numBlocksChanged(int count, int countOfPeers);

View File

@ -31,7 +31,7 @@ void ipcThread(void* parg)
ptime d = boost::posix_time::microsec_clock::universal_time() + millisec(100); ptime d = boost::posix_time::microsec_clock::universal_time() + millisec(100);
if(mq->timed_receive(&strBuf, sizeof(strBuf), nSize, nPriority, d)) if(mq->timed_receive(&strBuf, sizeof(strBuf), nSize, nPriority, d))
{ {
ThreadSafeHandleURI(std::string(strBuf, nSize)); uiInterface.ThreadSafeHandleURI(std::string(strBuf, nSize));
Sleep(1000); Sleep(1000);
} }
if (fShutdown) if (fShutdown)
@ -69,7 +69,7 @@ void ipcInit()
ptime d = boost::posix_time::microsec_clock::universal_time() + millisec(1); ptime d = boost::posix_time::microsec_clock::universal_time() + millisec(1);
if(mq->timed_receive(&strBuf, sizeof(strBuf), nSize, nPriority, d)) if(mq->timed_receive(&strBuf, sizeof(strBuf), nSize, nPriority, d))
{ {
ThreadSafeHandleURI(std::string(strBuf, nSize)); uiInterface.ThreadSafeHandleURI(std::string(strBuf, nSize));
} }
else else
break; break;

View File

@ -18,6 +18,13 @@ WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *p
{ {
addressTableModel = new AddressTableModel(wallet, this); addressTableModel = new AddressTableModel(wallet, this);
transactionTableModel = new TransactionTableModel(wallet, this); transactionTableModel = new TransactionTableModel(wallet, this);
subscribeToCoreSignals();
}
WalletModel::~WalletModel()
{
unsubscribeFromCoreSignals();
} }
qint64 WalletModel::getBalance() const qint64 WalletModel::getBalance() const
@ -147,7 +154,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList<SendCoinsRecipie
} }
return TransactionCreationFailed; return TransactionCreationFailed;
} }
if(!ThreadSafeAskFee(nFeeRequired, tr("Sending...").toStdString())) if(!uiInterface.ThreadSafeAskFee(nFeeRequired, tr("Sending...").toStdString()))
{ {
return Aborted; return Aborted;
} }
@ -254,6 +261,46 @@ bool WalletModel::backupWallet(const QString &filename)
return BackupWallet(*wallet, filename.toLocal8Bit().data()); return BackupWallet(*wallet, filename.toLocal8Bit().data());
} }
// Handlers for core signals
static void NotifyKeyStoreStatusChanged(WalletModel *walletmodel, CCryptoKeyStore *wallet)
{
OutputDebugStringF("NotifyKeyStoreStatusChanged\n");
QMetaObject::invokeMethod(walletmodel, "updateStatus", Qt::QueuedConnection);
}
static void NotifyAddressBookChanged(WalletModel *walletmodel, CWallet *wallet, const std::string &address, const std::string &label, ChangeType status)
{
OutputDebugStringF("NotifyAddressBookChanged %s %s status=%i\n", address.c_str(), label.c_str(), status);
QMetaObject::invokeMethod(walletmodel, "updateAddressBook", Qt::QueuedConnection,
Q_ARG(QString, QString::fromStdString(address)),
Q_ARG(QString, QString::fromStdString(label)),
Q_ARG(int, status));
}
static void NotifyTransactionChanged(WalletModel *walletmodel, CWallet *wallet, const uint256 &hash, ChangeType status)
{
OutputDebugStringF("NotifyTransactionChanged %s status=%i\n", hash.GetHex().c_str(), status);
QMetaObject::invokeMethod(walletmodel, "updateTransaction", Qt::QueuedConnection,
Q_ARG(QString, QString::fromStdString(hash.GetHex())),
Q_ARG(int, status));
}
void WalletModel::subscribeToCoreSignals()
{
// Connect signals to wallet
wallet->NotifyStatusChanged.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 implementation
WalletModel::UnlockContext WalletModel::requestUnlock() WalletModel::UnlockContext WalletModel::requestUnlock()
{ {

View File

@ -24,6 +24,7 @@ class WalletModel : public QObject
Q_OBJECT Q_OBJECT
public: public:
explicit WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *parent = 0); explicit WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *parent = 0);
~WalletModel();
enum StatusCode // Returned by sendCoins enum StatusCode // Returned by sendCoins
{ {
@ -118,6 +119,8 @@ private:
qint64 cachedNumTransactions; qint64 cachedNumTransactions;
EncryptionStatus cachedEncryptionStatus; EncryptionStatus cachedEncryptionStatus;
void subscribeToCoreSignals();
void unsubscribeFromCoreSignals();
signals: signals:
// Signal that balance in wallet changed // Signal that balance in wallet changed
void balanceChanged(qint64 balance, qint64 unconfirmedBalance); void balanceChanged(qint64 balance, qint64 unconfirmedBalance);

View File

@ -6,40 +6,47 @@
#include <string> #include <string>
#include "util.h" // for int64 #include "util.h" // for int64
#include <boost/signals2/signal.hpp>
#include <boost/signals2/last_value.hpp>
class CBasicKeyStore; class CBasicKeyStore;
class CWallet; class CWallet;
class uint256; class uint256;
#define wxYES 0x00000002 /** Flags for CClientUIInterface::ThreadSafeMessageBox */
#define wxOK 0x00000004 enum MessageBoxFlags
#define wxNO 0x00000008 {
#define wxYES_NO (wxYES|wxNO) MF_YES = 0x00000002,
#define wxCANCEL 0x00000010 MF_OK = 0x00000004,
#define wxAPPLY 0x00000020 MF_NO = 0x00000008,
#define wxCLOSE 0x00000040 MF_YES_NO = (MF_YES|MF_NO),
#define wxOK_DEFAULT 0x00000000 MF_CANCEL = 0x00000010,
#define wxYES_DEFAULT 0x00000000 MF_APPLY = 0x00000020,
#define wxNO_DEFAULT 0x00000080 MF_CLOSE = 0x00000040,
#define wxCANCEL_DEFAULT 0x80000000 MF_OK_DEFAULT = 0x00000000,
#define wxICON_EXCLAMATION 0x00000100 MF_YES_DEFAULT = 0x00000000,
#define wxICON_HAND 0x00000200 MF_NO_DEFAULT = 0x00000080,
#define wxICON_WARNING wxICON_EXCLAMATION MF_CANCEL_DEFAULT = 0x80000000,
#define wxICON_ERROR wxICON_HAND MF_ICON_EXCLAMATION = 0x00000100,
#define wxICON_QUESTION 0x00000400 MF_ICON_HAND = 0x00000200,
#define wxICON_INFORMATION 0x00000800 MF_ICON_WARNING = MF_ICON_EXCLAMATION,
#define wxICON_STOP wxICON_HAND MF_ICON_ERROR = MF_ICON_HAND,
#define wxICON_ASTERISK wxICON_INFORMATION MF_ICON_QUESTION = 0x00000400,
#define wxICON_MASK (0x00000100|0x00000200|0x00000400|0x00000800) MF_ICON_INFORMATION = 0x00000800,
#define wxFORWARD 0x00001000 MF_ICON_STOP = MF_ICON_HAND,
#define wxBACKWARD 0x00002000 MF_ICON_ASTERISK = MF_ICON_INFORMATION,
#define wxRESET 0x00004000 MF_ICON_MASK = (0x00000100|0x00000200|0x00000400|0x00000800),
#define wxHELP 0x00008000 MF_FORWARD = 0x00001000,
#define wxMORE 0x00010000 MF_BACKWARD = 0x00002000,
#define wxSETUP 0x00020000 MF_RESET = 0x00004000,
// Force blocking, modal message box dialog (not just notification) MF_HELP = 0x00008000,
#define wxMODAL 0x00040000 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 enum ChangeType
{ {
CT_NEW, CT_NEW,
@ -47,39 +54,51 @@ enum ChangeType
CT_DELETED 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<void (const std::string& message, const std::string& caption, int style)> ThreadSafeMessageBox;
extern int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style=wxOK); /** Ask the user whether he want to pay a fee or not. */
extern bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption); boost::signals2::signal<bool (int64 nFeeRequired, const std::string& strCaption), boost::signals2::last_value<bool> > ThreadSafeAskFee;
extern void ThreadSafeHandleURI(const std::string& strURI);
extern void QueueShutdown();
extern void InitMessage(const std::string &message);
extern std::string _(const char* psz);
/* Block chain changed. */ /** Handle an URL passed on the command line. */
extern void NotifyBlocksChanged(); boost::signals2::signal<void (const std::string& strURI)> ThreadSafeHandleURI;
/* Wallet status (encrypted, locked) changed. /** Progress message during initialization. */
* Note: Called without locks held. boost::signals2::signal<void (const std::string &message)> InitMessage;
/** Initiate client shutdown. */
boost::signals2::signal<void ()> QueueShutdown;
/** Translate a message to the native language of the user. */
boost::signals2::signal<std::string (const char* psz)> Translate;
/** Block chain changed. */
boost::signals2::signal<void ()> NotifyBlocksChanged;
/** Number of network connections changed. */
boost::signals2::signal<void (int newNumConnections)> NotifyNumConnectionsChanged;
/**
* New, updated or cancelled alert.
* @note called with lock cs_mapAlerts held.
*/ */
extern void NotifyKeyStoreStatusChanged(CBasicKeyStore *wallet); boost::signals2::signal<void (const uint256 &hash, ChangeType status)> NotifyAlertChanged;
};
/* Address book entry changed. extern CClientUIInterface uiInterface;
* Note: called with lock cs_wallet held.
/**
* 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 NotifyAddressBookChanged(CWallet *wallet, const std::string &address, const std::string &label, ChangeType status); inline std::string _(const char* psz)
{
/* Wallet transaction added, removed or updated. boost::optional<std::string> rv = uiInterface.Translate(psz);
* Note: called with lock cs_wallet held. return rv ? (*rv) : psz;
*/ }
extern void NotifyTransactionChanged(CWallet *wallet, const uint256 &hashTx, ChangeType status);
/* Number of connections changed. */
extern void NotifyNumConnectionsChanged(int newNumConnections);
/* New, updated or cancelled alert.
* Note: called with lock cs_mapAlerts held.
*/
extern void NotifyAlertChanged(const uint256 &hash, ChangeType status);
#endif #endif

View File

@ -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."); 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; strMiscWarning = strMessage;
printf("*** %s\n", strMessage.c_str()); printf("*** %s\n", strMessage.c_str());
ThreadSafeMessageBox(strMessage+" ", string("Bitcoin"), wxOK | wxICON_EXCLAMATION); uiInterface.ThreadSafeMessageBox(strMessage+" ", string("Bitcoin"), MF_OK | MF_ICON_EXCLAMATION);
} }
} }
} }

View File

@ -276,7 +276,7 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
CDB::Rewrite(strWalletFile); CDB::Rewrite(strWalletFile);
} }
NotifyKeyStoreStatusChanged(this); NotifyStatusChanged(this);
return true; return true;
} }
@ -1229,7 +1229,7 @@ string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew,
return strError; return strError;
} }
if (fAskFee && !ThreadSafeAskFee(nFeeRequired, _("Sending..."))) if (fAskFee && !uiInterface.ThreadSafeAskFee(nFeeRequired, _("Sending...")))
return "ABORTED"; return "ABORTED";
if (!CommitTransaction(wtxNew, reservekey)) if (!CommitTransaction(wtxNew, reservekey))

View File

@ -9,6 +9,7 @@
#include "key.h" #include "key.h"
#include "keystore.h" #include "keystore.h"
#include "script.h" #include "script.h"
#include "ui_interface.h"
class CWalletTx; class CWalletTx;
class CReserveKey; class CReserveKey;
@ -261,6 +262,16 @@ public:
// get the current wallet format (the oldest client version guaranteed to understand this wallet) // get the current wallet format (the oldest client version guaranteed to understand this wallet)
int GetVersion() { return nWalletVersion; } int GetVersion() { return nWalletVersion; }
/** Address book entry changed.
* @note called with lock cs_wallet held.
*/
boost::signals2::signal<void (CWallet *wallet, const std::string &address, const std::string &label, ChangeType status)> NotifyAddressBookChanged;
/** Wallet transaction added, removed or updated.
* @note called with lock cs_wallet held.
*/
boost::signals2::signal<void (CWallet *wallet, const uint256 &hashTx, ChangeType status)> NotifyTransactionChanged;
}; };
/** A key allocated from the key pool. */ /** A key allocated from the key pool. */