Bitcoin ABC  0.24.7
P2P Digital Currency
guiutil.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2019 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 #include <qt/guiutil.h>
6 
7 #include <cashaddrenc.h>
8 #include <chainparams.h>
9 #include <interfaces/node.h>
10 #include <key_io.h>
11 #include <policy/policy.h>
12 #include <primitives/transaction.h>
13 #include <protocol.h>
15 #include <qt/bitcoinunits.h>
16 #include <qt/qvalidatedlineedit.h>
17 #include <qt/sendcoinsrecipient.h>
18 #include <script/script.h>
19 #include <script/standard.h>
20 #include <util/strencodings.h>
21 #include <util/system.h>
22 
23 #ifdef WIN32
24 #ifndef NOMINMAX
25 #define NOMINMAX
26 #endif
27 #include <shellapi.h>
28 #include <shlobj.h>
29 #include <shlwapi.h>
30 #endif
31 
32 #include <QAbstractItemView>
33 #include <QApplication>
34 #include <QClipboard>
35 #include <QDateTime>
36 #include <QDesktopServices>
37 #include <QDoubleValidator>
38 #include <QFileDialog>
39 #include <QFont>
40 #include <QFontDatabase>
41 #include <QFontMetrics>
42 #include <QGuiApplication>
43 #include <QKeyEvent>
44 #include <QLineEdit>
45 #include <QList>
46 #include <QMenu>
47 #include <QMouseEvent>
48 #include <QProcess>
49 #include <QProgressDialog>
50 #include <QScreen>
51 #include <QSettings>
52 #include <QShortcut>
53 #include <QSize>
54 #include <QString>
55 #include <QTextDocument> // for Qt::mightBeRichText
56 #include <QThread>
57 #include <QUrlQuery>
58 #include <QtGlobal>
59 
60 #if defined(Q_OS_MAC)
61 
62 void ForceActivation();
63 #endif
64 
65 namespace GUIUtil {
66 
67 QString dateTimeStr(const QDateTime &date) {
68  return date.date().toString(QLocale().dateFormat(QLocale::ShortFormat)) +
69  QString(" ") + date.toString("hh:mm");
70 }
71 
72 QString dateTimeStr(qint64 nTime) {
73  return dateTimeStr(QDateTime::fromTime_t((qint32)nTime));
74 }
75 
76 QFont fixedPitchFont() {
77  return QFontDatabase::systemFont(QFontDatabase::FixedFont);
78 }
79 
80 static std::string MakeAddrInvalid(std::string addr,
81  const CChainParams &params) {
82  if (addr.size() < 2) {
83  return "";
84  }
85 
86  // Checksum is at the end of the address. Swapping chars to make it invalid.
87  std::swap(addr[addr.size() - 1], addr[addr.size() - 2]);
88  if (!IsValidDestinationString(addr, params)) {
89  return addr;
90  }
91 
92  return "";
93 }
94 
95 std::string DummyAddress(const CChainParams &params) {
96  // Just some dummy data to generate a convincing random-looking (but
97  // consistent) address
98  static const std::vector<uint8_t> dummydata = {
99  0xeb, 0x15, 0x23, 0x1d, 0xfc, 0xeb, 0x60, 0x92, 0x58, 0x86,
100  0xb6, 0x7d, 0x06, 0x52, 0x99, 0x92, 0x59, 0x15, 0xae, 0xb1};
101 
102  const CTxDestination dstKey = PKHash(uint160(dummydata));
103  return MakeAddrInvalid(EncodeCashAddr(dstKey, params), params);
104 }
105 
106 // Addresses are stored in the database with the encoding that the client was
107 // configured with at the time of creation.
108 //
109 // This converts to cashaddr.
110 QString convertToCashAddr(const CChainParams &params, const QString &addr) {
111  if (!IsValidDestinationString(addr.toStdString(), params)) {
112  // We have something sketchy as input. Do not try to convert.
113  return addr;
114  }
115  CTxDestination dst = DecodeDestination(addr.toStdString(), params);
116  return QString::fromStdString(EncodeCashAddr(dst, params));
117 }
118 
119 void setupAddressWidget(QValidatedLineEdit *widget, QWidget *parent) {
120  parent->setFocusProxy(widget);
121 
122  widget->setFont(fixedPitchFont());
123  // We don't want translators to use own addresses in translations
124  // and this is the only place, where this address is supplied.
125  widget->setPlaceholderText(
126  QObject::tr("Enter a Bitcoin address (e.g. %1)")
127  .arg(QString::fromStdString(DummyAddress(Params()))));
128  widget->setValidator(
129  new BitcoinAddressEntryValidator(Params().CashAddrPrefix(), parent));
130  widget->setCheckValidator(new BitcoinAddressCheckValidator(parent));
131 }
132 
133 bool parseBitcoinURI(const QString &scheme, const QUrl &uri,
134  SendCoinsRecipient *out) {
135  // return if URI has wrong scheme.
136  if (!uri.isValid() || uri.scheme() != scheme) {
137  return false;
138  }
139 
141  rv.address = uri.scheme() + ":" + uri.path();
142 
143  // Trim any following forward slash which may have been added by the OS
144  if (rv.address.endsWith("/")) {
145  rv.address.truncate(rv.address.length() - 1);
146  }
147  rv.amount = Amount::zero();
148 
149  QUrlQuery uriQuery(uri);
150  QList<QPair<QString, QString>> items = uriQuery.queryItems();
151  for (QList<QPair<QString, QString>>::iterator i = items.begin();
152  i != items.end(); i++) {
153  bool fShouldReturnFalse = false;
154  if (i->first.startsWith("req-")) {
155  i->first.remove(0, 4);
156  fShouldReturnFalse = true;
157  }
158 
159  if (i->first == "label") {
160  rv.label = i->second;
161  fShouldReturnFalse = false;
162  }
163  if (i->first == "message") {
164  rv.message = i->second;
165  fShouldReturnFalse = false;
166  } else if (i->first == "amount") {
167  if (!i->second.isEmpty()) {
168  if (!BitcoinUnits::parse(BitcoinUnits::base, i->second,
169  &rv.amount)) {
170  return false;
171  }
172  }
173  fShouldReturnFalse = false;
174  }
175 
176  if (fShouldReturnFalse) {
177  return false;
178  }
179  }
180  if (out) {
181  *out = rv;
182  }
183  return true;
184 }
185 
186 bool parseBitcoinURI(const QString &scheme, QString uri,
187  SendCoinsRecipient *out) {
188  //
189  // Cannot handle this later, because bitcoincash://
190  // will cause Qt to see the part after // as host,
191  // which will lower-case it (and thus invalidate the address).
192  if (uri.startsWith(scheme + "://", Qt::CaseInsensitive)) {
193  uri.replace(0, scheme.length() + 3, scheme + ":");
194  }
195  QUrl uriInstance(uri);
196  return parseBitcoinURI(scheme, uriInstance, out);
197 }
198 
199 QString formatBitcoinURI(const SendCoinsRecipient &info) {
200  return formatBitcoinURI(Params(), info);
201 }
202 
203 QString formatBitcoinURI(const CChainParams &params,
204  const SendCoinsRecipient &info) {
205  QString ret = convertToCashAddr(params, info.address);
206  int paramCount = 0;
207 
208  if (info.amount != Amount::zero()) {
209  ret += QString("?amount=%1")
211  BitcoinUnits::base, info.amount, false,
213  paramCount++;
214  }
215 
216  if (!info.label.isEmpty()) {
217  QString lbl(QUrl::toPercentEncoding(info.label));
218  ret += QString("%1label=%2").arg(paramCount == 0 ? "?" : "&").arg(lbl);
219  paramCount++;
220  }
221 
222  if (!info.message.isEmpty()) {
223  QString msg(QUrl::toPercentEncoding(info.message));
224  ret +=
225  QString("%1message=%2").arg(paramCount == 0 ? "?" : "&").arg(msg);
226  paramCount++;
227  }
228 
229  return ret;
230 }
231 
232 bool isDust(interfaces::Node &node, const QString &address, const Amount amount,
233  const CChainParams &chainParams) {
234  CTxDestination dest = DecodeDestination(address.toStdString(), chainParams);
235  CScript script = GetScriptForDestination(dest);
236  CTxOut txOut(amount, script);
237  return IsDust(txOut, node.getDustRelayFee());
238 }
239 
240 QString HtmlEscape(const QString &str, bool fMultiLine) {
241  QString escaped = str.toHtmlEscaped();
242  if (fMultiLine) {
243  escaped = escaped.replace("\n", "<br>\n");
244  }
245  return escaped;
246 }
247 
248 QString HtmlEscape(const std::string &str, bool fMultiLine) {
249  return HtmlEscape(QString::fromStdString(str), fMultiLine);
250 }
251 
252 void copyEntryData(const QAbstractItemView *view, int column, int role) {
253  if (!view || !view->selectionModel()) {
254  return;
255  }
256  QModelIndexList selection = view->selectionModel()->selectedRows(column);
257 
258  if (!selection.isEmpty()) {
259  // Copy first item
260  setClipboard(selection.at(0).data(role).toString());
261  }
262 }
263 
264 QList<QModelIndex> getEntryData(const QAbstractItemView *view, int column) {
265  if (!view || !view->selectionModel()) {
266  return QList<QModelIndex>();
267  }
268  return view->selectionModel()->selectedRows(column);
269 }
270 
271 bool hasEntryData(const QAbstractItemView *view, int column, int role) {
272  QModelIndexList selection = getEntryData(view, column);
273  if (selection.isEmpty()) {
274  return false;
275  }
276  return !selection.at(0).data(role).toString().isEmpty();
277 }
278 
281 }
282 
283 QString getSaveFileName(QWidget *parent, const QString &caption,
284  const QString &dir, const QString &filter,
285  QString *selectedSuffixOut) {
286  QString selectedFilter;
287  QString myDir;
288  // Default to user documents location
289  if (dir.isEmpty()) {
290  myDir =
291  QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
292  } else {
293  myDir = dir;
294  }
295  /* Directly convert path to native OS path separators */
296  QString result = QDir::toNativeSeparators(QFileDialog::getSaveFileName(
297  parent, caption, myDir, filter, &selectedFilter));
298 
299  /* Extract first suffix from filter pattern "Description (*.foo)" or
300  * "Description (*.foo *.bar ...) */
301  QRegExp filter_re(".* \\(\\*\\.(.*)[ \\)]");
302  QString selectedSuffix;
303  if (filter_re.exactMatch(selectedFilter)) {
304  selectedSuffix = filter_re.cap(1);
305  }
306 
307  /* Add suffix if needed */
308  QFileInfo info(result);
309  if (!result.isEmpty()) {
310  if (info.suffix().isEmpty() && !selectedSuffix.isEmpty()) {
311  /* No suffix specified, add selected suffix */
312  if (!result.endsWith(".")) {
313  result.append(".");
314  }
315  result.append(selectedSuffix);
316  }
317  }
318 
319  /* Return selected suffix if asked to */
320  if (selectedSuffixOut) {
321  *selectedSuffixOut = selectedSuffix;
322  }
323  return result;
324 }
325 
326 QString getOpenFileName(QWidget *parent, const QString &caption,
327  const QString &dir, const QString &filter,
328  QString *selectedSuffixOut) {
329  QString selectedFilter;
330  QString myDir;
331  // Default to user documents location
332  if (dir.isEmpty()) {
333  myDir =
334  QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
335  } else {
336  myDir = dir;
337  }
338  /* Directly convert path to native OS path separators */
339  QString result = QDir::toNativeSeparators(QFileDialog::getOpenFileName(
340  parent, caption, myDir, filter, &selectedFilter));
341 
342  if (selectedSuffixOut) {
343  /* Extract first suffix from filter pattern "Description (*.foo)" or
344  * "Description (*.foo *.bar ...) */
345  QRegExp filter_re(".* \\(\\*\\.(.*)[ \\)]");
346  QString selectedSuffix;
347  if (filter_re.exactMatch(selectedFilter)) {
348  selectedSuffix = filter_re.cap(1);
349  }
350  *selectedSuffixOut = selectedSuffix;
351  }
352  return result;
353 }
354 
356  if (QThread::currentThread() != qApp->thread()) {
357  return Qt::BlockingQueuedConnection;
358  } else {
359  return Qt::DirectConnection;
360  }
361 }
362 
363 bool checkPoint(const QPoint &p, const QWidget *w) {
364  QWidget *atW = QApplication::widgetAt(w->mapToGlobal(p));
365  if (!atW) {
366  return false;
367  }
368  return atW->window() == w;
369 }
370 
371 bool isObscured(QWidget *w) {
372  return !(checkPoint(QPoint(0, 0), w) &&
373  checkPoint(QPoint(w->width() - 1, 0), w) &&
374  checkPoint(QPoint(0, w->height() - 1), w) &&
375  checkPoint(QPoint(w->width() - 1, w->height() - 1), w) &&
376  checkPoint(QPoint(w->width() / 2, w->height() / 2), w));
377 }
378 
379 void bringToFront(QWidget *w) {
380 #ifdef Q_OS_MAC
381  ForceActivation();
382 #endif
383 
384  if (w) {
385  // activateWindow() (sometimes) helps with keyboard focus on Windows
386  if (w->isMinimized()) {
387  w->showNormal();
388  } else {
389  w->show();
390  }
391  w->activateWindow();
392  w->raise();
393  }
394 }
395 
396 void handleCloseWindowShortcut(QWidget *w) {
397  QObject::connect(new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_W), w),
398  &QShortcut::activated, w, &QWidget::close);
399 }
400 
402  fs::path pathDebug = GetDataDir() / "debug.log";
403 
404  /* Open debug.log with the associated application */
405  if (fs::exists(pathDebug)) {
406  QDesktopServices::openUrl(
407  QUrl::fromLocalFile(boostPathToQString(pathDebug)));
408  }
409 }
410 
412  fs::path pathConfig =
414 
415  /* Create the file */
416  fsbridge::ofstream configFile(pathConfig, std::ios_base::app);
417 
418  if (!configFile.good()) {
419  return false;
420  }
421 
422  configFile.close();
423 
424  /* Open bitcoin.conf with the associated application */
425  bool res = QDesktopServices::openUrl(
426  QUrl::fromLocalFile(boostPathToQString(pathConfig)));
427 #ifdef Q_OS_MAC
428  // Workaround for macOS-specific behavior; see #15409.
429  if (!res) {
430  res = QProcess::startDetached(
431  "/usr/bin/open", QStringList{"-t", boostPathToQString(pathConfig)});
432  }
433 #endif
434 
435  return res;
436 }
437 
438 QStringList splitSkipEmptyParts(const QString &s, const QString &separator) {
439  return s.split(separator,
440 #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
441  Qt::SkipEmptyParts
442 #else
443  QString::SkipEmptyParts
444 #endif
445  );
446 }
447 
449  QObject *parent)
450  : QObject(parent), size_threshold(_size_threshold) {}
451 
452 bool ToolTipToRichTextFilter::eventFilter(QObject *obj, QEvent *evt) {
453  if (evt->type() == QEvent::ToolTipChange) {
454  QWidget *widget = static_cast<QWidget *>(obj);
455  QString tooltip = widget->toolTip();
456  if (tooltip.size() > size_threshold && !tooltip.startsWith("<qt") &&
457  !Qt::mightBeRichText(tooltip)) {
458  // Envelop with <qt></qt> to make sure Qt detects this as rich text
459  // Escape the current message as HTML and replace \n by <br>
460  tooltip = "<qt>" + HtmlEscape(tooltip, true) + "</qt>";
461  widget->setToolTip(tooltip);
462  return true;
463  }
464  }
465  return QObject::eventFilter(obj, evt);
466 }
467 
469  : QObject(parent) {}
470 
471 bool LabelOutOfFocusEventFilter::eventFilter(QObject *watched, QEvent *event) {
472  if (event->type() == QEvent::FocusOut) {
473  auto focus_out = static_cast<QFocusEvent *>(event);
474  if (focus_out->reason() != Qt::PopupFocusReason) {
475  auto label = qobject_cast<QLabel *>(watched);
476  if (label) {
477  auto flags = label->textInteractionFlags();
478  label->setTextInteractionFlags(Qt::NoTextInteraction);
479  label->setTextInteractionFlags(flags);
480  }
481  }
482  }
483 
484  return QObject::eventFilter(watched, event);
485 }
486 
488  connect(tableView->horizontalHeader(), &QHeaderView::sectionResized, this,
490  connect(tableView->horizontalHeader(), &QHeaderView::geometriesChanged,
492 }
493 
494 // We need to disconnect these while handling the resize events, otherwise we
495 // can enter infinite loops.
497  disconnect(tableView->horizontalHeader(), &QHeaderView::sectionResized,
499  disconnect(tableView->horizontalHeader(), &QHeaderView::geometriesChanged,
501 } // namespace GUIUtil
502 
503 // Setup the resize mode, handles compatibility for Qt5 and below as the method
504 // signatures changed.
505 // Refactored here for readability.
507  int logicalIndex, QHeaderView::ResizeMode resizeMode) {
508  tableView->horizontalHeader()->setSectionResizeMode(logicalIndex,
509  resizeMode);
510 }
511 
513  int width) {
514  tableView->setColumnWidth(nColumnIndex, width);
515  tableView->horizontalHeader()->resizeSection(nColumnIndex, width);
516 }
517 
519  int nColumnsWidthSum = 0;
520  for (int i = 0; i < columnCount; i++) {
521  nColumnsWidthSum += tableView->horizontalHeader()->sectionSize(i);
522  }
523  return nColumnsWidthSum;
524 }
525 
527  int nResult = lastColumnMinimumWidth;
528  int nTableWidth = tableView->horizontalHeader()->width();
529 
530  if (nTableWidth > 0) {
531  int nOtherColsWidth =
532  getColumnsWidth() -
533  tableView->horizontalHeader()->sectionSize(column);
534  nResult = std::max(nResult, nTableWidth - nOtherColsWidth);
535  }
536 
537  return nResult;
538 }
539 
540 // Make sure we don't make the columns wider than the table's viewport width.
545 
546  int nTableWidth = tableView->horizontalHeader()->width();
547  int nColsWidth = getColumnsWidth();
548  if (nColsWidth > nTableWidth) {
551  }
552 }
553 
554 // Make column use all the space available, useful during window resizing.
557  resizeColumn(column, getAvailableWidthForColumn(column));
559 }
560 
561 // When a section is resized this is a slot-proxy for ajustAmountColumnWidth().
563  int oldSize,
564  int newSize) {
566  int remainingWidth = getAvailableWidthForColumn(logicalIndex);
567  if (newSize > remainingWidth) {
568  resizeColumn(logicalIndex, remainingWidth);
569  }
570 }
571 
572 // When the table's geometry is ready, we manually perform the stretch of the
573 // "Message" column,
574 // as the "Stretch" resize mode does not allow for interactive resizing.
576  if ((getColumnsWidth() - this->tableView->horizontalHeader()->width()) !=
577  0) {
582  }
583 }
584 
590  QTableView *table, int lastColMinimumWidth, int allColsMinimumWidth,
591  QObject *parent)
592  : QObject(parent), tableView(table),
593  lastColumnMinimumWidth(lastColMinimumWidth),
594  allColumnsMinimumWidth(allColsMinimumWidth) {
595  columnCount = tableView->horizontalHeader()->count();
598  tableView->horizontalHeader()->setMinimumSectionSize(
600  setViewHeaderResizeMode(secondToLastColumnIndex, QHeaderView::Interactive);
601  setViewHeaderResizeMode(lastColumnIndex, QHeaderView::Interactive);
602 }
603 
604 #ifdef WIN32
605 static fs::path StartupShortcutPath() {
606  std::string chain = gArgs.GetChainName();
607  if (chain == CBaseChainParams::MAIN) {
608  return GetSpecialFolderPath(CSIDL_STARTUP) / "Bitcoin.lnk";
609  }
610  // Remove this special case when CBaseChainParams::TESTNET = "testnet4"
611  if (chain == CBaseChainParams::TESTNET) {
612  return GetSpecialFolderPath(CSIDL_STARTUP) / "Bitcoin (testnet).lnk";
613  }
614  return GetSpecialFolderPath(CSIDL_STARTUP) /
615  strprintf("Bitcoin (%s).lnk", chain);
616 }
617 
619  // check for Bitcoin*.lnk
620  return fs::exists(StartupShortcutPath());
621 }
622 
623 bool SetStartOnSystemStartup(bool fAutoStart) {
624  // If the shortcut exists already, remove it for updating
625  fs::remove(StartupShortcutPath());
626 
627  if (fAutoStart) {
628  CoInitialize(nullptr);
629 
630  // Get a pointer to the IShellLink interface.
631  IShellLinkW *psl = nullptr;
632  HRESULT hres =
633  CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER,
634  IID_IShellLinkW, reinterpret_cast<void **>(&psl));
635 
636  if (SUCCEEDED(hres)) {
637  // Get the current executable path
638  WCHAR pszExePath[MAX_PATH];
639  GetModuleFileNameW(nullptr, pszExePath, ARRAYSIZE(pszExePath));
640 
641  // Start client minimized
642  QString strArgs = "-min";
643  // Set -testnet /-regtest options
644  strArgs += QString::fromStdString(
645  strprintf(" -chain=%s", gArgs.GetChainName()));
646 
647  // Set the path to the shortcut target
648  psl->SetPath(pszExePath);
649  PathRemoveFileSpecW(pszExePath);
650  psl->SetWorkingDirectory(pszExePath);
651  psl->SetShowCmd(SW_SHOWMINNOACTIVE);
652  psl->SetArguments(strArgs.toStdWString().c_str());
653 
654  // Query IShellLink for the IPersistFile interface for
655  // saving the shortcut in persistent storage.
656  IPersistFile *ppf = nullptr;
657  hres = psl->QueryInterface(IID_IPersistFile,
658  reinterpret_cast<void **>(&ppf));
659  if (SUCCEEDED(hres)) {
660  // Save the link by calling IPersistFile::Save.
661  hres = ppf->Save(StartupShortcutPath().wstring().c_str(), TRUE);
662  ppf->Release();
663  psl->Release();
664  CoUninitialize();
665  return true;
666  }
667  psl->Release();
668  }
669  CoUninitialize();
670  return false;
671  }
672  return true;
673 }
674 #elif defined(Q_OS_LINUX)
675 
676 // Follow the Desktop Application Autostart Spec:
677 // http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html
678 
679 static fs::path GetAutostartDir() {
680  char *pszConfigHome = getenv("XDG_CONFIG_HOME");
681  if (pszConfigHome) {
682  return fs::path(pszConfigHome) / "autostart";
683  }
684  char *pszHome = getenv("HOME");
685  if (pszHome) {
686  return fs::path(pszHome) / ".config" / "autostart";
687  }
688  return fs::path();
689 }
690 
691 static fs::path GetAutostartFilePath() {
692  std::string chain = gArgs.GetChainName();
693  if (chain == CBaseChainParams::MAIN) {
694  return GetAutostartDir() / "bitcoin.desktop";
695  }
696  return GetAutostartDir() / strprintf("bitcoin-%s.desktop", chain);
697 }
698 
700  fsbridge::ifstream optionFile(GetAutostartFilePath());
701  if (!optionFile.good()) {
702  return false;
703  }
704  // Scan through file for "Hidden=true":
705  std::string line;
706  while (!optionFile.eof()) {
707  getline(optionFile, line);
708  if (line.find("Hidden") != std::string::npos &&
709  line.find("true") != std::string::npos) {
710  return false;
711  }
712  }
713  optionFile.close();
714 
715  return true;
716 }
717 
718 bool SetStartOnSystemStartup(bool fAutoStart) {
719  if (!fAutoStart) {
720  fs::remove(GetAutostartFilePath());
721  } else {
722  char pszExePath[MAX_PATH + 1];
723  ssize_t r =
724  readlink("/proc/self/exe", pszExePath, sizeof(pszExePath) - 1);
725  if (r == -1) {
726  return false;
727  }
728  pszExePath[r] = '\0';
729 
730  fs::create_directories(GetAutostartDir());
731 
732  fsbridge::ofstream optionFile(
733  GetAutostartFilePath(), std::ios_base::out | std::ios_base::trunc);
734  if (!optionFile.good()) {
735  return false;
736  }
737  std::string chain = gArgs.GetChainName();
738  // Write a bitcoin.desktop file to the autostart directory:
739  optionFile << "[Desktop Entry]\n";
740  optionFile << "Type=Application\n";
741  if (chain == CBaseChainParams::MAIN) {
742  optionFile << "Name=Bitcoin\n";
743  } else {
744  optionFile << strprintf("Name=Bitcoin (%s)\n", chain);
745  }
746  optionFile << "Exec=" << pszExePath
747  << strprintf(" -min -chain=%s\n", chain);
748  optionFile << "Terminal=false\n";
749  optionFile << "Hidden=false\n";
750  optionFile.close();
751  }
752  return true;
753 }
754 
755 #else
756 
758  return false;
759 }
760 bool SetStartOnSystemStartup(bool fAutoStart) {
761  return false;
762 }
763 
764 #endif
765 
766 void setClipboard(const QString &str) {
767  QApplication::clipboard()->setText(str, QClipboard::Clipboard);
768  QApplication::clipboard()->setText(str, QClipboard::Selection);
769 }
770 
771 fs::path qstringToBoostPath(const QString &path) {
772  return fs::path(path.toStdString());
773 }
774 
775 QString boostPathToQString(const fs::path &path) {
776  return QString::fromStdString(path.string());
777 }
778 
779 QString formatDurationStr(int secs) {
780  QStringList strList;
781  int days = secs / 86400;
782  int hours = (secs % 86400) / 3600;
783  int mins = (secs % 3600) / 60;
784  int seconds = secs % 60;
785 
786  if (days) {
787  strList.append(QString(QObject::tr("%1 d")).arg(days));
788  }
789  if (hours) {
790  strList.append(QString(QObject::tr("%1 h")).arg(hours));
791  }
792  if (mins) {
793  strList.append(QString(QObject::tr("%1 m")).arg(mins));
794  }
795  if (seconds || (!days && !hours && !mins)) {
796  strList.append(QString(QObject::tr("%1 s")).arg(seconds));
797  }
798 
799  return strList.join(" ");
800 }
801 
802 QString formatServicesStr(quint64 mask) {
803  QStringList strList;
804 
805  constexpr uint64_t nonExperimentalMask =
807  for (const auto &flag : serviceFlagsToStr(mask & nonExperimentalMask)) {
808  strList.append(QString::fromStdString(flag));
809  }
810 
811  if (strList.size()) {
812  return strList.join(" & ");
813  } else {
814  return QObject::tr("None");
815  }
816 }
817 
818 QString formatPingTime(int64_t ping_usec) {
819  return (ping_usec == std::numeric_limits<int64_t>::max() || ping_usec == 0)
820  ? QObject::tr("N/A")
821  : QString(QObject::tr("%1 ms"))
822  .arg(QString::number(int(ping_usec / 1000), 10));
823 }
824 
825 QString formatTimeOffset(int64_t nTimeOffset) {
826  return QString(QObject::tr("%1 s"))
827  .arg(QString::number((int)nTimeOffset, 10));
828 }
829 
830 QString formatNiceTimeOffset(qint64 secs) {
831  // Represent time from last generated block in human readable text
832  QString timeBehindText;
833  const int HOUR_IN_SECONDS = 60 * 60;
834  const int DAY_IN_SECONDS = 24 * 60 * 60;
835  const int WEEK_IN_SECONDS = 7 * 24 * 60 * 60;
836  // Average length of year in Gregorian calendar
837  const int YEAR_IN_SECONDS = 31556952;
838  if (secs < 60) {
839  timeBehindText = QObject::tr("%n second(s)", "", secs);
840  } else if (secs < 2 * HOUR_IN_SECONDS) {
841  timeBehindText = QObject::tr("%n minute(s)", "", secs / 60);
842  } else if (secs < 2 * DAY_IN_SECONDS) {
843  timeBehindText = QObject::tr("%n hour(s)", "", secs / HOUR_IN_SECONDS);
844  } else if (secs < 2 * WEEK_IN_SECONDS) {
845  timeBehindText = QObject::tr("%n day(s)", "", secs / DAY_IN_SECONDS);
846  } else if (secs < YEAR_IN_SECONDS) {
847  timeBehindText = QObject::tr("%n week(s)", "", secs / WEEK_IN_SECONDS);
848  } else {
849  qint64 years = secs / YEAR_IN_SECONDS;
850  qint64 remainder = secs % YEAR_IN_SECONDS;
851  timeBehindText = QObject::tr("%1 and %2")
852  .arg(QObject::tr("%n year(s)", "", years))
853  .arg(QObject::tr("%n week(s)", "",
854  remainder / WEEK_IN_SECONDS));
855  }
856  return timeBehindText;
857 }
858 
859 QString formatBytes(uint64_t bytes) {
860  if (bytes < 1024) {
861  return QString(QObject::tr("%1 B")).arg(bytes);
862  }
863  if (bytes < 1024 * 1024) {
864  return QString(QObject::tr("%1 KB")).arg(bytes / 1024);
865  }
866  if (bytes < 1024 * 1024 * 1024) {
867  return QString(QObject::tr("%1 MB")).arg(bytes / 1024 / 1024);
868  }
869 
870  return QString(QObject::tr("%1 GB")).arg(bytes / 1024 / 1024 / 1024);
871 }
872 
874 #if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
875  return !pixmap(Qt::ReturnByValue).isNull();
876 #else
877  return pixmap() != nullptr;
878 #endif
879 }
880 
881 qreal calculateIdealFontSize(int width, const QString &text, QFont font,
882  qreal minPointSize, qreal font_size) {
883  while (font_size >= minPointSize) {
884  font.setPointSizeF(font_size);
885  QFontMetrics fm(font);
886  if (GUIUtil::TextWidth(fm, text) < width) {
887  break;
888  }
889  font_size -= 0.5;
890  }
891  return font_size;
892 }
893 
894 void ClickableLabel::mouseReleaseEvent(QMouseEvent *event) {
895  Q_EMIT clicked(event->pos());
896 }
897 
898 void ClickableProgressBar::mouseReleaseEvent(QMouseEvent *event) {
899  Q_EMIT clicked(event->pos());
900 }
901 
902 bool ItemDelegate::eventFilter(QObject *object, QEvent *event) {
903  if (event->type() == QEvent::KeyPress) {
904  if (static_cast<QKeyEvent *>(event)->key() == Qt::Key_Escape) {
905  Q_EMIT keyEscapePressed();
906  }
907  }
908  return QItemDelegate::eventFilter(object, event);
909 }
910 
911 int TextWidth(const QFontMetrics &fm, const QString &text) {
912 #if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0))
913  return fm.horizontalAdvance(text);
914 #else
915  return fm.width(text);
916 #endif
917 }
918 
919 void PolishProgressDialog(QProgressDialog *dialog) {
920 #ifdef Q_OS_MAC
921  // Workaround for macOS-only Qt bug; see: QTBUG-65750, QTBUG-70357.
922  const int margin = GUIUtil::TextWidth(dialog->fontMetrics(), "X");
923  dialog->resize(dialog->width() + 2 * margin, dialog->height());
924  dialog->show();
925 #else
926  Q_UNUSED(dialog);
927 #endif
928 }
929 
930 void LogQtInfo() {
931 #ifdef QT_STATIC
932  const std::string qt_link{"static"};
933 #else
934  const std::string qt_link{"dynamic"};
935 #endif
936 #ifdef QT_STATICPLUGIN
937  const std::string plugin_link{"static"};
938 #else
939  const std::string plugin_link{"dynamic"};
940 #endif
941  LogPrintf("Qt %s (%s), plugin=%s (%s)\n", qVersion(), qt_link,
942  QGuiApplication::platformName().toStdString(), plugin_link);
943  LogPrintf("System: %s, %s\n", QSysInfo::prettyProductName().toStdString(),
944  QSysInfo::buildAbi().toStdString());
945  for (const QScreen *s : QGuiApplication::screens()) {
946  LogPrintf("Screen: %s %dx%d, pixel ratio=%.1f\n",
947  s->name().toStdString(), s->size().width(),
948  s->size().height(), s->devicePixelRatio());
949  }
950 }
951 
952 void PopupMenu(QMenu *menu, const QPoint &point, QAction *at_action) {
953  // The qminimal plugin does not provide window system integration.
954  if (QApplication::platformName() == "minimal") {
955  return;
956  }
957  menu->popup(point, at_action);
958 }
959 
960 } // namespace GUIUtil
GUIUtil::TableViewLastColumnResizingFixer::on_geometriesChanged
void on_geometriesChanged()
Definition: guiutil.cpp:575
QValidatedLineEdit::setCheckValidator
void setCheckValidator(const QValidator *v)
Definition: qvalidatedlineedit.cpp:88
policy.h
GUIUtil::TableViewLastColumnResizingFixer::connectViewHeadersSignals
void connectViewHeadersSignals()
Definition: guiutil.cpp:487
BitcoinUnits::SeparatorStyle::NEVER
@ NEVER
GUIUtil::boostPathToQString
QString boostPathToQString(const fs::path &path)
Definition: guiutil.cpp:775
fsbridge::ifstream
fs::ifstream ifstream
Definition: fs.h:98
GUIUtil::openBitcoinConf
bool openBitcoinConf()
Definition: guiutil.cpp:411
GUIUtil::PopupMenu
void PopupMenu(QMenu *menu, const QPoint &point, QAction *at_action)
Call QMenu::popup() only on supported QT_QPA_PLATFORM.
Definition: guiutil.cpp:952
GUIUtil::TableViewLastColumnResizingFixer::columnCount
int columnCount
Definition: guiutil.h:237
GetConfigFile
fs::path GetConfigFile(const std::string &confPath)
Definition: system.cpp:831
GetDataDir
const fs::path & GetDataDir(bool fNetSpecific)
Definition: system.cpp:779
BitcoinAddressCheckValidator
Bitcoin address widget validator, checks for a valid bitcoin address.
Definition: bitcoinaddressvalidator.h:30
SendCoinsRecipient::amount
Amount amount
Definition: sendcoinsrecipient.h:41
BitcoinUnits::parse
static bool parse(int unit, const QString &value, Amount *val_out)
Parse string to coin amount.
Definition: bitcoinunits.cpp:189
flags
int flags
Definition: bitcoin-tx.cpp:532
key_io.h
GUIUtil::SetStartOnSystemStartup
bool SetStartOnSystemStartup(bool fAutoStart)
Definition: guiutil.cpp:760
GUIUtil::TableViewLastColumnResizingFixer::TableViewLastColumnResizingFixer
TableViewLastColumnResizingFixer(QTableView *table, int lastColMinimumWidth, int allColsMinimumWidth, QObject *parent)
Initializes all internal variables and prepares the the resize modes of the last 2 columns of the tab...
Definition: guiutil.cpp:589
GUIUtil::TableViewLastColumnResizingFixer::resizeColumn
void resizeColumn(int nColumnIndex, int width)
Definition: guiutil.cpp:512
transaction.h
GUIUtil::DummyAddress
std::string DummyAddress(const CChainParams &params)
Definition: guiutil.cpp:95
GetScriptForDestination
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
Definition: standard.cpp:243
GUIUtil::ItemDelegate::eventFilter
bool eventFilter(QObject *object, QEvent *event) override
Definition: guiutil.cpp:902
GUIUtil::ClickableProgressBar::clicked
void clicked(const QPoint &point)
Emitted when the progressbar is clicked.
ArgsManager::GetChainName
std::string GetChainName() const
Looks for -regtest, -testnet and returns the appropriate BIP70 chain name.
Definition: system.cpp:1033
SendCoinsRecipient::label
QString label
Definition: sendcoinsrecipient.h:40
node.h
CBaseChainParams::TESTNET
static const std::string TESTNET
Definition: chainparamsbase.h:22
GUIUtil
Utility functions used by the Bitcoin Qt UI.
Definition: bitcoingui.h:58
CChainParams
CChainParams defines various tweakable parameters of a given instance of the Bitcoin system.
Definition: chainparams.h:47
GUIUtil::openDebugLogfile
void openDebugLogfile()
Definition: guiutil.cpp:401
GUIUtil::hasEntryData
bool hasEntryData(const QAbstractItemView *view, int column, int role)
Returns true if the specified field of the currently selected view entry is not empty.
Definition: guiutil.cpp:271
GUIUtil::TableViewLastColumnResizingFixer::stretchColumnWidth
void stretchColumnWidth(int column)
Definition: guiutil.cpp:555
GUIUtil::splitSkipEmptyParts
QStringList splitSkipEmptyParts(const QString &s, const QString &separator)
Definition: guiutil.cpp:438
GUIUtil::formatBitcoinURI
QString formatBitcoinURI(const SendCoinsRecipient &info)
Definition: guiutil.cpp:199
GUIUtil::bringToFront
void bringToFront(QWidget *w)
Definition: guiutil.cpp:379
chainparams.h
GUIUtil::qstringToBoostPath
fs::path qstringToBoostPath(const QString &path)
Definition: guiutil.cpp:771
GUIUtil::ItemDelegate::keyEscapePressed
void keyEscapePressed()
GUIUtil::TableViewLastColumnResizingFixer::tableView
QTableView * tableView
Definition: guiutil.h:233
GUIUtil::convertToCashAddr
QString convertToCashAddr(const CChainParams &params, const QString &addr)
Definition: guiutil.cpp:110
GUIUtil::formatPingTime
QString formatPingTime(int64_t ping_usec)
Definition: guiutil.cpp:818
GUIUtil::isObscured
bool isObscured(QWidget *w)
Definition: guiutil.cpp:371
BitcoinUnits::format
static QString format(int unit, const Amount amount, bool plussign=false, SeparatorStyle separators=SeparatorStyle::STANDARD, bool justify=false)
Format as string.
Definition: bitcoinunits.cpp:108
GUIUtil::setClipboard
void setClipboard(const QString &str)
Definition: guiutil.cpp:766
Amount::zero
static constexpr Amount zero()
Definition: amount.h:42
GUIUtil::fixedPitchFont
QFont fixedPitchFont()
Definition: guiutil.cpp:76
fsbridge::ofstream
fs::ofstream ofstream
Definition: fs.h:99
strencodings.h
SendCoinsRecipient
Definition: sendcoinsrecipient.h:23
GUIUtil::MakeAddrInvalid
static std::string MakeAddrInvalid(std::string addr, const CChainParams &params)
Definition: guiutil.cpp:80
GUIUtil::checkPoint
bool checkPoint(const QPoint &p, const QWidget *w)
Definition: guiutil.cpp:363
GUIUtil::formatTimeOffset
QString formatTimeOffset(int64_t nTimeOffset)
Definition: guiutil.cpp:825
GUIUtil::getOpenFileName
QString getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedSuffixOut)
Get open filename, convenience wrapper for QFileDialog::getOpenFileName.
Definition: guiutil.cpp:326
GUIUtil::formatNiceTimeOffset
QString formatNiceTimeOffset(qint64 secs)
Definition: guiutil.cpp:830
GetDefaultDataDir
fs::path GetDefaultDataDir()
Definition: system.cpp:722
CTxOut
An output of a transaction.
Definition: transaction.h:130
GUIUtil::TableViewLastColumnResizingFixer::secondToLastColumnIndex
int secondToLastColumnIndex
Definition: guiutil.h:238
GUIUtil::TableViewLastColumnResizingFixer::getAvailableWidthForColumn
int getAvailableWidthForColumn(int column)
Definition: guiutil.cpp:526
EncodeCashAddr
std::string EncodeCashAddr(const CTxDestination &dst, const CChainParams &params)
Definition: cashaddrenc.cpp:91
GUIUtil::ClickableLabel::clicked
void clicked(const QPoint &point)
Emitted when the label is clicked.
GUIUtil::ClickableLabel::mouseReleaseEvent
void mouseReleaseEvent(QMouseEvent *event) override
Definition: guiutil.cpp:894
GUIUtil::LabelOutOfFocusEventFilter::eventFilter
bool eventFilter(QObject *watched, QEvent *event) override
Definition: guiutil.cpp:471
GUIUtil::isDust
bool isDust(interfaces::Node &node, const QString &address, const Amount amount, const CChainParams &chainParams)
Definition: guiutil.cpp:232
ArgsManager::GetArg
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
Definition: system.cpp:498
GUIUtil::PolishProgressDialog
void PolishProgressDialog(QProgressDialog *dialog)
Definition: guiutil.cpp:919
QValidatedLineEdit
Line edit that can be marked as "invalid" to show input validation feedback.
Definition: qvalidatedlineedit.h:14
standard.h
GUIUtil::TableViewLastColumnResizingFixer::adjustTableColumnsWidth
void adjustTableColumnsWidth()
Definition: guiutil.cpp:541
guiutil.h
BitcoinAddressEntryValidator
Bitcoin address entry widget validator, checks for valid characters and removes some whitespace.
Definition: bitcoinaddressvalidator.h:15
GUIUtil::TableViewLastColumnResizingFixer::getColumnsWidth
int getColumnsWidth()
Definition: guiutil.cpp:518
GUIUtil::TableViewLastColumnResizingFixer::disconnectViewHeadersSignals
void disconnectViewHeadersSignals()
Definition: guiutil.cpp:496
GUIUtil::formatBytes
QString formatBytes(uint64_t bytes)
Definition: guiutil.cpp:859
Amount
Definition: amount.h:19
GUIUtil::formatServicesStr
QString formatServicesStr(quint64 mask)
Definition: guiutil.cpp:802
CScript
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:430
GUIUtil::getDefaultDataDirectory
QString getDefaultDataDirectory()
Determine default data directory for operating system.
Definition: guiutil.cpp:279
interfaces::Node
Top-level interface for a bitcoin node (bitcoind process).
Definition: node.h:55
qvalidatedlineedit.h
CBaseChainParams::MAIN
static const std::string MAIN
BIP70 chain name strings (main, test or regtest)
Definition: chainparamsbase.h:21
GUIUtil::ToolTipToRichTextFilter::eventFilter
bool eventFilter(QObject *obj, QEvent *evt) override
Definition: guiutil.cpp:452
SUCCEEDED
@ SUCCEEDED
Succeeded.
Definition: netbase.cpp:311
GUIUtil::getSaveFileName
QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedSuffixOut)
Get save filename, mimics QFileDialog::getSaveFileName, except that it appends a default suffix when ...
Definition: guiutil.cpp:283
interfaces::Node::getDustRelayFee
virtual CFeeRate getDustRelayFee()=0
Get dust relay fee.
system.h
PKHash
Definition: standard.h:106
strprintf
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1201
GUIUtil::LabelOutOfFocusEventFilter::LabelOutOfFocusEventFilter
LabelOutOfFocusEventFilter(QObject *parent)
Definition: guiutil.cpp:468
GUIUtil::GetStartOnSystemStartup
bool GetStartOnSystemStartup()
Definition: guiutil.cpp:757
uint160
160-bit opaque blob.
Definition: uint256.h:115
GUIUtil::HtmlEscape
QString HtmlEscape(const QString &str, bool fMultiLine)
Definition: guiutil.cpp:240
bitcoinaddressvalidator.h
GUIUtil::copyEntryData
void copyEntryData(const QAbstractItemView *view, int column, int role)
Copy a field of the currently selected entry of a view to the clipboard.
Definition: guiutil.cpp:252
NODE_LAST_NON_EXPERIMENTAL_SERVICE_BIT
@ NODE_LAST_NON_EXPERIMENTAL_SERVICE_BIT
Definition: protocol.h:347
SendCoinsRecipient::address
QString address
Definition: sendcoinsrecipient.h:39
gArgs
ArgsManager gArgs
Definition: system.cpp:75
GUIUtil::ToolTipToRichTextFilter::size_threshold
int size_threshold
Definition: guiutil.h:194
GUIUtil::TableViewLastColumnResizingFixer::lastColumnMinimumWidth
int lastColumnMinimumWidth
Definition: guiutil.h:234
GUIUtil::ClickableLabel::hasPixmap
bool hasPixmap() const
Definition: guiutil.cpp:873
GUIUtil::TableViewLastColumnResizingFixer::on_sectionResized
void on_sectionResized(int logicalIndex, int oldSize, int newSize)
Definition: guiutil.cpp:562
GUIUtil::blockingGUIThreadConnection
Qt::ConnectionType blockingGUIThreadConnection()
Get connection type to call object slot in GUI thread with invokeMethod.
Definition: guiutil.cpp:355
GUIUtil::LogQtInfo
void LogQtInfo()
Writes to debug.log short info about the used Qt and the host system.
Definition: guiutil.cpp:930
Params
const CChainParams & Params()
Return the currently selected parameters.
Definition: chainparams.cpp:508
IsDust
bool IsDust(const CTxOut &txout, const CFeeRate &dustRelayFeeIn)
Definition: policy.cpp:34
bitcoinunits.h
IsValidDestinationString
bool IsValidDestinationString(const std::string &str, const CChainParams &params)
Definition: key_io.cpp:186
ForceActivation
void ForceActivation()
Force application activation on macOS.
Definition: macdockiconhandler.mm:48
GUIUtil::ClickableProgressBar::mouseReleaseEvent
void mouseReleaseEvent(QMouseEvent *event) override
Definition: guiutil.cpp:898
GUIUtil::ToolTipToRichTextFilter::ToolTipToRichTextFilter
ToolTipToRichTextFilter(int size_threshold, QObject *parent=0)
Definition: guiutil.cpp:448
BITCOIN_CONF_FILENAME
const char *const BITCOIN_CONF_FILENAME
Definition: system.cpp:72
GUIUtil::calculateIdealFontSize
qreal calculateIdealFontSize(int width, const QString &text, QFont font, qreal minPointSize, qreal font_size)
Definition: guiutil.cpp:881
GUIUtil::formatDurationStr
QString formatDurationStr(int secs)
Definition: guiutil.cpp:779
GUIUtil::TextWidth
int TextWidth(const QFontMetrics &fm, const QString &text)
Returns the distance in pixels appropriate for drawing a subsequent character after text.
Definition: guiutil.cpp:911
script.h
GUIUtil::dateTimeStr
QString dateTimeStr(const QDateTime &date)
Definition: guiutil.cpp:67
GUIUtil::handleCloseWindowShortcut
void handleCloseWindowShortcut(QWidget *w)
Definition: guiutil.cpp:396
GUIUtil::getEntryData
QList< QModelIndex > getEntryData(const QAbstractItemView *view, int column)
Return a field of the currently selected entry as a QString.
Definition: guiutil.cpp:264
BitcoinUnits::base
@ base
Definition: bitcoinunits.h:42
DecodeDestination
CTxDestination DecodeDestination(const std::string &addr, const CChainParams &params)
Definition: key_io.cpp:177
GUIUtil::setupAddressWidget
void setupAddressWidget(QValidatedLineEdit *widget, QWidget *parent)
Definition: guiutil.cpp:119
GUIUtil::parseBitcoinURI
bool parseBitcoinURI(const QString &scheme, const QUrl &uri, SendCoinsRecipient *out)
Definition: guiutil.cpp:133
ConnectionType
ConnectionType
Different types of connections to a peer.
Definition: net.h:154
MAX_PATH
#define MAX_PATH
Definition: compat.h:65
GUIUtil::TableViewLastColumnResizingFixer::lastColumnIndex
int lastColumnIndex
Definition: guiutil.h:236
CTxDestination
boost::variant< CNoDestination, PKHash, ScriptHash > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:132
serviceFlagsToStr
std::vector< std::string > serviceFlagsToStr(const uint64_t flags)
Convert service flags (a bitmask of NODE_*) to human readable strings.
Definition: protocol.cpp:280
cashaddrenc.h
LogPrintf
static void LogPrintf(const char *fmt, const Args &... args)
Definition: logging.h:175
GUIUtil::TableViewLastColumnResizingFixer::setViewHeaderResizeMode
void setViewHeaderResizeMode(int logicalIndex, QHeaderView::ResizeMode resizeMode)
Definition: guiutil.cpp:506
sendcoinsrecipient.h
GUIUtil::TableViewLastColumnResizingFixer::allColumnsMinimumWidth
int allColumnsMinimumWidth
Definition: guiutil.h:235
SendCoinsRecipient::message
QString message
Definition: sendcoinsrecipient.h:43