Bitcoin ABC  0.26.3
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 
15 ModalOverlay::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 
47 bool 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 
67 bool 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 
81 void ModalOverlay::setKnownBestHeight(int count, const QDateTime &blockDate,
82  bool presync) {
83  if (!presync && count > bestHeaderHeight) {
85  bestHeaderDate = blockDate;
87  }
88  if (presync) {
89  UpdateHeaderPresyncLabel(count, blockDate);
90  }
91 }
92 
93 void 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 
196  showHide(layerIsVisible, true);
197  if (!layerIsVisible) {
198  userClosed = true;
199  }
200 }
201 
202 void 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.
const Consensus::Params & GetConsensus() const
Definition: chainparams.h:86
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:862
int64_t nPowTargetSpacing
Definition: params.h:78
static int count
Definition: tests.c:31