From 0904c3cda4d1f40d41154bd9b2739660bdf12852 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Tue, 19 Jul 2016 15:22:01 +0200 Subject: [PATCH 1/7] [Refactor] refactor function that forms human readable text out of a timeoffset --- src/qt/bitcoingui.cpp | 25 +------------------------ src/qt/guiutil.cpp | 36 ++++++++++++++++++++++++++++++++++++ src/qt/guiutil.h | 2 ++ 3 files changed, 39 insertions(+), 24 deletions(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 272df3fdae..b3cd7cfbca 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -762,30 +762,7 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer } else { - // Represent time from last generated block in human readable text - QString timeBehindText; - const int HOUR_IN_SECONDS = 60*60; - const int DAY_IN_SECONDS = 24*60*60; - const int WEEK_IN_SECONDS = 7*24*60*60; - const int YEAR_IN_SECONDS = 31556952; // Average length of year in Gregorian calendar - if(secs < 2*DAY_IN_SECONDS) - { - timeBehindText = tr("%n hour(s)","",secs/HOUR_IN_SECONDS); - } - else if(secs < 2*WEEK_IN_SECONDS) - { - timeBehindText = tr("%n day(s)","",secs/DAY_IN_SECONDS); - } - else if(secs < YEAR_IN_SECONDS) - { - timeBehindText = tr("%n week(s)","",secs/WEEK_IN_SECONDS); - } - else - { - qint64 years = secs / YEAR_IN_SECONDS; - qint64 remainder = secs % YEAR_IN_SECONDS; - timeBehindText = tr("%1 and %2").arg(tr("%n year(s)", "", years)).arg(tr("%n week(s)","", remainder/WEEK_IN_SECONDS)); - } + QString timeBehindText = GUIUtil::formateNiceTimeOffset(secs); progressBarLabel->setVisible(true); progressBar->setFormat(tr("%1 behind").arg(timeBehindText)); diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 947a4c6821..fe9de1c7a1 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -952,4 +952,40 @@ QString formatTimeOffset(int64_t nTimeOffset) return QString(QObject::tr("%1 s")).arg(QString::number((int)nTimeOffset, 10)); } +QString formateNiceTimeOffset(qint64 secs) +{ + // Represent time from last generated block in human readable text + QString timeBehindText; + const int HOUR_IN_SECONDS = 60*60; + const int DAY_IN_SECONDS = 24*60*60; + const int WEEK_IN_SECONDS = 7*24*60*60; + const int YEAR_IN_SECONDS = 31556952; // Average length of year in Gregorian calendar + if(secs < 60) + { + timeBehindText = QObject::tr("%n seconds(s)","",secs); + } + else if(secs < 2*HOUR_IN_SECONDS) + { + timeBehindText = QObject::tr("%n minutes(s)","",secs/60); + } + else if(secs < 2*DAY_IN_SECONDS) + { + timeBehindText = QObject::tr("%n hour(s)","",secs/HOUR_IN_SECONDS); + } + else if(secs < 2*WEEK_IN_SECONDS) + { + timeBehindText = QObject::tr("%n day(s)","",secs/DAY_IN_SECONDS); + } + else if(secs < YEAR_IN_SECONDS) + { + timeBehindText = QObject::tr("%n week(s)","",secs/WEEK_IN_SECONDS); + } + else + { + qint64 years = secs / YEAR_IN_SECONDS; + qint64 remainder = secs % YEAR_IN_SECONDS; + timeBehindText = QObject::tr("%1 and %2").arg(QObject::tr("%n year(s)", "", years)).arg(QObject::tr("%n week(s)","", remainder/WEEK_IN_SECONDS)); + } + return timeBehindText; +} } // namespace GUIUtil diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index 9267e0a6c9..7697e53ae9 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -200,6 +200,8 @@ namespace GUIUtil /* Format a CNodeCombinedStats.nTimeOffset into a user-readable string. */ QString formatTimeOffset(int64_t nTimeOffset); + QString formateNiceTimeOffset(qint64 secs); + #if defined(Q_OS_MAC) && QT_VERSION >= 0x050000 // workaround for Qt OSX Bug: // https://bugreports.qt-project.org/browse/QTBUG-15631 From bd44a04dc3fe94d2764fadd9f9a7deb81ff49f45 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Tue, 19 Jul 2016 15:27:14 +0200 Subject: [PATCH 2/7] [Qt] make Out-Of-Sync warning icon clickable --- src/qt/forms/overviewpage.ui | 4 ++-- src/qt/overviewpage.cpp | 7 +++++++ src/qt/overviewpage.h | 2 ++ src/qt/walletframe.cpp | 6 ++++++ src/qt/walletframe.h | 6 ++++++ src/qt/walletview.cpp | 6 ++++++ src/qt/walletview.h | 5 +++++ 7 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/qt/forms/overviewpage.ui b/src/qt/forms/overviewpage.ui index 6d792d1475..923ed68996 100644 --- a/src/qt/forms/overviewpage.ui +++ b/src/qt/forms/overviewpage.ui @@ -61,7 +61,7 @@ - false + true @@ -447,7 +447,7 @@ - false + true diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 6a0404cbf7..e415a6c4dd 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -140,6 +140,8 @@ OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent) // start with displaying the "out of sync" warnings showOutOfSyncWarning(true); + connect(ui->labelWalletStatus, SIGNAL(clicked()), this, SLOT(handleOutOfSyncWarningClicks())); + connect(ui->labelTransactionsStatus, SIGNAL(clicked()), this, SLOT(handleOutOfSyncWarningClicks())); } void OverviewPage::handleTransactionClicked(const QModelIndex &index) @@ -148,6 +150,11 @@ void OverviewPage::handleTransactionClicked(const QModelIndex &index) Q_EMIT transactionClicked(filter->mapToSource(index)); } +void OverviewPage::handleOutOfSyncWarningClicks() +{ + Q_EMIT outOfSyncWarningClicked(); +} + OverviewPage::~OverviewPage() { delete ui; diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h index 911443c76a..65cd3341b6 100644 --- a/src/qt/overviewpage.h +++ b/src/qt/overviewpage.h @@ -42,6 +42,7 @@ public Q_SLOTS: Q_SIGNALS: void transactionClicked(const QModelIndex &index); + void outOfSyncWarningClicked(); private: Ui::OverviewPage *ui; @@ -62,6 +63,7 @@ private Q_SLOTS: void handleTransactionClicked(const QModelIndex &index); void updateAlerts(const QString &warnings); void updateWatchOnlyLabels(bool showWatchOnly); + void handleOutOfSyncWarningClicks(); }; #endif // BITCOIN_QT_OVERVIEWPAGE_H diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp index e4ca5e1831..9d68e54e3a 100644 --- a/src/qt/walletframe.cpp +++ b/src/qt/walletframe.cpp @@ -57,6 +57,8 @@ bool WalletFrame::addWallet(const QString& name, WalletModel *walletModel) // Ensure a walletView is able to show the main window connect(walletView, SIGNAL(showNormalIfMinimized()), gui, SLOT(showNormalIfMinimized())); + connect(walletView, SIGNAL(outOfSyncWarningClicked()), this, SLOT(outOfSyncWarningClicked())); + return true; } @@ -195,3 +197,7 @@ WalletView *WalletFrame::currentWalletView() return qobject_cast(walletStack->currentWidget()); } +void WalletFrame::outOfSyncWarningClicked() +{ + Q_EMIT requestedOfSyncWarningInfo(); +} \ No newline at end of file diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h index 9a5bc273c2..7e3a5690eb 100644 --- a/src/qt/walletframe.h +++ b/src/qt/walletframe.h @@ -38,6 +38,10 @@ public: void showOutOfSyncWarning(bool fShow); +Q_SIGNALS: + /** Notify that the user has requested more information about the out-of-sync warning */ + void requestedOfSyncWarningInfo(); + private: QStackedWidget *walletStack; BitcoinGUI *gui; @@ -78,6 +82,8 @@ public Q_SLOTS: void usedSendingAddresses(); /** Show used receiving addresses */ void usedReceivingAddresses(); + /** Pass on signal over requested out-of-sync-warning information */ + void outOfSyncWarningClicked(); }; #endif // BITCOIN_QT_WALLETFRAME_H diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index 495ebfd834..656b21586f 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -66,6 +66,7 @@ WalletView::WalletView(const PlatformStyle *platformStyle, QWidget *parent): // Clicking on a transaction on the overview pre-selects the transaction on the transaction history page connect(overviewPage, SIGNAL(transactionClicked(QModelIndex)), transactionView, SLOT(focusTransaction(QModelIndex))); + connect(overviewPage, SIGNAL(outOfSyncWarningClicked()), this, SLOT(requestedOfSyncWarningInfo())); // Double-clicking on a transaction on the transaction history page shows details connect(transactionView, SIGNAL(doubleClicked(QModelIndex)), transactionView, SLOT(showDetails())); @@ -322,3 +323,8 @@ void WalletView::showProgress(const QString &title, int nProgress) else if (progressDialog) progressDialog->setValue(nProgress); } + +void WalletView::requestedOfSyncWarningInfo() +{ + Q_EMIT outOfSyncWarningClicked(); +} diff --git a/src/qt/walletview.h b/src/qt/walletview.h index 2045605954..c0a27ab989 100644 --- a/src/qt/walletview.h +++ b/src/qt/walletview.h @@ -110,6 +110,9 @@ public Q_SLOTS: /** Show progress dialog e.g. for rescan */ void showProgress(const QString &title, int nProgress); + /** User has requested more information about the out of sync state */ + void requestedOfSyncWarningInfo(); + Q_SIGNALS: /** Signal that we want to show the main window */ void showNormalIfMinimized(); @@ -121,6 +124,8 @@ Q_SIGNALS: void hdEnabledStatusChanged(int hdEnabled); /** Notify that a new transaction appeared */ void incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address, const QString& label); + /** Notify that the out of sync warning icon has been pressed */ + void outOfSyncWarningClicked(); }; #endif // BITCOIN_QT_WALLETVIEW_H From a001f1880283089d3eb0aa83e889d9707d79fd5f Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Tue, 19 Jul 2016 15:49:50 +0200 Subject: [PATCH 3/7] [Qt] Always pass the numBlocksChanged signal for headers tip changed --- src/qt/clientmodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 14661b857a..30f412dd23 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -234,7 +234,7 @@ static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, const CB int64_t& nLastUpdateNotification = fHeader ? nLastHeaderTipUpdateNotification : nLastBlockTipUpdateNotification; // if we are in-sync, update the UI regardless of last update time - if (!initialSync || now - nLastUpdateNotification > MODEL_UPDATE_DELAY) { + if (fHeader || !initialSync || now - nLastUpdateNotification > MODEL_UPDATE_DELAY) { //pass a async signal to the UI thread QMetaObject::invokeMethod(clientmodel, "numBlocksChanged", Qt::QueuedConnection, Q_ARG(int, pIndex->nHeight), From e47052f6b5ea901ecdc1cb8245dd98a98b06618a Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Tue, 19 Jul 2016 15:50:50 +0200 Subject: [PATCH 4/7] [Qt] ClientModel add method to get the height of the header chain --- src/qt/clientmodel.cpp | 8 ++++++++ src/qt/clientmodel.h | 1 + 2 files changed, 9 insertions(+) diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 30f412dd23..e3240b95a2 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -68,6 +68,14 @@ int ClientModel::getNumBlocks() const return chainActive.Height(); } +int ClientModel::getHeaderHeight() const +{ + LOCK(cs_main); + if (!pindexBestHeader) + return 0; + return pindexBestHeader->nHeight; +} + quint64 ClientModel::getTotalBytesRecv() const { return CNode::GetTotalBytesRecv(); diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 99fd574b9e..f0c9a7988a 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -51,6 +51,7 @@ public: //! Return number of connections, default is in- and outbound (total) int getNumConnections(unsigned int flags = CONNECTIONS_ALL) const; int getNumBlocks() const; + int getHeaderHeight() const; //! Return number of transactions in the mempool long getMempoolSize() const; From e3245b43d5c6fc984e8c60495f6db54f85d64368 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Tue, 19 Jul 2016 15:51:24 +0200 Subject: [PATCH 5/7] [Qt] add out-of-sync modal info layer --- src/Makefile.qt.include | 4 + src/qt/bitcoingui.cpp | 31 ++- src/qt/bitcoingui.h | 4 + src/qt/forms/modaloverlay.ui | 370 +++++++++++++++++++++++++++++++++++ src/qt/modaloverlay.cpp | 150 ++++++++++++++ src/qt/modaloverlay.h | 44 +++++ 6 files changed, 602 insertions(+), 1 deletion(-) create mode 100644 src/qt/forms/modaloverlay.ui create mode 100644 src/qt/modaloverlay.cpp create mode 100644 src/qt/modaloverlay.h diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 8947aeaca0..ea9be82717 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -96,6 +96,7 @@ QT_FORMS_UI = \ qt/forms/editaddressdialog.ui \ qt/forms/helpmessagedialog.ui \ qt/forms/intro.ui \ + qt/forms/modaloverlay.ui \ qt/forms/openuridialog.ui \ qt/forms/optionsdialog.ui \ qt/forms/overviewpage.ui \ @@ -125,6 +126,7 @@ QT_MOC_CPP = \ qt/moc_intro.cpp \ qt/moc_macdockiconhandler.cpp \ qt/moc_macnotificationhandler.cpp \ + qt/moc_modaloverlay.cpp \ qt/moc_notificator.cpp \ qt/moc_openuridialog.cpp \ qt/moc_optionsdialog.cpp \ @@ -192,6 +194,7 @@ BITCOIN_QT_H = \ qt/intro.h \ qt/macdockiconhandler.h \ qt/macnotificationhandler.h \ + qt/modaloverlay.h \ qt/networkstyle.h \ qt/notificator.h \ qt/openuridialog.h \ @@ -292,6 +295,7 @@ BITCOIN_QT_CPP = \ qt/csvmodelwriter.cpp \ qt/guiutil.cpp \ qt/intro.cpp \ + qt/modaloverlay.cpp \ qt/networkstyle.cpp \ qt/notificator.cpp \ qt/optionsdialog.cpp \ diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index b3cd7cfbca..628d35b5ea 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -12,6 +12,7 @@ #include "clientmodel.h" #include "guiconstants.h" #include "guiutil.h" +#include "modaloverlay.h" #include "networkstyle.h" #include "notificator.h" #include "openuridialog.h" @@ -114,6 +115,7 @@ BitcoinGUI::BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *n notificator(0), rpcConsole(0), helpMessageDialog(0), + modalOverlay(0), prevBlocks(0), spinnerFrame(0), platformStyle(platformStyle) @@ -241,6 +243,12 @@ BitcoinGUI::BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *n // Subscribe to notifications from core subscribeToCoreSignals(); + + modalOverlay = new ModalOverlay(this->centralWidget()); +#ifdef ENABLE_WALLET + if(enableWallet) + connect(walletFrame, SIGNAL(requestedOfSyncWarningInfo()), this, SLOT(showModalOverlay())); +#endif } BitcoinGUI::~BitcoinGUI() @@ -491,6 +499,8 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel) // initialize the disable state of the tray icon with the current value in the model. setTrayIconVisible(optionsModel->getHideTrayIcon()); } + + modalOverlay->setKnownBestHeight(clientModel->getHeaderHeight()); } else { // Disable possibility to show main window via action toggleHideAction->setEnabled(false); @@ -705,7 +715,14 @@ void BitcoinGUI::setNumConnections(int count) void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool header) { - if(!clientModel) + if (modalOverlay) + { + if (header) + modalOverlay->setKnownBestHeight(count); + else + modalOverlay->tipUpdate(count, blockDate, nVerificationProgress); + } + if (!clientModel) return; // Prevent orphan statusbar messages (e.g. hover Quit in main menu, wait until chain-sync starts -> garbelled text) @@ -754,7 +771,10 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer #ifdef ENABLE_WALLET if(walletFrame) + { walletFrame->showOutOfSyncWarning(false); + modalOverlay->showHide(true, true); + } #endif // ENABLE_WALLET progressBarLabel->setVisible(false); @@ -782,7 +802,10 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer #ifdef ENABLE_WALLET if(walletFrame) + { walletFrame->showOutOfSyncWarning(true); + modalOverlay->showHide(); + } #endif // ENABLE_WALLET tooltip += QString("
"); @@ -1078,6 +1101,12 @@ void BitcoinGUI::setTrayIconVisible(bool fHideTrayIcon) } } +void BitcoinGUI::showModalOverlay() +{ + if (modalOverlay) + modalOverlay->showHide(false, true); +} + static bool ThreadSafeMessageBox(BitcoinGUI *gui, const std::string& message, const std::string& caption, unsigned int style) { bool modal = (style & CClientUIInterface::MODAL); diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 41770929b4..0eaa44b263 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -29,6 +29,7 @@ class UnitDisplayStatusBarControl; class WalletFrame; class WalletModel; class HelpMessageDialog; +class ModalOverlay; class CWallet; @@ -118,6 +119,7 @@ private: Notificator *notificator; RPCConsole *rpcConsole; HelpMessageDialog *helpMessageDialog; + ModalOverlay *modalOverlay; /** Keep track of previous number of blocks, to detect progress */ int prevBlocks; @@ -229,6 +231,8 @@ private Q_SLOTS: /** When hideTrayIcon setting is changed in OptionsModel hide or show the icon accordingly. */ void setTrayIconVisible(bool); + + void showModalOverlay(); }; class UnitDisplayStatusBarControl : public QLabel diff --git a/src/qt/forms/modaloverlay.ui b/src/qt/forms/modaloverlay.ui new file mode 100644 index 0000000000..f1967a7c05 --- /dev/null +++ b/src/qt/forms/modaloverlay.ui @@ -0,0 +1,370 @@ + + + ModalOverlay + + + + 0 + 0 + 640 + 385 + + + + Form + + + + QLayout::SetDefaultConstraint + + + 0 + + + 0 + + + 0 + + + 0 + + + + + #bgWidget { background: rgba(0,0,0,220); } + + + + 60 + + + 60 + + + 60 + + + 60 + + + + + #contentWidget { background: rgba(255,255,255,240); border-radius: 6px; } + +QLabel { color: rgb(40,40,40); } + + + + 0 + + + 10 + + + 10 + + + 10 + + + 10 + + + + + 20 + + + + + 0 + + + + + + + + + :/icons/warning + :/icons/warning:/icons/warning + + + + 48 + 48 + + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + 0 + + + 0 + + + + + The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet. + + + Qt::RichText + + + true + + + + + + + + 75 + true + + + + This means that recent transactions will not be visible, and the balance will not be up-to-date until this process has completed. Spending bitcoins is not possible during that phase! + + + Qt::RichText + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + QFormLayout::FieldsStayAtSizeHint + + + 6 + + + 6 + + + 10 + + + + + + 75 + true + + + + Amount of blocks left + + + + + + + unknown... + + + + + + + + 75 + true + + + + Last block time + + + + + + + + 0 + 0 + + + + unknown... + + + + + + + + 75 + true + + + + Progress + + + + + + + + + ~ + + + + + + + 24 + + + + + + + + + + 75 + true + + + + Progress increase per Hour + + + + + + + calculating... + + + + + + + + 75 + true + + + + Estimated time left until synced + + + + + + + calculating... + + + + + + + + + 10 + + + 10 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Hide + + + + + + + + + + + + + + + + ModalOverlay + QWidget +
modaloverlay.h
+ 1 +
+
+ + +
diff --git a/src/qt/modaloverlay.cpp b/src/qt/modaloverlay.cpp new file mode 100644 index 0000000000..1cd5b19966 --- /dev/null +++ b/src/qt/modaloverlay.cpp @@ -0,0 +1,150 @@ +// Copyright (c) 2017 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "modaloverlay.h" +#include "ui_modaloverlay.h" + +#include "guiutil.h" + +#include +#include + +ModalOverlay::ModalOverlay(QWidget *parent) : +QWidget(parent), +ui(new Ui::ModalOverlay), +bestBlockHeight(0), +layerIsVisible(false), +userClosed(false) +{ + ui->setupUi(this); + connect(ui->closeButton, SIGNAL(clicked()), this, SLOT(closeClicked())); + if (parent) { + parent->installEventFilter(this); + raise(); + } + + blockProcessTime.clear(); + setVisible(false); +} + +ModalOverlay::~ModalOverlay() +{ + delete ui; +} + +bool ModalOverlay::eventFilter(QObject * obj, QEvent * ev) { + if (obj == parent()) { + if (ev->type() == QEvent::Resize) { + QResizeEvent * rev = static_cast(ev); + resize(rev->size()); + if (!layerIsVisible) + setGeometry(0, height(), width(), height()); + + } + else if (ev->type() == QEvent::ChildAdded) { + raise(); + } + } + return QWidget::eventFilter(obj, ev); +} + +//! Tracks parent widget changes +bool ModalOverlay::event(QEvent* ev) { + if (ev->type() == QEvent::ParentAboutToChange) { + if (parent()) parent()->removeEventFilter(this); + } + else if (ev->type() == QEvent::ParentChange) { + if (parent()) { + parent()->installEventFilter(this); + raise(); + } + } + return QWidget::event(ev); +} + +void ModalOverlay::setKnownBestHeight(int count) +{ + if (count > bestBlockHeight) + bestBlockHeight = count; +} + +void ModalOverlay::tipUpdate(int count, const QDateTime& blockDate, double nVerificationProgress) +{ + QDateTime currentDate = QDateTime::currentDateTime(); + + // keep a vector of samples of verification progress at height + blockProcessTime.push_front(qMakePair(currentDate.currentMSecsSinceEpoch(), nVerificationProgress)); + + // show progress speed if we have more then one sample + if (blockProcessTime.size() >= 2) + { + // try to get the window from the last 500 seconds or at least 10 samples + double progressStart = blockProcessTime[0].second; + double progressDelta = 0; + double progressPerHour = 0; + qint64 timeDelta = 0; + qint64 remainingMSecs = 0; + double remainingProgress = 1.0 - nVerificationProgress; + for (int i = 1; i < blockProcessTime.size(); i++) + { + QPair sample = blockProcessTime[i]; + + // take first sample after 500 seconds or last available one + if (sample.first < (currentDate.currentMSecsSinceEpoch() - 500*1000) || i == blockProcessTime.size()-1) + { + progressDelta = progressStart-sample.second; + timeDelta = blockProcessTime[0].first - sample.first; + progressPerHour = progressDelta/(double)timeDelta*1000*3600; + remainingMSecs = remainingProgress / progressDelta * timeDelta; + break; + } + } + // show progress increase per hour + ui->progressIncreasePerH->setText(QString::number(progressPerHour*100, 'f', 2)+"%"); + + // show expected remaining time + ui->expectedTimeLeft->setText(GUIUtil::formateNiceTimeOffset(remainingMSecs/1000.0)); + + // keep maximal 5000 samples + static int maxSamples = 5000; + if (blockProcessTime.count() > maxSamples) + blockProcessTime.remove(maxSamples, blockProcessTime.count()-maxSamples); + } + + // show the last block date + ui->newestBlockDate->setText(blockDate.toString()); + + // show the percentage done according to nVerificationProgress + ui->percentageProgress->setText(QString::number(nVerificationProgress*100, 'f', 2)+"%"); + ui->progressBar->setValue(nVerificationProgress*100); + + // show remaining amount of blocks + if (bestBlockHeight > 0) + ui->amountOfBlocksLeft->setText(QString::number(bestBlockHeight-count)); +} + +void ModalOverlay::showHide(bool hide, bool userRequested) +{ + if ( (layerIsVisible && !hide) || (!layerIsVisible && hide) || (!hide && userClosed && !userRequested)) + return; + + if (!isVisible() && !hide) + setVisible(true); + + setGeometry(0, hide ? 0 : height(), width(), height()); + + QPropertyAnimation* animation = new QPropertyAnimation(this, "pos"); + animation->setDuration(300); + animation->setStartValue(QPoint(0, hide ? 0 : this->height())); + animation->setEndValue(QPoint(0, hide ? this->height() : 0)); + animation->setEasingCurve(QEasingCurve::OutQuad); + animation->start(QAbstractAnimation::DeleteWhenStopped); + layerIsVisible = !hide; +} + +void ModalOverlay::closeClicked() +{ + showHide(true); + userClosed = true; +} diff --git a/src/qt/modaloverlay.h b/src/qt/modaloverlay.h new file mode 100644 index 0000000000..5bf913a3f3 --- /dev/null +++ b/src/qt/modaloverlay.h @@ -0,0 +1,44 @@ +// Copyright (c) 2017 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_QT_MODALOVERLAY_H +#define BITCOIN_QT_MODALOVERLAY_H + +#include +#include + +namespace Ui { + class ModalOverlay; +} + +/** Modal overlay to display information about the chain-sync state */ +class ModalOverlay : public QWidget +{ + Q_OBJECT + +public: + explicit ModalOverlay(QWidget *parent); + ~ModalOverlay(); + +public Q_SLOTS: + void tipUpdate(int count, const QDateTime& blockDate, double nVerificationProgress); + void setKnownBestHeight(int count); + + // will show or hide the modal layer + void showHide(bool hide = false, bool userRequested = false); + void closeClicked(); + +protected: + bool eventFilter(QObject * obj, QEvent * ev); + bool event(QEvent* ev); + +private: + Ui::ModalOverlay *ui; + int bestBlockHeight; //best known height (based on the headers) + QVector > blockProcessTime; + bool layerIsVisible; + bool userClosed; +}; + +#endif // BITCOIN_QT_MODALOVERLAY_H From d8b062ef5eea3addff00a09bad1dab162452b4b5 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Tue, 13 Sep 2016 16:36:24 +0200 Subject: [PATCH 6/7] [Qt] only update "amount of blocks left" when the header chain is in-sync --- src/qt/bitcoingui.cpp | 7 +++++-- src/qt/clientmodel.cpp | 10 +++++++++- src/qt/clientmodel.h | 4 ++-- src/qt/forms/modaloverlay.ui | 3 +++ src/qt/modaloverlay.cpp | 15 ++++++++++++--- src/qt/modaloverlay.h | 2 +- 6 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 628d35b5ea..c184745dbe 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -500,7 +500,7 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel) setTrayIconVisible(optionsModel->getHideTrayIcon()); } - modalOverlay->setKnownBestHeight(clientModel->getHeaderHeight()); + modalOverlay->setKnownBestHeight(clientModel->getHeaderTipHeight(), QDateTime::fromTime_t(clientModel->getHeaderTipTime())); } else { // Disable possibility to show main window via action toggleHideAction->setEnabled(false); @@ -718,7 +718,10 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer if (modalOverlay) { if (header) - modalOverlay->setKnownBestHeight(count); + { + /* use clientmodels getHeaderTipHeight and getHeaderTipTime because the NotifyHeaderTip signal does not fire when updating the best header */ + modalOverlay->setKnownBestHeight(clientModel->getHeaderTipHeight(), QDateTime::fromTime_t(clientModel->getHeaderTipTime())); + } else modalOverlay->tipUpdate(count, blockDate, nVerificationProgress); } diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index e3240b95a2..fb0cce59cc 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -68,7 +68,7 @@ int ClientModel::getNumBlocks() const return chainActive.Height(); } -int ClientModel::getHeaderHeight() const +int ClientModel::getHeaderTipHeight() const { LOCK(cs_main); if (!pindexBestHeader) @@ -76,6 +76,14 @@ int ClientModel::getHeaderHeight() const return pindexBestHeader->nHeight; } +int64_t ClientModel::getHeaderTipTime() const +{ + LOCK(cs_main); + if (!pindexBestHeader) + return 0; + return pindexBestHeader->GetBlockTime(); +} + quint64 ClientModel::getTotalBytesRecv() const { return CNode::GetTotalBytesRecv(); diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index f0c9a7988a..3fd8404cbb 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -51,8 +51,8 @@ public: //! Return number of connections, default is in- and outbound (total) int getNumConnections(unsigned int flags = CONNECTIONS_ALL) const; int getNumBlocks() const; - int getHeaderHeight() const; - + int getHeaderTipHeight() const; + int64_t getHeaderTipTime() const; //! Return number of transactions in the mempool long getMempoolSize() const; //! Return the dynamic memory usage of the mempool diff --git a/src/qt/forms/modaloverlay.ui b/src/qt/forms/modaloverlay.ui index f1967a7c05..ce9ceaaadd 100644 --- a/src/qt/forms/modaloverlay.ui +++ b/src/qt/forms/modaloverlay.ui @@ -82,6 +82,9 @@ QLabel { color: rgb(40,40,40); }
+ + false + diff --git a/src/qt/modaloverlay.cpp b/src/qt/modaloverlay.cpp index 1cd5b19966..c548890391 100644 --- a/src/qt/modaloverlay.cpp +++ b/src/qt/modaloverlay.cpp @@ -63,10 +63,17 @@ bool ModalOverlay::event(QEvent* ev) { return QWidget::event(ev); } -void ModalOverlay::setKnownBestHeight(int count) +void ModalOverlay::setKnownBestHeight(int count, const QDateTime& blockDate) { - if (count > bestBlockHeight) - bestBlockHeight = count; + + /* only update the blockheight if the headerschain-tip is not older then 30 days */ + int64_t now = QDateTime::currentDateTime().toTime_t(); + int64_t btime = blockDate.toTime_t(); + if (btime+3600*24*30 > now) + { + if (count > bestBlockHeight) + bestBlockHeight = count; + } } void ModalOverlay::tipUpdate(int count, const QDateTime& blockDate, double nVerificationProgress) @@ -122,6 +129,8 @@ void ModalOverlay::tipUpdate(int count, const QDateTime& blockDate, double nVeri // show remaining amount of blocks if (bestBlockHeight > 0) ui->amountOfBlocksLeft->setText(QString::number(bestBlockHeight-count)); + else + ui->expectedTimeLeft->setText(tr("Unknown. Syncing Headers...")); } void ModalOverlay::showHide(bool hide, bool userRequested) diff --git a/src/qt/modaloverlay.h b/src/qt/modaloverlay.h index 5bf913a3f3..bdbe3c39a7 100644 --- a/src/qt/modaloverlay.h +++ b/src/qt/modaloverlay.h @@ -23,7 +23,7 @@ public: public Q_SLOTS: void tipUpdate(int count, const QDateTime& blockDate, double nVerificationProgress); - void setKnownBestHeight(int count); + void setKnownBestHeight(int count, const QDateTime& blockDate); // will show or hide the modal layer void showHide(bool hide = false, bool userRequested = false); From 08827df3ecce925928dc3bedcdef63bfca290300 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Wed, 21 Sep 2016 10:29:57 +0200 Subject: [PATCH 7/7] [Qt] modalinfolayer: removed unused comments, renamed signal, code style overhaul --- src/qt/bitcoingui.cpp | 8 ++++---- src/qt/forms/modaloverlay.ui | 4 ++-- src/qt/modaloverlay.cpp | 7 +++---- src/qt/walletframe.cpp | 4 ++-- src/qt/walletframe.h | 2 +- src/qt/walletview.cpp | 4 ++-- src/qt/walletview.h | 2 +- 7 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index c184745dbe..2a9afc51a0 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -247,7 +247,7 @@ BitcoinGUI::BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *n modalOverlay = new ModalOverlay(this->centralWidget()); #ifdef ENABLE_WALLET if(enableWallet) - connect(walletFrame, SIGNAL(requestedOfSyncWarningInfo()), this, SLOT(showModalOverlay())); + connect(walletFrame, SIGNAL(requestedSyncWarningInfo()), this, SLOT(showModalOverlay())); #endif } @@ -717,13 +717,13 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer { if (modalOverlay) { - if (header) - { + if (header) { /* use clientmodels getHeaderTipHeight and getHeaderTipTime because the NotifyHeaderTip signal does not fire when updating the best header */ modalOverlay->setKnownBestHeight(clientModel->getHeaderTipHeight(), QDateTime::fromTime_t(clientModel->getHeaderTipTime())); } - else + else { modalOverlay->tipUpdate(count, blockDate, nVerificationProgress); + } } if (!clientModel) return; diff --git a/src/qt/forms/modaloverlay.ui b/src/qt/forms/modaloverlay.ui index ce9ceaaadd..ccec1b3e1e 100644 --- a/src/qt/forms/modaloverlay.ui +++ b/src/qt/forms/modaloverlay.ui @@ -130,7 +130,7 @@ QLabel { color: rgb(40,40,40); } - The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet. + The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet. This means that recent transactions will not be visible, and the balance will not be up-to-date until this process has completed. Qt::RichText @@ -149,7 +149,7 @@ QLabel { color: rgb(40,40,40); } - This means that recent transactions will not be visible, and the balance will not be up-to-date until this process has completed. Spending bitcoins is not possible during that phase! + Spending bitcoins may not be possible during that phase! Qt::RichText diff --git a/src/qt/modaloverlay.cpp b/src/qt/modaloverlay.cpp index c548890391..7b121e9e88 100644 --- a/src/qt/modaloverlay.cpp +++ b/src/qt/modaloverlay.cpp @@ -86,7 +86,6 @@ void ModalOverlay::tipUpdate(int count, const QDateTime& blockDate, double nVeri // show progress speed if we have more then one sample if (blockProcessTime.size() >= 2) { - // try to get the window from the last 500 seconds or at least 10 samples double progressStart = blockProcessTime[0].second; double progressDelta = 0; double progressPerHour = 0; @@ -114,9 +113,9 @@ void ModalOverlay::tipUpdate(int count, const QDateTime& blockDate, double nVeri ui->expectedTimeLeft->setText(GUIUtil::formateNiceTimeOffset(remainingMSecs/1000.0)); // keep maximal 5000 samples - static int maxSamples = 5000; - if (blockProcessTime.count() > maxSamples) - blockProcessTime.remove(maxSamples, blockProcessTime.count()-maxSamples); + static const int MAX_SAMPLES = 5000; + if (blockProcessTime.count() > MAX_SAMPLES) + blockProcessTime.remove(MAX_SAMPLES, blockProcessTime.count()-MAX_SAMPLES); } // show the last block date diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp index 9d68e54e3a..518d9ea90a 100644 --- a/src/qt/walletframe.cpp +++ b/src/qt/walletframe.cpp @@ -199,5 +199,5 @@ WalletView *WalletFrame::currentWalletView() void WalletFrame::outOfSyncWarningClicked() { - Q_EMIT requestedOfSyncWarningInfo(); -} \ No newline at end of file + Q_EMIT requestedSyncWarningInfo(); +} diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h index 7e3a5690eb..00c2f56363 100644 --- a/src/qt/walletframe.h +++ b/src/qt/walletframe.h @@ -40,7 +40,7 @@ public: Q_SIGNALS: /** Notify that the user has requested more information about the out-of-sync warning */ - void requestedOfSyncWarningInfo(); + void requestedSyncWarningInfo(); private: QStackedWidget *walletStack; diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index 656b21586f..b163ce3dcf 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -66,7 +66,7 @@ WalletView::WalletView(const PlatformStyle *platformStyle, QWidget *parent): // Clicking on a transaction on the overview pre-selects the transaction on the transaction history page connect(overviewPage, SIGNAL(transactionClicked(QModelIndex)), transactionView, SLOT(focusTransaction(QModelIndex))); - connect(overviewPage, SIGNAL(outOfSyncWarningClicked()), this, SLOT(requestedOfSyncWarningInfo())); + connect(overviewPage, SIGNAL(outOfSyncWarningClicked()), this, SLOT(requestedSyncWarningInfo())); // Double-clicking on a transaction on the transaction history page shows details connect(transactionView, SIGNAL(doubleClicked(QModelIndex)), transactionView, SLOT(showDetails())); @@ -324,7 +324,7 @@ void WalletView::showProgress(const QString &title, int nProgress) progressDialog->setValue(nProgress); } -void WalletView::requestedOfSyncWarningInfo() +void WalletView::requestedSyncWarningInfo() { Q_EMIT outOfSyncWarningClicked(); } diff --git a/src/qt/walletview.h b/src/qt/walletview.h index c0a27ab989..aaa6aacbf0 100644 --- a/src/qt/walletview.h +++ b/src/qt/walletview.h @@ -111,7 +111,7 @@ public Q_SLOTS: void showProgress(const QString &title, int nProgress); /** User has requested more information about the out of sync state */ - void requestedOfSyncWarningInfo(); + void requestedSyncWarningInfo(); Q_SIGNALS: /** Signal that we want to show the main window */