Bitcoin ABC 0.26.3
P2P Digital Currency
Loading...
Searching...
No Matches
intro.cpp
Go to the documentation of this file.
1// Copyright (c) 2011-2016 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#if defined(HAVE_CONFIG_H)
6#include <config/bitcoin-config.h>
7#endif
8
9#include <common/args.h>
10#include <config.h>
11#include <interfaces/node.h>
12#include <qt/forms/ui_intro.h>
13#include <qt/guiconstants.h>
14#include <qt/guiutil.h>
15#include <qt/intro.h>
16#include <qt/optionsmodel.h>
17#include <util/fs.h>
18#include <util/fs_helpers.h>
19
20#include <QFileDialog>
21#include <QMessageBox>
22#include <QSettings>
23
24#include <cmath>
25
26/* Check free space asynchronously to prevent hanging the UI thread.
27
28 Up to one request to check a path is in flight to this thread; when the
29 check()
30 function runs, the current path is requested from the associated Intro
31 object.
32 The reply is sent back through a signal.
33
34 This ensures that no queue of checking requests is built up while the user is
35 still entering the path, and that always the most recently entered path is
36 checked as
37 soon as the thread becomes available.
38*/
39class FreespaceChecker : public QObject {
41
42public:
43 explicit FreespaceChecker(Intro *intro);
44
46
47public Q_SLOTS:
48 void check();
49
51 void reply(int status, const QString &message, quint64 available);
52
53private:
55};
56
57#include <qt/intro.moc>
58
62
67 int replyStatus = ST_OK;
68 QString replyMessage = tr("A new data directory will be created.");
69
70 /* Find first parent that exists, so that fs::space does not fail */
71 fs::path parentDir = dataDir;
73 while (parentDir.has_parent_path() && !fs::exists(parentDir)) {
74 parentDir = parentDir.parent_path();
75
76 /* Check if we make any progress, break if not to prevent an infinite
77 * loop here */
78 if (parentDirOld == parentDir) {
79 break;
80 }
81
83 }
84
85 try {
86 freeBytesAvailable = fs::space(parentDir).available;
87 if (fs::exists(dataDir)) {
88 if (fs::is_directory(dataDir)) {
89 QString separator = "<code>" + QDir::toNativeSeparators("/") +
90 tr("name") + "</code>";
92 replyMessage = tr("Directory already exists. Add %1 if you "
93 "intend to create a new directory here.")
94 .arg(separator);
95 } else {
98 tr("Path already exists, and is not a directory.");
99 }
100 }
101 } catch (const fs::filesystem_error &) {
102 /* Parent directory does not exist or is not accessible */
104 replyMessage = tr("Cannot create data directory here.");
105 }
107}
108
109namespace {
111int GetPruneTargetGB() {
113 // >1 means automatic pruning is enabled by config, 1 means manual pruning,
114 // 0 means no pruning.
117}
118} // namespace
119
122 : QDialog(parent), ui(new Ui::Intro), thread(nullptr), signalled(false),
123 m_blockchain_size_gb(blockchain_size_gb),
124 m_chain_state_size_gb(chain_state_size_gb),
125 m_prune_target_gb(GetPruneTargetGB()) {
126 ui->setupUi(this);
127 ui->welcomeLabel->setText(ui->welcomeLabel->text().arg(PACKAGE_NAME));
128 ui->storageLabel->setText(ui->storageLabel->text().arg(PACKAGE_NAME));
129
130 ui->lblExplanation1->setText(ui->lblExplanation1->text()
131 .arg(PACKAGE_NAME)
133 .arg(2009)
134 .arg(tr("Bitcoin")));
135 ui->lblExplanation2->setText(ui->lblExplanation2->text().arg(PACKAGE_NAME));
136
137 // -prune=1 means enabled, above that it's a size in MiB
138 if (gArgs.GetIntArg("-prune", 0) > 1) {
139 ui->prune->setChecked(true);
140 ui->prune->setEnabled(false);
141 }
142 ui->prune->setText(tr("Discard blocks after verification, except most "
143 "recent %1 GB (prune)")
145 UpdatePruneLabels(ui->prune->isChecked());
146
147 connect(ui->prune, &QCheckBox::toggled, [this](bool prune_checked) {
148 UpdatePruneLabels(prune_checked);
149 UpdateFreeSpaceLabel();
150 });
151
152 startThread();
153}
154
156 delete ui;
157 /* Ensure thread is finished before it is deleted */
158 thread->quit();
159 thread->wait();
160}
161
163 return ui->dataDirectory->text();
164}
165
166void Intro::setDataDirectory(const QString &dataDir) {
167 ui->dataDirectory->setText(dataDir);
168 if (dataDir == GUIUtil::getDefaultDataDirectory()) {
169 ui->dataDirDefault->setChecked(true);
170 ui->dataDirectory->setEnabled(false);
171 ui->ellipsisButton->setEnabled(false);
172 } else {
173 ui->dataDirCustom->setChecked(true);
174 ui->dataDirectory->setEnabled(true);
175 ui->ellipsisButton->setEnabled(true);
176 }
177}
178
179bool Intro::showIfNeeded(bool &did_show_intro, bool &prune) {
180 did_show_intro = false;
181
183 /* If data directory provided on command line, no need to look at settings
184 or show a picking dialog */
185 if (!gArgs.GetArg("-datadir", "").empty()) {
186 return true;
187 }
188 /* 1) Default data directory for operating system */
190 /* 2) Allow QSettings to override default dir */
191 dataDir = settings.value("strDataDir", dataDir).toString();
192
194 gArgs.GetBoolArg("-choosedatadir", DEFAULT_CHOOSE_DATADIR) ||
195 settings.value("fReset", false).toBool() ||
196 gArgs.GetBoolArg("-resetguisettings", false)) {
201 try {
203 } catch (const std::exception &) {
204 return false;
205 }
206
211 const CChainParams &params = GetConfig().GetChainParams();
212 Intro intro(nullptr, params.AssumedBlockchainSize(),
213 params.AssumedChainStateSize());
214 intro.setDataDirectory(dataDir);
215 intro.setWindowIcon(QIcon(":icons/bitcoin"));
216 did_show_intro = true;
217
218 while (true) {
219 if (!intro.exec()) {
220 /* Cancel clicked */
221 return false;
222 }
223 dataDir = intro.getDataDirectory();
224 try {
226 GUIUtil::qstringToBoostPath(dataDir))) {
227 // If a new data directory has been created, make wallets
228 // subdirectory too
230 "wallets");
231 }
232 break;
233 } catch (const fs::filesystem_error &) {
234 QMessageBox::critical(nullptr, PACKAGE_NAME,
235 tr("Error: Specified data directory "
236 "\"%1\" cannot be created.")
237 .arg(dataDir));
238 /* fall through, back to choosing screen */
239 }
240 }
241
242 // Additional preferences:
243 prune = intro.ui->prune->isChecked();
244
245 settings.setValue("strDataDir", dataDir);
246 settings.setValue("fReset", false);
247 }
248 /* Only override -datadir if different from the default, to make it possible
249 * to
250 * override -datadir in the bitcoin.conf file in the default data directory
251 * (to be consistent with bitcoind behavior)
252 */
253 if (dataDir != GUIUtil::getDefaultDataDirectory()) {
254 // use OS locale for path setting
256 "-datadir", fs::PathToString(GUIUtil::qstringToBoostPath(dataDir)));
257 }
258 return true;
259}
260
261void Intro::setStatus(int status, const QString &message,
263 switch (status) {
265 ui->errorMessage->setText(message);
266 ui->errorMessage->setStyleSheet("");
267 break;
269 ui->errorMessage->setText(tr("Error") + ": " + message);
270 ui->errorMessage->setStyleSheet("QLabel { color: #800000 }");
271 break;
272 }
273 /* Indicate number of bytes available */
274 if (status == FreespaceChecker::ST_ERROR) {
275 ui->freeSpace->setText("");
276 } else {
278 if (ui->prune->isEnabled()) {
279 ui->prune->setChecked(
282 }
284 }
285 /* Don't allow confirm in ERROR state */
286 ui->buttonBox->button(QDialogButtonBox::Ok)
287 ->setEnabled(status != FreespaceChecker::ST_ERROR);
288}
289
292 tr("%n GB of free space available", "", m_bytes_available / GB_BYTES);
294 freeString += " " + tr("(of %n GB needed)", "", m_required_space_gb);
295 ui->freeSpace->setStyleSheet("QLabel { color: #800000 }");
296 } else if (m_bytes_available / GB_BYTES - m_required_space_gb < 10) {
297 freeString +=
298 " " + tr("(%n GB needed for full chain)", "", m_required_space_gb);
299 ui->freeSpace->setStyleSheet("QLabel { color: #999900 }");
300 } else {
301 ui->freeSpace->setStyleSheet("");
302 }
303 ui->freeSpace->setText(freeString + ".");
304}
305
307 /* Disable OK button until check result comes in */
308 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
310}
311
313 QString dir = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(
314 nullptr, "Choose data directory", ui->dataDirectory->text()));
315 if (!dir.isEmpty()) {
316 ui->dataDirectory->setText(dir);
317 }
318}
319
323
325 ui->dataDirectory->setEnabled(true);
326 ui->ellipsisButton->setEnabled(true);
327}
328
330 thread = new QThread(this);
332 executor->moveToThread(thread);
333
336 /* make sure executor object is deleted in its own thread */
337 connect(thread, &QThread::finished, executor, &QObject::deleteLater);
338
339 thread->start();
340}
341
342void Intro::checkPath(const QString &dataDir) {
343 mutex.lock();
344 pathToCheck = dataDir;
345 if (!signalled) {
346 signalled = true;
348 }
349 mutex.unlock();
350}
351
354 mutex.lock();
356 signalled = false; /* new request can be queued now */
357 mutex.unlock();
358 return retval;
359}
360
364 tr("At least %1 GB of data will be stored in this directory, and it "
365 "will grow over time.");
369 tr("Approximately %1 GB of data will be stored in this directory.");
370 }
371 ui->lblExplanation3->setVisible(prune_checked);
372 ui->sizeWarningLabel->setText(
373 tr("%1 will download and store a copy of the Bitcoin block chain.")
374 .arg(PACKAGE_NAME) +
375 " " + storageRequiresMsg.arg(m_required_space_gb) + " " +
376 tr("The wallet will also be stored in this directory."));
377 this->adjustSize();
378}
ArgsManager gArgs
Definition args.cpp:38
void SelectParams(const std::string &network)
Sets the params returned by Params() to those for the given BIP70 chain name.
bool SoftSetArg(const std::string &strArg, const std::string &strValue)
Set an argument if it doesn't already have a value.
Definition args.cpp:579
int64_t GetIntArg(const std::string &strArg, int64_t nDefault) const
Return integer argument or default value.
Definition args.cpp:526
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
Definition args.cpp:494
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
Definition args.cpp:556
std::string GetChainName() const
Looks for -regtest, -testnet and returns the appropriate BIP70 chain name.
Definition args.cpp:793
CChainParams defines various tweakable parameters of a given instance of the Bitcoin system.
Definition chainparams.h:80
uint64_t AssumedBlockchainSize() const
Minimum free space (in GB) needed for data directory.
uint64_t AssumedChainStateSize() const
Minimum free space (in GB) needed for data directory when pruned; Does not include prune target.
virtual const CChainParams & GetChainParams() const =0
FreespaceChecker(Intro *intro)
Definition intro.cpp:59
Intro * intro
Definition intro.cpp:54
void reply(int status, const QString &message, quint64 available)
Introduction screen (pre-GUI startup).
Definition intro.h:28
~Intro()
Definition intro.cpp:155
void setStatus(int status, const QString &message, quint64 bytesAvailable)
Definition intro.cpp:261
void on_ellipsisButton_clicked()
Definition intro.cpp:312
QMutex mutex
Definition intro.h:68
void UpdatePruneLabels(bool prune_checked)
Definition intro.cpp:361
const int64_t m_blockchain_size_gb
Definition intro.h:71
void setDataDirectory(const QString &dataDir)
Definition intro.cpp:166
static bool showIfNeeded(bool &did_show_intro, bool &prune)
Determine data directory.
Definition intro.cpp:179
uint64_t m_bytes_available
Definition intro.h:76
QString pathToCheck
Definition intro.h:70
friend class FreespaceChecker
Definition intro.h:85
void on_dataDirectory_textChanged(const QString &arg1)
Definition intro.cpp:306
int64_t m_required_space_gb
Total required space (in GB) depending on user choice (prune or not prune).
Definition intro.h:75
void UpdateFreeSpaceLabel()
Definition intro.cpp:290
bool signalled
Definition intro.h:69
QString getPathToCheck()
Definition intro.cpp:352
Ui::Intro * ui
Definition intro.h:66
void requestCheck()
Intro(QWidget *parent=nullptr, int64_t blockchain_size_gb=0, int64_t chain_state_size_gb=0)
Definition intro.cpp:120
const int64_t m_chain_state_size_gb
Definition intro.h:72
QString getDataDirectory()
Definition intro.cpp:162
void checkPath(const QString &dataDir)
Definition intro.cpp:342
void startThread()
Definition intro.cpp:329
void on_dataDirDefault_clicked()
Definition intro.cpp:320
const int64_t m_prune_target_gb
Definition intro.h:77
QThread * thread
Definition intro.h:67
void on_dataDirCustom_clicked()
Definition intro.cpp:324
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition fs.h:30
const Config & GetConfig()
Definition config.cpp:40
bool TryCreateDirectories(const fs::path &p)
Ignores exceptions thrown by create_directories if the requested directory exists.
static constexpr int DEFAULT_PRUNE_TARGET_GB
static constexpr uint64_t GB_BYTES
static const bool DEFAULT_CHOOSE_DATADIR
Definition intro.h:12
fs::path qstringToBoostPath(const QString &path)
Convert QString to OS specific boost path through UTF-8.
Definition guiutil.cpp:781
QString getDefaultDataDirectory()
Determine default data directory for operating system.
Definition guiutil.cpp:290
static bool exists(const path &p)
Definition fs.h:102
static std::string PathToString(const path &path)
Convert path object to byte string.
Definition fs.h:142
static int PruneMiBtoGB(int64_t mib)
Convert configured prune target MiB to displayed GB.
T GetRand(T nMax=std::numeric_limits< T >::max()) noexcept
Generate a uniform random integer of type T in the range [0..nMax) nMax defaults to std::numeric_limi...
Definition random.h:85