Changeset View
Changeset View
Standalone View
Standalone View
src/qt/intro.cpp
// Copyright (c) 2011-2016 The Bitcoin Core developers | // Copyright (c) 2011-2016 The Bitcoin Core developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#if defined(HAVE_CONFIG_H) | #if defined(HAVE_CONFIG_H) | ||||
#include <config/bitcoin-config.h> | #include <config/bitcoin-config.h> | ||||
#endif | #endif | ||||
#include <config.h> | #include <config.h> | ||||
#include <fs.h> | #include <fs.h> | ||||
#include <interfaces/node.h> | #include <interfaces/node.h> | ||||
#include <qt/forms/ui_intro.h> | #include <qt/forms/ui_intro.h> | ||||
#include <qt/guiconstants.h> | #include <qt/guiconstants.h> | ||||
#include <qt/guiutil.h> | #include <qt/guiutil.h> | ||||
#include <qt/intro.h> | #include <qt/intro.h> | ||||
#include <qt/optionsmodel.h> | |||||
#include <util/system.h> | #include <util/system.h> | ||||
#include <QFileDialog> | #include <QFileDialog> | ||||
#include <QMessageBox> | #include <QMessageBox> | ||||
#include <QSettings> | #include <QSettings> | ||||
#include <cmath> | #include <cmath> | ||||
/** | |||||
* Total required space (in GB) depending on user choice (prune, not prune). | |||||
*/ | |||||
static uint64_t requiredSpace; | |||||
/* Check free space asynchronously to prevent hanging the UI thread. | /* Check free space asynchronously to prevent hanging the UI thread. | ||||
Up to one request to check a path is in flight to this thread; when the | Up to one request to check a path is in flight to this thread; when the | ||||
check() | check() | ||||
function runs, the current path is requested from the associated Intro | function runs, the current path is requested from the associated Intro | ||||
object. | object. | ||||
The reply is sent back through a signal. | The reply is sent back through a signal. | ||||
▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | void FreespaceChecker::check() { | ||||
} catch (const fs::filesystem_error &) { | } catch (const fs::filesystem_error &) { | ||||
/* Parent directory does not exist or is not accessible */ | /* Parent directory does not exist or is not accessible */ | ||||
replyStatus = ST_ERROR; | replyStatus = ST_ERROR; | ||||
replyMessage = tr("Cannot create data directory here."); | replyMessage = tr("Cannot create data directory here."); | ||||
} | } | ||||
Q_EMIT reply(replyStatus, replyMessage, freeBytesAvailable); | Q_EMIT reply(replyStatus, replyMessage, freeBytesAvailable); | ||||
} | } | ||||
Intro::Intro(QWidget *parent, uint64_t blockchain_size, | namespace { | ||||
uint64_t chain_state_size) | //! Return pruning size that will be used if automatic pruning is enabled. | ||||
int GetPruneTargetGB() { | |||||
int64_t prune_target_mib = gArgs.GetArg("-prune", 0); | |||||
// >1 means automatic pruning is enabled by config, 1 means manual pruning, | |||||
// 0 means no pruning. | |||||
return prune_target_mib > 1 ? PruneMiBtoGB(prune_target_mib) | |||||
: DEFAULT_PRUNE_TARGET_GB; | |||||
} | |||||
} // namespace | |||||
Intro::Intro(QWidget *parent, int64_t blockchain_size_gb, | |||||
int64_t chain_state_size_gb) | |||||
: QDialog(parent), ui(new Ui::Intro), thread(nullptr), signalled(false), | : QDialog(parent), ui(new Ui::Intro), thread(nullptr), signalled(false), | ||||
m_blockchain_size(blockchain_size), m_chain_state_size(chain_state_size) { | m_blockchain_size_gb(blockchain_size_gb), | ||||
m_chain_state_size_gb(chain_state_size_gb), | |||||
m_prune_target_gb(GetPruneTargetGB()) { | |||||
ui->setupUi(this); | ui->setupUi(this); | ||||
ui->welcomeLabel->setText(ui->welcomeLabel->text().arg(PACKAGE_NAME)); | ui->welcomeLabel->setText(ui->welcomeLabel->text().arg(PACKAGE_NAME)); | ||||
ui->storageLabel->setText(ui->storageLabel->text().arg(PACKAGE_NAME)); | ui->storageLabel->setText(ui->storageLabel->text().arg(PACKAGE_NAME)); | ||||
ui->lblExplanation1->setText(ui->lblExplanation1->text() | ui->lblExplanation1->setText(ui->lblExplanation1->text() | ||||
.arg(PACKAGE_NAME) | .arg(PACKAGE_NAME) | ||||
.arg(m_blockchain_size) | .arg(m_blockchain_size_gb) | ||||
.arg(2009) | .arg(2009) | ||||
.arg(tr("Bitcoin"))); | .arg(tr("Bitcoin"))); | ||||
ui->lblExplanation2->setText(ui->lblExplanation2->text().arg(PACKAGE_NAME)); | ui->lblExplanation2->setText(ui->lblExplanation2->text().arg(PACKAGE_NAME)); | ||||
uint64_t pruneTarget = std::max<int64_t>(0, gArgs.GetArg("-prune", 0)); | // -prune=1 means enabled, above that it's a size in MiB | ||||
// -prune=1 means enabled, above that it's a size in MB | if (gArgs.GetArg("-prune", 0) > 1) { | ||||
if (pruneTarget > 1) { | |||||
ui->prune->setChecked(true); | ui->prune->setChecked(true); | ||||
ui->prune->setEnabled(false); | ui->prune->setEnabled(false); | ||||
} | } | ||||
ui->prune->setText( | ui->prune->setText(tr("Discard blocks after verification, except most " | ||||
tr("Discard blocks after verification, except most " | |||||
"recent %1 GB (prune)") | "recent %1 GB (prune)") | ||||
.arg(pruneTarget ? pruneTarget / 1000 : DEFAULT_PRUNE_TARGET_GB)); | .arg(m_prune_target_gb)); | ||||
requiredSpace = m_blockchain_size; | UpdatePruneLabels(ui->prune->isChecked()); | ||||
QString storageRequiresMsg = | |||||
tr("At least %1 GB of data will be stored in this directory, and it " | connect(ui->prune, &QCheckBox::toggled, [this](bool prune_checked) { | ||||
"will grow over time."); | UpdatePruneLabels(prune_checked); | ||||
if (pruneTarget) { | UpdateFreeSpaceLabel(); | ||||
uint64_t prunedGBs = std::ceil(pruneTarget * 1024 * 1024.0 / GB_BYTES); | }); | ||||
if (prunedGBs <= requiredSpace) { | |||||
requiredSpace = prunedGBs; | |||||
storageRequiresMsg = tr("Approximately %1 GB of data will be " | |||||
"stored in this directory."); | |||||
} | |||||
ui->lblExplanation3->setVisible(true); | |||||
} else { | |||||
ui->lblExplanation3->setVisible(false); | |||||
} | |||||
requiredSpace += m_chain_state_size; | |||||
ui->sizeWarningLabel->setText( | |||||
tr("%1 will download and store a copy of the Bitcoin block chain.") | |||||
.arg(PACKAGE_NAME) + | |||||
" " + storageRequiresMsg.arg(requiredSpace) + " " + | |||||
tr("The wallet will also be stored in this directory.")); | |||||
this->adjustSize(); | |||||
startThread(); | startThread(); | ||||
} | } | ||||
Intro::~Intro() { | Intro::~Intro() { | ||||
delete ui; | delete ui; | ||||
/* Ensure thread is finished before it is deleted */ | /* Ensure thread is finished before it is deleted */ | ||||
thread->quit(); | thread->quit(); | ||||
thread->wait(); | thread->wait(); | ||||
▲ Show 20 Lines • Show All 113 Lines • ▼ Show 20 Lines | switch (status) { | ||||
ui->errorMessage->setText(tr("Error") + ": " + message); | ui->errorMessage->setText(tr("Error") + ": " + message); | ||||
ui->errorMessage->setStyleSheet("QLabel { color: #800000 }"); | ui->errorMessage->setStyleSheet("QLabel { color: #800000 }"); | ||||
break; | break; | ||||
} | } | ||||
/* Indicate number of bytes available */ | /* Indicate number of bytes available */ | ||||
if (status == FreespaceChecker::ST_ERROR) { | if (status == FreespaceChecker::ST_ERROR) { | ||||
ui->freeSpace->setText(""); | ui->freeSpace->setText(""); | ||||
} else { | } else { | ||||
m_bytes_available = bytesAvailable; | |||||
if (ui->prune->isEnabled()) { | |||||
ui->prune->setChecked( | |||||
m_bytes_available < | |||||
(m_blockchain_size_gb + m_chain_state_size_gb + 10) * GB_BYTES); | |||||
} | |||||
UpdateFreeSpaceLabel(); | |||||
} | |||||
/* Don't allow confirm in ERROR state */ | |||||
ui->buttonBox->button(QDialogButtonBox::Ok) | |||||
->setEnabled(status != FreespaceChecker::ST_ERROR); | |||||
} | |||||
void Intro::UpdateFreeSpaceLabel() { | |||||
QString freeString = | QString freeString = | ||||
tr("%n GB of free space available", "", bytesAvailable / GB_BYTES); | tr("%n GB of free space available", "", m_bytes_available / GB_BYTES); | ||||
if (bytesAvailable < requiredSpace * GB_BYTES) { | if (m_bytes_available < m_required_space_gb * GB_BYTES) { | ||||
freeString += " " + tr("(of %n GB needed)", "", requiredSpace); | freeString += " " + tr("(of %n GB needed)", "", m_required_space_gb); | ||||
ui->freeSpace->setStyleSheet("QLabel { color: #800000 }"); | ui->freeSpace->setStyleSheet("QLabel { color: #800000 }"); | ||||
} else if (bytesAvailable / GB_BYTES - requiredSpace < 10) { | } else if (m_bytes_available / GB_BYTES - m_required_space_gb < 10) { | ||||
freeString += | freeString += | ||||
" " + tr("(%n GB needed for full chain)", "", requiredSpace); | " " + tr("(%n GB needed for full chain)", "", m_required_space_gb); | ||||
ui->freeSpace->setStyleSheet("QLabel { color: #999900 }"); | ui->freeSpace->setStyleSheet("QLabel { color: #999900 }"); | ||||
} else { | } else { | ||||
ui->freeSpace->setStyleSheet(""); | ui->freeSpace->setStyleSheet(""); | ||||
} | } | ||||
ui->freeSpace->setText(freeString + "."); | ui->freeSpace->setText(freeString + "."); | ||||
} | } | ||||
/* Don't allow confirm in ERROR state */ | |||||
ui->buttonBox->button(QDialogButtonBox::Ok) | |||||
->setEnabled(status != FreespaceChecker::ST_ERROR); | |||||
} | |||||
void Intro::on_dataDirectory_textChanged(const QString &dataDirStr) { | void Intro::on_dataDirectory_textChanged(const QString &dataDirStr) { | ||||
/* Disable OK button until check result comes in */ | /* Disable OK button until check result comes in */ | ||||
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); | ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); | ||||
checkPath(dataDirStr); | checkPath(dataDirStr); | ||||
} | } | ||||
void Intro::on_ellipsisButton_clicked() { | void Intro::on_ellipsisButton_clicked() { | ||||
Show All 39 Lines | |||||
QString Intro::getPathToCheck() { | QString Intro::getPathToCheck() { | ||||
QString retval; | QString retval; | ||||
mutex.lock(); | mutex.lock(); | ||||
retval = pathToCheck; | retval = pathToCheck; | ||||
signalled = false; /* new request can be queued now */ | signalled = false; /* new request can be queued now */ | ||||
mutex.unlock(); | mutex.unlock(); | ||||
return retval; | return retval; | ||||
} | } | ||||
void Intro::UpdatePruneLabels(bool prune_checked) { | |||||
m_required_space_gb = m_blockchain_size_gb + m_chain_state_size_gb; | |||||
QString storageRequiresMsg = | |||||
tr("At least %1 GB of data will be stored in this directory, and it " | |||||
"will grow over time."); | |||||
if (prune_checked && m_prune_target_gb <= m_blockchain_size_gb) { | |||||
m_required_space_gb = m_prune_target_gb + m_chain_state_size_gb; | |||||
storageRequiresMsg = | |||||
tr("Approximately %1 GB of data will be stored in this directory."); | |||||
} | |||||
ui->lblExplanation3->setVisible(prune_checked); | |||||
ui->sizeWarningLabel->setText( | |||||
tr("%1 will download and store a copy of the Bitcoin block chain.") | |||||
.arg(PACKAGE_NAME) + | |||||
" " + storageRequiresMsg.arg(m_required_space_gb) + " " + | |||||
tr("The wallet will also be stored in this directory.")); | |||||
this->adjustSize(); | |||||
} |