Raven Core  3.0.0
P2P Digital Currency
guiutil.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2016 The Bitcoin Core developers
2 // Copyright (c) 2017-2019 The Raven 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 #include "guiutil.h"
7 
9 #include "ravenunits.h"
10 #include "qvalidatedlineedit.h"
11 #include "walletmodel.h"
12 
13 #include "fs.h"
14 #include "primitives/transaction.h"
15 #include "init.h"
16 #include "policy/policy.h"
17 #include "protocol.h"
18 #include "script/script.h"
19 #include "script/standard.h"
20 #include "util.h"
21 
22 #ifdef WIN32
23 #ifdef _WIN32_WINNT
24 #undef _WIN32_WINNT
25 #endif
26 #define _WIN32_WINNT 0x0501
27 #ifdef _WIN32_IE
28 #undef _WIN32_IE
29 #endif
30 #define _WIN32_IE 0x0501
31 #define WIN32_LEAN_AND_MEAN 1
32 #ifndef NOMINMAX
33 #define NOMINMAX
34 #endif
35 #include "shellapi.h"
36 #include "shlobj.h"
37 #include "shlwapi.h"
38 #endif
39 
40 #include <boost/scoped_array.hpp>
41 
42 #include <QAbstractItemView>
43 #include <QApplication>
44 #include <QClipboard>
45 #include <QDateTime>
46 #include <QDesktopServices>
47 #include <QDesktopWidget>
48 #include <QDoubleValidator>
49 #include <QFileDialog>
50 #include <QFont>
51 #include <QLineEdit>
52 #include <QSettings>
53 #include <QTextDocument> // for Qt::mightBeRichText
54 #include <QThread>
55 #include <QMouseEvent>
56 #include <QPainter>
57 
58 #if QT_VERSION < 0x050000
59 #include <QUrl>
60 #else
61 #include <QUrlQuery>
62 #endif
63 
64 #if QT_VERSION >= 0x50200
65 #include <QFontDatabase>
66 #endif
67 
68 static fs::detail::utf8_codecvt_facet utf8;
69 
70 #if defined(Q_OS_MAC)
71 extern double NSAppKitVersionNumber;
72 #if !defined(NSAppKitVersionNumber10_8)
73 #define NSAppKitVersionNumber10_8 1187
74 #endif
75 #if !defined(NSAppKitVersionNumber10_9)
76 #define NSAppKitVersionNumber10_9 1265
77 #endif
78 #endif
79 
80 #include <QGraphicsDropShadowEffect>
81 #include "guiconstants.h"
82 #include "platformstyle.h"
83 
84 namespace GUIUtil {
85 
87 {
88  QFont labelSubFont;
89 #if !defined(Q_OS_MAC)
90  labelSubFont.setFamily("Open Sans");
91 #endif
92  labelSubFont.setWeight(QFont::Weight::ExtraLight);
93  labelSubFont.setLetterSpacing(QFont::SpacingType::AbsoluteSpacing, -0.6);
94  labelSubFont.setPixelSize(14);
95  return labelSubFont;
96 }
97 
99 {
100  QFont labelSubFont;
101 #if !defined(Q_OS_MAC)
102  labelSubFont.setFamily("Open Sans");
103 #endif
104  labelSubFont.setWeight(QFont::Weight::Bold);
105  labelSubFont.setLetterSpacing(QFont::SpacingType::AbsoluteSpacing, -0.6);
106  labelSubFont.setPixelSize(14);
107  return labelSubFont;
108 }
109 
111 {
112  QFont labelTopFont;
113 #if !defined(Q_OS_MAC)
114  labelTopFont.setFamily("Open Sans");
115 #endif
116  labelTopFont.setWeight(QFont::Weight::Bold);
117  labelTopFont.setLetterSpacing(QFont::SpacingType::AbsoluteSpacing, -0.6);
118  labelTopFont.setPixelSize(18);
119  return labelTopFont;
120 }
121 
122 QFont getTopLabelFont(int weight, int pxsize)
123 {
124  QFont labelTopFont;
125 #if !defined(Q_OS_MAC)
126  labelTopFont.setFamily("Open Sans");
127 #endif
128  labelTopFont.setWeight(weight);
129  labelTopFont.setLetterSpacing(QFont::SpacingType::AbsoluteSpacing, -0.6);
130  labelTopFont.setPixelSize(pxsize);
131  return labelTopFont;
132 }
133 
135 {
136  QFont labelTopFont;
137 #if !defined(Q_OS_MAC)
138  labelTopFont.setFamily("Open Sans");
139 #endif
140  labelTopFont.setWeight(QFont::Weight::Light);
141  labelTopFont.setLetterSpacing(QFont::SpacingType::AbsoluteSpacing, -0.6);
142  labelTopFont.setPixelSize(18);
143  return labelTopFont;
144 }
145 
146 QGraphicsDropShadowEffect* getShadowEffect()
147 {
148 #if defined(Q_OS_MAC)
149  return nullptr;
150 #endif
151  QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect;
152  shadow->setBlurRadius(50);
154  shadow->setOffset(8.0);
155  return shadow;
156 }
157 
158 QString dateTimeStr(const QDateTime &date)
159 {
160  return date.date().toString(Qt::SystemLocaleShortDate) + QString(" ") + date.toString("hh:mm");
161 }
162 
163 QString dateTimeStr(qint64 nTime)
164 {
165  return dateTimeStr(QDateTime::fromTime_t((qint32)nTime));
166 }
167 
169 {
170 #if QT_VERSION >= 0x50200
171  return QFontDatabase::systemFont(QFontDatabase::FixedFont);
172 #else
173  QFont font("Monospace");
174 #if QT_VERSION >= 0x040800
175  font.setStyleHint(QFont::Monospace);
176 #else
177  font.setStyleHint(QFont::TypeWriter);
178 #endif
179  return font;
180 #endif
181 }
182 
183 // Just some dummy data to generate an convincing random-looking (but consistent) address
184 static const uint8_t dummydata[] = {0xeb,0x15,0x23,0x1d,0xfc,0xeb,0x60,0x92,0x58,0x86,0xb6,0x7d,0x06,0x52,0x99,0x92,0x59,0x15,0xae,0xb1,0x72,0xc0,0x66,0x47};
185 
186 // Generate a dummy address with invalid CRC, starting with the network prefix.
187 static std::string DummyAddress(const CChainParams &params)
188 {
189  std::vector<unsigned char> sourcedata = params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
190  sourcedata.insert(sourcedata.end(), dummydata, dummydata + sizeof(dummydata));
191  for(int i=0; i<256; ++i) { // Try every trailing byte
192  std::string s = EncodeBase58(sourcedata.data(), sourcedata.data() + sourcedata.size());
193  if (!IsValidDestinationString(s)) {
194  return s;
195  }
196  sourcedata[sourcedata.size()-1] += 1;
197  }
198  return "";
199 }
200 
201 void setupAddressWidget(QValidatedLineEdit *widget, QWidget *parent)
202 {
203  parent->setFocusProxy(widget);
204 
205  widget->setFont(getSubLabelFont());
206 #if QT_VERSION >= 0x040700
207  // We don't want translators to use own addresses in translations
208  // and this is the only place, where this address is supplied.
209  widget->setPlaceholderText(QObject::tr("Enter a Raven address (e.g. %1)").arg(
210  QString::fromStdString(DummyAddress(Params()))));
211 #endif
212  widget->setValidator(new RavenAddressEntryValidator(parent));
213  widget->setCheckValidator(new RavenAddressCheckValidator(parent));
214 }
215 
216 void setupAmountWidget(QLineEdit *widget, QWidget *parent)
217 {
218  QDoubleValidator *amountValidator = new QDoubleValidator(parent);
219  amountValidator->setDecimals(8);
220  amountValidator->setBottom(0.0);
221  widget->setValidator(amountValidator);
222  widget->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
223 }
224 
225 bool parseRavenURI(const QUrl &uri, SendCoinsRecipient *out)
226 {
227  // return if URI is not valid or is no raven: URI
228  if(!uri.isValid() || uri.scheme() != QString("raven"))
229  return false;
230 
232  rv.address = uri.path();
233  // Trim any following forward slash which may have been added by the OS
234  if (rv.address.endsWith("/")) {
235  rv.address.truncate(rv.address.length() - 1);
236  }
237  rv.amount = 0;
238 
239 #if QT_VERSION < 0x050000
240  QList<QPair<QString, QString> > items = uri.queryItems();
241 #else
242  QUrlQuery uriQuery(uri);
243  QList<QPair<QString, QString> > items = uriQuery.queryItems();
244 #endif
245  for (QList<QPair<QString, QString> >::iterator i = items.begin(); i != items.end(); i++)
246  {
247  bool fShouldReturnFalse = false;
248  if (i->first.startsWith("req-"))
249  {
250  i->first.remove(0, 4);
251  fShouldReturnFalse = true;
252  }
253 
254  if (i->first == "label")
255  {
256  rv.label = i->second;
257  fShouldReturnFalse = false;
258  }
259  if (i->first == "message")
260  {
261  rv.message = i->second;
262  fShouldReturnFalse = false;
263  }
264  else if (i->first == "amount")
265  {
266  if(!i->second.isEmpty())
267  {
268  if(!RavenUnits::parse(RavenUnits::RVN, i->second, &rv.amount))
269  {
270  return false;
271  }
272  }
273  fShouldReturnFalse = false;
274  }
275 
276  if (fShouldReturnFalse)
277  return false;
278  }
279  if(out)
280  {
281  *out = rv;
282  }
283  return true;
284 }
285 
286 bool parseRavenURI(QString uri, SendCoinsRecipient *out)
287 {
288  // Convert raven:// to raven:
289  //
290  // Cannot handle this later, because raven:// will cause Qt to see the part after // as host,
291  // which will lower-case it (and thus invalidate the address).
292  if(uri.startsWith("raven://", Qt::CaseInsensitive))
293  {
294  uri.replace(0, 10, "raven:");
295  }
296  QUrl uriInstance(uri);
297  return parseRavenURI(uriInstance, out);
298 }
299 
300 QString formatRavenURI(const SendCoinsRecipient &info)
301 {
302  QString ret = QString("raven:%1").arg(info.address);
303  int paramCount = 0;
304 
305  if (info.amount)
306  {
307  ret += QString("?amount=%1").arg(RavenUnits::format(RavenUnits::RVN, info.amount, false, RavenUnits::separatorNever));
308  paramCount++;
309  }
310 
311  if (!info.label.isEmpty())
312  {
313  QString lbl(QUrl::toPercentEncoding(info.label));
314  ret += QString("%1label=%2").arg(paramCount == 0 ? "?" : "&").arg(lbl);
315  paramCount++;
316  }
317 
318  if (!info.message.isEmpty())
319  {
320  QString msg(QUrl::toPercentEncoding(info.message));
321  ret += QString("%1message=%2").arg(paramCount == 0 ? "?" : "&").arg(msg);
322  paramCount++;
323  }
324 
325  return ret;
326 }
327 
328 bool isDust(const QString& address, const CAmount& amount)
329 {
330  CTxDestination dest = DecodeDestination(address.toStdString());
331  CScript script = GetScriptForDestination(dest);
332  CTxOut txOut(amount, script);
333  return IsDust(txOut, ::dustRelayFee);
334 }
335 
336 QString HtmlEscape(const QString& str, bool fMultiLine)
337 {
338 #if QT_VERSION < 0x050000
339  QString escaped = Qt::escape(str);
340 #else
341  QString escaped = str.toHtmlEscaped();
342 #endif
343  if(fMultiLine)
344  {
345  escaped = escaped.replace("\n", "<br>\n");
346  }
347  return escaped;
348 }
349 
350 QString HtmlEscape(const std::string& str, bool fMultiLine)
351 {
352  return HtmlEscape(QString::fromStdString(str), fMultiLine);
353 }
354 
355 void copyEntryData(QAbstractItemView *view, int column, int role)
356 {
357  if(!view || !view->selectionModel())
358  return;
359  QModelIndexList selection = view->selectionModel()->selectedRows(column);
360 
361  if(!selection.isEmpty())
362  {
363  // Copy first item
364  setClipboard(selection.at(0).data(role).toString());
365  }
366 }
367 
368 QList<QModelIndex> getEntryData(QAbstractItemView *view, int column)
369 {
370  if(!view || !view->selectionModel())
371  return QList<QModelIndex>();
372  return view->selectionModel()->selectedRows(column);
373 }
374 
375 QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir,
376  const QString &filter,
377  QString *selectedSuffixOut)
378 {
379  QString selectedFilter;
380  QString myDir;
381  if(dir.isEmpty()) // Default to user documents location
382  {
383 #if QT_VERSION < 0x050000
384  myDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation);
385 #else
386  myDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
387 #endif
388  }
389  else
390  {
391  myDir = dir;
392  }
393  /* Directly convert path to native OS path separators */
394  QString result = QDir::toNativeSeparators(QFileDialog::getSaveFileName(parent, caption, myDir, filter, &selectedFilter));
395 
396  /* Extract first suffix from filter pattern "Description (*.foo)" or "Description (*.foo *.bar ...) */
397  QRegExp filter_re(".* \\(\\*\\.(.*)[ \\)]");
398  QString selectedSuffix;
399  if(filter_re.exactMatch(selectedFilter))
400  {
401  selectedSuffix = filter_re.cap(1);
402  }
403 
404  /* Add suffix if needed */
405  QFileInfo info(result);
406  if(!result.isEmpty())
407  {
408  if(info.suffix().isEmpty() && !selectedSuffix.isEmpty())
409  {
410  /* No suffix specified, add selected suffix */
411  if(!result.endsWith("."))
412  result.append(".");
413  result.append(selectedSuffix);
414  }
415  }
416 
417  /* Return selected suffix if asked to */
418  if(selectedSuffixOut)
419  {
420  *selectedSuffixOut = selectedSuffix;
421  }
422  return result;
423 }
424 
425 QString getOpenFileName(QWidget *parent, const QString &caption, const QString &dir,
426  const QString &filter,
427  QString *selectedSuffixOut)
428 {
429  QString selectedFilter;
430  QString myDir;
431  if(dir.isEmpty()) // Default to user documents location
432  {
433 #if QT_VERSION < 0x050000
434  myDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation);
435 #else
436  myDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
437 #endif
438  }
439  else
440  {
441  myDir = dir;
442  }
443  /* Directly convert path to native OS path separators */
444  QString result = QDir::toNativeSeparators(QFileDialog::getOpenFileName(parent, caption, myDir, filter, &selectedFilter));
445 
446  if(selectedSuffixOut)
447  {
448  /* Extract first suffix from filter pattern "Description (*.foo)" or "Description (*.foo *.bar ...) */
449  QRegExp filter_re(".* \\(\\*\\.(.*)[ \\)]");
450  QString selectedSuffix;
451  if(filter_re.exactMatch(selectedFilter))
452  {
453  selectedSuffix = filter_re.cap(1);
454  }
455  *selectedSuffixOut = selectedSuffix;
456  }
457  return result;
458 }
459 
460 Qt::ConnectionType blockingGUIThreadConnection()
461 {
462  if(QThread::currentThread() != qApp->thread())
463  {
464  return Qt::BlockingQueuedConnection;
465  }
466  else
467  {
468  return Qt::DirectConnection;
469  }
470 }
471 
472 bool checkPoint(const QPoint &p, const QWidget *w)
473 {
474  QWidget *atW = QApplication::widgetAt(w->mapToGlobal(p));
475  if (!atW) return false;
476  return atW->topLevelWidget() == w;
477 }
478 
479 bool isObscured(QWidget *w)
480 {
481  return !(checkPoint(QPoint(0, 0), w)
482  && checkPoint(QPoint(w->width() - 1, 0), w)
483  && checkPoint(QPoint(0, w->height() - 1), w)
484  && checkPoint(QPoint(w->width() - 1, w->height() - 1), w)
485  && checkPoint(QPoint(w->width() / 2, w->height() / 2), w));
486 }
487 
489 {
490  fs::path pathDebug = GetDataDir() / "debug.log";
491 
492  /* Open debug.log with the associated application */
493  if (fs::exists(pathDebug))
494  QDesktopServices::openUrl(QUrl::fromLocalFile(boostPathToQString(pathDebug)));
495 }
496 
498 {
499  boost::filesystem::path pathConfig = GetConfigFile(RAVEN_CONF_FILENAME);
500 
501  /* Create the file */
502  boost::filesystem::ofstream configFile(pathConfig, std::ios_base::app);
503 
504  if (!configFile.good())
505  return false;
506 
507  configFile.close();
508 
509  /* Open raven.conf with the associated application */
510  return QDesktopServices::openUrl(QUrl::fromLocalFile(boostPathToQString(pathConfig)));
511 }
512 
513 void SubstituteFonts(const QString& language)
514 {
515 #if defined(Q_OS_MAC)
516 // Background:
517 // OSX's default font changed in 10.9 and Qt is unable to find it with its
518 // usual fallback methods when building against the 10.7 sdk or lower.
519 // The 10.8 SDK added a function to let it find the correct fallback font.
520 // If this fallback is not properly loaded, some characters may fail to
521 // render correctly.
522 //
523 // The same thing happened with 10.10. .Helvetica Neue DeskInterface is now default.
524 //
525 // Solution: If building with the 10.7 SDK or lower and the user's platform
526 // is 10.9 or higher at runtime, substitute the correct font. This needs to
527 // happen before the QApplication is created.
528 #if defined(MAC_OS_X_VERSION_MAX_ALLOWED) && MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8
529  if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_8)
530  {
531  if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_9)
532  /* On a 10.9 - 10.9.x system */
533  QFont::insertSubstitution(".Lucida Grande UI", "Lucida Grande");
534  else
535  {
536  /* 10.10 or later system */
537  if (language == "zh_CN" || language == "zh_TW" || language == "zh_HK") // traditional or simplified Chinese
538  QFont::insertSubstitution(".Helvetica Neue DeskInterface", "Heiti SC");
539  else if (language == "ja") // Japanese
540  QFont::insertSubstitution(".Helvetica Neue DeskInterface", "Songti SC");
541  else
542  QFont::insertSubstitution(".Helvetica Neue DeskInterface", "Lucida Grande");
543  }
544  }
545 #endif
546 #endif
547 }
548 
549 ToolTipToRichTextFilter::ToolTipToRichTextFilter(int _size_threshold, QObject *parent) :
550  QObject(parent),
551  size_threshold(_size_threshold)
552 {
553 
554 }
555 
556 bool ToolTipToRichTextFilter::eventFilter(QObject *obj, QEvent *evt)
557 {
558  if(evt->type() == QEvent::ToolTipChange)
559  {
560  QWidget *widget = static_cast<QWidget*>(obj);
561  QString tooltip = widget->toolTip();
562  if(tooltip.size() > size_threshold && !tooltip.startsWith("<qt") && !Qt::mightBeRichText(tooltip))
563  {
564  // Envelop with <qt></qt> to make sure Qt detects this as rich text
565  // Escape the current message as HTML and replace \n by <br>
566  tooltip = "<qt>" + HtmlEscape(tooltip, true) + "</qt>";
567  widget->setToolTip(tooltip);
568  return true;
569  }
570  }
571  return QObject::eventFilter(obj, evt);
572 }
573 
575 {
576  connect(tableView->horizontalHeader(), SIGNAL(sectionResized(int,int,int)), this, SLOT(on_sectionResized(int,int,int)));
577  connect(tableView->horizontalHeader(), SIGNAL(geometriesChanged()), this, SLOT(on_geometriesChanged()));
578 }
579 
580 // We need to disconnect these while handling the resize events, otherwise we can enter infinite loops.
582 {
583  disconnect(tableView->horizontalHeader(), SIGNAL(sectionResized(int,int,int)), this, SLOT(on_sectionResized(int,int,int)));
584  disconnect(tableView->horizontalHeader(), SIGNAL(geometriesChanged()), this, SLOT(on_geometriesChanged()));
585 }
586 
587 // Setup the resize mode, handles compatibility for Qt5 and below as the method signatures changed.
588 // Refactored here for readability.
589 void TableViewLastColumnResizingFixer::setViewHeaderResizeMode(int logicalIndex, QHeaderView::ResizeMode resizeMode)
590 {
591 #if QT_VERSION < 0x050000
592  tableView->horizontalHeader()->setResizeMode(logicalIndex, resizeMode);
593 #else
594  tableView->horizontalHeader()->setSectionResizeMode(logicalIndex, resizeMode);
595 #endif
596 }
597 
598 void TableViewLastColumnResizingFixer::resizeColumn(int nColumnIndex, int width)
599 {
600  tableView->setColumnWidth(nColumnIndex, width);
601  tableView->horizontalHeader()->resizeSection(nColumnIndex, width);
602 }
603 
605 {
606  int nColumnsWidthSum = 0;
607  for (int i = 0; i < columnCount; i++)
608  {
609  nColumnsWidthSum += tableView->horizontalHeader()->sectionSize(i);
610  }
611  return nColumnsWidthSum;
612 }
613 
615 {
616  int nResult = lastColumnMinimumWidth;
617  int nTableWidth = tableView->horizontalHeader()->width();
618 
619  if (nTableWidth > 0)
620  {
621  int nOtherColsWidth = getColumnsWidth() - tableView->horizontalHeader()->sectionSize(column);
622  nResult = std::max(nResult, nTableWidth - nOtherColsWidth);
623  }
624 
625  return nResult;
626 }
627 
628 // Make sure we don't make the columns wider than the table's viewport width.
630 {
631  disconnectViewHeadersSignals();
632  resizeColumn(lastColumnIndex, getAvailableWidthForColumn(lastColumnIndex));
633  connectViewHeadersSignals();
634 
635  int nTableWidth = tableView->horizontalHeader()->width();
636  int nColsWidth = getColumnsWidth();
637  if (nColsWidth > nTableWidth)
638  {
639  resizeColumn(secondToLastColumnIndex,getAvailableWidthForColumn(secondToLastColumnIndex));
640  }
641 }
642 
643 // Make column use all the space available, useful during window resizing.
645 {
646  disconnectViewHeadersSignals();
647  resizeColumn(column, getAvailableWidthForColumn(column));
648  connectViewHeadersSignals();
649 }
650 
651 // When a section is resized this is a slot-proxy for ajustAmountColumnWidth().
652 void TableViewLastColumnResizingFixer::on_sectionResized(int logicalIndex, int oldSize, int newSize)
653 {
654  adjustTableColumnsWidth();
655  int remainingWidth = getAvailableWidthForColumn(logicalIndex);
656  if (newSize > remainingWidth)
657  {
658  resizeColumn(logicalIndex, remainingWidth);
659  }
660 }
661 
662 // When the table's geometry is ready, we manually perform the stretch of the "Message" column,
663 // as the "Stretch" resize mode does not allow for interactive resizing.
665 {
666  if ((getColumnsWidth() - this->tableView->horizontalHeader()->width()) != 0)
667  {
668  disconnectViewHeadersSignals();
669  resizeColumn(secondToLastColumnIndex, getAvailableWidthForColumn(secondToLastColumnIndex));
670  connectViewHeadersSignals();
671  }
672 }
673 
678 TableViewLastColumnResizingFixer::TableViewLastColumnResizingFixer(QTableView* table, int lastColMinimumWidth, int allColsMinimumWidth, QObject *parent) :
679  QObject(parent),
680  tableView(table),
681  lastColumnMinimumWidth(lastColMinimumWidth),
682  allColumnsMinimumWidth(allColsMinimumWidth)
683 {
684  columnCount = tableView->horizontalHeader()->count();
687  tableView->horizontalHeader()->setMinimumSectionSize(allColumnsMinimumWidth);
688  setViewHeaderResizeMode(columnCount - 3, QHeaderView::ResizeToContents);
689  setViewHeaderResizeMode(secondToLastColumnIndex, QHeaderView::ResizeToContents);
690  setViewHeaderResizeMode(lastColumnIndex, QHeaderView::Stretch);
691 }
692 
693 #ifdef WIN32
694 fs::path static StartupShortcutPath()
695 {
696  std::string chain = ChainNameFromCommandLine();
697  if (chain == CBaseChainParams::MAIN)
698  return GetSpecialFolderPath(CSIDL_STARTUP) / "Raven.lnk";
699  if (chain == CBaseChainParams::TESTNET) // Remove this special case when CBaseChainParams::TESTNET = "testnet4"
700  return GetSpecialFolderPath(CSIDL_STARTUP) / "Raven (testnet).lnk";
701  return GetSpecialFolderPath(CSIDL_STARTUP) / strprintf("Raven (%s).lnk", chain);
702 }
703 
705 {
706  // check for Raven*.lnk
707  return fs::exists(StartupShortcutPath());
708 }
709 
710 bool SetStartOnSystemStartup(bool fAutoStart)
711 {
712  // If the shortcut exists already, remove it for updating
713  fs::remove(StartupShortcutPath());
714 
715  if (fAutoStart)
716  {
717  CoInitialize(nullptr);
718 
719  // Get a pointer to the IShellLink interface.
720  IShellLink* psl = nullptr;
721  HRESULT hres = CoCreateInstance(CLSID_ShellLink, nullptr,
722  CLSCTX_INPROC_SERVER, IID_IShellLink,
723  reinterpret_cast<void**>(&psl));
724 
725  if (SUCCEEDED(hres))
726  {
727  // Get the current executable path
728  TCHAR pszExePath[MAX_PATH];
729  GetModuleFileName(nullptr, pszExePath, sizeof(pszExePath));
730 
731  // Start client minimized
732  QString strArgs = "-min";
733  // Set -testnet /-regtest options
734  strArgs += QString::fromStdString(strprintf(" -testnet=%d -regtest=%d", gArgs.GetBoolArg("-testnet", false), gArgs.GetBoolArg("-regtest", false)));
735 
736 #ifdef UNICODE
737  boost::scoped_array<TCHAR> args(new TCHAR[strArgs.length() + 1]);
738  // Convert the QString to TCHAR*
739  strArgs.toWCharArray(args.get());
740  // Add missing '\0'-termination to string
741  args[strArgs.length()] = '\0';
742 #endif
743 
744  // Set the path to the shortcut target
745  psl->SetPath(pszExePath);
746  PathRemoveFileSpec(pszExePath);
747  psl->SetWorkingDirectory(pszExePath);
748  psl->SetShowCmd(SW_SHOWMINNOACTIVE);
749 #ifndef UNICODE
750  psl->SetArguments(strArgs.toStdString().c_str());
751 #else
752  psl->SetArguments(args.get());
753 #endif
754 
755  // Query IShellLink for the IPersistFile interface for
756  // saving the shortcut in persistent storage.
757  IPersistFile* ppf = nullptr;
758  hres = psl->QueryInterface(IID_IPersistFile, reinterpret_cast<void**>(&ppf));
759  if (SUCCEEDED(hres))
760  {
761  WCHAR pwsz[MAX_PATH];
762  // Ensure that the string is ANSI.
763  MultiByteToWideChar(CP_ACP, 0, StartupShortcutPath().string().c_str(), -1, pwsz, MAX_PATH);
764  // Save the link by calling IPersistFile::Save.
765  hres = ppf->Save(pwsz, TRUE);
766  ppf->Release();
767  psl->Release();
768  CoUninitialize();
769  return true;
770  }
771  psl->Release();
772  }
773  CoUninitialize();
774  return false;
775  }
776  return true;
777 }
778 #elif defined(Q_OS_LINUX)
779 
780 // Follow the Desktop Application Autostart Spec:
781 // http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html
782 
783 fs::path static GetAutostartDir()
784 {
785  char* pszConfigHome = getenv("XDG_CONFIG_HOME");
786  if (pszConfigHome) return fs::path(pszConfigHome) / "autostart";
787  char* pszHome = getenv("HOME");
788  if (pszHome) return fs::path(pszHome) / ".config" / "autostart";
789  return fs::path();
790 }
791 
792 fs::path static GetAutostartFilePath()
793 {
794  std::string chain = ChainNameFromCommandLine();
795  if (chain == CBaseChainParams::MAIN)
796  return GetAutostartDir() / "raven.desktop";
797  return GetAutostartDir() / strprintf("raven-%s.lnk", chain);
798 }
799 
801 {
802  fs::ifstream optionFile(GetAutostartFilePath());
803  if (!optionFile.good())
804  return false;
805  // Scan through file for "Hidden=true":
806  std::string line;
807  while (!optionFile.eof())
808  {
809  getline(optionFile, line);
810  if (line.find("Hidden") != std::string::npos &&
811  line.find("true") != std::string::npos)
812  return false;
813  }
814  optionFile.close();
815 
816  return true;
817 }
818 
819 bool SetStartOnSystemStartup(bool fAutoStart)
820 {
821  if (!fAutoStart)
822  fs::remove(GetAutostartFilePath());
823  else
824  {
825  char pszExePath[MAX_PATH+1];
826  ssize_t r = readlink("/proc/self/exe", pszExePath, sizeof(pszExePath) - 1);
827  if (r == -1)
828  return false;
829  pszExePath[r] = '\0';
830 
831  fs::create_directories(GetAutostartDir());
832 
833  fs::ofstream optionFile(GetAutostartFilePath(), std::ios_base::out|std::ios_base::trunc);
834  if (!optionFile.good())
835  return false;
836  std::string chain = ChainNameFromCommandLine();
837  // Write a raven.desktop file to the autostart directory:
838  optionFile << "[Desktop Entry]\n";
839  optionFile << "Type=Application\n";
840  if (chain == CBaseChainParams::MAIN)
841  optionFile << "Name=Raven\n";
842  else
843  optionFile << strprintf("Name=Raven (%s)\n", chain);
844  optionFile << "Exec=" << pszExePath << strprintf(" -min -testnet=%d -regtest=%d\n", gArgs.GetBoolArg("-testnet", false), gArgs.GetBoolArg("-regtest", false));
845  optionFile << "Terminal=false\n";
846  optionFile << "Hidden=false\n";
847  optionFile.close();
848  }
849  return true;
850 }
851 
852 
853 #elif defined(Q_OS_MAC)
854 #pragma GCC diagnostic push
855 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
856 // based on: https://github.com/Mozketo/LaunchAtLoginController/blob/master/LaunchAtLoginController.m
857 
858 #include <CoreFoundation/CoreFoundation.h>
859 #include <CoreServices/CoreServices.h>
860 
861 LSSharedFileListItemRef findStartupItemInList(LSSharedFileListRef list, CFURLRef findUrl);
862 LSSharedFileListItemRef findStartupItemInList(LSSharedFileListRef list, CFURLRef findUrl)
863 {
864  CFArrayRef listSnapshot = LSSharedFileListCopySnapshot(list, nullptr);
865  if (listSnapshot == nullptr) {
866  return nullptr;
867  }
868 
869  // loop through the list of startup items and try to find the raven app
870  for(int i = 0; i < CFArrayGetCount(listSnapshot); i++) {
871  LSSharedFileListItemRef item = (LSSharedFileListItemRef)CFArrayGetValueAtIndex(listSnapshot, i);
872  UInt32 resolutionFlags = kLSSharedFileListNoUserInteraction | kLSSharedFileListDoNotMountVolumes;
873  CFURLRef currentItemURL = nullptr;
874 
875 #if defined(MAC_OS_X_VERSION_MAX_ALLOWED) && MAC_OS_X_VERSION_MAX_ALLOWED >= 10100
876  if(&LSSharedFileListItemCopyResolvedURL)
877  currentItemURL = LSSharedFileListItemCopyResolvedURL(item, resolutionFlags, nullptr);
878 #if defined(MAC_OS_X_VERSION_MIN_REQUIRED) && MAC_OS_X_VERSION_MIN_REQUIRED < 10100
879  else
880  LSSharedFileListItemResolve(item, resolutionFlags, &currentItemURL, nullptr);
881 #endif
882 #else
883  LSSharedFileListItemResolve(item, resolutionFlags, &currentItemURL, nullptr);
884 #endif
885 
886  if(currentItemURL) {
887  if (CFEqual(currentItemURL, findUrl)) {
888  // found
889  CFRelease(listSnapshot);
890  CFRelease(currentItemURL);
891  return item;
892  }
893  CFRelease(currentItemURL);
894  }
895  }
896 
897  CFRelease(listSnapshot);
898  return nullptr;
899 }
900 
902 {
903  CFURLRef ravenAppUrl = CFBundleCopyBundleURL(CFBundleGetMainBundle());
904  if (ravenAppUrl == nullptr) {
905  return false;
906  }
907 
908  LSSharedFileListRef loginItems = LSSharedFileListCreate(nullptr, kLSSharedFileListSessionLoginItems, nullptr);
909  LSSharedFileListItemRef foundItem = findStartupItemInList(loginItems, ravenAppUrl);
910 
911  CFRelease(ravenAppUrl);
912  return !!foundItem; // return boolified object
913 }
914 
915 bool SetStartOnSystemStartup(bool fAutoStart)
916 {
917  CFURLRef ravenAppUrl = CFBundleCopyBundleURL(CFBundleGetMainBundle());
918  if (ravenAppUrl == nullptr) {
919  return false;
920  }
921 
922  LSSharedFileListRef loginItems = LSSharedFileListCreate(nullptr, kLSSharedFileListSessionLoginItems, nullptr);
923  LSSharedFileListItemRef foundItem = findStartupItemInList(loginItems, ravenAppUrl);
924 
925  if(fAutoStart && !foundItem) {
926  // add raven app to startup item list
927  LSSharedFileListInsertItemURL(loginItems, kLSSharedFileListItemBeforeFirst, nullptr, nullptr, ravenAppUrl, nullptr, nullptr);
928  }
929  else if(!fAutoStart && foundItem) {
930  // remove item
931  LSSharedFileListItemRemove(loginItems, foundItem);
932  }
933 
934  CFRelease(ravenAppUrl);
935  return true;
936 }
937 #pragma GCC diagnostic pop
938 #else
939 
940 bool GetStartOnSystemStartup() { return false; }
941 bool SetStartOnSystemStartup(bool fAutoStart) { return false; }
942 
943 #endif
944 
945 void setClipboard(const QString& str)
946 {
947  QApplication::clipboard()->setText(str, QClipboard::Clipboard);
948  QApplication::clipboard()->setText(str, QClipboard::Selection);
949 }
950 
951 fs::path qstringToBoostPath(const QString &path)
952 {
953  return fs::path(path.toStdString(), utf8);
954 }
955 
956 QString boostPathToQString(const fs::path &path)
957 {
958  return QString::fromStdString(path.string(utf8));
959 }
960 
961 QString formatDurationStr(int secs)
962 {
963  QStringList strList;
964  int days = secs / 86400;
965  int hours = (secs % 86400) / 3600;
966  int mins = (secs % 3600) / 60;
967  int seconds = secs % 60;
968 
969  if (days)
970  strList.append(QString(QObject::tr("%1 d")).arg(days));
971  if (hours)
972  strList.append(QString(QObject::tr("%1 h")).arg(hours));
973  if (mins)
974  strList.append(QString(QObject::tr("%1 m")).arg(mins));
975  if (seconds || (!days && !hours && !mins))
976  strList.append(QString(QObject::tr("%1 s")).arg(seconds));
977 
978  return strList.join(" ");
979 }
980 
981 QString formatServicesStr(quint64 mask)
982 {
983  QStringList strList;
984 
985  // Just scan the last 8 bits for now.
986  for (int i = 0; i < 8; i++) {
987  uint64_t check = 1 << i;
988  if (mask & check)
989  {
990  switch (check)
991  {
992  case NODE_NETWORK:
993  strList.append("NETWORK");
994  break;
995  case NODE_GETUTXO:
996  strList.append("GETUTXO");
997  break;
998  case NODE_BLOOM:
999  strList.append("BLOOM");
1000  break;
1001  case NODE_WITNESS:
1002  strList.append("WITNESS");
1003  break;
1004  case NODE_XTHIN:
1005  strList.append("XTHIN");
1006  break;
1007  default:
1008  strList.append(QString("%1[%2]").arg("UNKNOWN").arg(check));
1009  }
1010  }
1011  }
1012 
1013  if (strList.size())
1014  return strList.join(" & ");
1015  else
1016  return QObject::tr("None");
1017 }
1018 
1019 QString formatPingTime(double dPingTime)
1020 {
1021  return (dPingTime == std::numeric_limits<int64_t>::max()/1e6 || dPingTime == 0) ? QObject::tr("N/A") : QString(QObject::tr("%1 ms")).arg(QString::number((int)(dPingTime * 1000), 10));
1022 }
1023 
1024 QString formatTimeOffset(int64_t nTimeOffset)
1025 {
1026  return QString(QObject::tr("%1 s")).arg(QString::number((int)nTimeOffset, 10));
1027 }
1028 
1029 QString formatNiceTimeOffset(qint64 secs)
1030 {
1031  // Represent time from last generated block in human readable text
1032  QString timeBehindText;
1033  const int HOUR_IN_SECONDS = 60*60;
1034  const int DAY_IN_SECONDS = 24*60*60;
1035  const int WEEK_IN_SECONDS = 7*24*60*60;
1036  const int YEAR_IN_SECONDS = 31556952; // Average length of year in Gregorian calendar
1037  if(secs < 60)
1038  {
1039  timeBehindText = QObject::tr("%n second(s)","",secs);
1040  }
1041  else if(secs < 2*HOUR_IN_SECONDS)
1042  {
1043  timeBehindText = QObject::tr("%n minute(s)","",secs/60);
1044  }
1045  else if(secs < 2*DAY_IN_SECONDS)
1046  {
1047  timeBehindText = QObject::tr("%n hour(s)","",secs/HOUR_IN_SECONDS);
1048  }
1049  else if(secs < 2*WEEK_IN_SECONDS)
1050  {
1051  timeBehindText = QObject::tr("%n day(s)","",secs/DAY_IN_SECONDS);
1052  }
1053  else if(secs < YEAR_IN_SECONDS)
1054  {
1055  timeBehindText = QObject::tr("%n week(s)","",secs/WEEK_IN_SECONDS);
1056  }
1057  else
1058  {
1059  qint64 years = secs / YEAR_IN_SECONDS;
1060  qint64 remainder = secs % YEAR_IN_SECONDS;
1061  timeBehindText = QObject::tr("%1 and %2").arg(QObject::tr("%n year(s)", "", years)).arg(QObject::tr("%n week(s)","", remainder/WEEK_IN_SECONDS));
1062  }
1063  return timeBehindText;
1064 }
1065 
1066 QString formatBytes(uint64_t bytes)
1067 {
1068  if(bytes < 1024)
1069  return QString(QObject::tr("%1 B")).arg(bytes);
1070  if(bytes < 1024 * 1024)
1071  return QString(QObject::tr("%1 KB")).arg(bytes / 1024);
1072  if(bytes < 1024 * 1024 * 1024)
1073  return QString(QObject::tr("%1 MB")).arg(bytes / 1024 / 1024);
1074 
1075  return QString(QObject::tr("%1 GB")).arg(bytes / 1024 / 1024 / 1024);
1076 }
1077 
1078 void ClickableLabel::mouseReleaseEvent(QMouseEvent *event)
1079 {
1080  Q_EMIT clicked(event->pos());
1081 }
1082 
1084 {
1085  Q_EMIT clicked(event->pos());
1086 }
1087 
1088 void concatenate(QPainter* painter, QString& catString, int static_width, int left_side, int right_size)
1089 {
1090  // Starting length of the name
1091  int start_name_length = catString.size();
1092 
1093  // Get the length of the dots
1094  int dots_width = painter->fontMetrics().width("...");
1095 
1096  // Add the dots width to the amount width
1097  static_width += dots_width;
1098 
1099  // Start concatenation loop, end loop if name is at three characters
1100  while (catString.size() > 3) {
1101  // Get the text width of the current name
1102  int text_width = painter->fontMetrics().width(catString);
1103 
1104  // Check to see if the text width is going to overlap the amount width if it doesn't break the loop
1105  if (left_side + text_width < right_size - static_width)
1106  break;
1107 
1108  // substring the name minus the last character of it and continue the loop
1109  catString = catString.left(catString.size() - 1);
1110  }
1111 
1112  // Add the ... if the name was concatenated
1113  if (catString.size() != start_name_length)
1114  catString.append("...");
1115 }
1116 
1117 } // namespace GUIUtil
void SubstituteFonts(const QString &language)
Definition: guiutil.cpp:513
void openDebugLogfile()
Definition: guiutil.cpp:488
bool isDust(const QString &address, const CAmount &amount)
Definition: guiutil.cpp:328
static QString format(int unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=separatorStandard, const int nAssetUnit=MIN_ASSET_UNITS - 1)
Format as string.
Definition: ravenunits.cpp:101
boost::variant< CNoDestination, CKeyID, CScriptID > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:89
const char *const RAVEN_CONF_FILENAME
Definition: util.cpp:91
QFont fixedPitchFont()
Definition: guiutil.cpp:168
Utility functions used by the Raven Qt UI.
Definition: guiutil.cpp:84
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:425
QList< QModelIndex > getEntryData(QAbstractItemView *view, int column)
Return a field of the currently selected entry as a QString.
Definition: guiutil.cpp:368
void setupAmountWidget(QLineEdit *widget, QWidget *parent)
Definition: guiutil.cpp:216
QGraphicsDropShadowEffect * getShadowEffect()
Definition: guiutil.cpp:146
void concatenate(QPainter *painter, QString &catString, int static_width, int left_side, int right_size)
Definition: guiutil.cpp:1088
void setViewHeaderResizeMode(int logicalIndex, QHeaderView::ResizeMode resizeMode)
Definition: guiutil.cpp:589
#define strprintf
Definition: tinyformat.h:1054
bool parseRavenURI(const QUrl &uri, SendCoinsRecipient *out)
Definition: guiutil.cpp:225
CTxDestination DecodeDestination(const std::string &str)
Definition: base58.cpp:333
#define MAX_PATH
Definition: compat.h:89
QString dateTimeStr(const QDateTime &date)
Definition: guiutil.cpp:158
std::string EncodeBase58(const unsigned char *pbegin, const unsigned char *pend)
Why base-58 instead of standard base-64 encoding?
Definition: base58.cpp:72
Qt::ConnectionType blockingGUIThreadConnection()
Get connection type to call object slot in GUI thread with invokeMethod.
Definition: guiutil.cpp:460
QString formatBytes(uint64_t bytes)
Definition: guiutil.cpp:1066
QString formatTimeOffset(int64_t nTimeOffset)
Definition: guiutil.cpp:1024
Raven address widget validator, checks for a valid raven address.
bool GetStartOnSystemStartup()
Definition: guiutil.cpp:940
ToolTipToRichTextFilter(int size_threshold, QObject *parent=0)
Definition: guiutil.cpp:549
CChainParams defines various tweakable parameters of a given instance of the Raven system...
Definition: chainparams.h:48
QString HtmlEscape(const QString &str, bool fMultiLine)
Definition: guiutil.cpp:336
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
Definition: util.cpp:470
Line edit that can be marked as "invalid" to show input validation feedback.
bool openRavenConf()
Definition: guiutil.cpp:497
static bool parse(int unit, const QString &value, CAmount *val_out)
Parse string to coin amount.
Definition: ravenunits.cpp:164
Base58 entry widget validator, checks for valid characters and removes some whitespace.
QFont getTopLabelFontBolded()
Definition: guiutil.cpp:110
static const std::string MAIN
BIP70 chain name strings (main, test or regtest)
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:678
int64_t CAmount
Amount in corbies (Can be negative)
Definition: amount.h:13
QFont getSubLabelFont()
Definition: guiutil.cpp:86
bool darkModeEnabled
void setupAddressWidget(QValidatedLineEdit *widget, QWidget *parent)
Definition: guiutil.cpp:201
bool IsValidDestinationString(const std::string &str, const CChainParams &params)
Definition: base58.cpp:338
#define COLOR_SHADOW_LIGHT
Definition: guiconstants.h:60
bool isObscured(QWidget *w)
Definition: guiutil.cpp:479
bool eventFilter(QObject *obj, QEvent *evt)
Definition: guiutil.cpp:556
QString formatDurationStr(int secs)
Definition: guiutil.cpp:961
void setClipboard(const QString &str)
Definition: guiutil.cpp:945
An output of a transaction.
Definition: transaction.h:137
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Raven scriptPubKey for the given CTxDestination.
Definition: standard.cpp:347
QString formatPingTime(double dPingTime)
Definition: guiutil.cpp:1019
void on_sectionResized(int logicalIndex, int oldSize, int newSize)
Definition: guiutil.cpp:652
void mouseReleaseEvent(QMouseEvent *event)
Definition: guiutil.cpp:1078
#define COLOR_SHADOW_DARK
Definition: guiconstants.h:70
ArgsManager gArgs
Definition: util.cpp:94
QString formatRavenURI(const SendCoinsRecipient &info)
Definition: guiutil.cpp:300
void mouseReleaseEvent(QMouseEvent *event)
Definition: guiutil.cpp:1083
fs::path qstringToBoostPath(const QString &path)
Definition: guiutil.cpp:951
const CChainParams & Params()
Return the currently selected parameters.
fs::path GetConfigFile(const std::string &confPath)
Definition: util.cpp:612
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:396
QString formatServicesStr(quint64 mask)
Definition: guiutil.cpp:981
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:375
bool checkPoint(const QPoint &p, const QWidget *w)
Definition: guiutil.cpp:472
std::string ChainNameFromCommandLine()
Looks for -regtest, -testnet and returns the appropriate BIP70 chain name.
void setCheckValidator(const QValidator *v)
static const std::string TESTNET
bool IsDust(const CTxOut &txout, const CFeeRate &dustRelayFeeIn)
Definition: policy.cpp:53
QFont getTopLabelFont(int weight, int pxsize)
Definition: guiutil.cpp:122
bool SetStartOnSystemStartup(bool fAutoStart)
Definition: guiutil.cpp:941
const fs::path & GetDataDir(bool fNetSpecific)
Definition: util.cpp:572
QString formatNiceTimeOffset(qint64 secs)
Definition: guiutil.cpp:1029
QFont getSubLabelFontBolded()
Definition: guiutil.cpp:98
void copyEntryData(QAbstractItemView *view, int column, int role)
Copy a field of the currently selected entry of a view to the clipboard.
Definition: guiutil.cpp:355
QString boostPathToQString(const fs::path &path)
Definition: guiutil.cpp:956
void resizeColumn(int nColumnIndex, int width)
Definition: guiutil.cpp:598
const std::vector< unsigned char > & Base58Prefix(Base58Type type) const
Definition: chainparams.h:77
CFeeRate dustRelayFee
Definition: policy.cpp:263