1 // Copyright (c) 2011-2020 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 #ifndef BITCOIN_QT_GUIUTIL_H
6 #define BITCOIN_QT_GUIUTIL_H
7 
8 #include <amount.h>
9 #include <fs.h>
10 
11 #include <QEvent>
12 #include <QHeaderView>
13 #include <QItemDelegate>
14 #include <QMessageBox>
15 #include <QObject>
16 #include <QProgressBar>
17 #include <QString>
18 #include <QTableView>
19 #include <QLabel>
20 #include <QToolButton>
21 
22 class QValidatedLineEdit;
23 class SendCoinsRecipient;
24 
25 namespace interfaces
26 {
27     class Node;
28 }
29 
30 QT_BEGIN_NAMESPACE
31 class QAbstractItemView;
32 class QDateTime;
33 class QFont;
34 class QLineEdit;
35 class QProgressDialog;
36 class QUrl;
37 class QWidget;
38 QT_END_NAMESPACE
39 
40 /** Utility functions used by the Bitcoin Qt UI.
41  */
42 namespace GUIUtil
43 {
44     // Create human-readable string from date
45     QString dateTimeStr(const QDateTime &datetime);
46     QString dateTimeStr(qint64 nTime);
47 
48     // Return a monospace font
49     QFont fixedPitchFont();
50 
51     // Set up widget for address
52     void setupAddressWidget(QValidatedLineEdit *widget, QWidget *parent);
53 
54     // Parse "bitcoin:" URI into recipient object, return true on successful parsing
55     bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out);
56     bool parseBitcoinURI(QString uri, SendCoinsRecipient *out);
57     QString formatBitcoinURI(const SendCoinsRecipient &info);
58 
59     // Returns true if given address+amount meets "dust" definition
60     bool isDust(interfaces::Node& node, const QString& address, const CAmount& amount);
61 
62     // HTML escaping for rich text controls
63     QString HtmlEscape(const QString& str, bool fMultiLine=false);
64     QString HtmlEscape(const std::string& str, bool fMultiLine=false);
65 
66     /** Copy a field of the currently selected entry of a view to the clipboard. Does nothing if nothing
67         is selected.
68        @param[in] column  Data column to extract from the model
69        @param[in] role    Data role to extract from the model
70        @see  TransactionView::copyLabel, TransactionView::copyAmount, TransactionView::copyAddress
71      */
72     void copyEntryData(QAbstractItemView *view, int column, int role=Qt::EditRole);
73 
74     /** Copy a field of the currently selected entry of a view to the clipboard. Does nothing if nothing
75         is selected.
76        @param[in] role    Data role to extract from the model
77        @see  QRCToken::copyTokenAddress
78      */
79     void copyEntryDataFromList(QAbstractItemView *view, int role=Qt::EditRole);
80 
81     /** Return a field of the currently selected entry as a QString. Does nothing if nothing
82         is selected.
83        @param[in] column  Data column to extract from the model
84        @see  TransactionView::copyLabel, TransactionView::copyAmount, TransactionView::copyAddress
85      */
86     QList<QModelIndex> getEntryData(QAbstractItemView *view, int column);
87 
88     void setClipboard(const QString& str);
89 
90     /**
91      * Determine default data directory for operating system.
92      */
93     QString getDefaultDataDirectory();
94 
95     /** Get save filename, mimics QFileDialog::getSaveFileName, except that it appends a default suffix
96         when no suffix is provided by the user.
97 
98       @param[in] parent  Parent window (or 0)
99       @param[in] caption Window caption (or empty, for default)
100       @param[in] dir     Starting directory (or empty, to default to documents directory)
101       @param[in] filter  Filter specification such as "Comma Separated Files (*.csv)"
102       @param[out] selectedSuffixOut  Pointer to return the suffix (file type) that was selected (or 0).
103                   Can be useful when choosing the save file format based on suffix.
104      */
105     QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir,
106         const QString &filter,
107         QString *selectedSuffixOut);
108 
109     /** Get open filename, convenience wrapper for QFileDialog::getOpenFileName.
110 
111       @param[in] parent  Parent window (or 0)
112       @param[in] caption Window caption (or empty, for default)
113       @param[in] dir     Starting directory (or empty, to default to documents directory)
114       @param[in] filter  Filter specification such as "Comma Separated Files (*.csv)"
115       @param[out] selectedSuffixOut  Pointer to return the suffix (file type) that was selected (or 0).
116                   Can be useful when choosing the save file format based on suffix.
117      */
118     QString getOpenFileName(QWidget *parent, const QString &caption, const QString &dir,
119         const QString &filter,
120         QString *selectedSuffixOut);
121 
122     /** Get connection type to call object slot in GUI thread with invokeMethod. The call will be blocking.
123 
124        @returns If called from the GUI thread, return a Qt::DirectConnection.
125                 If called from another thread, return a Qt::BlockingQueuedConnection.
126     */
127     Qt::ConnectionType blockingGUIThreadConnection();
128 
129     // Determine whether a widget is hidden behind other windows
130     bool isObscured(QWidget *w);
131 
132     // Activate, show and raise the widget
133     void bringToFront(QWidget* w);
134 
135     // Open debug.log
136     void openDebugLogfile();
137 
138     // Open the config file
139     bool openBitcoinConf();
140 
141     /** Qt event filter that intercepts ToolTipChange events, and replaces the tooltip with a rich text
142       representation if needed. This assures that Qt can word-wrap long tooltip messages.
143       Tooltips longer than the provided size threshold (in characters) are wrapped.
144      */
145     class ToolTipToRichTextFilter : public QObject
146     {
147         Q_OBJECT
148 
149     public:
150         explicit ToolTipToRichTextFilter(int size_threshold, QObject *parent = nullptr);
151 
152     protected:
153         bool eventFilter(QObject *obj, QEvent *evt);
154 
155     private:
156         int size_threshold;
157     };
158 
159     /**
160      * Makes a QTableView last column feel as if it was being resized from its left border.
161      * Also makes sure the column widths are never larger than the table's viewport.
162      * In Qt, all columns are resizable from the right, but it's not intuitive resizing the last column from the right.
163      * Usually our second to last columns behave as if stretched, and when on stretch mode, columns aren't resizable
164      * interactively or programmatically.
165      *
166      * This helper object takes care of this issue.
167      *
168      */
169     class TableViewLastColumnResizingFixer: public QObject
170     {
171         Q_OBJECT
172 
173         public:
174             TableViewLastColumnResizingFixer(QTableView* table, int lastColMinimumWidth, int allColsMinimumWidth, QObject *parent, int columnStretch = 2);
175             void stretchColumnWidth(int column);
176 
177         private:
178             QTableView* tableView;
179             int lastColumnMinimumWidth;
180             int allColumnsMinimumWidth;
181             int lastColumnIndex;
182             int columnCount;
183             int secondToLastColumnIndex;
184 
185             void adjustTableColumnsWidth();
186             int getAvailableWidthForColumn(int column);
187             int getColumnsWidth();
188             void connectViewHeadersSignals();
189             void disconnectViewHeadersSignals();
190             void setViewHeaderResizeMode(int logicalIndex, QHeaderView::ResizeMode resizeMode);
191             void resizeColumn(int nColumnIndex, int width);
192 
193         private Q_SLOTS:
194             void on_sectionResized(int logicalIndex, int oldSize, int newSize);
195             void on_geometriesChanged();
196     };
197 
198     bool GetStartOnSystemStartup();
199     bool SetStartOnSystemStartup(bool fAutoStart);
200 
201     /* Convert QString to OS specific boost path through UTF-8 */
202     fs::path qstringToBoostPath(const QString &path);
203 
204     /* Convert OS specific boost path to QString through UTF-8 */
205     QString boostPathToQString(const fs::path &path);
206 
207     /* Convert seconds into a QString with days, hours, mins, secs */
208     QString formatDurationStr(int secs);
209 
210     /* Format CNodeStats.nServices bitmask into a user-readable string */
211     QString formatServicesStr(quint64 mask);
212 
213     /* Format a CNodeStats.m_ping_usec into a user-readable string or display N/A, if 0*/
214     QString formatPingTime(int64_t ping_usec);
215 
216     /* Format a CNodeCombinedStats.nTimeOffset into a user-readable string. */
217     QString formatTimeOffset(int64_t nTimeOffset);
218 
219     QString formatNiceTimeOffset(qint64 secs);
220 
221     QString formatBytes(uint64_t bytes);
222 
223     qreal calculateIdealFontSize(int width, const QString& text, QFont font, qreal minPointSize = 4, qreal startPointSize = 14);
224 
225     class ClickableLabel : public QLabel
226     {
227         Q_OBJECT
228 
229     Q_SIGNALS:
230         /** Emitted when the label is clicked. The relative mouse coordinates of the click are
231          * passed to the signal.
232          */
233         void clicked(const QPoint& point);
234     protected:
235         void mouseReleaseEvent(QMouseEvent *event);
236     };
237 
238     class ClickableProgressBar : public QProgressBar
239     {
240         Q_OBJECT
241 
242     Q_SIGNALS:
243         /** Emitted when the progressbar is clicked. The relative mouse coordinates of the click are
244          * passed to the signal.
245          */
246         void clicked(const QPoint& point);
247     protected:
248         void mouseReleaseEvent(QMouseEvent *event);
249     };
250 
251     typedef ClickableProgressBar ProgressBar;
252 
253     class ItemDelegate : public QItemDelegate
254     {
255         Q_OBJECT
256     public:
ItemDelegate(QObject * parent)257         ItemDelegate(QObject* parent) : QItemDelegate(parent) {}
258 
259     Q_SIGNALS:
260         void keyEscapePressed();
261 
262     private:
263         bool eventFilter(QObject *object, QEvent *event);
264     };
265 
266     // Fix known bugs in QProgressDialog class.
267     void PolishProgressDialog(QProgressDialog* dialog);
268 
269     /**
270      * Returns the distance in pixels appropriate for drawing a subsequent character after text.
271      *
272      * In Qt 5.12 and before the QFontMetrics::width() is used and it is deprecated since Qt 13.0.
273      * In Qt 5.11 the QFontMetrics::horizontalAdvance() was introduced.
274      */
275     int TextWidth(const QFontMetrics& fm, const QString& text);
276 
277     /**
278      * Writes to debug.log short info about the used Qt and the host system.
279      */
280     void LogQtInfo();
281 
282     void formatToolButtons(QToolButton* btn1, QToolButton* btn2 = 0, QToolButton* btn3 = 0);
283 
284     QString cutString(const QString& text, int length);
285 
286 } // namespace GUIUtil
287 
288 #endif // BITCOIN_QT_GUIUTIL_H
289