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