Bitcoin Core  0.19.99
P2P Digital Currency
modaloverlay.cpp
Go to the documentation of this file.
1 // Copyright (c) 2016-2019 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>
6 #include <qt/forms/ui_modaloverlay.h>
7 
8 #include <qt/guiutil.h>
9 
10 #include <chainparams.h>
11 
12 #include <QResizeEvent>
13 #include <QPropertyAnimation>
14 
15 ModalOverlay::ModalOverlay(bool enable_wallet, QWidget *parent) :
16 QWidget(parent),
17 ui(new Ui::ModalOverlay),
18 bestHeaderHeight(0),
19 bestHeaderDate(QDateTime()),
20 layerIsVisible(false),
21 userClosed(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 
39 {
40  delete ui;
41 }
42 
43 bool ModalOverlay::eventFilter(QObject * obj, QEvent * ev) {
44  if (obj == parent()) {
45  if (ev->type() == QEvent::Resize) {
46  QResizeEvent * rev = static_cast<QResizeEvent*>(ev);
47  resize(rev->size());
48  if (!layerIsVisible)
49  setGeometry(0, height(), width(), height());
50 
51  }
52  else if (ev->type() == QEvent::ChildAdded) {
53  raise();
54  }
55  }
56  return QWidget::eventFilter(obj, ev);
57 }
58 
60 bool ModalOverlay::event(QEvent* ev) {
61  if (ev->type() == QEvent::ParentAboutToChange) {
62  if (parent()) parent()->removeEventFilter(this);
63  }
64  else if (ev->type() == QEvent::ParentChange) {
65  if (parent()) {
66  parent()->installEventFilter(this);
67  raise();
68  }
69  }
70  return QWidget::event(ev);
71 }
72 
73 void ModalOverlay::setKnownBestHeight(int count, const QDateTime& blockDate)
74 {
75  if (count > bestHeaderHeight) {
77  bestHeaderDate = blockDate;
79  }
80 }
81 
82 void ModalOverlay::tipUpdate(int count, const QDateTime& blockDate, double nVerificationProgress)
83 {
84  QDateTime currentDate = QDateTime::currentDateTime();
85 
86  // keep a vector of samples of verification progress at height
87  blockProcessTime.push_front(qMakePair(currentDate.toMSecsSinceEpoch(), nVerificationProgress));
88 
89  // show progress speed if we have more than one sample
90  if (blockProcessTime.size() >= 2) {
91  double progressDelta = 0;
92  double progressPerHour = 0;
93  qint64 timeDelta = 0;
94  qint64 remainingMSecs = 0;
95  double remainingProgress = 1.0 - nVerificationProgress;
96  for (int i = 1; i < blockProcessTime.size(); i++) {
97  QPair<qint64, double> sample = blockProcessTime[i];
98 
99  // take first sample after 500 seconds or last available one
100  if (sample.first < (currentDate.toMSecsSinceEpoch() - 500 * 1000) || i == blockProcessTime.size() - 1) {
101  progressDelta = blockProcessTime[0].second - sample.second;
102  timeDelta = blockProcessTime[0].first - sample.first;
103  progressPerHour = progressDelta / (double) timeDelta * 1000 * 3600;
104  remainingMSecs = (progressDelta > 0) ? remainingProgress / progressDelta * timeDelta : -1;
105  break;
106  }
107  }
108  // show progress increase per hour
109  ui->progressIncreasePerH->setText(QString::number(progressPerHour * 100, 'f', 2)+"%");
110 
111  // show expected remaining time
112  if(remainingMSecs >= 0) {
113  ui->expectedTimeLeft->setText(GUIUtil::formatNiceTimeOffset(remainingMSecs / 1000.0));
114  } else {
115  ui->expectedTimeLeft->setText(QObject::tr("unknown"));
116  }
117 
118  static const int MAX_SAMPLES = 5000;
119  if (blockProcessTime.count() > MAX_SAMPLES) {
120  blockProcessTime.remove(MAX_SAMPLES, blockProcessTime.count() - MAX_SAMPLES);
121  }
122  }
123 
124  // show the last block date
125  ui->newestBlockDate->setText(blockDate.toString());
126 
127  // show the percentage done according to nVerificationProgress
128  ui->percentageProgress->setText(QString::number(nVerificationProgress*100, 'f', 2)+"%");
129  ui->progressBar->setValue(nVerificationProgress*100);
130 
131  if (!bestHeaderDate.isValid())
132  // not syncing
133  return;
134 
135  // estimate the number of headers left based on nPowTargetSpacing
136  // and check if the gui is not aware of the best header (happens rarely)
137  int estimateNumHeadersLeft = bestHeaderDate.secsTo(currentDate) / Params().GetConsensus().nPowTargetSpacing;
138  bool hasBestHeader = bestHeaderHeight >= count;
139 
140  // show remaining number of blocks
141  if (estimateNumHeadersLeft < HEADER_HEIGHT_DELTA_SYNC && hasBestHeader) {
142  ui->numberOfBlocksLeft->setText(QString::number(bestHeaderHeight - count));
143  } else {
145  ui->expectedTimeLeft->setText(tr("Unknown..."));
146  }
147 }
148 
150  int est_headers_left = bestHeaderDate.secsTo(QDateTime::currentDateTime()) / Params().GetConsensus().nPowTargetSpacing;
151  ui->numberOfBlocksLeft->setText(tr("Unknown. Syncing Headers (%1, %2%)...").arg(bestHeaderHeight).arg(QString::number(100.0 / (bestHeaderHeight + est_headers_left) * bestHeaderHeight, 'f', 1)));
152 }
153 
155 {
156  showHide(layerIsVisible, true);
157  if (!layerIsVisible)
158  userClosed = true;
159 }
160 
161 void ModalOverlay::showHide(bool hide, bool userRequested)
162 {
163  if ( (layerIsVisible && !hide) || (!layerIsVisible && hide) || (!hide && userClosed && !userRequested))
164  return;
165 
166  if (!isVisible() && !hide)
167  setVisible(true);
168 
169  setGeometry(0, hide ? 0 : height(), width(), height());
170 
171  QPropertyAnimation* animation = new QPropertyAnimation(this, "pos");
172  animation->setDuration(300);
173  animation->setStartValue(QPoint(0, hide ? 0 : this->height()));
174  animation->setEndValue(QPoint(0, hide ? this->height() : 0));
175  animation->setEasingCurve(QEasingCurve::OutQuad);
176  animation->start(QAbstractAnimation::DeleteWhenStopped);
177  layerIsVisible = !hide;
178 }
179 
181 {
182  showHide(true);
183  userClosed = true;
184 }
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:12
bool event(QEvent *ev)
Tracks parent widget changes.
bool eventFilter(QObject *obj, QEvent *ev)
void tipUpdate(int count, const QDateTime &blockDate, double nVerificationProgress)
#define PACKAGE_NAME
void UpdateHeaderSyncLabel()
Modal overlay to display information about the chain-sync state.
Definition: modaloverlay.h:19
Ui::ModalOverlay * ui
Definition: modaloverlay.h:42
void setKnownBestHeight(int count, const QDateTime &blockDate)
int64_t nPowTargetSpacing
Definition: params.h:78
void toggleVisibility()
ModalOverlay(bool enable_wallet, QWidget *parent)
QDateTime bestHeaderDate
Definition: modaloverlay.h:44
bool layerIsVisible
Definition: modaloverlay.h:46
int bestHeaderHeight
Definition: modaloverlay.h:43
void showHide(bool hide=false, bool userRequested=false)
const CChainParams & Params()
Return the currently selected parameters.
static int count
Definition: tests.c:45
QVector< QPair< qint64, double > > blockProcessTime
Definition: modaloverlay.h:45
QString formatNiceTimeOffset(qint64 secs)
Definition: guiutil.cpp:786
const Consensus::Params & GetConsensus() const
Definition: chainparams.h:60
void closeClicked()