Bitcoin Core 22.99.0
P2P Digital Currency
modaloverlay.cpp
Go to the documentation of this file.
1// Copyright (c) 2016-2020 The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5#include <qt/modaloverlay.h>
7
8#include <chainparams.h>
9#include <qt/guiutil.h>
10
11#include <QEasingCurve>
12#include <QPropertyAnimation>
13#include <QResizeEvent>
14
15ModalOverlay::ModalOverlay(bool enable_wallet, QWidget *parent) :
16QWidget(parent),
17ui(new Ui::ModalOverlay),
18bestHeaderHeight(0),
19bestHeaderDate(QDateTime()),
20layerIsVisible(false),
21userClosed(false)
22{
23 ui->setupUi(this);
24 connect(ui->closeButton, &QPushButton::clicked, this, &ModalOverlay::closeClicked);
25 if (parent) {
26 parent->installEventFilter(this);
27 raise();
28 }
29
30 blockProcessTime.clear();
31 setVisible(false);
32 if (!enable_wallet) {
33 ui->infoText->setVisible(false);
34 ui->infoTextStrong->setText(tr("%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.").arg(PACKAGE_NAME));
35 }
36
37 m_animation.setTargetObject(this);
38 m_animation.setPropertyName("pos");
39 m_animation.setDuration(300 /* ms */);
40 m_animation.setEasingCurve(QEasingCurve::OutQuad);
41}
42
44{
45 delete ui;
46}
47
48bool ModalOverlay::eventFilter(QObject * obj, QEvent * ev) {
49 if (obj == parent()) {
50 if (ev->type() == QEvent::Resize) {
51 QResizeEvent * rev = static_cast<QResizeEvent*>(ev);
52 resize(rev->size());
53 if (!layerIsVisible)
54 setGeometry(0, height(), width(), height());
55
56 if (m_animation.endValue().toPoint().y() > 0) {
57 m_animation.setEndValue(QPoint(0, height()));
58 }
59 }
60 else if (ev->type() == QEvent::ChildAdded) {
61 raise();
62 }
63 }
64 return QWidget::eventFilter(obj, ev);
65}
66
68bool ModalOverlay::event(QEvent* ev) {
69 if (ev->type() == QEvent::ParentAboutToChange) {
70 if (parent()) parent()->removeEventFilter(this);
71 }
72 else if (ev->type() == QEvent::ParentChange) {
73 if (parent()) {
74 parent()->installEventFilter(this);
75 raise();
76 }
77 }
78 return QWidget::event(ev);
79}
80
81void ModalOverlay::setKnownBestHeight(int count, const QDateTime& blockDate)
82{
83 if (count > bestHeaderHeight) {
85 bestHeaderDate = blockDate;
87 }
88}
89
90void ModalOverlay::tipUpdate(int count, const QDateTime& blockDate, double nVerificationProgress)
91{
92 QDateTime currentDate = QDateTime::currentDateTime();
93
94 // keep a vector of samples of verification progress at height
95 blockProcessTime.push_front(qMakePair(currentDate.toMSecsSinceEpoch(), nVerificationProgress));
96
97 // show progress speed if we have more than one sample
98 if (blockProcessTime.size() >= 2) {
99 double progressDelta = 0;
100 double progressPerHour = 0;
101 qint64 timeDelta = 0;
102 qint64 remainingMSecs = 0;
103 double remainingProgress = 1.0 - nVerificationProgress;
104 for (int i = 1; i < blockProcessTime.size(); i++) {
105 QPair<qint64, double> sample = blockProcessTime[i];
106
107 // take first sample after 500 seconds or last available one
108 if (sample.first < (currentDate.toMSecsSinceEpoch() - 500 * 1000) || i == blockProcessTime.size() - 1) {
109 progressDelta = blockProcessTime[0].second - sample.second;
110 timeDelta = blockProcessTime[0].first - sample.first;
111 progressPerHour = progressDelta / (double) timeDelta * 1000 * 3600;
112 remainingMSecs = (progressDelta > 0) ? remainingProgress / progressDelta * timeDelta : -1;
113 break;
114 }
115 }
116 // show progress increase per hour
117 ui->progressIncreasePerH->setText(QString::number(progressPerHour * 100, 'f', 2)+"%");
118
119 // show expected remaining time
120 if(remainingMSecs >= 0) {
121 ui->expectedTimeLeft->setText(GUIUtil::formatNiceTimeOffset(remainingMSecs / 1000.0));
122 } else {
123 ui->expectedTimeLeft->setText(QObject::tr("unknown"));
124 }
125
126 static const int MAX_SAMPLES = 5000;
127 if (blockProcessTime.count() > MAX_SAMPLES) {
128 blockProcessTime.remove(MAX_SAMPLES, blockProcessTime.count() - MAX_SAMPLES);
129 }
130 }
131
132 // show the last block date
133 ui->newestBlockDate->setText(blockDate.toString());
134
135 // show the percentage done according to nVerificationProgress
136 ui->percentageProgress->setText(QString::number(nVerificationProgress*100, 'f', 2)+"%");
137
138 if (!bestHeaderDate.isValid())
139 // not syncing
140 return;
141
142 // estimate the number of headers left based on nPowTargetSpacing
143 // and check if the gui is not aware of the best header (happens rarely)
144 int estimateNumHeadersLeft = bestHeaderDate.secsTo(currentDate) / Params().GetConsensus().nPowTargetSpacing;
145 bool hasBestHeader = bestHeaderHeight >= count;
146
147 // show remaining number of blocks
148 if (estimateNumHeadersLeft < HEADER_HEIGHT_DELTA_SYNC && hasBestHeader) {
149 ui->numberOfBlocksLeft->setText(QString::number(bestHeaderHeight - count));
150 } else {
152 ui->expectedTimeLeft->setText(tr("Unknown…"));
153 }
154}
155
157 int est_headers_left = bestHeaderDate.secsTo(QDateTime::currentDateTime()) / Params().GetConsensus().nPowTargetSpacing;
158 ui->numberOfBlocksLeft->setText(tr("Unknown. Syncing Headers (%1, %2%)…").arg(bestHeaderHeight).arg(QString::number(100.0 / (bestHeaderHeight + est_headers_left) * bestHeaderHeight, 'f', 1)));
159}
160
162{
164 if (!layerIsVisible)
165 userClosed = true;
166}
167
168void ModalOverlay::showHide(bool hide, bool userRequested)
169{
170 if ( (layerIsVisible && !hide) || (!layerIsVisible && hide) || (!hide && userClosed && !userRequested))
171 return;
172
173 Q_EMIT triggered(hide);
174
175 if (!isVisible() && !hide)
176 setVisible(true);
177
178 m_animation.setStartValue(QPoint(0, hide ? 0 : height()));
179 // The eventFilter() updates the endValue if it is required for QEvent::Resize.
180 m_animation.setEndValue(QPoint(0, hide ? height() : 0));
181 m_animation.start(QAbstractAnimation::KeepWhenStopped);
182 layerIsVisible = !hide;
183}
184
186{
187 showHide(true);
188 userClosed = true;
189}
#define PACKAGE_NAME
const CChainParams & Params()
Return the currently selected parameters.
const Consensus::Params & GetConsensus() const
Definition: chainparams.h:82
Modal overlay to display information about the chain-sync state.
Definition: modaloverlay.h:21
void showHide(bool hide=false, bool userRequested=false)
bool event(QEvent *ev) override
Tracks parent widget changes.
void setKnownBestHeight(int count, const QDateTime &blockDate)
void tipUpdate(int count, const QDateTime &blockDate, double nVerificationProgress)
void UpdateHeaderSyncLabel()
ModalOverlay(bool enable_wallet, QWidget *parent)
void toggleVisibility()
QDateTime bestHeaderDate
Definition: modaloverlay.h:49
bool layerIsVisible
Definition: modaloverlay.h:51
void triggered(bool hidden)
Ui::ModalOverlay * ui
Definition: modaloverlay.h:47
void closeClicked()
QVector< QPair< qint64, double > > blockProcessTime
Definition: modaloverlay.h:50
int bestHeaderHeight
Definition: modaloverlay.h:48
bool eventFilter(QObject *obj, QEvent *ev) override
QPropertyAnimation m_animation
Definition: modaloverlay.h:53
QLabel * numberOfBlocksLeft
void setupUi(QWidget *ModalOverlay)
QLabel * progressIncreasePerH
QLabel * newestBlockDate
QLabel * percentageProgress
QPushButton * closeButton
QLabel * expectedTimeLeft
QLabel * infoTextStrong
static constexpr int HEADER_HEIGHT_DELTA_SYNC
The required delta of headers to the estimated number of available headers until we show the IBD prog...
Definition: modaloverlay.h:13
QString formatNiceTimeOffset(qint64 secs)
Definition: guiutil.cpp:754
int64_t nPowTargetSpacing
Definition: params.h:103
static int count
Definition: tests.c:41