From fe4a655042f7de31dce120aeed72345579f1b59f Mon Sep 17 00:00:00 2001
From: "Wladimir J. van der Laan" <laanwj@gmail.com>
Date: Sat, 5 May 2012 16:07:14 +0200
Subject: Fine-grained UI updates

Gets rid of `MainFrameRepaint` in favor of specific update functions that tell the UI exactly what changed.

This improves the efficiency of various handlers. Also fixes problems with mined transactions not showing up until restart.

The following notifications were added:

- `NotifyBlocksChanged`: Block chain changed
- `NotifyKeyStoreStatusChanged`: Wallet status (encrypted, locked) changed.
- `NotifyAddressBookChanged`: Address book entry changed.
- `NotifyTransactionChanged`: Wallet transaction added, removed or updated.
- `NotifyNumConnectionsChanged`: Number of connections changed.
- `NotifyAlertChanged`: New, updated or cancelled alert. As this finally makes it possible for the UI to know when a new alert arrived, it can be shown as OS notification.

These notifications could also be useful for RPC clients. However, currently, they are ignored in bitcoind (in noui.cpp).

Also brings back polling with timer for numBlocks in ClientModel. This value updates so frequently during initial download that the number of signals clogs the UI thread and causes heavy CPU usage. And after initial block download, the value changes so rarely that a delay of half a second until the UI updates is unnoticable.
---
 src/keystore.cpp                 |  16 ++++
 src/keystore.h                   |  13 +--
 src/main.cpp                     |  22 ++++-
 src/main.h                       |   5 ++
 src/net.cpp                      |   2 +-
 src/noui.cpp                     |  31 +++++--
 src/qt/addresstablemodel.cpp     |   3 +-
 src/qt/addresstablemodel.h       |   4 +-
 src/qt/bitcoin.cpp               |  69 ++++++++++++---
 src/qt/bitcoingui.cpp            |   9 +-
 src/qt/bitcoingui.h              |   2 +-
 src/qt/clientmodel.cpp           |  57 ++++++++----
 src/qt/clientmodel.h             |  14 +--
 src/qt/rpcconsole.cpp            |   7 +-
 src/qt/rpcconsole.h              |   2 +-
 src/qt/transactionrecord.cpp     | 181 +++++++++++++++++++--------------------
 src/qt/transactiontablemodel.cpp | 146 ++++++++++++++++---------------
 src/qt/transactiontablemodel.h   |   6 +-
 src/qt/walletmodel.cpp           |  24 ++++--
 src/qt/walletmodel.h             |   8 +-
 src/rpcdump.cpp                  |   2 -
 src/ui_interface.h               |  39 ++++++++-
 src/wallet.cpp                   |  33 ++++---
 src/wallet.h                     |  10 +--
 24 files changed, 432 insertions(+), 273 deletions(-)

(limited to 'src')

diff --git a/src/keystore.cpp b/src/keystore.cpp
index 313518711b..55fba4c372 100644
--- a/src/keystore.cpp
+++ b/src/keystore.cpp
@@ -5,6 +5,7 @@
 
 #include "keystore.h"
 #include "script.h"
+#include "ui_interface.h"
 
 bool CKeyStore::GetPubKey(const CBitcoinAddress &address, std::vector<unsigned char> &vchPubKeyOut) const
 {
@@ -73,6 +74,20 @@ bool CCryptoKeyStore::SetCrypted()
     return true;
 }
 
+bool CCryptoKeyStore::Lock()
+{
+    if (!SetCrypted())
+        return false;
+
+    {
+        LOCK(cs_KeyStore);
+        vMasterKey.clear();
+    }
+
+    NotifyKeyStoreStatusChanged(this);
+    return true;
+}
+
 bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
 {
     {
@@ -99,6 +114,7 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
         }
         vMasterKey = vMasterKeyIn;
     }
+    NotifyKeyStoreStatusChanged(this);
     return true;
 }
 
diff --git a/src/keystore.h b/src/keystore.h
index 52889b184e..dd7110db58 100644
--- a/src/keystore.h
+++ b/src/keystore.h
@@ -143,18 +143,7 @@ public:
         return result;
     }
 
-    bool Lock()
-    {
-        if (!SetCrypted())
-            return false;
-
-        {
-            LOCK(cs_KeyStore);
-            vMasterKey.clear();
-        }
-
-        return true;
-    }
+    bool Lock();
 
     virtual bool AddCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
     bool AddKey(const CKey& key);
diff --git a/src/main.cpp b/src/main.cpp
index 8ff6d6fec0..7e7a0badfd 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -946,7 +946,7 @@ void static InvalidChainFound(CBlockIndex* pindexNew)
     {
         bnBestInvalidWork = pindexNew->bnChainWork;
         CTxDB().WriteBestInvalidWork(bnBestInvalidWork);
-        MainFrameRepaint();
+        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();
     }
 
-    MainFrameRepaint();
+    NotifyBlocksChanged();
     return true;
 }
 
@@ -2176,6 +2176,18 @@ string GetWarnings(string strFor)
     return "error";
 }
 
+CAlert CAlert::getAlertByHash(const uint256 &hash)
+{
+    CAlert retval;
+    {
+        LOCK(cs_mapAlerts);
+        map<uint256, CAlert>::iterator mi = mapAlerts.find(hash);
+        if(mi != mapAlerts.end())
+            retval = mi->second;
+    }
+    return retval;
+}
+
 bool CAlert::ProcessAlert()
 {
     if (!CheckSignature())
@@ -2192,11 +2204,13 @@ bool CAlert::ProcessAlert()
             if (Cancels(alert))
             {
                 printf("cancelling alert %d\n", alert.nID);
+                NotifyAlertChanged((*mi).first, CT_DELETED);
                 mapAlerts.erase(mi++);
             }
             else if (!alert.IsInEffect())
             {
                 printf("expiring alert %d\n", alert.nID);
+                NotifyAlertChanged((*mi).first, CT_DELETED);
                 mapAlerts.erase(mi++);
             }
             else
@@ -2216,10 +2230,12 @@ bool CAlert::ProcessAlert()
 
         // Add to mapAlerts
         mapAlerts.insert(make_pair(GetHash(), *this));
+        // Notify UI if it applies to me
+        if(AppliesToMe())
+            NotifyAlertChanged(GetHash(), CT_NEW);
     }
 
     printf("accepted alert %d, AppliesToMe()=%d\n", nID, AppliesToMe());
-    MainFrameRepaint();
     return true;
 }
 
diff --git a/src/main.h b/src/main.h
index 9700909f8b..f4a9759d76 100644
--- a/src/main.h
+++ b/src/main.h
@@ -1574,6 +1574,11 @@ public:
     }
 
     bool ProcessAlert();
+
+    /*
+     * Get copy of (active) alert object by hash. Returns a null alert if it is not found.
+     */
+    static CAlert getAlertByHash(const uint256 &hash);
 };
 
 class CTxMemPool
diff --git a/src/net.cpp b/src/net.cpp
index 8d19387602..32875b0f06 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -705,7 +705,7 @@ void ThreadSocketHandler2(void* parg)
         if (vNodes.size() != nPrevNodeCount)
         {
             nPrevNodeCount = vNodes.size();
-            MainFrameRepaint();
+            NotifyNumConnectionsChanged(vNodes.size());
         }
 
 
diff --git a/src/noui.cpp b/src/noui.cpp
index 08a08b439a..c7b74bea73 100644
--- a/src/noui.cpp
+++ b/src/noui.cpp
@@ -19,14 +19,6 @@ bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption)
     return true;
 }
 
-void MainFrameRepaint()
-{
-}
-
-void AddressBookRepaint()
-{
-}
-
 void InitMessage(const std::string &message)
 {
 }
@@ -42,3 +34,26 @@ void QueueShutdown()
     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/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp
index 7b95f51c04..4af4c3ac13 100644
--- a/src/qt/addresstablemodel.cpp
+++ b/src/qt/addresstablemodel.cpp
@@ -232,9 +232,10 @@ QModelIndex AddressTableModel::index(int row, int column, const QModelIndex & pa
     }
 }
 
-void AddressTableModel::update()
+void AddressTableModel::updateEntry(const QString &address, const QString &label, int status)
 {
     // Update address book model from Bitcoin core
+    // TODO: use address, label, status to update only the specified entry (like in WalletModel)
     beginResetModel();
     priv->refreshAddressTable();
     endResetModel();
diff --git a/src/qt/addresstablemodel.h b/src/qt/addresstablemodel.h
index 7fd07cfb81..bd73c6d147 100644
--- a/src/qt/addresstablemodel.h
+++ b/src/qt/addresstablemodel.h
@@ -78,9 +78,9 @@ signals:
     void defaultAddressChanged(const QString &address);
 
 public slots:
-    /* Update address list from core. Invalidates any indices.
+    /* Update address list from core.
      */
-    void update();
+    void updateEntry(const QString &address, const QString &label, int status);
 };
 
 #endif // ADDRESSTABLEMODEL_H
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 6a0a32fbd9..a50443021f 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -84,20 +84,6 @@ void ThreadSafeHandleURI(const std::string& strURI)
                                Q_ARG(QString, QString::fromStdString(strURI)));
 }
 
-void MainFrameRepaint()
-{
-    if(clientmodel)
-        QMetaObject::invokeMethod(clientmodel, "update", Qt::QueuedConnection);
-    if(walletmodel)
-        QMetaObject::invokeMethod(walletmodel, "update", Qt::QueuedConnection);
-}
-
-void AddressBookRepaint()
-{
-    if(walletmodel)
-        QMetaObject::invokeMethod(walletmodel, "updateAddressList", Qt::QueuedConnection);
-}
-
 void InitMessage(const std::string &message)
 {
     if(splashref)
@@ -120,6 +106,61 @@ std::string _(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)
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 7070e59444..9deaa4b6d3 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -350,11 +350,11 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel)
         setNumConnections(clientModel->getNumConnections());
         connect(clientModel, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
 
-        setNumBlocks(clientModel->getNumBlocks());
-        connect(clientModel, SIGNAL(numBlocksChanged(int)), this, SLOT(setNumBlocks(int)));
+        setNumBlocks(clientModel->getNumBlocks(), clientModel->getNumBlocksOfPeers());
+        connect(clientModel, SIGNAL(numBlocksChanged(int,int)), this, SLOT(setNumBlocks(int,int)));
 
         // Report errors from network/worker thread
-        connect(clientModel, SIGNAL(error(QString,QString, bool)), this, SLOT(error(QString,QString,bool)));
+        connect(clientModel, SIGNAL(error(QString,QString,bool)), this, SLOT(error(QString,QString,bool)));
 
         rpcConsole->setClientModel(clientModel);
     }
@@ -493,7 +493,7 @@ void BitcoinGUI::setNumConnections(int count)
     labelConnectionsIcon->setToolTip(tr("%n active connection(s) to Bitcoin network", "", count));
 }
 
-void BitcoinGUI::setNumBlocks(int count)
+void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks)
 {
     // don't show / hide progressBar and it's label if we have no connection(s) to the network
     if (!clientModel || clientModel->getNumConnections() == 0)
@@ -504,7 +504,6 @@ void BitcoinGUI::setNumBlocks(int count)
         return;
     }
 
-    int nTotalBlocks = clientModel->getNumBlocksOfPeers();
     QString tooltip;
 
     if(count < nTotalBlocks)
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index 88e6d064d7..8a7f6e541b 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -111,7 +111,7 @@ public slots:
     /** Set number of connections shown in the UI */
     void setNumConnections(int count);
     /** Set number of blocks shown in the UI */
-    void setNumBlocks(int count);
+    void setNumBlocks(int count, int countOfPeers);
     /** Set the encryption status as shown in the UI.
        @param[in] status            current encryption status
        @see WalletModel::EncryptionStatus
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index 85ab03612d..1914ef90b5 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -5,15 +5,23 @@
 #include "transactiontablemodel.h"
 
 #include "main.h"
-static const int64 nClientStartupTime = GetTime();
+#include "ui_interface.h"
 
 #include <QDateTime>
+#include <QTimer>
+
+static const int64 nClientStartupTime = GetTime();
 
 ClientModel::ClientModel(OptionsModel *optionsModel, QObject *parent) :
     QObject(parent), optionsModel(optionsModel),
-    cachedNumConnections(0), cachedNumBlocks(0)
+    cachedNumBlocks(0), cachedNumBlocksOfPeers(0), pollTimer(0)
 {
     numBlocksAtStartup = -1;
+
+    pollTimer = new QTimer();
+    pollTimer->setInterval(MODEL_UPDATE_DELAY);
+    pollTimer->start();
+    connect(pollTimer, SIGNAL(timeout()), this, SLOT(updateTimer()));
 }
 
 int ClientModel::getNumConnections() const
@@ -37,27 +45,42 @@ QDateTime ClientModel::getLastBlockDate() const
     return QDateTime::fromTime_t(pindexBest->GetBlockTime());
 }
 
-void ClientModel::update()
+void ClientModel::updateTimer()
 {
-    int newNumConnections = getNumConnections();
+    // Some quantities (such as number of blocks) change so fast that we don't want to be notified for each change.
+    // Periodically check and update with a timer.
     int newNumBlocks = getNumBlocks();
-    QString newStatusBar = getStatusBarWarnings();
+    int newNumBlocksOfPeers = getNumBlocksOfPeers();
 
-    if(cachedNumConnections != newNumConnections)
-        emit numConnectionsChanged(newNumConnections);
-    if(cachedNumBlocks != newNumBlocks || cachedStatusBar != newStatusBar)
+    if(cachedNumBlocks != newNumBlocks || cachedNumBlocksOfPeers != newNumBlocksOfPeers)
+        emit numBlocksChanged(newNumBlocks, newNumBlocksOfPeers);
+
+    cachedNumBlocks = newNumBlocks;
+    cachedNumBlocksOfPeers = newNumBlocksOfPeers;
+}
+
+void ClientModel::updateNumConnections(int numConnections)
+{
+    emit numConnectionsChanged(numConnections);
+}
+
+void ClientModel::updateAlert(const QString &hash, int status)
+{
+    // Show error message notification for new alert
+    if(status == CT_NEW)
     {
-        // Simply emit a numBlocksChanged for now in case the status message changes,
-        // so that the view updates the status bar.
-        // TODO: It should send a notification.
-        //    (However, this might generate looped notifications and needs to be thought through and tested carefully)
-        //    error(tr("Network Alert"), newStatusBar);
-        emit numBlocksChanged(newNumBlocks);
+        uint256 hash_256;
+        hash_256.SetHex(hash.toStdString());
+        CAlert alert = CAlert::getAlertByHash(hash_256);
+        if(!alert.IsNull())
+        {
+            emit error(tr("Network Alert"), QString::fromStdString(alert.strStatusBar), false);
+        }
     }
 
-    cachedNumConnections = newNumConnections;
-    cachedNumBlocks = newNumBlocks;
-    cachedStatusBar = newStatusBar;
+    // Emit a numBlocksChanged when the status message changes,
+    // so that the view recomputes and updates the status bar.
+    emit numBlocksChanged(getNumBlocks(), getNumBlocksOfPeers());
 }
 
 bool ClientModel::isTestNet() const
diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h
index 67835db727..bf2cd84a1c 100644
--- a/src/qt/clientmodel.h
+++ b/src/qt/clientmodel.h
@@ -10,6 +10,7 @@ class CWallet;
 
 QT_BEGIN_NAMESPACE
 class QDateTime;
+class QTimer;
 QT_END_NAMESPACE
 
 /** Model for Bitcoin network client. */
@@ -44,23 +45,24 @@ public:
 private:
     OptionsModel *optionsModel;
 
-    int cachedNumConnections;
     int cachedNumBlocks;
-    QString cachedStatusBar;
+    int cachedNumBlocksOfPeers;
 
     int numBlocksAtStartup;
 
+    QTimer *pollTimer;
+
 signals:
     void numConnectionsChanged(int count);
-    void numBlocksChanged(int count);
+    void numBlocksChanged(int count, int countOfPeers);
 
     //! Asynchronous error notification
     void error(const QString &title, const QString &message, bool modal);
 
 public slots:
-
-private slots:
-    void update();
+    void updateTimer();
+    void updateNumConnections(int numConnections);
+    void updateAlert(const QString &hash, int status);
 };
 
 #endif // CLIENTMODEL_H
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 0c77b05c56..7029ee33bc 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -157,7 +157,7 @@ void RPCConsole::setClientModel(ClientModel *model)
     {
         // Subscribe to information, replies, messages, errors
         connect(model, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
-        connect(model, SIGNAL(numBlocksChanged(int)), this, SLOT(setNumBlocks(int)));
+        connect(model, SIGNAL(numBlocksChanged(int,int)), this, SLOT(setNumBlocks(int,int)));
 
         // Provide initial values
         ui->clientVersion->setText(model->formatFullVersion());
@@ -168,7 +168,7 @@ void RPCConsole::setClientModel(ClientModel *model)
         setNumConnections(model->getNumConnections());
         ui->isTestNet->setChecked(model->isTestNet());
 
-        setNumBlocks(model->getNumBlocks());
+        setNumBlocks(model->getNumBlocks(), model->getNumBlocksOfPeers());
     }
 }
 
@@ -235,9 +235,10 @@ void RPCConsole::setNumConnections(int count)
     ui->numberOfConnections->setText(QString::number(count));
 }
 
-void RPCConsole::setNumBlocks(int count)
+void RPCConsole::setNumBlocks(int count, int countOfPeers)
 {
     ui->numberOfBlocks->setText(QString::number(count));
+    ui->totalBlocks->setText(QString::number(countOfPeers));
     if(clientModel)
     {
         // If there is no current number available display N/A instead of 0, which can't ever be true
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index 27f41817ea..4b71cdb988 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -42,7 +42,7 @@ public slots:
     /** Set number of connections shown in the UI */
     void setNumConnections(int count);
     /** Set number of blocks shown in the UI */
-    void setNumBlocks(int count);
+    void setNumBlocks(int count, int countOfPeers);
     /** Go forward or back in history */
     void browseHistory(int offset);
     /** Scroll console view to end */
diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp
index 53cfb409ff..017244ffd0 100644
--- a/src/qt/transactionrecord.cpp
+++ b/src/qt/transactionrecord.cpp
@@ -40,114 +40,111 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
     uint256 hash = wtx.GetHash();
     std::map<std::string, std::string> mapValue = wtx.mapValue;
 
-    if (showTransaction(wtx))
+    if (nNet > 0 || wtx.IsCoinBase())
     {
-        if (nNet > 0 || wtx.IsCoinBase())
+        //
+        // Credit
+        //
+        BOOST_FOREACH(const CTxOut& txout, wtx.vout)
         {
-            //
-            // Credit
-            //
-            BOOST_FOREACH(const CTxOut& txout, wtx.vout)
+            if(wallet->IsMine(txout))
             {
-                if(wallet->IsMine(txout))
+                TransactionRecord sub(hash, nTime);
+                CBitcoinAddress address;
+                sub.idx = parts.size(); // sequence number
+                sub.credit = txout.nValue;
+                if (wtx.IsCoinBase())
                 {
-                    TransactionRecord sub(hash, nTime);
-                    CBitcoinAddress address;
-                    sub.idx = parts.size(); // sequence number
-                    sub.credit = txout.nValue;
-                    if (wtx.IsCoinBase())
-                    {
-                        // Generated
-                        sub.type = TransactionRecord::Generated;
-                    }
-                    else if (ExtractAddress(txout.scriptPubKey, address) && wallet->HaveKey(address))
-                    {
-                        // Received by Bitcoin Address
-                        sub.type = TransactionRecord::RecvWithAddress;
-                        sub.address = address.ToString();
-                    }
-                    else
-                    {
-                        // Received by IP connection (deprecated features), or a multisignature or other non-simple transaction
-                        sub.type = TransactionRecord::RecvFromOther;
-                        sub.address = mapValue["from"];
-                    }
-
-                    parts.append(sub);
+                    // Generated
+                    sub.type = TransactionRecord::Generated;
                 }
+                else if (ExtractAddress(txout.scriptPubKey, address) && wallet->HaveKey(address))
+                {
+                    // Received by Bitcoin Address
+                    sub.type = TransactionRecord::RecvWithAddress;
+                    sub.address = address.ToString();
+                }
+                else
+                {
+                    // Received by IP connection (deprecated features), or a multisignature or other non-simple transaction
+                    sub.type = TransactionRecord::RecvFromOther;
+                    sub.address = mapValue["from"];
+                }
+
+                parts.append(sub);
             }
         }
-        else
+    }
+    else
+    {
+        bool fAllFromMe = true;
+        BOOST_FOREACH(const CTxIn& txin, wtx.vin)
+            fAllFromMe = fAllFromMe && wallet->IsMine(txin);
+
+        bool fAllToMe = true;
+        BOOST_FOREACH(const CTxOut& txout, wtx.vout)
+            fAllToMe = fAllToMe && wallet->IsMine(txout);
+
+        if (fAllFromMe && fAllToMe)
         {
-            bool fAllFromMe = true;
-            BOOST_FOREACH(const CTxIn& txin, wtx.vin)
-                fAllFromMe = fAllFromMe && wallet->IsMine(txin);
+            // Payment to self
+            int64 nChange = wtx.GetChange();
 
-            bool fAllToMe = true;
-            BOOST_FOREACH(const CTxOut& txout, wtx.vout)
-                fAllToMe = fAllToMe && wallet->IsMine(txout);
+            parts.append(TransactionRecord(hash, nTime, TransactionRecord::SendToSelf, "",
+                            -(nDebit - nChange), nCredit - nChange));
+        }
+        else if (fAllFromMe)
+        {
+            //
+            // Debit
+            //
+            int64 nTxFee = nDebit - wtx.GetValueOut();
 
-            if (fAllFromMe && fAllToMe)
+            for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++)
             {
-                // Payment to self
-                int64 nChange = wtx.GetChange();
+                const CTxOut& txout = wtx.vout[nOut];
+                TransactionRecord sub(hash, nTime);
+                sub.idx = parts.size();
 
-                parts.append(TransactionRecord(hash, nTime, TransactionRecord::SendToSelf, "",
-                                -(nDebit - nChange), nCredit - nChange));
-            }
-            else if (fAllFromMe)
-            {
-                //
-                // Debit
-                //
-                int64 nTxFee = nDebit - wtx.GetValueOut();
+                if(wallet->IsMine(txout))
+                {
+                    // Ignore parts sent to self, as this is usually the change
+                    // from a transaction sent back to our own address.
+                    continue;
+                }
 
-                for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++)
+                CBitcoinAddress address;
+                if (ExtractAddress(txout.scriptPubKey, address))
                 {
-                    const CTxOut& txout = wtx.vout[nOut];
-                    TransactionRecord sub(hash, nTime);
-                    sub.idx = parts.size();
-
-                    if(wallet->IsMine(txout))
-                    {
-                        // Ignore parts sent to self, as this is usually the change
-                        // from a transaction sent back to our own address.
-                        continue;
-                    }
-
-                    CBitcoinAddress address;
-                    if (ExtractAddress(txout.scriptPubKey, address))
-                    {
-                        // Sent to Bitcoin Address
-                        sub.type = TransactionRecord::SendToAddress;
-                        sub.address = address.ToString();
-                    }
-                    else
-                    {
-                        // Sent to IP, or other non-address transaction like OP_EVAL
-                        sub.type = TransactionRecord::SendToOther;
-                        sub.address = mapValue["to"];
-                    }
-
-                    int64 nValue = txout.nValue;
-                    /* Add fee to first output */
-                    if (nTxFee > 0)
-                    {
-                        nValue += nTxFee;
-                        nTxFee = 0;
-                    }
-                    sub.debit = -nValue;
-
-                    parts.append(sub);
+                    // Sent to Bitcoin Address
+                    sub.type = TransactionRecord::SendToAddress;
+                    sub.address = address.ToString();
                 }
+                else
+                {
+                    // Sent to IP, or other non-address transaction like OP_EVAL
+                    sub.type = TransactionRecord::SendToOther;
+                    sub.address = mapValue["to"];
+                }
+
+                int64 nValue = txout.nValue;
+                /* Add fee to first output */
+                if (nTxFee > 0)
+                {
+                    nValue += nTxFee;
+                    nTxFee = 0;
+                }
+                sub.debit = -nValue;
+
+                parts.append(sub);
             }
-            else
-            {
-                //
-                // Mixed debit transaction, can't break down payees
-                //
-                parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, 0));
-            }
+        }
+        else
+        {
+            //
+            // Mixed debit transaction, can't break down payees
+            //
+            parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, 0));
         }
     }
 
diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp
index 5f505f444e..d36bb495a0 100644
--- a/src/qt/transactiontablemodel.cpp
+++ b/src/qt/transactiontablemodel.cpp
@@ -9,6 +9,7 @@
 #include "bitcoinunits.h"
 
 #include "wallet.h"
+#include "ui_interface.h"
 
 #include <QLocale>
 #include <QList>
@@ -66,15 +67,14 @@ public:
      */
     void refreshWallet()
     {
-#ifdef WALLET_UPDATE_DEBUG
-        qDebug() << "refreshWallet";
-#endif
+        OutputDebugStringF("refreshWallet\n");
         cachedWallet.clear();
         {
             LOCK(wallet->cs_wallet);
             for(std::map<uint256, CWalletTx>::iterator it = wallet->mapWallet.begin(); it != wallet->mapWallet.end(); ++it)
             {
-                cachedWallet.append(TransactionRecord::decomposeTransaction(wallet, it->second));
+                if(TransactionRecord::showTransaction(it->second))
+                    cachedWallet.append(TransactionRecord::decomposeTransaction(wallet, it->second));
             }
         }
     }
@@ -82,49 +82,55 @@ public:
     /* Update our model of the wallet incrementally, to synchronize our model of the wallet
        with that of the core.
 
-       Call with list of hashes of transactions that were added, removed or changed.
+       Call with transaction that was added, removed or changed.
      */
-    void updateWallet(const QList<uint256> &updated)
+    void updateWallet(const uint256 &hash, int status)
     {
-        // Walk through updated transactions, update model as needed.
-#ifdef WALLET_UPDATE_DEBUG
-        qDebug() << "updateWallet";
-#endif
-        // Sort update list, and iterate through it in reverse, so that model updates
-        //  can be emitted from end to beginning (so that earlier updates will not influence
-        // the indices of latter ones).
-        QList<uint256> updated_sorted = updated;
-        qSort(updated_sorted);
-
+        OutputDebugStringF("updateWallet %s %i\n", hash.ToString().c_str(), status);
         {
             LOCK(wallet->cs_wallet);
-            for(int update_idx = updated_sorted.size()-1; update_idx >= 0; --update_idx)
+
+            // Find transaction in wallet
+            std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(hash);
+            bool inWallet = mi != wallet->mapWallet.end();
+
+            // Find bounds of this transaction in model
+            QList<TransactionRecord>::iterator lower = qLowerBound(
+                cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan());
+            QList<TransactionRecord>::iterator upper = qUpperBound(
+                cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan());
+            int lowerIndex = (lower - cachedWallet.begin());
+            int upperIndex = (upper - cachedWallet.begin());
+            bool inModel = (lower != upper);
+
+            // Determine whether to show transaction or not
+            bool showTransaction = (inWallet && TransactionRecord::showTransaction(mi->second));
+
+            if(status == CT_UPDATED)
             {
-                const uint256 &hash = updated_sorted.at(update_idx);
-                // Find transaction in wallet
-                std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(hash);
-                bool inWallet = mi != wallet->mapWallet.end();
-                // Find bounds of this transaction in model
-                QList<TransactionRecord>::iterator lower = qLowerBound(
-                    cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan());
-                QList<TransactionRecord>::iterator upper = qUpperBound(
-                    cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan());
-                int lowerIndex = (lower - cachedWallet.begin());
-                int upperIndex = (upper - cachedWallet.begin());
-
-                // Determine if transaction is in model already
-                bool inModel = false;
-                if(lower != upper)
-                {
-                    inModel = true;
-                }
+                if(showTransaction && !inModel)
+                    status = CT_NEW; /* Not in model, but want to show, treat as new */
+                if(!showTransaction && inModel)
+                    status = CT_DELETED; /* In model, but want to hide, treat as deleted */
+            }
 
-#ifdef WALLET_UPDATE_DEBUG
-                qDebug() << "  " << QString::fromStdString(hash.ToString()) << inWallet << " " << inModel
-                        << lowerIndex << "-" << upperIndex;
-#endif
+            OutputDebugStringF("   inWallet=%i inModel=%i Index=%i-%i showTransaction=%i derivedStatus=%i\n",
+                     inWallet, inModel, lowerIndex, upperIndex, showTransaction, status);
 
-                if(inWallet && !inModel)
+            switch(status)
+            {
+            case CT_NEW:
+                if(inModel)
+                {
+                    OutputDebugStringF("Warning: updateWallet: Got CT_NEW, but transaction is already in model\n");
+                    break;
+                }
+                if(!inWallet)
+                {
+                    OutputDebugStringF("Warning: updateWallet: Got CT_NEW, but transaction is not in wallet\n");
+                    break;
+                }
+                if(showTransaction)
                 {
                     // Added -- insert at the right position
                     QList<TransactionRecord> toInsert =
@@ -141,17 +147,22 @@ public:
                         parent->endInsertRows();
                     }
                 }
-                else if(!inWallet && inModel)
-                {
-                    // Removed -- remove entire transaction from table
-                    parent->beginRemoveRows(QModelIndex(), lowerIndex, upperIndex-1);
-                    cachedWallet.erase(lower, upper);
-                    parent->endRemoveRows();
-                }
-                else if(inWallet && inModel)
+                break;
+            case CT_DELETED:
+                if(!inModel)
                 {
-                    // Updated -- nothing to do, status update will take care of this
+                    OutputDebugStringF("Warning: updateWallet: Got CT_DELETED, but transaction is not in model\n");
+                    break;
                 }
+                // Removed -- remove entire transaction from table
+                parent->beginRemoveRows(QModelIndex(), lowerIndex, upperIndex-1);
+                cachedWallet.erase(lower, upper);
+                parent->endRemoveRows();
+                break;
+            case CT_UPDATED:
+                // Miscellaneous updates -- nothing to do, status update will take care of this, and is only computed for
+                // visible transactions.
+                break;
             }
         }
     }
@@ -209,14 +220,15 @@ TransactionTableModel::TransactionTableModel(CWallet* wallet, WalletModel *paren
         QAbstractTableModel(parent),
         wallet(wallet),
         walletModel(parent),
-        priv(new TransactionTablePriv(wallet, this))
+        priv(new TransactionTablePriv(wallet, this)),
+        cachedNumBlocks(0)
 {
     columns << QString() << tr("Date") << tr("Type") << tr("Address") << tr("Amount");
 
     priv->refreshWallet();
 
     QTimer *timer = new QTimer(this);
-    connect(timer, SIGNAL(timeout()), this, SLOT(update()));
+    connect(timer, SIGNAL(timeout()), this, SLOT(updateConfirmations()));
     timer->start(MODEL_UPDATE_DELAY);
 }
 
@@ -225,29 +237,23 @@ TransactionTableModel::~TransactionTableModel()
     delete priv;
 }
 
-void TransactionTableModel::update()
+void TransactionTableModel::updateTransaction(const QString &hash, int status)
 {
-    QList<uint256> updated;
+    uint256 updated;
+    updated.SetHex(hash.toStdString());
 
-    // Check if there are changes to wallet map
-    {
-        TRY_LOCK(wallet->cs_wallet, lockWallet);
-        if (lockWallet && !wallet->vWalletUpdated.empty())
-        {
-            BOOST_FOREACH(uint256 hash, wallet->vWalletUpdated)
-            {
-                updated.append(hash);
-            }
-            wallet->vWalletUpdated.clear();
-        }
-    }
+    priv->updateWallet(updated, status);
+}
 
-    if(!updated.empty())
+void TransactionTableModel::updateConfirmations()
+{
+    if(nBestHeight != cachedNumBlocks)
     {
-        priv->updateWallet(updated);
-
-        // Status (number of confirmations) and (possibly) description
-        //  columns changed for all rows.
+        cachedNumBlocks = nBestHeight;
+        // Blocks came in since last poll.
+        // Invalidate status (number of confirmations) and (possibly) description
+        //  for all rows. Qt is smart enough to only actually request the data for the
+        //  visible rows.
         emit dataChanged(index(0, Status), index(priv->size()-1, Status));
         emit dataChanged(index(0, ToAddress), index(priv->size()-1, ToAddress));
     }
diff --git a/src/qt/transactiontablemodel.h b/src/qt/transactiontablemodel.h
index db88a0604f..0aafa70915 100644
--- a/src/qt/transactiontablemodel.h
+++ b/src/qt/transactiontablemodel.h
@@ -60,6 +60,7 @@ private:
     WalletModel *walletModel;
     QStringList columns;
     TransactionTablePriv *priv;
+    int cachedNumBlocks;
 
     QString lookupAddress(const std::string &address, bool tooltip) const;
     QVariant addressColor(const TransactionRecord *wtx) const;
@@ -72,8 +73,9 @@ private:
     QVariant txStatusDecoration(const TransactionRecord *wtx) const;
     QVariant txAddressDecoration(const TransactionRecord *wtx) const;
 
-private slots:
-    void update();
+public slots:
+    void updateTransaction(const QString &hash, int status);
+    void updateConfirmations();
 
     friend class TransactionTablePriv;
 };
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index b9ccb06c09..4e082a8abc 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -40,30 +40,38 @@ int WalletModel::getNumTransactions() const
     return numTransactions;
 }
 
-void WalletModel::update()
+void WalletModel::updateStatus()
 {
+    EncryptionStatus newEncryptionStatus = getEncryptionStatus();
+
+    if(cachedEncryptionStatus != newEncryptionStatus)
+        emit encryptionStatusChanged(newEncryptionStatus);
+}
+
+void WalletModel::updateTransaction(const QString &hash, int status)
+{
+    if(transactionTableModel)
+        transactionTableModel->updateTransaction(hash, status);
+
+    // Balance and number of transactions might have changed
     qint64 newBalance = getBalance();
     qint64 newUnconfirmedBalance = getUnconfirmedBalance();
     int newNumTransactions = getNumTransactions();
-    EncryptionStatus newEncryptionStatus = getEncryptionStatus();
 
     if(cachedBalance != newBalance || cachedUnconfirmedBalance != newUnconfirmedBalance)
         emit balanceChanged(newBalance, newUnconfirmedBalance);
-
     if(cachedNumTransactions != newNumTransactions)
         emit numTransactionsChanged(newNumTransactions);
 
-    if(cachedEncryptionStatus != newEncryptionStatus)
-        emit encryptionStatusChanged(newEncryptionStatus);
-
     cachedBalance = newBalance;
     cachedUnconfirmedBalance = newUnconfirmedBalance;
     cachedNumTransactions = newNumTransactions;
 }
 
-void WalletModel::updateAddressList()
+void WalletModel::updateAddressBook(const QString &address, const QString &label, int status)
 {
-    addressTableModel->update();
+    if(addressTableModel)
+        addressTableModel->updateEntry(address, label, status);
 }
 
 bool WalletModel::validateAddress(const QString &address)
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index 6c47f61bef..8250794f21 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -137,8 +137,12 @@ signals:
     void error(const QString &title, const QString &message, bool modal);
 
 public slots:
-    void update();
-    void updateAddressList();
+    /* Wallet status might have changed */
+    void updateStatus();
+    /* New transaction, or transaction changed status */
+    void updateTransaction(const QString &hash, int status);
+    /* New, updated or removed address book entry */
+    void updateAddressBook(const QString &address, const QString &label, int status);
 };
 
 
diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp
index 1119aeaf75..9f5693a8bd 100644
--- a/src/rpcdump.cpp
+++ b/src/rpcdump.cpp
@@ -73,8 +73,6 @@ Value importprivkey(const Array& params, bool fHelp)
         pwalletMain->ReacceptWalletTransactions();
     }
 
-    MainFrameRepaint();
-
     return Value::null;
 }
 
diff --git a/src/ui_interface.h b/src/ui_interface.h
index 514768086d..c1ed265a01 100644
--- a/src/ui_interface.h
+++ b/src/ui_interface.h
@@ -7,6 +7,10 @@
 #include <string>
 #include "util.h" // for int64
 
+class CBasicKeyStore;
+class CWallet;
+class uint256;
+
 #define wxYES                   0x00000002
 #define wxOK                    0x00000004
 #define wxNO                    0x00000008
@@ -36,15 +40,46 @@
 // Force blocking, modal message box dialog (not just notification)
 #define wxMODAL                 0x00040000
 
+enum ChangeType
+{
+    CT_NEW,
+    CT_UPDATED,
+    CT_DELETED
+};
+
 /* These UI communication functions are implemented in bitcoin.cpp (for ui) and noui.cpp (no ui) */
 
 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 MainFrameRepaint();
-extern void AddressBookRepaint();
 extern void QueueShutdown();
 extern void InitMessage(const std::string &message);
 extern std::string _(const char* psz);
 
+/* Block chain changed. */
+extern void NotifyBlocksChanged();
+
+/* Wallet status (encrypted, locked) changed.
+ * Note: Called without locks held.
+ */
+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);
+
 #endif
diff --git a/src/wallet.cpp b/src/wallet.cpp
index 768f9f85ea..132f68bee6 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -274,7 +274,9 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
         // Need to completely rewrite the wallet file; if we don't, bdb might keep
         // bits of the unencrypted private key in slack space in the database file.
         CDB::Rewrite(strWalletFile);
+
     }
+    NotifyKeyStoreStatusChanged(this);
 
     return true;
 }
@@ -297,7 +299,7 @@ void CWallet::WalletUpdateSpent(const CTransaction &tx)
                     printf("WalletUpdateSpent found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
                     wtx.MarkSpent(txin.prevout.n);
                     wtx.WriteToDisk();
-                    vWalletUpdated.push_back(txin.prevout.hash);
+                    NotifyTransactionChanged(this, txin.prevout.hash, CT_UPDATED);
                 }
             }
         }
@@ -373,15 +375,12 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn)
             }
         }
 #endif
-        // Notify UI
-        vWalletUpdated.push_back(hash);
-
         // since AddToWallet is called directly for self-originating transactions, check for consumption of own coins
         WalletUpdateSpent(wtx);
-    }
 
-    // Refresh UI
-    MainFrameRepaint();
+        // Notify UI of new or updated transaction
+        NotifyTransactionChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED);
+    }
     return true;
 }
 
@@ -1183,7 +1182,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
                 coin.BindWallet(this);
                 coin.MarkSpent(txin.prevout.n);
                 coin.WriteToDisk();
-                vWalletUpdated.push_back(coin.GetHash());
+                NotifyTransactionChanged(this, coin.GetHash(), CT_UPDATED);
             }
 
             if (fFileBacked)
@@ -1202,7 +1201,6 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
         }
         wtxNew.RelayWalletTransaction();
     }
-    MainFrameRepaint();
     return true;
 }
 
@@ -1237,7 +1235,6 @@ string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew,
     if (!CommitTransaction(wtxNew, reservekey))
         return _("Error: The transaction was rejected.  This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
 
-    MainFrameRepaint();
     return "";
 }
 
@@ -1290,8 +1287,9 @@ int CWallet::LoadWallet(bool& fFirstRunRet)
 
 bool CWallet::SetAddressBookName(const CBitcoinAddress& address, const string& strName)
 {
+    std::map<CBitcoinAddress, std::string>::iterator mi = mapAddressBook.find(address);
     mapAddressBook[address] = strName;
-    AddressBookRepaint();
+    NotifyAddressBookChanged(this, address.ToString(), strName, (mi == mapAddressBook.end()) ? CT_NEW : CT_UPDATED);
     if (!fFileBacked)
         return false;
     return CWalletDB(strWalletFile).WriteName(address.ToString(), strName);
@@ -1300,7 +1298,7 @@ bool CWallet::SetAddressBookName(const CBitcoinAddress& address, const string& s
 bool CWallet::DelAddressBookName(const CBitcoinAddress& address)
 {
     mapAddressBook.erase(address);
-    AddressBookRepaint();
+    NotifyAddressBookChanged(this, address.ToString(), "", CT_DELETED);
     if (!fFileBacked)
         return false;
     return CWalletDB(strWalletFile).EraseName(address.ToString());
@@ -1558,3 +1556,14 @@ void CWallet::GetAllReserveAddresses(set<CBitcoinAddress>& setAddress)
         setAddress.insert(address);
     }
 }
+
+void CWallet::UpdatedTransaction(const uint256 &hashTx)
+{
+    {
+        LOCK(cs_wallet);
+        // Only notify UI if this transaction is in this wallet
+        map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(hashTx);
+        if (mi != mapWallet.end())
+            NotifyTransactionChanged(this, hashTx, CT_UPDATED);
+    }
+}
diff --git a/src/wallet.h b/src/wallet.h
index 44c11e2ec4..f84e6a3292 100644
--- a/src/wallet.h
+++ b/src/wallet.h
@@ -102,8 +102,6 @@ public:
     }
 
     std::map<uint256, CWalletTx> mapWallet;
-    std::vector<uint256> vWalletUpdated;
-
     std::map<uint256, int> mapRequestCount;
 
     std::map<CBitcoinAddress, std::string> mapAddressBook;
@@ -232,13 +230,7 @@ public:
 
     bool DelAddressBookName(const CBitcoinAddress& address);
 
-    void UpdatedTransaction(const uint256 &hashTx)
-    {
-        {
-            LOCK(cs_wallet);
-            vWalletUpdated.push_back(hashTx);
-        }
-    }
+    void UpdatedTransaction(const uint256 &hashTx);
 
     void PrintWallet(const CBlock& block);
 
-- 
cgit v1.2.3


From ab1b288fa7994db5f036e93d5f8ba73372017c40 Mon Sep 17 00:00:00 2001
From: "Wladimir J. van der Laan" <laanwj@gmail.com>
Date: Sun, 6 May 2012 19:40:58 +0200
Subject: 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

(limited to 'src')

diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp
index 334425a9a9..cc4d85cbbe 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 47b6f92324..096f289640 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 55fba4c372..bdeae30135 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<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;
 }
 
diff --git a/src/keystore.h b/src/keystore.h
index dd7110db58..6b5d01cfa5 100644
--- a/src/keystore.h
+++ b/src/keystore.h
@@ -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
diff --git a/src/main.cpp b/src/main.cpp
index 7e7a0badfd..8410b9af4a 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 61b38a663e..1e9dd687f3 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 47bf8d5304..fdd4f4635d 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 227756f274..d6433a6983 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 04e17866e5..ec6609f991 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 32875b0f06..8eff9cbe78 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 c7b74bea73..0000000000
--- 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 <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)
-{
-}
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index a50443021f..c5592b28df 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 1914ef90b5..64fd2a9450 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 bf2cd84a1c..0349c389c5 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 06ada5aaca..3d7d90e902 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 4e082a8abc..1a9700ef09 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 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()
 {
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index 8250794f21..c413ed2436 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 c1ed265a01..954a781005 100644
--- a/src/ui_interface.h
+++ b/src/ui_interface.h
@@ -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.
- */
-extern void NotifyKeyStoreStatusChanged(CBasicKeyStore *wallet);
+    /** Progress message during initialization. */
+    boost::signals2::signal<void (const std::string &message)> 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<void ()> 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<std::string (const char* psz)> Translate;
 
-/* Number of connections changed. */
-extern void NotifyNumConnectionsChanged(int newNumConnections);
+    /** Block chain changed. */
+    boost::signals2::signal<void ()> NotifyBlocksChanged;
 
-/* New, updated or cancelled alert.
- * Note: called with lock cs_mapAlerts held.
+    /** 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 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
diff --git a/src/util.cpp b/src/util.cpp
index c778e51e3b..a9b65ed941 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 132f68bee6..92ad8c0f10 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 f84e6a3292..b3b2e4f468 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<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. */
-- 
cgit v1.2.3


From 0832c0d1669a3504b7ec21d583aecc79f84e8506 Mon Sep 17 00:00:00 2001
From: "Wladimir J. van der Laan" <laanwj@gmail.com>
Date: Sun, 6 May 2012 22:41:35 +0200
Subject: Process address book updates incrementally

- No longer invalidates selection model, thus retains selection on address book changes
- Fixes selection of new address when added
---
 src/qt/addressbookpage.cpp   | 29 +++++++++------
 src/qt/addressbookpage.h     |  5 +++
 src/qt/addresstablemodel.cpp | 86 +++++++++++++++++++++++++++++++++++++-------
 src/qt/addresstablemodel.h   |  7 +++-
 src/qt/walletmodel.cpp       | 13 +++----
 src/qt/walletmodel.h         |  2 +-
 src/wallet.cpp               |  4 +--
 src/wallet.h                 |  2 +-
 8 files changed, 113 insertions(+), 35 deletions(-)

(limited to 'src')

diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp
index d314e62b5a..c207987561 100644
--- a/src/qt/addressbookpage.cpp
+++ b/src/qt/addressbookpage.cpp
@@ -132,6 +132,10 @@ void AddressBookPage::setModel(AddressTableModel *model)
     connect(ui->tableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
             this, SLOT(selectionChanged()));
 
+    // Select row for newly created address
+    connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
+            this, SLOT(selectNewAddress(QModelIndex,int,int)));
+
     if(mode == ForSending)
     {
         // Auto-select first row when in sending mode
@@ -193,20 +197,11 @@ void AddressBookPage::on_newAddressButton_clicked()
     EditAddressDialog dlg(
             tab == SendingTab ?
             EditAddressDialog::NewSendingAddress :
-            EditAddressDialog::NewReceivingAddress);
+            EditAddressDialog::NewReceivingAddress, this);
     dlg.setModel(model);
     if(dlg.exec())
     {
-        // Select row for newly created address
-        QString address = dlg.getAddress();
-        QModelIndexList lst = proxyModel->match(proxyModel->index(0,
-                          AddressTableModel::Address, QModelIndex()),
-                          Qt::EditRole, address, 1, Qt::MatchExactly);
-        if(!lst.isEmpty())
-        {
-            ui->tableView->setFocus();
-            ui->tableView->selectRow(lst.at(0).row());
-        }
+        newAddressToSelect = dlg.getAddress();
     }
 }
 
@@ -338,3 +333,15 @@ void AddressBookPage::contextualMenu(const QPoint &point)
         contextMenu->exec(QCursor::pos());
     }
 }
+
+void AddressBookPage::selectNewAddress(const QModelIndex &parent, int begin, int end)
+{
+    QModelIndex idx = proxyModel->mapFromSource(model->index(begin, AddressTableModel::Address, parent));
+    if(idx.isValid() && (idx.data(Qt::EditRole).toString() == newAddressToSelect))
+    {
+        // Select row of newly created address, once
+        ui->tableView->setFocus();
+        ui->tableView->selectRow(idx.row());
+        newAddressToSelect.clear();
+    }
+}
diff --git a/src/qt/addressbookpage.h b/src/qt/addressbookpage.h
index b2cf2db979..b2e91c7cb2 100644
--- a/src/qt/addressbookpage.h
+++ b/src/qt/addressbookpage.h
@@ -13,6 +13,7 @@ class QTableView;
 class QItemSelection;
 class QSortFilterProxyModel;
 class QMenu;
+class QModelIndex;
 QT_END_NAMESPACE
 
 /** Widget that shows a list of sending or receiving addresses.
@@ -51,6 +52,7 @@ private:
     QSortFilterProxyModel *proxyModel;
     QMenu *contextMenu;
     QAction *deleteAction;
+    QString newAddressToSelect;
 
 private slots:
     void on_deleteButton_clicked();
@@ -67,6 +69,9 @@ private slots:
     void onCopyLabelAction();
     /** Edit currently selected address entry */
     void onEditAction();
+
+    /** New entry/entries were added to address table */
+    void selectNewAddress(const QModelIndex &parent, int begin, int end);
 };
 
 #endif // ADDRESSBOOKDIALOG_H
diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp
index 4af4c3ac13..75ea2c12c5 100644
--- a/src/qt/addresstablemodel.cpp
+++ b/src/qt/addresstablemodel.cpp
@@ -26,20 +26,36 @@ struct AddressTableEntry
         type(type), label(label), address(address) {}
 };
 
+struct AddressTableEntryLessThan
+{
+    bool operator()(const AddressTableEntry &a, const AddressTableEntry &b) const
+    {
+        return a.address < b.address;
+    }
+    bool operator()(const AddressTableEntry &a, const QString &b) const
+    {
+        return a.address < b;
+    }
+    bool operator()(const QString &a, const AddressTableEntry &b) const
+    {
+        return a < b.address;
+    }
+};
+
 // Private implementation
 class AddressTablePriv
 {
 public:
     CWallet *wallet;
     QList<AddressTableEntry> cachedAddressTable;
+    AddressTableModel *parent;
 
-    AddressTablePriv(CWallet *wallet):
-            wallet(wallet) {}
+    AddressTablePriv(CWallet *wallet, AddressTableModel *parent):
+        wallet(wallet), parent(parent) {}
 
     void refreshAddressTable()
     {
         cachedAddressTable.clear();
-
         {
             LOCK(wallet->cs_wallet);
             BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, std::string)& item, wallet->mapAddressBook)
@@ -54,6 +70,53 @@ public:
         }
     }
 
+    void updateEntry(const QString &address, const QString &label, bool isMine, int status)
+    {
+        // Find address / label in model
+        QList<AddressTableEntry>::iterator lower = qLowerBound(
+            cachedAddressTable.begin(), cachedAddressTable.end(), address, AddressTableEntryLessThan());
+        QList<AddressTableEntry>::iterator upper = qUpperBound(
+            cachedAddressTable.begin(), cachedAddressTable.end(), address, AddressTableEntryLessThan());
+        int lowerIndex = (lower - cachedAddressTable.begin());
+        int upperIndex = (upper - cachedAddressTable.begin());
+        bool inModel = (lower != upper);
+        AddressTableEntry::Type newEntryType = isMine ? AddressTableEntry::Receiving : AddressTableEntry::Sending;
+
+        switch(status)
+        {
+        case CT_NEW:
+            if(inModel)
+            {
+                OutputDebugStringF("Warning: AddressTablePriv::updateEntry: Got CT_NOW, but entry is already in model\n");
+                break;
+            }
+            parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex);
+            cachedAddressTable.insert(lowerIndex, AddressTableEntry(newEntryType, label, address));
+            parent->endInsertRows();
+            break;
+        case CT_UPDATED:
+            if(!inModel)
+            {
+                OutputDebugStringF("Warning: AddressTablePriv::updateEntry: Got CT_UPDATED, but entry is not in model\n");
+                break;
+            }
+            lower->type = newEntryType;
+            lower->label = label;
+            parent->emitDataChanged(lowerIndex);
+            break;
+        case CT_DELETED:
+            if(!inModel)
+            {
+                OutputDebugStringF("Warning: AddressTablePriv::updateEntry: Got CT_DELETED, but entry is not in model\n");
+                break;
+            }
+            parent->beginRemoveRows(QModelIndex(), lowerIndex, upperIndex-1);
+            cachedAddressTable.erase(lower, upper);
+            parent->endRemoveRows();
+            break;
+        }
+    }
+
     int size()
     {
         return cachedAddressTable.size();
@@ -76,7 +139,7 @@ AddressTableModel::AddressTableModel(CWallet *wallet, WalletModel *parent) :
     QAbstractTableModel(parent),walletModel(parent),wallet(wallet),priv(0)
 {
     columns << tr("Label") << tr("Address");
-    priv = new AddressTablePriv(wallet);
+    priv = new AddressTablePriv(wallet, this);
     priv->refreshAddressTable();
 }
 
@@ -158,7 +221,6 @@ bool AddressTableModel::setData(const QModelIndex & index, const QVariant & valu
         {
         case Label:
             wallet->SetAddressBookName(rec->address.toStdString(), value.toString().toStdString());
-            rec->label = value.toString();
             break;
         case Address:
             // Refuse to set invalid address, set error status and return false
@@ -177,12 +239,9 @@ bool AddressTableModel::setData(const QModelIndex & index, const QVariant & valu
                     // Add new entry with new address
                     wallet->SetAddressBookName(value.toString().toStdString(), rec->label.toStdString());
                 }
-
-                rec->address = value.toString();
             }
             break;
         }
-        emit dataChanged(index, index);
 
         return true;
     }
@@ -232,13 +291,10 @@ QModelIndex AddressTableModel::index(int row, int column, const QModelIndex & pa
     }
 }
 
-void AddressTableModel::updateEntry(const QString &address, const QString &label, int status)
+void AddressTableModel::updateEntry(const QString &address, const QString &label, bool isMine, int status)
 {
     // Update address book model from Bitcoin core
-    // TODO: use address, label, status to update only the specified entry (like in WalletModel)
-    beginResetModel();
-    priv->refreshAddressTable();
-    endResetModel();
+    priv->updateEntry(address, label, isMine, status);
 }
 
 QString AddressTableModel::addRow(const QString &type, const QString &label, const QString &address)
@@ -342,3 +398,7 @@ int AddressTableModel::lookupAddress(const QString &address) const
     }
 }
 
+void AddressTableModel::emitDataChanged(int idx)
+{
+    emit dataChanged(index(idx, 0, QModelIndex()), index(idx, columns.length()-1, QModelIndex()));
+}
diff --git a/src/qt/addresstablemodel.h b/src/qt/addresstablemodel.h
index bd73c6d147..42974e3e1f 100644
--- a/src/qt/addresstablemodel.h
+++ b/src/qt/addresstablemodel.h
@@ -74,13 +74,18 @@ private:
     QStringList columns;
     EditStatus editStatus;
 
+    /** Notify listeners that data changed. */
+    void emitDataChanged(int index);
+
 signals:
     void defaultAddressChanged(const QString &address);
 
 public slots:
     /* Update address list from core.
      */
-    void updateEntry(const QString &address, const QString &label, int status);
+    void updateEntry(const QString &address, const QString &label, bool isMine, int status);
+
+    friend class AddressTablePriv;
 };
 
 #endif // ADDRESSTABLEMODEL_H
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index 1a9700ef09..b89c3dba33 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -75,10 +75,10 @@ void WalletModel::updateTransaction(const QString &hash, int status)
     cachedNumTransactions = newNumTransactions;
 }
 
-void WalletModel::updateAddressBook(const QString &address, const QString &label, int status)
+void WalletModel::updateAddressBook(const QString &address, const QString &label, bool isMine, int status)
 {
     if(addressTableModel)
-        addressTableModel->updateEntry(address, label, status);
+        addressTableModel->updateEntry(address, label, isMine, status);
 }
 
 bool WalletModel::validateAddress(const QString &address)
@@ -268,12 +268,13 @@ static void NotifyKeyStoreStatusChanged(WalletModel *walletmodel, CCryptoKeyStor
     QMetaObject::invokeMethod(walletmodel, "updateStatus", Qt::QueuedConnection);
 }
 
-static void NotifyAddressBookChanged(WalletModel *walletmodel, CWallet *wallet, const std::string &address, const std::string &label, ChangeType status)
+static void NotifyAddressBookChanged(WalletModel *walletmodel, CWallet *wallet, const std::string &address, const std::string &label, bool isMine, ChangeType status)
 {
-    OutputDebugStringF("NotifyAddressBookChanged %s %s status=%i\n", address.c_str(), label.c_str(), status);
+    OutputDebugStringF("NotifyAddressBookChanged %s %s isMine=%i status=%i\n", address.c_str(), label.c_str(), isMine, status);
     QMetaObject::invokeMethod(walletmodel, "updateAddressBook", Qt::QueuedConnection,
                               Q_ARG(QString, QString::fromStdString(address)),
                               Q_ARG(QString, QString::fromStdString(label)),
+                              Q_ARG(bool, isMine),
                               Q_ARG(int, status));
 }
 
@@ -289,7 +290,7 @@ 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->NotifyAddressBookChanged.connect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5));
     wallet->NotifyTransactionChanged.connect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3));
 }
 
@@ -297,7 +298,7 @@ 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->NotifyAddressBookChanged.disconnect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5));
     wallet->NotifyTransactionChanged.disconnect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3));
 }
 
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index c413ed2436..8b615ffe8e 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -145,7 +145,7 @@ public slots:
     /* New transaction, or transaction changed status */
     void updateTransaction(const QString &hash, int status);
     /* New, updated or removed address book entry */
-    void updateAddressBook(const QString &address, const QString &label, int status);
+    void updateAddressBook(const QString &address, const QString &label, bool isMine, int status);
 };
 
 
diff --git a/src/wallet.cpp b/src/wallet.cpp
index 92ad8c0f10..d67cdf4b71 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -1289,7 +1289,7 @@ bool CWallet::SetAddressBookName(const CBitcoinAddress& address, const string& s
 {
     std::map<CBitcoinAddress, std::string>::iterator mi = mapAddressBook.find(address);
     mapAddressBook[address] = strName;
-    NotifyAddressBookChanged(this, address.ToString(), strName, (mi == mapAddressBook.end()) ? CT_NEW : CT_UPDATED);
+    NotifyAddressBookChanged(this, address.ToString(), strName, HaveKey(address), (mi == mapAddressBook.end()) ? CT_NEW : CT_UPDATED);
     if (!fFileBacked)
         return false;
     return CWalletDB(strWalletFile).WriteName(address.ToString(), strName);
@@ -1298,7 +1298,7 @@ bool CWallet::SetAddressBookName(const CBitcoinAddress& address, const string& s
 bool CWallet::DelAddressBookName(const CBitcoinAddress& address)
 {
     mapAddressBook.erase(address);
-    NotifyAddressBookChanged(this, address.ToString(), "", CT_DELETED);
+    NotifyAddressBookChanged(this, address.ToString(), "", HaveKey(address), CT_DELETED);
     if (!fFileBacked)
         return false;
     return CWalletDB(strWalletFile).EraseName(address.ToString());
diff --git a/src/wallet.h b/src/wallet.h
index b3b2e4f468..55deffdde2 100644
--- a/src/wallet.h
+++ b/src/wallet.h
@@ -266,7 +266,7 @@ public:
     /** 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;
+    boost::signals2::signal<void (CWallet *wallet, const std::string &address, const std::string &label, bool isMine, ChangeType status)> NotifyAddressBookChanged;
 
     /** Wallet transaction added, removed or updated.
      * @note called with lock cs_wallet held.
-- 
cgit v1.2.3


From 239c11d0dd4287e74286c40fb338aea85f4b1996 Mon Sep 17 00:00:00 2001
From: "Wladimir J. van der Laan" <laanwj@gmail.com>
Date: Sat, 19 May 2012 09:35:26 +0200
Subject: Make testcases build, prevent windows symbol collision

---
 src/bitcoinrpc.cpp        |  4 +--
 src/init.cpp              | 55 +++++++++++++--------------------------
 src/init.h                |  1 -
 src/main.cpp              |  2 +-
 src/makefile.linux-mingw  |  3 ++-
 src/makefile.mingw        |  3 ++-
 src/makefile.osx          |  3 ++-
 src/makefile.unix         |  3 ++-
 src/noui.cpp              | 35 +++++++++++++++++++++++++
 src/qt/bitcoin.cpp        |  2 +-
 src/test/test_bitcoin.cpp |  4 +++
 src/ui_interface.h        | 66 +++++++++++++++++++++++------------------------
 src/util.cpp              |  2 +-
 13 files changed, 103 insertions(+), 80 deletions(-)
 create mode 100644 src/noui.cpp

(limited to 'src')

diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp
index cc4d85cbbe..6c51bad6db 100644
--- a/src/bitcoinrpc.cpp
+++ b/src/bitcoinrpc.cpp
@@ -2630,7 +2630,7 @@ void ThreadRPCServer2(void* parg)
                 strWhatAmI.c_str(),
                 GetConfigFile().string().c_str(),
                 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
-            _("Error"), MF_OK | MF_MODAL);
+            _("Error"), CClientUIInterface::OK | CClientUIInterface::MODAL);
         uiInterface.QueueShutdown();
         return;
     }
@@ -2651,7 +2651,7 @@ void ThreadRPCServer2(void* parg)
     catch(boost::system::system_error &e)
     {
         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);
+                             _("Error"), CClientUIInterface::OK | CClientUIInterface::MODAL);
         uiInterface.QueueShutdown();
         return;
     }
diff --git a/src/init.cpp b/src/init.cpp
index 096f289640..e0c0c893aa 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -91,41 +91,6 @@ 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)
-        return 0;
-
-    return 1;
-}
-
 bool AppInit(int argc, char* argv[])
 {
     bool fRet = false;
@@ -181,17 +146,33 @@ bool AppInit(int argc, char* argv[])
         Shutdown(NULL);
     return fRet;
 }
+
+extern void noui_connect();
+int main(int argc, char* argv[])
+{
+    bool fRet = false;
+
+    // Connect bitcoind signal handlers
+    noui_connect();
+
+    fRet = AppInit(argc, argv);
+
+    if (fRet && fDaemon)
+        return 0;
+
+    return 1;
+}
 #endif
 
 bool static InitError(const std::string &str)
 {
-    uiInterface.ThreadSafeMessageBox(str, _("Bitcoin"), MF_OK|MF_MODAL);
+    uiInterface.ThreadSafeMessageBox(str, _("Bitcoin"), CClientUIInterface::OK | CClientUIInterface::MODAL);
     return false;
 }
 
 bool static InitWarning(const std::string &str)
 {
-    uiInterface.ThreadSafeMessageBox(str, _("Bitcoin"), MF_OK | MF_ICON_EXCLAMATION | MF_MODAL);
+    uiInterface.ThreadSafeMessageBox(str, _("Bitcoin"), CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION | CClientUIInterface::MODAL);
     return true;
 }
 
diff --git a/src/init.h b/src/init.h
index 9a8f98cce9..970527c7ce 100644
--- a/src/init.h
+++ b/src/init.h
@@ -10,7 +10,6 @@
 extern CWallet* pwalletMain;
 
 void Shutdown(void* parg);
-bool AppInit(int argc, char* argv[]);
 bool AppInit2();
 std::string HelpMessage();
 
diff --git a/src/main.cpp b/src/main.cpp
index 8410b9af4a..e62331debf 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1858,7 +1858,7 @@ bool CheckDiskSpace(uint64 nAdditionalBytes)
         string strMessage = _("Warning: Disk space is low");
         strMiscWarning = strMessage;
         printf("*** %s\n", strMessage.c_str());
-        uiInterface.ThreadSafeMessageBox(strMessage, "Bitcoin", MF_OK | MF_ICON_EXCLAMATION | MF_MODAL);
+        uiInterface.ThreadSafeMessageBox(strMessage, "Bitcoin", CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION | CClientUIInterface::MODAL);
         uiInterface.QueueShutdown();
         return false;
     }
diff --git a/src/makefile.linux-mingw b/src/makefile.linux-mingw
index 1e9dd687f3..61b38a663e 100644
--- a/src/makefile.linux-mingw
+++ b/src/makefile.linux-mingw
@@ -64,7 +64,8 @@ OBJS= \
     obj/sync.o \
     obj/util.o \
     obj/wallet.o \
-    obj/walletdb.o
+    obj/walletdb.o \
+    obj/noui.o
 
 all: bitcoind.exe
 
diff --git a/src/makefile.mingw b/src/makefile.mingw
index fdd4f4635d..47bf8d5304 100644
--- a/src/makefile.mingw
+++ b/src/makefile.mingw
@@ -61,7 +61,8 @@ OBJS= \
     obj/sync.o \
     obj/util.o \
     obj/wallet.o \
-    obj/walletdb.o
+    obj/walletdb.o \
+    obj/noui.o
 
 
 all: bitcoind.exe
diff --git a/src/makefile.osx b/src/makefile.osx
index d6433a6983..227756f274 100644
--- a/src/makefile.osx
+++ b/src/makefile.osx
@@ -88,7 +88,8 @@ OBJS= \
     obj/sync.o \
     obj/util.o \
     obj/wallet.o \
-    obj/walletdb.o
+    obj/walletdb.o \
+    obj/noui.o
 
 ifdef USE_UPNP
 	DEFS += -DUSE_UPNP=$(USE_UPNP)
diff --git a/src/makefile.unix b/src/makefile.unix
index ec6609f991..04e17866e5 100644
--- a/src/makefile.unix
+++ b/src/makefile.unix
@@ -108,7 +108,8 @@ OBJS= \
     obj/sync.o \
     obj/util.o \
     obj/wallet.o \
-    obj/walletdb.o
+    obj/walletdb.o \
+    obj/noui.o
 
 
 all: bitcoind
diff --git a/src/noui.cpp b/src/noui.cpp
new file mode 100644
index 0000000000..57f53b1c0d
--- /dev/null
+++ b/src/noui.cpp
@@ -0,0 +1,35 @@
+// 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 "init.h"
+#include "bitcoinrpc.h"
+
+#include <string>
+
+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);
+}
+
+void noui_connect()
+{
+    // Connect bitcoind signal handlers
+    uiInterface.ThreadSafeMessageBox.connect(noui_ThreadSafeMessageBox);
+    uiInterface.ThreadSafeAskFee.connect(noui_ThreadSafeAskFee);
+    uiInterface.QueueShutdown.connect(noui_QueueShutdown);
+}
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index c5592b28df..07bdee0886 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -42,7 +42,7 @@ static void ThreadSafeMessageBox(const std::string& message, const std::string&
     // Message from network thread
     if(guiref)
     {
-        bool modal = (style & MF_MODAL);
+        bool modal = (style & CClientUIInterface::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,
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index 7ff7545ab4..bf597c9b73 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -5,11 +5,15 @@
 #include "wallet.h"
 
 CWallet* pwalletMain;
+CClientUIInterface uiInterface;
 
 extern bool fPrintToConsole;
+extern void noui_connect();
+
 struct TestingSetup {
     TestingSetup() {
         fPrintToConsole = true; // don't want to write to debug.log file
+        noui_connect();
         pwalletMain = new CWallet();
         RegisterWallet(pwalletMain);
     }
diff --git a/src/ui_interface.h b/src/ui_interface.h
index 954a781005..711a56d5ec 100644
--- a/src/ui_interface.h
+++ b/src/ui_interface.h
@@ -13,39 +13,6 @@ class CBasicKeyStore;
 class CWallet;
 class uint256;
 
-/** 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
 {
@@ -58,6 +25,39 @@ enum ChangeType
 class CClientUIInterface
 {
 public:
+    /** Flags for CClientUIInterface::ThreadSafeMessageBox */
+    enum MessageBoxFlags
+    {
+        YES                   = 0x00000002,
+        OK                    = 0x00000004,
+        NO                    = 0x00000008,
+        YES_NO                = (YES|NO),
+        CANCEL                = 0x00000010,
+        APPLY                 = 0x00000020,
+        CLOSE                 = 0x00000040,
+        OK_DEFAULT            = 0x00000000,
+        YES_DEFAULT           = 0x00000000,
+        NO_DEFAULT            = 0x00000080,
+        CANCEL_DEFAULT        = 0x80000000,
+        ICON_EXCLAMATION      = 0x00000100,
+        ICON_HAND             = 0x00000200,
+        ICON_WARNING          = ICON_EXCLAMATION,
+        ICON_ERROR            = ICON_HAND,
+        ICON_QUESTION         = 0x00000400,
+        ICON_INFORMATION      = 0x00000800,
+        ICON_STOP             = ICON_HAND,
+        ICON_ASTERISK         = ICON_INFORMATION,
+        ICON_MASK             = (0x00000100|0x00000200|0x00000400|0x00000800),
+        FORWARD               = 0x00001000,
+        BACKWARD              = 0x00002000,
+        RESET                 = 0x00004000,
+        HELP                  = 0x00008000,
+        MORE                  = 0x00010000,
+        SETUP                 = 0x00020000,
+        // Force blocking, modal message box dialog (not just OS notification)
+        MODAL                 = 0x00040000
+    };
+
     /** Show message box. */
     boost::signals2::signal<void (const std::string& message, const std::string& caption, int style)> ThreadSafeMessageBox;
 
diff --git a/src/util.cpp b/src/util.cpp
index a9b65ed941..108f33b78e 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());
-                    uiInterface.ThreadSafeMessageBox(strMessage+" ", string("Bitcoin"), MF_OK | MF_ICON_EXCLAMATION);
+                    uiInterface.ThreadSafeMessageBox(strMessage+" ", string("Bitcoin"), CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION);
                 }
             }
         }
-- 
cgit v1.2.3