Bitcoin Core  27.99.0
P2P Digital Currency
modaloverlay.cpp
Go to the documentation of this file.
1 // Copyright (c) 2016-2022 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 #if defined(HAVE_CONFIG_H)
7 #endif
8 
9 #include <qt/modaloverlay.h>
10 #include <qt/forms/ui_modaloverlay.h>
11 
12 #include <chainparams.h>
13 #include <qt/guiutil.h>
14 
15 #include <QEasingCurve>
16 #include <QPropertyAnimation>
17 #include <QResizeEvent>
18 
19 ModalOverlay::ModalOverlay(bool enable_wallet, QWidget* parent)
20  : QWidget(parent),
21  ui(new Ui::ModalOverlay),
22  bestHeaderDate(QDateTime())
23 {
24  ui->setupUi(this);
25  connect(ui->closeButton, &QPushButton::clicked, this, &ModalOverlay::closeClicked);
26  if (parent) {
27  parent->installEventFilter(this);
28  raise();
29  }
30 
31  blockProcessTime.clear();
32  setVisible(false);
33  if (!enable_wallet) {
34  ui->infoText->setVisible(false);
35  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));
36  }
37 
38  m_animation.setTargetObject(this);
39  m_animation.setPropertyName("pos");
40  m_animation.setDuration(300 /* ms */);
41  m_animation.setEasingCurve(QEasingCurve::OutQuad);
42 }
43 
45 {
46  delete ui;
47 }
48 
49 bool ModalOverlay::eventFilter(QObject * obj, QEvent * ev) {
50  if (obj == parent()) {
51  if (ev->type() == QEvent::Resize) {
52  QResizeEvent * rev = static_cast<QResizeEvent*>(ev);
53  resize(rev->size());
54  if (!layerIsVisible)
55  setGeometry(0, height(), width(), height());
56 
57  if (m_animation.endValue().toPoint().y() > 0) {
58  m_animation.setEndValue(QPoint(0, height()));
59  }
60  }
61  else if (ev->type() == QEvent::ChildAdded) {
62  raise();
63  }
64  }
65  return QWidget::eventFilter(obj, ev);
66 }
67 
69 bool ModalOverlay::event(QEvent* ev) {
70  if (ev->type() == QEvent::ParentAboutToChange) {
71  if (parent()) parent()->removeEventFilter(this);
72  }
73  else if (ev->type() == QEvent::ParentChange) {
74  if (parent()) {
75  parent()->installEventFilter(this);
76  raise();
77  }
78  }
79  return QWidget::event(ev);
80 }
81 
82 void ModalOverlay::setKnownBestHeight(int count, const QDateTime& blockDate, bool presync)
83 {
84  if (!presync && count > bestHeaderHeight) {
86  bestHeaderDate = blockDate;
88  }
89  if (presync) {
90  UpdateHeaderPresyncLabel(count, blockDate);
91  }
92 }
93 
94 void ModalOverlay::tipUpdate(int count, const QDateTime& blockDate, double nVerificationProgress)
95 {
96  QDateTime currentDate = QDateTime::currentDateTime();
97 
98  // keep a vector of samples of verification progress at height
99  blockProcessTime.push_front(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) || i == blockProcessTime.size() - 1) {
113  progressDelta = blockProcessTime[0].second - sample.second;
114  timeDelta = blockProcessTime[0].first - sample.first;
115  progressPerHour = (progressDelta > 0) ? progressDelta / (double)timeDelta * 1000 * 3600 : 0;
116  remainingMSecs = (progressDelta > 0) ? remainingProgress / progressDelta * timeDelta : -1;
117  break;
118  }
119  }
120  // show progress increase per hour
121  ui->progressIncreasePerH->setText(QString::number(progressPerHour * 100, 'f', 2)+"%");
122 
123  // show expected remaining time
124  if(remainingMSecs >= 0) {
125  ui->expectedTimeLeft->setText(GUIUtil::formatNiceTimeOffset(remainingMSecs / 1000.0));
126  } else {
127  ui->expectedTimeLeft->setText(QObject::tr("unknown"));
128  }
129 
130  static const int MAX_SAMPLES = 5000;
131  if (blockProcessTime.count() > MAX_SAMPLES) {
132  blockProcessTime.remove(MAX_SAMPLES, blockProcessTime.count() - MAX_SAMPLES);
133  }
134  }
135 
136  // show the last block date
137  ui->newestBlockDate->setText(blockDate.toString());
138 
139  // show the percentage done according to nVerificationProgress
140  ui->percentageProgress->setText(QString::number(nVerificationProgress*100, 'f', 2)+"%");
141 
142  if (!bestHeaderDate.isValid())
143  // not syncing
144  return;
145 
146  // estimate the number of headers left based on nPowTargetSpacing
147  // and check if the gui is not aware of the best header (happens rarely)
148  int estimateNumHeadersLeft = bestHeaderDate.secsTo(currentDate) / Params().GetConsensus().nPowTargetSpacing;
149  bool hasBestHeader = bestHeaderHeight >= count;
150 
151  // show remaining number of blocks
152  if (estimateNumHeadersLeft < HEADER_HEIGHT_DELTA_SYNC && hasBestHeader) {
153  ui->numberOfBlocksLeft->setText(QString::number(bestHeaderHeight - count));
154  } else {
156  ui->expectedTimeLeft->setText(tr("Unknown…"));
157  }
158 }
159 
161  int est_headers_left = bestHeaderDate.secsTo(QDateTime::currentDateTime()) / Params().GetConsensus().nPowTargetSpacing;
162  ui->numberOfBlocksLeft->setText(tr("Unknown. Syncing Headers (%1, %2%)…").arg(bestHeaderHeight).arg(QString::number(100.0 / (bestHeaderHeight + est_headers_left) * bestHeaderHeight, 'f', 1)));
163 }
164 
165 void ModalOverlay::UpdateHeaderPresyncLabel(int height, const QDateTime& blockDate) {
166  int est_headers_left = blockDate.secsTo(QDateTime::currentDateTime()) / Params().GetConsensus().nPowTargetSpacing;
167  ui->numberOfBlocksLeft->setText(tr("Unknown. Pre-syncing Headers (%1, %2%)…").arg(height).arg(QString::number(100.0 / (height + est_headers_left) * height, 'f', 1)));
168 }
169 
171 {
172  showHide(layerIsVisible, true);
173  if (!layerIsVisible)
174  userClosed = true;
175 }
176 
177 void ModalOverlay::showHide(bool hide, bool userRequested)
178 {
179  if ( (layerIsVisible && !hide) || (!layerIsVisible && hide) || (!hide && userClosed && !userRequested))
180  return;
181 
182  Q_EMIT triggered(hide);
183 
184  if (!isVisible() && !hide)
185  setVisible(true);
186 
187  m_animation.setStartValue(QPoint(0, hide ? 0 : height()));
188  // The eventFilter() updates the endValue if it is required for QEvent::Resize.
189  m_animation.setEndValue(QPoint(0, hide ? height() : 0));
190  m_animation.start(QAbstractAnimation::KeepWhenStopped);
191  layerIsVisible = !hide;
192 }
193 
195 {
196  showHide(true);
197  userClosed = true;
198 }
#define PACKAGE_NAME
const CChainParams & Params()
Return the currently selected parameters.
const Consensus::Params & GetConsensus() const
Definition: chainparams.h:93
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:49
bool layerIsVisible
Definition: modaloverlay.h:51
void triggered(bool hidden)
Ui::ModalOverlay * ui
Definition: modaloverlay.h:47
void closeClicked()
void setKnownBestHeight(int count, const QDateTime &blockDate, bool presync)
QVector< QPair< qint64, double > > blockProcessTime
Definition: modaloverlay.h:50
int bestHeaderHeight
Definition: modaloverlay.h:48
bool eventFilter(QObject *obj, QEvent *ev) override
void UpdateHeaderPresyncLabel(int height, const QDateTime &blockDate)
QPropertyAnimation m_animation
Definition: modaloverlay.h:53
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:783
int64_t nPowTargetSpacing
Definition: params.h:112
static int count