Bitcoin ABC 0.30.5
P2P Digital Currency
modaloverlay.cpp
Go to the documentation of this file.
1// Copyright (c) 2016 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/forms/ui_modaloverlay.h>
6#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)
16 : QWidget(parent), ui(new Ui::ModalOverlay), bestHeaderHeight(0),
17 bestHeaderDate(QDateTime()), layerIsVisible(false), userClosed(false) {
18 ui->setupUi(this);
19 connect(ui->closeButton, &QPushButton::clicked, this,
21 if (parent) {
22 parent->installEventFilter(this);
23 raise();
24 }
25
26 blockProcessTime.clear();
27 setVisible(false);
28 if (!enable_wallet) {
29 ui->infoText->setVisible(false);
30 ui->infoTextStrong->setText(
31 tr("%1 is currently syncing. It will download headers "
32 "and blocks from peers and validate them until reaching the tip "
33 "of the block chain.")
34 .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 delete ui;
45}
46
47bool ModalOverlay::eventFilter(QObject *obj, QEvent *ev) {
48 if (obj == parent()) {
49 if (ev->type() == QEvent::Resize) {
50 QResizeEvent *rev = static_cast<QResizeEvent *>(ev);
51 resize(rev->size());
52 if (!layerIsVisible) {
53 setGeometry(0, height(), width(), height());
54 }
55
56 if (m_animation.endValue().toPoint().y() > 0) {
57 m_animation.setEndValue(QPoint(0, height()));
58 }
59 } else if (ev->type() == QEvent::ChildAdded) {
60 raise();
61 }
62 }
63 return QWidget::eventFilter(obj, ev);
64}
65
67bool ModalOverlay::event(QEvent *ev) {
68 if (ev->type() == QEvent::ParentAboutToChange) {
69 if (parent()) {
70 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 bool presync) {
83 if (!presync && count > bestHeaderHeight) {
85 bestHeaderDate = blockDate;
87 }
88 if (presync) {
90 }
91}
92
93void ModalOverlay::tipUpdate(int count, const QDateTime &blockDate,
94 double nVerificationProgress) {
95 QDateTime currentDate = QDateTime::currentDateTime();
96
97 // keep a vector of samples of verification progress at height
98 blockProcessTime.push_front(
99 qMakePair(currentDate.toMSecsSinceEpoch(), nVerificationProgress));
100
101 // show progress speed if we have more than one sample
102 if (blockProcessTime.size() >= 2) {
103 double progressDelta = 0;
104 double progressPerHour = 0;
105 qint64 timeDelta = 0;
106 qint64 remainingMSecs = 0;
107 double remainingProgress = 1.0 - nVerificationProgress;
108 for (int i = 1; i < blockProcessTime.size(); i++) {
109 QPair<qint64, double> sample = blockProcessTime[i];
110
111 // take first sample after 500 seconds or last available one
112 if (sample.first < (currentDate.toMSecsSinceEpoch() - 500 * 1000) ||
113 i == blockProcessTime.size() - 1) {
114 progressDelta = blockProcessTime[0].second - sample.second;
115 timeDelta = blockProcessTime[0].first - sample.first;
116 progressPerHour =
117 progressDelta / (double)timeDelta * 1000 * 3600;
118 remainingMSecs =
119 (progressDelta > 0)
120 ? remainingProgress / progressDelta * timeDelta
121 : -1;
122 break;
123 }
124 }
125 // show progress increase per hour
126 ui->progressIncreasePerH->setText(
127 QString::number(progressPerHour * 100, 'f', 2) + "%");
128
129 // show expected remaining time
130 if (remainingMSecs >= 0) {
131 ui->expectedTimeLeft->setText(
132 GUIUtil::formatNiceTimeOffset(remainingMSecs / 1000.0));
133 } else {
134 ui->expectedTimeLeft->setText(QObject::tr("unknown"));
135 }
136
137 static const int MAX_SAMPLES = 5000;
138 if (blockProcessTime.count() > MAX_SAMPLES) {
139 blockProcessTime.remove(MAX_SAMPLES,
140 blockProcessTime.count() - MAX_SAMPLES);
141 }
142 }
143
144 // show the last block date
145 ui->newestBlockDate->setText(blockDate.toString());
146
147 // show the percentage done according to nVerificationProgress
148 ui->percentageProgress->setText(
149 QString::number(nVerificationProgress * 100, 'f', 2) + "%");
150 ui->progressBar->setValue(nVerificationProgress * 100);
151
152 if (!bestHeaderDate.isValid()) {
153 // not syncing
154 return;
155 }
156
157 // estimate the number of headers left based on nPowTargetSpacing
158 // and check if the gui is not aware of the best header (happens rarely)
159 int estimateNumHeadersLeft = bestHeaderDate.secsTo(currentDate) /
161 bool hasBestHeader = bestHeaderHeight >= count;
162
163 // show remaining number of blocks
164 if (estimateNumHeadersLeft < HEADER_HEIGHT_DELTA_SYNC && hasBestHeader) {
165 ui->numberOfBlocksLeft->setText(
166 QString::number(bestHeaderHeight - count));
167 } else {
169 ui->expectedTimeLeft->setText(tr("Unknown..."));
170 }
171}
172
174 int est_headers_left = bestHeaderDate.secsTo(QDateTime::currentDateTime()) /
176 ui->numberOfBlocksLeft->setText(
177 tr("Unknown. Syncing Headers (%1, %2%)...")
178 .arg(bestHeaderHeight)
179 .arg(QString::number(100.0 / (bestHeaderHeight + est_headers_left) *
181 'f', 1)));
182}
183
185 const QDateTime &blockDate) {
186 int est_headers_left = blockDate.secsTo(QDateTime::currentDateTime()) /
188 ui->numberOfBlocksLeft->setText(
189 tr("Unknown. Pre-syncing Headers (%1, %2%)…")
190 .arg(height)
191 .arg(QString::number(100.0 / (height + est_headers_left) * height,
192 'f', 1)));
193}
194
197 if (!layerIsVisible) {
198 userClosed = true;
199 }
200}
201
202void ModalOverlay::showHide(bool hide, bool userRequested) {
203 if ((layerIsVisible && !hide) || (!layerIsVisible && hide) ||
204 (!hide && userClosed && !userRequested)) {
205 return;
206 }
207
208 Q_EMIT triggered(hide);
209
210 if (!isVisible() && !hide) {
211 setVisible(true);
212 }
213
214 m_animation.setStartValue(QPoint(0, hide ? 0 : height()));
215 // The eventFilter() updates the endValue if it is required for
216 // QEvent::Resize.
217 m_animation.setEndValue(QPoint(0, hide ? height() : 0));
218 m_animation.start(QAbstractAnimation::KeepWhenStopped);
219 layerIsVisible = !hide;
220}
221
223 showHide(true);
224 userClosed = true;
225}
const CChainParams & Params()
Return the currently selected parameters.
Definition: chainparams.cpp:19
const Consensus::Params & GetConsensus() const
Definition: chainparams.h:92
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 tipUpdate(int count, const QDateTime &blockDate, double nVerificationProgress)
void UpdateHeaderSyncLabel()
ModalOverlay(bool enable_wallet, QWidget *parent)
void toggleVisibility()
QDateTime bestHeaderDate
Definition: modaloverlay.h:51
bool layerIsVisible
Definition: modaloverlay.h:53
void triggered(bool hidden)
Ui::ModalOverlay * ui
Definition: modaloverlay.h:49
void closeClicked()
void setKnownBestHeight(int count, const QDateTime &blockDate, bool presync)
QVector< QPair< qint64, double > > blockProcessTime
Definition: modaloverlay.h:52
int bestHeaderHeight
Definition: modaloverlay.h:50
bool eventFilter(QObject *obj, QEvent *ev) override
void UpdateHeaderPresyncLabel(int height, const QDateTime &blockDate)
QPropertyAnimation m_animation
Definition: modaloverlay.h:55
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:14
QString formatNiceTimeOffset(qint64 secs)
Definition: guiutil.cpp:864
int64_t nPowTargetSpacing
Definition: params.h:80
static int count
Definition: tests.c:31