Dash Core Source Documentation (0.16.0.1)

Find detailed information regarding the Dash Core source code.

intro.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2015 The Bitcoin Core developers
2 // Copyright (c) 2014-2019 The Dash Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #if defined(HAVE_CONFIG_H)
7 #include <config/dash-config.h>
8 #endif
9 
10 #include <fs.h>
11 #include <qt/intro.h>
12 #include <qt/forms/ui_intro.h>
13 
14 #include <qt/guiutil.h>
15 
16 #include <util.h>
17 
18 #include <QFileDialog>
19 #include <QSettings>
20 #include <QMessageBox>
21 
22 #include <cmath>
23 
24 static const uint64_t GB_BYTES = 1000000000LL;
25 /* Minimum free space (in GB) needed for data directory */
26 static const uint64_t BLOCK_CHAIN_SIZE = 30;
27 /* Minimum free space (in GB) needed for data directory when pruned; Does not include prune target */
28 static const uint64_t CHAIN_STATE_SIZE = 1;
29 /* Total required space (in GB) depending on user choice (prune, not prune) */
30 static uint64_t requiredSpace;
31 
32 /* Check free space asynchronously to prevent hanging the UI thread.
33 
34  Up to one request to check a path is in flight to this thread; when the check()
35  function runs, the current path is requested from the associated Intro object.
36  The reply is sent back through a signal.
37 
38  This ensures that no queue of checking requests is built up while the user is
39  still entering the path, and that always the most recently entered path is checked as
40  soon as the thread becomes available.
41 */
42 class FreespaceChecker : public QObject
43 {
44  Q_OBJECT
45 
46 public:
47  explicit FreespaceChecker(Intro *intro);
48 
49  enum Status {
52  };
53 
54 public Q_SLOTS:
55  void check();
56 
57 Q_SIGNALS:
58  void reply(int status, const QString &message, quint64 available);
59 
60 private:
62 };
63 
64 #include <qt/intro.moc>
65 
67 {
68  this->intro = _intro;
69 }
70 
72 {
73  QString dataDirStr = intro->getPathToCheck();
74  fs::path dataDir = GUIUtil::qstringToBoostPath(dataDirStr);
75  uint64_t freeBytesAvailable = 0;
76  int replyStatus = ST_OK;
77  QString replyMessage = tr("A new data directory will be created.");
78 
79  /* Find first parent that exists, so that fs::space does not fail */
80  fs::path parentDir = dataDir;
81  fs::path parentDirOld = fs::path();
82  while(parentDir.has_parent_path() && !fs::exists(parentDir))
83  {
84  parentDir = parentDir.parent_path();
85 
86  /* Check if we make any progress, break if not to prevent an infinite loop here */
87  if (parentDirOld == parentDir)
88  break;
89 
90  parentDirOld = parentDir;
91  }
92 
93  try {
94  freeBytesAvailable = fs::space(parentDir).available;
95  if(fs::exists(dataDir))
96  {
97  if(fs::is_directory(dataDir))
98  {
99  QString separator = "<code>" + QDir::toNativeSeparators("/") + tr("name") + "</code>";
100  replyStatus = ST_OK;
101  replyMessage = tr("Directory already exists. Add %1 if you intend to create a new directory here.").arg(separator);
102  } else {
103  replyStatus = ST_ERROR;
104  replyMessage = tr("Path already exists, and is not a directory.");
105  }
106  }
107  } catch (const fs::filesystem_error&)
108  {
109  /* Parent directory does not exist or is not accessible */
110  replyStatus = ST_ERROR;
111  replyMessage = tr("Cannot create data directory here.");
112  }
113  Q_EMIT reply(replyStatus, replyMessage, freeBytesAvailable);
114 }
115 
116 
117 Intro::Intro(QWidget *parent) :
118  QDialog(parent),
119  ui(new Ui::Intro),
120  thread(0),
121  signalled(false)
122 {
123  ui->setupUi(this);
124  ui->welcomeLabel->setText(ui->welcomeLabel->text().arg(tr(PACKAGE_NAME)));
125  ui->storageLabel->setText(ui->storageLabel->text().arg(tr(PACKAGE_NAME)));
126 
127  ui->lblExplanation1->setText(ui->lblExplanation1->text()
128  .arg(tr(PACKAGE_NAME))
129  .arg(BLOCK_CHAIN_SIZE)
130  .arg(2014)
131  .arg("Dash")
132  );
133  ui->lblExplanation2->setText(ui->lblExplanation2->text().arg(tr(PACKAGE_NAME)));
134 
135  uint64_t pruneTarget = std::max<int64_t>(0, gArgs.GetArg("-prune", 0));
137  QString storageRequiresMsg = tr("At least %1 GB of data will be stored in this directory, and it will grow over time.");
138  if (pruneTarget) {
139  uint64_t prunedGBs = std::ceil(pruneTarget * 1024 * 1024.0 / GB_BYTES);
140  if (prunedGBs <= requiredSpace) {
141  requiredSpace = prunedGBs;
142  storageRequiresMsg = tr("Approximately %1 GB of data will be stored in this directory.");
143  }
144  ui->lblExplanation3->setVisible(true);
145  } else {
146  ui->lblExplanation3->setVisible(false);
147  }
149  ui->sizeWarningLabel->setText(
150  tr("%1 will download and store a copy of the Dash block chain.").arg(tr(PACKAGE_NAME)) + " " +
151  storageRequiresMsg.arg(requiredSpace) + " " +
152  tr("The wallet will also be stored in this directory.")
153  );
154  startThread();
155 }
156 
158 {
159  delete ui;
160  /* Ensure thread is finished before it is deleted */
161  Q_EMIT stopThread();
162  thread->wait();
163 }
164 
166 {
167  return ui->dataDirectory->text();
168 }
169 
170 void Intro::setDataDirectory(const QString &dataDir)
171 {
172  ui->dataDirectory->setText(dataDir);
173  if(dataDir == getDefaultDataDirectory())
174  {
175  ui->dataDirDefault->setChecked(true);
176  ui->dataDirectory->setEnabled(false);
177  ui->ellipsisButton->setEnabled(false);
178  } else {
179  ui->dataDirCustom->setChecked(true);
180  ui->dataDirectory->setEnabled(true);
181  ui->ellipsisButton->setEnabled(true);
182  }
183 }
184 
186 {
188 }
189 
191 {
192  QSettings settings;
193  /* If data directory provided on command line, no need to look at settings
194  or show a picking dialog */
195  if(!gArgs.GetArg("-datadir", "").empty())
196  return true;
197  /* 1) Default data directory for operating system */
198  QString dataDirDefaultCurrent = getDefaultDataDirectory();
199  /* 2) Allow QSettings to override default dir */
200  QString dataDir = settings.value("strDataDir", dataDirDefaultCurrent).toString();
201  /* 3) Check to see if default datadir is the one we expect */
202  QString dataDirDefaultSettings = settings.value("strDataDirDefault").toString();
203 
204  if(!fs::exists(GUIUtil::qstringToBoostPath(dataDir)) || gArgs.GetBoolArg("-choosedatadir", DEFAULT_CHOOSE_DATADIR) || dataDirDefaultCurrent != dataDirDefaultSettings)
205  {
206  /* Let the user choose one */
207  Intro intro;
209  GUIUtil::loadStyleSheet(&intro);
210  intro.setDataDirectory(dataDirDefaultCurrent);
211  intro.setWindowIcon(QIcon(":icons/bitcoin"));
212 
213  while(true)
214  {
215  if(!intro.exec())
216  {
217  /* Cancel clicked */
218  return false;
219  }
220  dataDir = intro.getDataDirectory();
221  try {
223  // If a new data directory has been created, make wallets subdirectory too
225  }
226  break;
227  } catch (const fs::filesystem_error&) {
228  QMessageBox::critical(0, tr(PACKAGE_NAME),
229  tr("Error: Specified data directory \"%1\" cannot be created.").arg(dataDir));
230  /* fall through, back to choosing screen */
231  }
232  }
233 
234  settings.setValue("strDataDir", dataDir);
235  settings.setValue("strDataDirDefault", dataDirDefaultCurrent);
236  }
237  /* Only override -datadir if different from the default, to make it possible to
238  * override -datadir in the dash.conf file in the default data directory
239  * (to be consistent with dashd behavior)
240  */
241  if(dataDir != dataDirDefaultCurrent)
242  gArgs.SoftSetArg("-datadir", GUIUtil::qstringToBoostPath(dataDir).string()); // use OS locale for path setting
243  return true;
244 }
245 
246 void Intro::setStatus(int status, const QString &message, quint64 bytesAvailable)
247 {
248  switch(status)
249  {
251  ui->errorMessage->setText(message);
252  ui->errorMessage->setStyleSheet("");
253  break;
255  ui->errorMessage->setText(tr("Error") + ": " + message);
257  break;
258  }
259  /* Indicate number of bytes available */
260  if(status == FreespaceChecker::ST_ERROR)
261  {
262  ui->freeSpace->setText("");
263  } else {
264  QString freeString = tr("%1 GB of free space available").arg(bytesAvailable/GB_BYTES);
265  if(bytesAvailable < requiredSpace * GB_BYTES)
266  {
267  freeString += " " + tr("(of %1 GB needed)").arg(requiredSpace);
269  } else {
270  ui->freeSpace->setStyleSheet("");
271  }
272  ui->freeSpace->setText(freeString + ".");
273  }
274  /* Don't allow confirm in ERROR state */
275  ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(status != FreespaceChecker::ST_ERROR);
276 }
277 
278 void Intro::on_dataDirectory_textChanged(const QString &dataDirStr)
279 {
280  /* Disable OK button until check result comes in */
281  ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
282  checkPath(dataDirStr);
283 }
284 
286 {
287  QString dir = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(0, "Choose data directory", ui->dataDirectory->text()));
288  if(!dir.isEmpty())
289  ui->dataDirectory->setText(dir);
290 }
291 
293 {
295 }
296 
298 {
299  ui->dataDirectory->setEnabled(true);
300  ui->ellipsisButton->setEnabled(true);
301 }
302 
304 {
305  thread = new QThread(this);
306  FreespaceChecker *executor = new FreespaceChecker(this);
307  executor->moveToThread(thread);
308 
309  connect(executor, SIGNAL(reply(int,QString,quint64)), this, SLOT(setStatus(int,QString,quint64)));
310  connect(this, SIGNAL(requestCheck()), executor, SLOT(check()));
311  /* make sure executor object is deleted in its own thread */
312  connect(this, SIGNAL(stopThread()), executor, SLOT(deleteLater()));
313  connect(this, SIGNAL(stopThread()), thread, SLOT(quit()));
314 
315  thread->start();
316 }
317 
318 void Intro::checkPath(const QString &dataDir)
319 {
320  mutex.lock();
321  pathToCheck = dataDir;
322  if(!signalled)
323  {
324  signalled = true;
325  Q_EMIT requestCheck();
326  }
327  mutex.unlock();
328 }
329 
331 {
332  QString retval;
333  mutex.lock();
334  retval = pathToCheck;
335  signalled = false; /* new request can be queued now */
336  mutex.unlock();
337  return retval;
338 }
static const bool DEFAULT_CHOOSE_DATADIR
Definition: intro.h:12
void reply(int status, const QString &message, quint64 available)
void requestCheck()
void on_dataDirCustom_clicked()
Definition: intro.cpp:297
FreespaceChecker(Intro *intro)
Definition: intro.cpp:66
static const uint64_t BLOCK_CHAIN_SIZE
Definition: intro.cpp:26
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
Definition: util.cpp:824
QString getDataDirectory()
Definition: intro.cpp:165
Intro(QWidget *parent=0)
Definition: intro.cpp:117
bool SoftSetArg(const std::string &strArg, const std::string &strValue)
Set an argument if it doesn&#39;t already have a value.
Definition: util.cpp:832
bool signalled
Definition: intro.h:68
static uint64_t requiredSpace
Definition: intro.cpp:30
false
Definition: bls_dkg.cpp:168
static QString getDefaultDataDirectory()
Determine default data directory for operating system.
Definition: intro.cpp:185
void on_dataDirectory_textChanged(const QString &arg1)
Definition: intro.cpp:278
void setStatus(int status, const QString &message, quint64 bytesAvailable)
Definition: intro.cpp:246
void checkPath(const QString &dataDir)
Definition: intro.cpp:318
void on_ellipsisButton_clicked()
Definition: intro.cpp:285
bool TryCreateDirectories(const fs::path &p)
Ignores exceptions thrown by Boost&#39;s create_directories if the requested directory exists...
Definition: util.cpp:1085
void on_dataDirDefault_clicked()
Definition: intro.cpp:292
static const uint64_t GB_BYTES
Definition: intro.cpp:24
QString getPathToCheck()
Definition: intro.cpp:330
fs::path GetDefaultDataDir()
Definition: util.cpp:898
void disableMacFocusRect(const QWidget *w)
Disable the OS default focus rect for macOS because we have custom focus rects set in the css files...
Definition: guiutil.cpp:1789
ArgsManager gArgs
Definition: util.cpp:108
friend class FreespaceChecker
Definition: intro.h:75
void setDataDirectory(const QString &dataDir)
Definition: intro.cpp:170
fs::path qstringToBoostPath(const QString &path)
Definition: guiutil.cpp:1823
Ui::Intro * ui
Definition: intro.h:65
void startThread()
Definition: intro.cpp:303
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
Definition: util.cpp:808
QString getThemedStyleQString(ThemedStyle style)
Helper to get css style strings which are injected into rich text through qt.
Definition: guiutil.cpp:210
void check()
Definition: intro.cpp:71
void loadStyleSheet(QWidget *widget, bool fForceUpdate)
Updates the widgets stylesheet and adds it to the list of ui debug elements.
Definition: guiutil.cpp:1155
QString boostPathToQString(const fs::path &path)
Definition: guiutil.cpp:1828
~Intro()
Definition: intro.cpp:157
static bool pickDataDirectory()
Determine data directory.
Definition: intro.cpp:190
QMutex mutex
Definition: intro.h:67
Intro * intro
Definition: intro.cpp:61
QThread * thread
Definition: intro.h:66
QString pathToCheck
Definition: intro.h:69
Introduction screen (pre-GUI startup).
Definition: intro.h:24
void stopThread()
static const uint64_t CHAIN_STATE_SIZE
Definition: intro.cpp:28
Released under the MIT license