1 // Copyright (c) 2016-2017 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.
5 #include <qt/modaloverlay.h>
6 #include <qt/forms/ui_modaloverlay.h>
8 #include <qt/guiutil.h>
10 #include <chainparams.h>
12 #include <QResizeEvent>
13 #include <QPropertyAnimation>
15 ModalOverlay::ModalOverlay(QWidget
*parent
) :
17 ui(new Ui::ModalOverlay
),
19 bestHeaderDate(QDateTime()),
20 layerIsVisible(false),
24 connect(ui
->closeButton
, SIGNAL(clicked()), this, SLOT(closeClicked()));
26 parent
->installEventFilter(this);
30 blockProcessTime
.clear();
34 ModalOverlay::~ModalOverlay()
39 bool ModalOverlay::eventFilter(QObject
* obj
, QEvent
* ev
) {
40 if (obj
== parent()) {
41 if (ev
->type() == QEvent::Resize
) {
42 QResizeEvent
* rev
= static_cast<QResizeEvent
*>(ev
);
45 setGeometry(0, height(), width(), height());
48 else if (ev
->type() == QEvent::ChildAdded
) {
52 return QWidget::eventFilter(obj
, ev
);
55 //! Tracks parent widget changes
56 bool ModalOverlay::event(QEvent
* ev
) {
57 if (ev
->type() == QEvent::ParentAboutToChange
) {
58 if (parent()) parent()->removeEventFilter(this);
60 else if (ev
->type() == QEvent::ParentChange
) {
62 parent()->installEventFilter(this);
66 return QWidget::event(ev
);
69 void ModalOverlay::setKnownBestHeight(int count
, const QDateTime
& blockDate
)
71 if (count
> bestHeaderHeight
) {
72 bestHeaderHeight
= count
;
73 bestHeaderDate
= blockDate
;
77 void ModalOverlay::tipUpdate(int count
, const QDateTime
& blockDate
, double nVerificationProgress
)
79 QDateTime currentDate
= QDateTime::currentDateTime();
81 // keep a vector of samples of verification progress at height
82 blockProcessTime
.push_front(qMakePair(currentDate
.toMSecsSinceEpoch(), nVerificationProgress
));
84 // show progress speed if we have more then one sample
85 if (blockProcessTime
.size() >= 2) {
86 double progressDelta
= 0;
87 double progressPerHour
= 0;
89 qint64 remainingMSecs
= 0;
90 double remainingProgress
= 1.0 - nVerificationProgress
;
91 for (int i
= 1; i
< blockProcessTime
.size(); i
++) {
92 QPair
<qint64
, double> sample
= blockProcessTime
[i
];
94 // take first sample after 500 seconds or last available one
95 if (sample
.first
< (currentDate
.toMSecsSinceEpoch() - 500 * 1000) || i
== blockProcessTime
.size() - 1) {
96 progressDelta
= blockProcessTime
[0].second
- sample
.second
;
97 timeDelta
= blockProcessTime
[0].first
- sample
.first
;
98 progressPerHour
= progressDelta
/ (double) timeDelta
* 1000 * 3600;
99 remainingMSecs
= (progressDelta
> 0) ? remainingProgress
/ progressDelta
* timeDelta
: -1;
103 // show progress increase per hour
104 ui
->progressIncreasePerH
->setText(QString::number(progressPerHour
* 100, 'f', 2)+"%");
106 // show expected remaining time
107 if(remainingMSecs
>= 0) {
108 ui
->expectedTimeLeft
->setText(GUIUtil::formatNiceTimeOffset(remainingMSecs
/ 1000.0));
110 ui
->expectedTimeLeft
->setText(QObject::tr("unknown"));
113 static const int MAX_SAMPLES
= 5000;
114 if (blockProcessTime
.count() > MAX_SAMPLES
) {
115 blockProcessTime
.remove(MAX_SAMPLES
, blockProcessTime
.count() - MAX_SAMPLES
);
119 // show the last block date
120 ui
->newestBlockDate
->setText(blockDate
.toString());
122 // show the percentage done according to nVerificationProgress
123 ui
->percentageProgress
->setText(QString::number(nVerificationProgress
*100, 'f', 2)+"%");
124 ui
->progressBar
->setValue(nVerificationProgress
*100);
126 if (!bestHeaderDate
.isValid())
130 // estimate the number of headers left based on nPowTargetSpacing
131 // and check if the gui is not aware of the best header (happens rarely)
132 int estimateNumHeadersLeft
= bestHeaderDate
.secsTo(currentDate
) / Params().GetConsensus().nPowTargetSpacing
;
133 bool hasBestHeader
= bestHeaderHeight
>= count
;
135 // show remaining number of blocks
136 if (estimateNumHeadersLeft
< HEADER_HEIGHT_DELTA_SYNC
&& hasBestHeader
) {
137 ui
->numberOfBlocksLeft
->setText(QString::number(bestHeaderHeight
- count
));
139 ui
->numberOfBlocksLeft
->setText(tr("Unknown. Syncing Headers (%1)...").arg(bestHeaderHeight
));
140 ui
->expectedTimeLeft
->setText(tr("Unknown..."));
144 void ModalOverlay::toggleVisibility()
146 showHide(layerIsVisible
, true);
151 void ModalOverlay::showHide(bool hide
, bool userRequested
)
153 if ( (layerIsVisible
&& !hide
) || (!layerIsVisible
&& hide
) || (!hide
&& userClosed
&& !userRequested
))
156 if (!isVisible() && !hide
)
159 setGeometry(0, hide
? 0 : height(), width(), height());
161 QPropertyAnimation
* animation
= new QPropertyAnimation(this, "pos");
162 animation
->setDuration(300);
163 animation
->setStartValue(QPoint(0, hide
? 0 : this->height()));
164 animation
->setEndValue(QPoint(0, hide
? this->height() : 0));
165 animation
->setEasingCurve(QEasingCurve::OutQuad
);
166 animation
->start(QAbstractAnimation::DeleteWhenStopped
);
167 layerIsVisible
= !hide
;
170 void ModalOverlay::closeClicked()