aboutsummaryrefslogtreecommitdiff
path: root/src/qt/modaloverlay.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qt/modaloverlay.cpp')
-rw-r--r--src/qt/modaloverlay.cpp172
1 files changed, 172 insertions, 0 deletions
diff --git a/src/qt/modaloverlay.cpp b/src/qt/modaloverlay.cpp
new file mode 100644
index 0000000000..4779ffa43f
--- /dev/null
+++ b/src/qt/modaloverlay.cpp
@@ -0,0 +1,172 @@
+// Copyright (c) 2016 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "modaloverlay.h"
+#include "ui_modaloverlay.h"
+
+#include "guiutil.h"
+
+#include "chainparams.h"
+
+#include <QResizeEvent>
+#include <QPropertyAnimation>
+
+ModalOverlay::ModalOverlay(QWidget *parent) :
+QWidget(parent),
+ui(new Ui::ModalOverlay),
+bestHeaderHeight(0),
+bestHeaderDate(QDateTime()),
+layerIsVisible(false),
+userClosed(false)
+{
+ ui->setupUi(this);
+ connect(ui->closeButton, SIGNAL(clicked()), this, SLOT(closeClicked()));
+ if (parent) {
+ parent->installEventFilter(this);
+ raise();
+ }
+
+ blockProcessTime.clear();
+ setVisible(false);
+}
+
+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());
+
+ }
+ 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)
+{
+ if (count > bestHeaderHeight) {
+ bestHeaderHeight = count;
+ bestHeaderDate = blockDate;
+ }
+}
+
+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));
+
+ // show progress speed if we have more then one sample
+ if (blockProcessTime.size() >= 2)
+ {
+ double progressStart = blockProcessTime[0].second;
+ double progressDelta = 0;
+ double progressPerHour = 0;
+ qint64 timeDelta = 0;
+ qint64 remainingMSecs = 0;
+ double remainingProgress = 1.0 - nVerificationProgress;
+ for (int i = 1; i < blockProcessTime.size(); i++)
+ {
+ 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) {
+ progressDelta = progressStart-sample.second;
+ timeDelta = blockProcessTime[0].first - sample.first;
+ progressPerHour = progressDelta/(double)timeDelta*1000*3600;
+ remainingMSecs = remainingProgress / progressDelta * timeDelta;
+ break;
+ }
+ }
+ // show progress increase per hour
+ ui->progressIncreasePerH->setText(QString::number(progressPerHour*100, 'f', 2)+"%");
+
+ // show expected remaining time
+ ui->expectedTimeLeft->setText(GUIUtil::formatNiceTimeOffset(remainingMSecs/1000.0));
+
+ static const int MAX_SAMPLES = 5000;
+ if (blockProcessTime.count() > MAX_SAMPLES)
+ blockProcessTime.remove(MAX_SAMPLES, blockProcessTime.count()-MAX_SAMPLES);
+ }
+
+ // 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 the best header (happens rarely)
+ int estimateNumHeadersLeft = bestHeaderDate.secsTo(currentDate) / Params().GetConsensus().nPowTargetSpacing;
+ bool hasBestHeader = bestHeaderHeight >= count;
+
+ // show remaining number of blocks
+ if (estimateNumHeadersLeft < HEADER_HEIGHT_DELTA_SYNC && hasBestHeader) {
+ ui->numberOfBlocksLeft->setText(QString::number(bestHeaderHeight - count));
+ } else {
+ ui->numberOfBlocksLeft->setText(tr("Unknown. Syncing Headers (%1)...").arg(bestHeaderHeight));
+ ui->expectedTimeLeft->setText(tr("Unknown..."));
+ }
+}
+
+void ModalOverlay::toggleVisibility()
+{
+ showHide(layerIsVisible, true);
+ if (!layerIsVisible)
+ userClosed = true;
+}
+
+void ModalOverlay::showHide(bool hide, bool userRequested)
+{
+ if ( (layerIsVisible && !hide) || (!layerIsVisible && hide) || (!hide && userClosed && !userRequested))
+ return;
+
+ if (!isVisible() && !hide)
+ setVisible(true);
+
+ setGeometry(0, hide ? 0 : height(), width(), height());
+
+ QPropertyAnimation* animation = new QPropertyAnimation(this, "pos");
+ animation->setDuration(300);
+ animation->setStartValue(QPoint(0, hide ? 0 : this->height()));
+ animation->setEndValue(QPoint(0, hide ? this->height() : 0));
+ animation->setEasingCurve(QEasingCurve::OutQuad);
+ animation->start(QAbstractAnimation::DeleteWhenStopped);
+ layerIsVisible = !hide;
+}
+
+void ModalOverlay::closeClicked()
+{
+ showHide(true);
+ userClosed = true;
+}