forked from bitcoin/bitcoin
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
Copy pathguiutil.h
620 lines (508 loc) · 23 KB
/
guiutil.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
// Copyright (c) 2011-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_QT_GUIUTIL_H
#define BITCOIN_QT_GUIUTIL_H
#include <consensus/amount.h>
#include <fs.h>
#include <qt/guiconstants.h>
#include <net.h>
#include <netaddress.h>
#include <util/check.h>
#include <QApplication>
#include <QEvent>
#include <QHeaderView>
#include <QItemDelegate>
#include <QLabel>
#include <QMessageBox>
#include <QMetaObject>
#include <QObject>
#include <QProgressBar>
#include <QString>
#include <QTableView>
#include <cassert>
#include <chrono>
#include <utility>
class QValidatedLineEdit;
class OptionsModel;
class SendCoinsRecipient;
namespace interfaces
{
class Node;
}
QT_BEGIN_NAMESPACE
class QAbstractButton;
class QAbstractItemView;
class QAction;
class QButtonGroup;
class QDateTime;
class QDialog;
class QFont;
class QKeySequence;
class QLineEdit;
class QMenu;
class QPoint;
class QProgressDialog;
class QUrl;
class QWidget;
QT_END_NAMESPACE
/** Utility functions used by the Dash Qt UI.
*/
namespace GUIUtil
{
/* Enumeration of possible "colors" */
enum class ThemedColor {
/* Transaction list -- TX status decoration - default color */
DEFAULT,
/* Transaction list -- unconfirmed transaction */
UNCONFIRMED,
/* Theme related blue color */
BLUE,
/* Eye-friendly orange color */
ORANGE,
/* Eye-friendly red color, e.g. Transaction list -- negative amount */
RED,
/* Eye-friendly green color */
GREEN,
/* Transaction list -- bare address (without label) */
BAREADDRESS,
/* Transaction list -- TX status decoration - open until date */
TX_STATUS_OPENUNTILDATE,
/* Background used for some widgets. Its slightly darker than the wallets frame background. */
BACKGROUND_WIDGET,
/* Border color used for some widgets. Its slightly brighter than BACKGROUND_WIDGET. */
BORDER_WIDGET,
/* Border color of network statistics overlay in debug window. */
BORDER_NETSTATS,
/* Background color of network statistics overlay in debug window. */
BACKGROUND_NETSTATS,
/* Pixel color of generated QR codes. */
QR_PIXEL,
/* Alternative color for black/white icons. White part will be filled with this color by default. */
ICON_ALTERNATIVE_COLOR,
};
/* Enumeration of possible "styles" */
enum class ThemedStyle {
/* Invalid field background style */
TS_INVALID,
/* Warning text style */
TS_WARNING,
/* Failed operation text style */
TS_ERROR,
/* Successful operation text style */
TS_SUCCESS,
/* Command text style */
TS_COMMAND,
/* General text styles */
TS_PRIMARY,
TS_SECONDARY,
};
/** Helper to get colors for various themes which can't be applied via css for some reason */
QColor getThemedQColor(ThemedColor color);
/** Helper to get css style strings which are injected into rich text through qt */
QString getThemedStyleQString(ThemedStyle style);
/** Helper to get an icon colorized with the given color (replaces black) and colorAlternative (replaces white) */
QIcon getIcon(const QString& strIcon, ThemedColor color, ThemedColor colorAlternative, const QString& strIconPath = ICONS_PATH);
QIcon getIcon(const QString& strIcon, ThemedColor color = ThemedColor::BLUE, const QString& strIconPath = ICONS_PATH);
/** Helper to set an icon for a button with the given color (replaces black) and colorAlternative (replaces white). */
void setIcon(QAbstractButton* button, const QString& strIcon, ThemedColor color, ThemedColor colorAlternative, const QSize& size);
void setIcon(QAbstractButton* button, const QString& strIcon, ThemedColor color = ThemedColor::BLUE, const QSize& size = QSize(BUTTON_ICONSIZE, BUTTON_ICONSIZE));
// Use this flags to prevent a "What's This" button in the title bar of the dialog on Windows.
constexpr auto dialog_flags = Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint;
// Create human-readable string from date
QString dateTimeStr(const QDateTime &datetime);
QString dateTimeStr(qint64 nTime);
// Return a monospace font
QFont fixedPitchFont(bool use_embedded_font = false);
// Set up widget for address
void setupAddressWidget(QValidatedLineEdit *widget, QWidget *parent, bool fAllowURI = false);
// Setup appearance settings if not done yet
void setupAppearance(QWidget* parent, OptionsModel* model);
/**
* Connects an additional shortcut to a QAbstractButton. Works around the
* one shortcut limitation of the button's shortcut property.
* @param[in] button QAbstractButton to assign shortcut to
* @param[in] shortcut QKeySequence to use as shortcut
*/
void AddButtonShortcut(QAbstractButton* button, const QKeySequence& shortcut);
// Parse "dash:" URI into recipient object, return true on successful parsing
bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out);
bool parseBitcoinURI(QString uri, SendCoinsRecipient *out);
bool validateBitcoinURI(const QString& uri);
QString formatBitcoinURI(const SendCoinsRecipient &info);
// Returns true if given address+amount meets "dust" definition
bool isDust(interfaces::Node& node, const QString& address, const CAmount& amount);
// HTML escaping for rich text controls
QString HtmlEscape(const QString& str, bool fMultiLine=false);
QString HtmlEscape(const std::string& str, bool fMultiLine=false);
/** Copy a field of the currently selected entry of a view to the clipboard. Does nothing if nothing
is selected.
@param[in] column Data column to extract from the model
@param[in] role Data role to extract from the model
@see TransactionView::copyLabel, TransactionView::copyAmount, TransactionView::copyAddress
*/
void copyEntryData(const QAbstractItemView *view, int column, int role=Qt::EditRole);
/** Return a field of the currently selected entry as a QString. Does nothing if nothing
is selected.
@param[in] column Data column to extract from the model
@see TransactionView::copyLabel, TransactionView::copyAmount, TransactionView::copyAddress
*/
QList<QModelIndex> getEntryData(const QAbstractItemView *view, int column);
/** Returns true if the specified field of the currently selected view entry is not empty.
@param[in] column Data column to extract from the model
@param[in] role Data role to extract from the model
@see TransactionView::contextualMenu
*/
bool hasEntryData(const QAbstractItemView *view, int column, int role);
void setClipboard(const QString& str);
/**
* Loads the font from the file specified by file_name, aborts if it fails.
*/
void LoadFont(const QString& file_name);
/**
* Determine default data directory for operating system.
*/
QString getDefaultDataDirectory();
/**
* Extract first suffix from filter pattern "Description (*.foo)" or "Description (*.foo *.bar ...).
*
* @param[in] filter Filter specification such as "Comma Separated Files (*.csv)"
* @return QString
*/
QString ExtractFirstSuffixFromFilter(const QString& filter);
/** Get save filename, mimics QFileDialog::getSaveFileName, except that it appends a default suffix
when no suffix is provided by the user.
@param[in] parent Parent window (or 0)
@param[in] caption Window caption (or empty, for default)
@param[in] dir Starting directory (or empty, to default to documents directory)
@param[in] filter Filter specification such as "Comma Separated Files (*.csv)"
@param[out] selectedSuffixOut Pointer to return the suffix (file type) that was selected (or 0).
Can be useful when choosing the save file format based on suffix.
*/
QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir,
const QString &filter,
QString *selectedSuffixOut);
/** Get open filename, convenience wrapper for QFileDialog::getOpenFileName.
@param[in] parent Parent window (or 0)
@param[in] caption Window caption (or empty, for default)
@param[in] dir Starting directory (or empty, to default to documents directory)
@param[in] filter Filter specification such as "Comma Separated Files (*.csv)"
@param[out] selectedSuffixOut Pointer to return the suffix (file type) that was selected (or 0).
Can be useful when choosing the save file format based on suffix.
*/
QString getOpenFileName(QWidget *parent, const QString &caption, const QString &dir,
const QString &filter,
QString *selectedSuffixOut);
/** Get connection type to call object slot in GUI thread with invokeMethod. The call will be blocking.
@returns If called from the GUI thread, return a Qt::DirectConnection.
If called from another thread, return a Qt::BlockingQueuedConnection.
*/
Qt::ConnectionType blockingGUIThreadConnection();
// Determine whether a widget is hidden behind other windows
bool isObscured(QWidget *w);
// Activate, show and raise the widget
void bringToFront(QWidget* w);
// Set shortcut to close window
void handleCloseWindowShortcut(QWidget* w);
// Open debug.log
void openDebugLogfile();
// Open dash.conf
void openConfigfile();
// Browse backup folder
void showBackups();
/** Qt event filter that intercepts ToolTipChange events, and replaces the tooltip with a rich text
representation if needed. This assures that Qt can word-wrap long tooltip messages.
Tooltips longer than the provided size threshold (in characters) are wrapped.
*/
class ToolTipToRichTextFilter : public QObject
{
Q_OBJECT
public:
explicit ToolTipToRichTextFilter(int size_threshold, QObject *parent = nullptr);
protected:
bool eventFilter(QObject *obj, QEvent *evt) override;
private:
int size_threshold;
};
/**
* Qt event filter that intercepts QEvent::FocusOut events for QLabel objects, and
* resets their `textInteractionFlags' property to get rid of the visible cursor.
*
* This is a temporary fix of QTBUG-59514.
*/
class LabelOutOfFocusEventFilter : public QObject
{
Q_OBJECT
public:
explicit LabelOutOfFocusEventFilter(QObject* parent);
bool eventFilter(QObject* watched, QEvent* event) override;
};
bool GetStartOnSystemStartup();
bool SetStartOnSystemStartup(bool fAutoStart);
/** Change the stylesheet directory. This is used by
the parameter -custom-css-dir.*/
void setStyleSheetDirectory(const QString& path);
/** Check if a custom css directory has been set with -custom-css-dir */
bool isStyleSheetDirectoryCustom();
/** Return a list of all required css files */
const std::vector<QString> listStyleSheets();
/** Return a list of all theme css files */
const std::vector<QString> listThemes();
/** Return the name of the default theme `*/
const QString getDefaultTheme();
/** Check if the given theme name is valid or not */
bool isValidTheme(const QString& strTheme);
/** Sets the stylesheet of the whole app and updates it if the
related css files has been changed and -debug-ui mode is active. */
void loadStyleSheet(bool fForceUpdate = false);
enum class FontFamily {
SystemDefault,
Montserrat,
};
FontFamily fontFamilyFromString(const QString& strFamily);
QString fontFamilyToString(FontFamily family);
/** set/get font family: GUIUtil::fontFamily */
FontFamily getFontFamilyDefault();
FontFamily getFontFamily();
void setFontFamily(FontFamily family);
enum class FontWeight {
Normal, // Font weight for normal text
Bold, // Font weight for bold text
};
/** Convert weight value from args (0-8) to QFont::Weight */
bool weightFromArg(int nArg, QFont::Weight& weight);
/** Convert QFont::Weight to an arg value (0-8) */
int weightToArg(const QFont::Weight weight);
/** Convert GUIUtil::FontWeight to QFont::Weight */
QFont::Weight toQFontWeight(FontWeight weight);
/** set/get normal font weight: GUIUtil::fontWeightNormal */
QFont::Weight getFontWeightNormalDefault();
QFont::Weight getFontWeightNormal();
void setFontWeightNormal(QFont::Weight weight);
/** set/get bold font weight: GUIUtil::fontWeightBold */
QFont::Weight getFontWeightBoldDefault();
QFont::Weight getFontWeightBold();
void setFontWeightBold(QFont::Weight weight);
/** set/get font scale: GUIUtil::fontScale */
int getFontScaleDefault();
int getFontScale();
void setFontScale(int nScale);
/** get font size with GUIUtil::fontScale applied */
double getScaledFontSize(int nSize);
/** Load dash specific appliciation fonts */
bool loadFonts();
/** Check if the fonts have been loaded successfully */
bool fontsLoaded();
/** Set an application wide default font, depends on the selected theme */
void setApplicationFont();
/** Workaround to set correct font styles in all themes since there is a bug in macOS which leads to
issues loading variations of montserrat in css it also keeps track of the set fonts to update on
theme changes. */
void setFont(const std::vector<QWidget*>& vecWidgets, FontWeight weight, int nPointSize = -1, bool fItalic = false);
/** Update the font of all widgets where a custom font has been set with
GUIUtil::setFont */
void updateFonts();
/** Get a properly weighted QFont object with the selected font. */
QFont getFont(FontFamily family, QFont::Weight qWeight, bool fItalic = false, int nPointSize = -1);
QFont getFont(QFont::Weight qWeight, bool fItalic = false, int nPointSize = -1);
QFont getFont(FontWeight weight, bool fItalic = false, int nPointSize = -1);
/** Get the default normal QFont */
QFont getFontNormal();
/** Get the default bold QFont */
QFont getFontBold();
/** Return supported normal default for the current font family */
QFont::Weight getSupportedFontWeightNormalDefault();
/** Return supported bold default for the current font family */
QFont::Weight getSupportedFontWeightBoldDefault();
/** Return supported weights for the current font family */
std::vector<QFont::Weight> getSupportedWeights();
/** Convert an index to a weight in the supported weights vector */
QFont::Weight supportedWeightFromIndex(int nIndex);
/** Convert a weight to an index in the supported weights vector */
int supportedWeightToIndex(QFont::Weight weight);
/** Check if a weight is supported by the current font family */
bool isSupportedWeight(QFont::Weight weight);
/** Return the name of the currently active theme.*/
QString getActiveTheme();
/** Check if a dash specific theme is activated (light/dark).*/
bool dashThemeActive();
/** Load the theme and update all UI elements according to the appearance settings. */
void loadTheme(bool fForce = false);
/** Disable the OS default focus rect for macOS because we have custom focus rects
* set in the css files */
void disableMacFocusRect(const QWidget* w);
/** Enable/Disable the macOS focus rects depending on the current theme. */
void updateMacFocusRects();
/** Update shortcuts for individual buttons in QButtonGroup based on their visibility. */
void updateButtonGroupShortcuts(QButtonGroup* buttonGroup);
/** Convert QString to OS specific boost path through UTF-8 */
fs::path QStringToPath(const QString &path);
/** Convert OS specific boost path to QString through UTF-8 */
QString PathToQString(const fs::path &path);
/** Convert enum Network to QString */
QString NetworkToQString(Network net);
/** Convert enum ConnectionType to QString */
QString ConnectionTypeToQString(ConnectionType conn_type, bool prepend_direction);
/** Convert seconds into a QString with days, hours, mins, secs */
QString formatDurationStr(std::chrono::seconds dur);
/** Convert peer connection time to a QString denominated in the most relevant unit. */
QString FormatPeerAge(std::chrono::seconds time_connected);
/** Format CNodeStats.nServices bitmask into a user-readable string */
QString formatServicesStr(quint64 mask);
/** Format a CNodeStats.m_last_ping_time into a user-readable string or display N/A, if 0 */
QString formatPingTime(std::chrono::microseconds ping_time);
/** Format a CNodeCombinedStats.nTimeOffset into a user-readable string */
QString formatTimeOffset(int64_t nTimeOffset);
QString formatNiceTimeOffset(qint64 secs);
QString formatBytes(uint64_t bytes);
qreal calculateIdealFontSize(int width, const QString& text, QFont font, qreal minPointSize = 4, qreal startPointSize = 14);
class ClickableLabel : public QLabel
{
Q_OBJECT
Q_SIGNALS:
/** Emitted when the label is clicked. The relative mouse coordinates of the click are
* passed to the signal.
*/
void clicked(const QPoint& point);
protected:
void mouseReleaseEvent(QMouseEvent *event) override;
};
class ClickableProgressBar : public QProgressBar
{
Q_OBJECT
Q_SIGNALS:
/** Emitted when the progressbar is clicked. The relative mouse coordinates of the click are
* passed to the signal.
*/
void clicked(const QPoint& point);
protected:
void mouseReleaseEvent(QMouseEvent *event) override;
};
typedef ClickableProgressBar ProgressBar;
class ItemDelegate : public QItemDelegate
{
Q_OBJECT
public:
ItemDelegate(QObject* parent) : QItemDelegate(parent) {}
Q_SIGNALS:
void keyEscapePressed();
private:
bool eventFilter(QObject *object, QEvent *event) override;
};
// Fix known bugs in QProgressDialog class.
void PolishProgressDialog(QProgressDialog* dialog);
/**
* Returns the distance in pixels appropriate for drawing a subsequent character after text.
*
* In Qt 5.12 and before the QFontMetrics::width() is used and it is deprecated since Qt 5.13.
* In Qt 5.11 the QFontMetrics::horizontalAdvance() was introduced.
*/
int TextWidth(const QFontMetrics& fm, const QString& text);
/**
* Writes to debug.log short info about the used Qt and the host system.
*/
void LogQtInfo();
/**
* Call QMenu::popup() only on supported QT_QPA_PLATFORM.
*/
void PopupMenu(QMenu* menu, const QPoint& point, QAction* at_action = nullptr);
/**
* Returns the start-moment of the day in local time.
*
* QDateTime::QDateTime(const QDate& date) is deprecated since Qt 5.15.
* QDate::startOfDay() was introduced in Qt 5.14.
*/
QDateTime StartOfDay(const QDate& date);
/**
* Returns true if pixmap has been set.
*
* QPixmap* QLabel::pixmap() is deprecated since Qt 5.15.
*/
bool HasPixmap(const QLabel* label);
QImage GetImage(const QLabel* label);
/**
* Splits the string into substrings wherever separator occurs, and returns
* the list of those strings. Empty strings do not appear in the result.
*
* QString::split() signature differs in different Qt versions:
* - QString::SplitBehavior is deprecated since Qt 5.15
* - Qt::SplitBehavior was introduced in Qt 5.14
* If {QString|Qt}::SkipEmptyParts behavior is required, use this
* function instead of QString::split().
*/
template <typename SeparatorType>
QStringList SplitSkipEmptyParts(const QString& string, const SeparatorType& separator)
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
return string.split(separator, Qt::SkipEmptyParts);
#else
return string.split(separator, QString::SkipEmptyParts);
#endif
}
/**
* Queue a function to run in an object's event loop. This can be
* replaced by a call to the QMetaObject::invokeMethod functor overload after Qt 5.10, but
* for now use a QObject::connect for compatibility with older Qt versions, based on
* https://stackoverflow.com/questions/21646467/how-to-execute-a-functor-or-a-lambda-in-a-given-thread-in-qt-gcd-style
*/
template <typename Fn>
void ObjectInvoke(QObject* object, Fn&& function, Qt::ConnectionType connection = Qt::QueuedConnection)
{
QObject source;
QObject::connect(&source, &QObject::destroyed, object, std::forward<Fn>(function), connection);
}
/**
* Replaces a plain text link with an HTML tagged one.
*/
QString MakeHtmlLink(const QString& source, const QString& link);
void PrintSlotException(
const std::exception* exception,
const QObject* sender,
const QObject* receiver);
/**
* A drop-in replacement of QObject::connect function
* (see: https://doc.qt.io/qt-5/qobject.html#connect-3), that
* guaranties that all exceptions are handled within the slot.
*
* NOTE: This function is incompatible with Qt private signals.
*/
template <typename Sender, typename Signal, typename Receiver, typename Slot>
auto ExceptionSafeConnect(
Sender sender, Signal signal, Receiver receiver, Slot method,
Qt::ConnectionType type = Qt::AutoConnection)
{
return QObject::connect(
sender, signal, receiver,
[sender, receiver, method](auto&&... args) {
bool ok{true};
try {
(receiver->*method)(std::forward<decltype(args)>(args)...);
} catch (const NonFatalCheckError& e) {
PrintSlotException(&e, sender, receiver);
ok = QMetaObject::invokeMethod(
qApp, "handleNonFatalException",
blockingGUIThreadConnection(),
Q_ARG(QString, QString::fromStdString(e.what())));
} catch (const std::exception& e) {
PrintSlotException(&e, sender, receiver);
ok = QMetaObject::invokeMethod(
qApp, "handleRunawayException",
blockingGUIThreadConnection(),
Q_ARG(QString, QString::fromStdString(e.what())));
} catch (...) {
PrintSlotException(nullptr, sender, receiver);
ok = QMetaObject::invokeMethod(
qApp, "handleRunawayException",
blockingGUIThreadConnection(),
Q_ARG(QString, "Unknown failure occurred."));
}
assert(ok);
},
type);
}
/**
* Shows a QDialog instance asynchronously, and deletes it on close.
*/
void ShowModalDialogAsynchronously(QDialog* dialog);
} // namespace GUIUtil
#endif // BITCOIN_QT_GUIUTIL_H