]> Git Repo - VerusCoin.git/blame - src/qt/intro.cpp
Merge pull request #12 from miketout/dev
[VerusCoin.git] / src / qt / intro.cpp
CommitLineData
f914f1a7 1// Copyright (c) 2011-2014 The Bitcoin Core developers
78253fcb 2// Distributed under the MIT software license, see the accompanying
e592d43f
WL
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
be77b637
WL
5#include "intro.h"
6#include "ui_intro.h"
51ed9ec9 7
7e591c19 8#include "guiutil.h"
9b7d3fb1 9#include "scicon.h"
7e591c19 10
be77b637
WL
11#include "util.h"
12
51ed9ec9 13#include <boost/filesystem.hpp>
7e591c19 14
be77b637
WL
15#include <QFileDialog>
16#include <QSettings>
17#include <QMessageBox>
18
be77b637 19/* Minimum free space (in bytes) needed for data directory */
51ed9ec9 20static const uint64_t GB_BYTES = 1000000000LL;
70b8cb9c 21static const uint64_t BLOCK_CHAIN_SIZE = 20LL * GB_BYTES;
be77b637
WL
22
23/* Check free space asynchronously to prevent hanging the UI thread.
24
25 Up to one request to check a path is in flight to this thread; when the check()
26 function runs, the current path is requested from the associated Intro object.
27 The reply is sent back through a signal.
28
29 This ensures that no queue of checking requests is built up while the user is
30 still entering the path, and that always the most recently entered path is checked as
31 soon as the thread becomes available.
32*/
33class FreespaceChecker : public QObject
34{
35 Q_OBJECT
5bc6d8e5 36
be77b637
WL
37public:
38 FreespaceChecker(Intro *intro);
39
40 enum Status {
41 ST_OK,
42 ST_ERROR
43 };
44
e092f229 45public Q_SLOTS:
be77b637
WL
46 void check();
47
e092f229 48Q_SIGNALS:
be77b637
WL
49 void reply(int status, const QString &message, quint64 available);
50
51private:
52 Intro *intro;
53};
54
55#include "intro.moc"
56
57FreespaceChecker::FreespaceChecker(Intro *intro)
58{
59 this->intro = intro;
60}
61
62void FreespaceChecker::check()
63{
64 namespace fs = boost::filesystem;
65 QString dataDirStr = intro->getPathToCheck();
7e591c19 66 fs::path dataDir = GUIUtil::qstringToBoostPath(dataDirStr);
51ed9ec9 67 uint64_t freeBytesAvailable = 0;
be77b637
WL
68 int replyStatus = ST_OK;
69 QString replyMessage = tr("A new data directory will be created.");
70
71 /* Find first parent that exists, so that fs::space does not fail */
72 fs::path parentDir = dataDir;
5bc6d8e5 73 fs::path parentDirOld = fs::path();
be77b637
WL
74 while(parentDir.has_parent_path() && !fs::exists(parentDir))
75 {
76 parentDir = parentDir.parent_path();
5bc6d8e5
PK
77
78 /* Check if we make any progress, break if not to prevent an infinite loop here */
79 if (parentDirOld == parentDir)
80 break;
81
82 parentDirOld = parentDir;
be77b637
WL
83 }
84
85 try {
86 freeBytesAvailable = fs::space(parentDir).available;
87 if(fs::exists(dataDir))
88 {
89 if(fs::is_directory(dataDir))
90 {
bef9f573 91 QString separator = "<code>" + QDir::toNativeSeparators("/") + tr("name") + "</code>";
be77b637 92 replyStatus = ST_OK;
bef9f573 93 replyMessage = tr("Directory already exists. Add %1 if you intend to create a new directory here.").arg(separator);
be77b637
WL
94 } else {
95 replyStatus = ST_ERROR;
96 replyMessage = tr("Path already exists, and is not a directory.");
97 }
98 }
27df4123 99 } catch (const fs::filesystem_error&)
be77b637
WL
100 {
101 /* Parent directory does not exist or is not accessible */
102 replyStatus = ST_ERROR;
103 replyMessage = tr("Cannot create data directory here.");
104 }
e092f229 105 Q_EMIT reply(replyStatus, replyMessage, freeBytesAvailable);
be77b637
WL
106}
107
108
109Intro::Intro(QWidget *parent) :
110 QDialog(parent),
111 ui(new Ui::Intro),
112 thread(0),
113 signalled(false)
114{
115 ui->setupUi(this);
116 ui->sizeWarningLabel->setText(ui->sizeWarningLabel->text().arg(BLOCK_CHAIN_SIZE/GB_BYTES));
117 startThread();
118}
119
120Intro::~Intro()
121{
122 delete ui;
123 /* Ensure thread is finished before it is deleted */
e092f229 124 Q_EMIT stopThread();
be77b637
WL
125 thread->wait();
126}
127
128QString Intro::getDataDirectory()
129{
130 return ui->dataDirectory->text();
131}
132
133void Intro::setDataDirectory(const QString &dataDir)
134{
135 ui->dataDirectory->setText(dataDir);
136 if(dataDir == getDefaultDataDirectory())
137 {
138 ui->dataDirDefault->setChecked(true);
139 ui->dataDirectory->setEnabled(false);
140 ui->ellipsisButton->setEnabled(false);
141 } else {
142 ui->dataDirCustom->setChecked(true);
143 ui->dataDirectory->setEnabled(true);
144 ui->ellipsisButton->setEnabled(true);
145 }
146}
147
148QString Intro::getDefaultDataDirectory()
149{
7e591c19 150 return GUIUtil::boostPathToQString(GetDefaultDataDir());
be77b637
WL
151}
152
c52c4e5d 153void Intro::pickDataDirectory()
be77b637 154{
2102ab9f 155 namespace fs = boost::filesystem;
be77b637
WL
156 QSettings settings;
157 /* If data directory provided on command line, no need to look at settings
158 or show a picking dialog */
159 if(!GetArg("-datadir", "").empty())
160 return;
161 /* 1) Default data directory for operating system */
162 QString dataDir = getDefaultDataDirectory();
163 /* 2) Allow QSettings to override default dir */
164 dataDir = settings.value("strDataDir", dataDir).toString();
165
7e591c19 166 if(!fs::exists(GUIUtil::qstringToBoostPath(dataDir)) || GetBoolArg("-choosedatadir", false))
be77b637
WL
167 {
168 /* If current default data directory does not exist, let the user choose one */
169 Intro intro;
170 intro.setDataDirectory(dataDir);
9b7d3fb1 171 intro.setWindowIcon(SingleColorIcon(":icons/bitcoin"));
d9baa28f 172
be77b637
WL
173 while(true)
174 {
175 if(!intro.exec())
176 {
177 /* Cancel clicked */
178 exit(0);
179 }
180 dataDir = intro.getDataDirectory();
181 try {
2b7709dc 182 TryCreateDirectory(GUIUtil::qstringToBoostPath(dataDir));
be77b637 183 break;
27df4123 184 } catch (const fs::filesystem_error&) {
a409467e 185 QMessageBox::critical(0, tr("Bitcoin Core"),
bd26fee1 186 tr("Error: Specified data directory \"%1\" cannot be created.").arg(dataDir));
be77b637
WL
187 /* fall through, back to choosing screen */
188 }
189 }
190
191 settings.setValue("strDataDir", dataDir);
192 }
c61fe441 193 /* Only override -datadir if different from the default, to make it possible to
5166804f 194 * override -datadir in the komodo.conf file in the default data directory
c61fe441
WL
195 * (to be consistent with bitcoind behavior)
196 */
197 if(dataDir != getDefaultDataDirectory())
198 SoftSetArg("-datadir", GUIUtil::qstringToBoostPath(dataDir).string()); // use OS locale for path setting
be77b637
WL
199}
200
201void Intro::setStatus(int status, const QString &message, quint64 bytesAvailable)
202{
203 switch(status)
204 {
205 case FreespaceChecker::ST_OK:
206 ui->errorMessage->setText(message);
207 ui->errorMessage->setStyleSheet("");
208 break;
209 case FreespaceChecker::ST_ERROR:
210 ui->errorMessage->setText(tr("Error") + ": " + message);
211 ui->errorMessage->setStyleSheet("QLabel { color: #800000 }");
212 break;
213 }
214 /* Indicate number of bytes available */
215 if(status == FreespaceChecker::ST_ERROR)
216 {
217 ui->freeSpace->setText("");
218 } else {
9acbb418 219 QString freeString = tr("%n GB of free space available", "", bytesAvailable/GB_BYTES);
be77b637
WL
220 if(bytesAvailable < BLOCK_CHAIN_SIZE)
221 {
9acbb418 222 freeString += " " + tr("(of %n GB needed)", "", BLOCK_CHAIN_SIZE/GB_BYTES);
be77b637
WL
223 ui->freeSpace->setStyleSheet("QLabel { color: #800000 }");
224 } else {
225 ui->freeSpace->setStyleSheet("");
226 }
5bc6d8e5 227 ui->freeSpace->setText(freeString + ".");
be77b637
WL
228 }
229 /* Don't allow confirm in ERROR state */
230 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(status != FreespaceChecker::ST_ERROR);
231}
232
233void Intro::on_dataDirectory_textChanged(const QString &dataDirStr)
234{
235 /* Disable OK button until check result comes in */
236 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
237 checkPath(dataDirStr);
238}
239
240void Intro::on_ellipsisButton_clicked()
241{
6a1bf004 242 QString dir = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(0, "Choose data directory", ui->dataDirectory->text()));
be77b637
WL
243 if(!dir.isEmpty())
244 ui->dataDirectory->setText(dir);
245}
246
247void Intro::on_dataDirDefault_clicked()
248{
249 setDataDirectory(getDefaultDataDirectory());
250}
251
252void Intro::on_dataDirCustom_clicked()
253{
254 ui->dataDirectory->setEnabled(true);
255 ui->ellipsisButton->setEnabled(true);
256}
257
258void Intro::startThread()
259{
260 thread = new QThread(this);
261 FreespaceChecker *executor = new FreespaceChecker(this);
262 executor->moveToThread(thread);
263
264 connect(executor, SIGNAL(reply(int,QString,quint64)), this, SLOT(setStatus(int,QString,quint64)));
265 connect(this, SIGNAL(requestCheck()), executor, SLOT(check()));
266 /* make sure executor object is deleted in its own thread */
267 connect(this, SIGNAL(stopThread()), executor, SLOT(deleteLater()));
268 connect(this, SIGNAL(stopThread()), thread, SLOT(quit()));
269
270 thread->start();
271}
272
273void Intro::checkPath(const QString &dataDir)
274{
275 mutex.lock();
276 pathToCheck = dataDir;
277 if(!signalled)
278 {
279 signalled = true;
e092f229 280 Q_EMIT requestCheck();
be77b637
WL
281 }
282 mutex.unlock();
283}
284
285QString Intro::getPathToCheck()
286{
287 QString retval;
288 mutex.lock();
289 retval = pathToCheck;
290 signalled = false; /* new request can be queued now */
291 mutex.unlock();
292 return retval;
293}
This page took 0.26981 seconds and 4 git commands to generate.