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