bitcoin/src/qt/modaloverlay.cpp

191 lines
6.5 KiB
C++
Raw Normal View History

// Copyright (c) 2016-2020 The Bitcoin Core developers
2016-07-19 09:51:24 -04:00
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <qt/modaloverlay.h>
#include <qt/forms/ui_modaloverlay.h>
2016-07-19 09:51:24 -04:00
#include <chainparams.h>
#include <qt/guiutil.h>
2017-01-19 16:51:59 -03:00
#include <QEasingCurve>
2016-07-19 09:51:24 -04:00
#include <QPropertyAnimation>
#include <QResizeEvent>
2016-07-19 09:51:24 -04:00
ModalOverlay::ModalOverlay(bool enable_wallet, QWidget *parent) :
2016-07-19 09:51:24 -04:00
QWidget(parent),
ui(new Ui::ModalOverlay),
bestHeaderHeight(0),
bestHeaderDate(QDateTime()),
2016-07-19 09:51:24 -04:00
layerIsVisible(false),
userClosed(false)
{
ui->setupUi(this);
2018-06-24 11:18:22 -04:00
connect(ui->closeButton, &QPushButton::clicked, this, &ModalOverlay::closeClicked);
2016-07-19 09:51:24 -04:00
if (parent) {
parent->installEventFilter(this);
raise();
}
blockProcessTime.clear();
setVisible(false);
if (!enable_wallet) {
ui->infoText->setVisible(false);
2020-01-14 15:14:10 -03:00
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));
}
m_animation.setTargetObject(this);
m_animation.setPropertyName("pos");
m_animation.setDuration(300 /* ms */);
m_animation.setEasingCurve(QEasingCurve::OutQuad);
2016-07-19 09:51:24 -04:00
}
ModalOverlay::~ModalOverlay()
{
delete ui;
}
bool ModalOverlay::eventFilter(QObject * obj, QEvent * ev) {
if (obj == parent()) {
if (ev->type() == QEvent::Resize) {
QResizeEvent * rev = static_cast<QResizeEvent*>(ev);
resize(rev->size());
if (!layerIsVisible)
setGeometry(0, height(), width(), height());
if (m_animation.endValue().toPoint().y() > 0) {
m_animation.setEndValue(QPoint(0, height()));
}
2016-07-19 09:51:24 -04:00
}
else if (ev->type() == QEvent::ChildAdded) {
raise();
}
}
return QWidget::eventFilter(obj, ev);
}
//! Tracks parent widget changes
bool ModalOverlay::event(QEvent* ev) {
if (ev->type() == QEvent::ParentAboutToChange) {
if (parent()) parent()->removeEventFilter(this);
}
else if (ev->type() == QEvent::ParentChange) {
if (parent()) {
parent()->installEventFilter(this);
raise();
}
}
return QWidget::event(ev);
}
void ModalOverlay::setKnownBestHeight(int count, const QDateTime& blockDate)
2016-07-19 09:51:24 -04:00
{
if (count > bestHeaderHeight) {
bestHeaderHeight = count;
bestHeaderDate = blockDate;
2019-01-03 18:37:18 -03:00
UpdateHeaderSyncLabel();
}
2016-07-19 09:51:24 -04:00
}
void ModalOverlay::tipUpdate(int count, const QDateTime& blockDate, double nVerificationProgress)
{
QDateTime currentDate = QDateTime::currentDateTime();
// keep a vector of samples of verification progress at height
blockProcessTime.push_front(qMakePair(currentDate.toMSecsSinceEpoch(), nVerificationProgress));
2016-07-19 09:51:24 -04:00
2018-03-18 11:26:45 -03:00
// show progress speed if we have more than one sample
2017-09-05 19:50:05 -03:00
if (blockProcessTime.size() >= 2) {
2016-07-19 09:51:24 -04:00
double progressDelta = 0;
double progressPerHour = 0;
qint64 timeDelta = 0;
qint64 remainingMSecs = 0;
double remainingProgress = 1.0 - nVerificationProgress;
2017-09-05 19:50:05 -03:00
for (int i = 1; i < blockProcessTime.size(); i++) {
2016-07-19 09:51:24 -04:00
QPair<qint64, double> sample = blockProcessTime[i];
// take first sample after 500 seconds or last available one
if (sample.first < (currentDate.toMSecsSinceEpoch() - 500 * 1000) || i == blockProcessTime.size() - 1) {
2017-09-05 19:50:05 -03:00
progressDelta = blockProcessTime[0].second - sample.second;
2016-07-19 09:51:24 -04:00
timeDelta = blockProcessTime[0].first - sample.first;
2017-09-05 19:50:05 -03:00
progressPerHour = progressDelta / (double) timeDelta * 1000 * 3600;
2017-09-05 19:49:36 -03:00
remainingMSecs = (progressDelta > 0) ? remainingProgress / progressDelta * timeDelta : -1;
2016-07-19 09:51:24 -04:00
break;
}
}
// show progress increase per hour
2017-09-05 19:50:05 -03:00
ui->progressIncreasePerH->setText(QString::number(progressPerHour * 100, 'f', 2)+"%");
2016-07-19 09:51:24 -04:00
2017-09-05 19:50:05 -03:00
// show expected remaining time
if(remainingMSecs >= 0) {
2017-09-05 19:49:36 -03:00
ui->expectedTimeLeft->setText(GUIUtil::formatNiceTimeOffset(remainingMSecs / 1000.0));
} else {
ui->expectedTimeLeft->setText(QObject::tr("unknown"));
}
2016-07-19 09:51:24 -04:00
static const int MAX_SAMPLES = 5000;
2017-09-05 19:50:05 -03:00
if (blockProcessTime.count() > MAX_SAMPLES) {
blockProcessTime.remove(MAX_SAMPLES, blockProcessTime.count() - MAX_SAMPLES);
}
2016-07-19 09:51:24 -04:00
}
// show the last block date
ui->newestBlockDate->setText(blockDate.toString());
// show the percentage done according to nVerificationProgress
ui->percentageProgress->setText(QString::number(nVerificationProgress*100, 'f', 2)+"%");
ui->progressBar->setValue(nVerificationProgress*100);
if (!bestHeaderDate.isValid())
// not syncing
return;
// estimate the number of headers left based on nPowTargetSpacing
// and check if the gui is not aware of the best header (happens rarely)
2017-01-19 16:51:59 -03:00
int estimateNumHeadersLeft = bestHeaderDate.secsTo(currentDate) / Params().GetConsensus().nPowTargetSpacing;
bool hasBestHeader = bestHeaderHeight >= count;
2016-09-24 14:22:47 -03:00
// show remaining number of blocks
2017-01-19 16:51:59 -03:00
if (estimateNumHeadersLeft < HEADER_HEIGHT_DELTA_SYNC && hasBestHeader) {
ui->numberOfBlocksLeft->setText(QString::number(bestHeaderHeight - count));
} else {
2019-01-03 18:37:18 -03:00
UpdateHeaderSyncLabel();
ui->expectedTimeLeft->setText(tr("Unknown..."));
}
2016-07-19 09:51:24 -04:00
}
2019-01-03 18:37:18 -03:00
void ModalOverlay::UpdateHeaderSyncLabel() {
int est_headers_left = bestHeaderDate.secsTo(QDateTime::currentDateTime()) / Params().GetConsensus().nPowTargetSpacing;
ui->numberOfBlocksLeft->setText(tr("Unknown. Syncing Headers (%1, %2%)...").arg(bestHeaderHeight).arg(QString::number(100.0 / (bestHeaderHeight + est_headers_left) * bestHeaderHeight, 'f', 1)));
}
void ModalOverlay::toggleVisibility()
{
showHide(layerIsVisible, true);
if (!layerIsVisible)
userClosed = true;
}
2016-07-19 09:51:24 -04:00
void ModalOverlay::showHide(bool hide, bool userRequested)
{
if ( (layerIsVisible && !hide) || (!layerIsVisible && hide) || (!hide && userClosed && !userRequested))
return;
Q_EMIT triggered(hide);
2016-07-19 09:51:24 -04:00
if (!isVisible() && !hide)
setVisible(true);
m_animation.setStartValue(QPoint(0, hide ? 0 : height()));
// The eventFilter() updates the endValue if it is required for QEvent::Resize.
m_animation.setEndValue(QPoint(0, hide ? height() : 0));
m_animation.start(QAbstractAnimation::KeepWhenStopped);
2016-07-19 09:51:24 -04:00
layerIsVisible = !hide;
}
void ModalOverlay::closeClicked()
{
showHide(true);
userClosed = true;
2017-09-05 19:50:05 -03:00
}