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

View File

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

View File

@ -5,7 +5,6 @@
#include "keystore.h"
#include "script.h"
#include "ui_interface.h"
bool CKeyStore::GetPubKey(const CBitcoinAddress &address, std::vector<unsigned char> &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;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -705,7 +705,7 @@ void ThreadSocketHandler2(void* parg)
if (vNodes.size() != nPrevNodeCount)
{
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
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);
}

View File

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

View File

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

View File

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

View File

@ -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 QList<SendCoinsRecipie
}
return TransactionCreationFailed;
}
if(!ThreadSafeAskFee(nFeeRequired, tr("Sending...").toStdString()))
if(!uiInterface.ThreadSafeAskFee(nFeeRequired, tr("Sending...").toStdString()))
{
return Aborted;
}
@ -254,6 +261,46 @@ bool WalletModel::backupWallet(const QString &filename)
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 WalletModel::requestUnlock()
{

View File

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

View File

@ -6,40 +6,47 @@
#include <string>
#include "util.h" // for int64
#include <boost/signals2/signal.hpp>
#include <boost/signals2/last_value.hpp>
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<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);
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<bool (int64 nFeeRequired, const std::string& strCaption), boost::signals2::last_value<bool> > ThreadSafeAskFee;
/* Block chain changed. */
extern void NotifyBlocksChanged();
/** Handle an URL passed on the command line. */
boost::signals2::signal<void (const std::string& strURI)> ThreadSafeHandleURI;
/* Wallet status (encrypted, locked) changed.
* Note: Called without locks held.
/** Progress message during initialization. */
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.
*/
boost::signals2::signal<void (const uint256 &hash, ChangeType status)> 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 NotifyKeyStoreStatusChanged(CBasicKeyStore *wallet);
/* 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);
/* Wallet transaction added, removed or updated.
* Note: called with lock cs_wallet held.
*/
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);
inline std::string _(const char* psz)
{
boost::optional<std::string> rv = uiInterface.Translate(psz);
return rv ? (*rv) : psz;
}
#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.");
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);
}
}
}

View File

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

View File

@ -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<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. */