diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index 9db1f5e10..9ab8b6844 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -21,7 +21,7 @@ namespace Checkpoints // every system. When reindexing from a fast disk with a slow CPU, it // can be up to 20, while when downloading from a slow network with a // fast multicore CPU, it won't be much higher than 1. - static const double fSigcheckVerificationFactor = 5.0; + static const double SIGCHECK_VERIFICATION_FACTOR = 5.0; struct CCheckpointData { const MapCheckpoints *mapCheckpoints; @@ -104,12 +104,13 @@ namespace Checkpoints } // Guess how far we are in the verification process at the given block index - double GuessVerificationProgress(CBlockIndex *pindex) { + double GuessVerificationProgress(CBlockIndex *pindex, bool fSigchecks) { if (pindex==NULL) return 0.0; int64_t nNow = time(NULL); + double fSigcheckVerificationFactor = fSigchecks ? SIGCHECK_VERIFICATION_FACTOR : 1.0; double fWorkBefore = 0.0; // Amount of work done before pindex double fWorkAfter = 0.0; // Amount of work left after pindex (estimated) // Work is defined as: 1.0 per transaction before the last checkpoint, and diff --git a/src/checkpoints.h b/src/checkpoints.h index 3724c5753..1b4aacee2 100644 --- a/src/checkpoints.h +++ b/src/checkpoints.h @@ -24,7 +24,7 @@ namespace Checkpoints // Returns last CBlockIndex* in mapBlockIndex that is a checkpoint CBlockIndex* GetLastCheckpoint(const std::map& mapBlockIndex); - double GuessVerificationProgress(CBlockIndex *pindex); + double GuessVerificationProgress(CBlockIndex *pindex, bool fSigchecks = true); extern bool fEnabled; } diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index cacf5dc49..7c79b0efd 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -5,8 +5,12 @@ #include "splashscreen.h" #include "clientversion.h" +#include "init.h" #include "ui_interface.h" #include "util.h" +#ifdef ENABLE_WALLET +#include "wallet.h" +#endif #include #include @@ -109,14 +113,33 @@ static void InitMessage(SplashScreen *splash, const std::string &message) Q_ARG(QColor, QColor(55,55,55))); } +static void ShowProgress(SplashScreen *splash, const std::string &title, int nProgress) +{ + InitMessage(splash, title + strprintf("%d", nProgress) + "%"); +} + +#ifdef ENABLE_WALLET +static void ConnectWallet(SplashScreen *splash, CWallet* wallet) +{ + wallet->ShowProgress.connect(boost::bind(ShowProgress, splash, _1, _2)); +} +#endif + void SplashScreen::subscribeToCoreSignals() { // Connect signals to client uiInterface.InitMessage.connect(boost::bind(InitMessage, this, _1)); +#ifdef ENABLE_WALLET + uiInterface.LoadWallet.connect(boost::bind(ConnectWallet, this, _1)); +#endif } void SplashScreen::unsubscribeFromCoreSignals() { // Disconnect signals from client uiInterface.InitMessage.disconnect(boost::bind(InitMessage, this, _1)); +#ifdef ENABLE_WALLET + if(pwalletMain) + pwalletMain->ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2)); +#endif } diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index eae448fee..424c9ee27 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -419,8 +419,17 @@ static void NotifyAddressBookChanged(WalletModel *walletmodel, CWallet *wallet, Q_ARG(int, status)); } +// queue notifications to show a non freezing progress dialog e.g. for rescan +static bool fQueueNotifications = false; +static std::vector > vQueueNotifications; static void NotifyTransactionChanged(WalletModel *walletmodel, CWallet *wallet, const uint256 &hash, ChangeType status) { + if (fQueueNotifications) + { + vQueueNotifications.push_back(make_pair(hash, status)); + return; + } + QString strHash = QString::fromStdString(hash.GetHex()); qDebug() << "NotifyTransactionChanged : " + strHash + " status= " + QString::number(status); @@ -429,12 +438,32 @@ static void NotifyTransactionChanged(WalletModel *walletmodel, CWallet *wallet, Q_ARG(int, status)); } +static void ShowProgress(WalletModel *walletmodel, const std::string &title, int nProgress) +{ + // emits signal "showProgress" + QMetaObject::invokeMethod(walletmodel, "showProgress", Qt::QueuedConnection, + Q_ARG(QString, QString::fromStdString(title)), + Q_ARG(int, nProgress)); + + if (nProgress == 0) + fQueueNotifications = true; + + if (nProgress == 100) + { + fQueueNotifications = false; + BOOST_FOREACH(const PAIRTYPE(uint256, ChangeType)& notification, vQueueNotifications) + NotifyTransactionChanged(walletmodel, NULL, notification.first, notification.second); + std::vector >().swap(vQueueNotifications); // clear + } +} + 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, _5, _6)); wallet->NotifyTransactionChanged.connect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3)); + wallet->ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2)); } void WalletModel::unsubscribeFromCoreSignals() @@ -443,6 +472,7 @@ void WalletModel::unsubscribeFromCoreSignals() wallet->NotifyStatusChanged.disconnect(boost::bind(&NotifyKeyStoreStatusChanged, this, _1)); wallet->NotifyAddressBookChanged.disconnect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5, _6)); wallet->NotifyTransactionChanged.disconnect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3)); + wallet->ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2)); } // WalletModel::UnlockContext implementation diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 28a9169e2..ccf590aae 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -237,6 +237,9 @@ signals: // Coins sent: from wallet, to recipient, in (serialized) transaction: void coinsSent(CWallet* wallet, SendCoinsRecipient recipient, QByteArray transaction); + // Show progress dialog e.g. for rescan + void showProgress(const QString &title, int nProgress); + public slots: /* Wallet status might have changed */ void updateStatus(); diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index 1a9c7866d..1cef48344 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -127,6 +128,9 @@ void WalletView::setWalletModel(WalletModel *walletModel) // Ask for passphrase if needed connect(walletModel, SIGNAL(requireUnlock()), this, SLOT(unlockWallet())); + + // Show progress dialog + connect(walletModel, SIGNAL(showProgress(QString,int)), this, SLOT(showProgress(QString,int))); } } @@ -277,3 +281,26 @@ void WalletView::usedReceivingAddresses() dlg->setModel(walletModel->getAddressTableModel()); dlg->show(); } + +void WalletView::showProgress(const QString &title, int nProgress) +{ + if (nProgress == 0) + { + progressDialog = new QProgressDialog(title, "", 0, 100); + progressDialog->setWindowModality(Qt::ApplicationModal); + progressDialog->setMinimumDuration(0); + progressDialog->setCancelButton(0); + progressDialog->setAutoClose(false); + progressDialog->setValue(0); + } + else if (nProgress == 100) + { + if (progressDialog) + { + progressDialog->close(); + progressDialog->deleteLater(); + } + } + else if (progressDialog) + progressDialog->setValue(nProgress); +} diff --git a/src/qt/walletview.h b/src/qt/walletview.h index ecfa06ac5..9cfa8d676 100644 --- a/src/qt/walletview.h +++ b/src/qt/walletview.h @@ -18,6 +18,7 @@ class WalletModel; QT_BEGIN_NAMESPACE class QModelIndex; +class QProgressDialog; QT_END_NAMESPACE /* @@ -60,6 +61,8 @@ private: TransactionView *transactionView; + QProgressDialog *progressDialog; + public slots: /** Switch to overview (home) page */ void gotoOverviewPage(); @@ -97,6 +100,9 @@ public slots: /** Re-emit encryption status signal */ void updateEncryptionStatus(); + /** Show progress dialog e.g. for rescan */ + void showProgress(const QString &title, int nProgress); + signals: /** Signal that we want to show the main window */ void showNormalIfMinimized(); diff --git a/src/ui_interface.h b/src/ui_interface.h index 677d097fa..7b655ac95 100644 --- a/src/ui_interface.h +++ b/src/ui_interface.h @@ -91,6 +91,9 @@ public: * @note called with lock cs_mapAlerts held. */ boost::signals2::signal NotifyAlertChanged; + + /** A wallet has been loaded. */ + boost::signals2::signal LoadWallet; }; extern CClientUIInterface uiInterface; diff --git a/src/wallet.cpp b/src/wallet.cpp index df1eb549a..775eb8f58 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -835,14 +835,19 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) CBlockIndex* pindex = pindexStart; { LOCK(cs_wallet); + + // no need to read and scan block, if block was created before + // our wallet birthday (as adjusted for block time variability) + while (pindex && nTimeFirstKey && (pindex->nTime < (nTimeFirstKey - 7200))) + pindex = chainActive.Next(pindex); + + ShowProgress(_("Rescanning..."), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup + double dProgressStart = Checkpoints::GuessVerificationProgress(pindex, false); + double dProgressTip = Checkpoints::GuessVerificationProgress(chainActive.Tip(), false); while (pindex) { - // no need to read and scan block, if block was created before - // our wallet birthday (as adjusted for block time variability) - if (nTimeFirstKey && (pindex->nTime < (nTimeFirstKey - 7200))) { - pindex = chainActive.Next(pindex); - continue; - } + if (pindex->nHeight % 100 == 0 && dProgressTip - dProgressStart > 0.0) + ShowProgress(_("Rescanning..."), std::max(1, std::min(99, (int)((Checkpoints::GuessVerificationProgress(pindex, false) - dProgressStart) / (dProgressTip - dProgressStart) * 100)))); CBlock block; ReadBlockFromDisk(block, pindex); @@ -857,6 +862,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) LogPrintf("Still rescanning. At block %d. Progress=%f\n", pindex->nHeight, Checkpoints::GuessVerificationProgress(pindex)); } } + ShowProgress(_("Rescanning..."), 100); // hide progress dialog in GUI } return ret; } @@ -1492,6 +1498,8 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet) return nLoadWalletRet; fFirstRunRet = !vchDefaultKey.IsValid(); + uiInterface.LoadWallet(this); + return DB_LOAD_OK; } diff --git a/src/wallet.h b/src/wallet.h index ef02c90ed..5fd56d0af 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -391,6 +391,9 @@ public: */ boost::signals2::signal NotifyTransactionChanged; + + /** Show progress e.g. for rescan */ + boost::signals2::signal ShowProgress; }; /** A key allocated from the key pool. */