1 /***************************************************************************
2                           qgsmessagebar.h  -  description
3                              -------------------
4     begin                : June 2012
5     copyright            : (C) 2012 by Giuseppe Sucameli
6     email                : sucameli at faunalia dot it
7  ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 #ifndef QGSMESSAGEBAR_H
18 #define QGSMESSAGEBAR_H
19 
20 #include "qgsguiutils.h"
21 #include "qgis.h"
22 
23 #include <QString>
24 #include <QFrame>
25 #include <QIcon>
26 #include <QColor>
27 #include <QList>
28 #include "qgis_gui.h"
29 
30 class QWidget;
31 class QGridLayout;
32 class QMenu;
33 class QProgressBar;
34 class QToolButton;
35 class QLabel;
36 class QAction;
37 class QTimer;
38 
39 class QgsMessageBarItem;
40 
41 /**
42  * \ingroup gui
43  * \brief A bar for displaying non-blocking messages to the user.
44  *
45  * QgsMessageBar is a reusable widget which allows for providing feedback to users in
46  * a non-intrusive way. Messages are shown in a horizontal bar widget, which is styled
47  * automatically to reflect the severity ("message level") of the displayed message (e.g.
48  * warning messages are styled in an orange color scheme, critical errors are shown in
49  * red, etc).
50  *
51  * The message bar supports automatic stacking of multiple messages, so that
52  * only the most recent message is shown to users. Users can then manually dismiss
53  * individual messages to remove them from the stack, causing the next-most-recent
54  * message to be shown. If no messages are available to show then the message bar
55  * automatically hides.
56  *
57  * The class also supports pushing custom widgets to the notification stack via
58  * the pushWidget() method.
59  */
60 class GUI_EXPORT QgsMessageBar: public QFrame
61 {
62     Q_OBJECT
63 
64   public:
65 
66     //! Constructor for QgsMessageBar
67     QgsMessageBar( QWidget *parent SIP_TRANSFERTHIS = nullptr );
68 
69     /**
70      * Display a message \a item on the bar, after hiding the currently visible one
71      * and putting it in a stack.
72      *
73      * The message bar will take ownership of \a item.
74      */
75     void pushItem( QgsMessageBarItem *item SIP_TRANSFER );
76 
77     /**
78      * Display a \a widget as a message on the bar, after hiding the currently visible one
79      * and putting it in a stack.
80      *
81      * \param widget message widget to display
82      * \param level is Qgis::MessageLevel::Info, Warning, Critical or Success
83      * \param duration timeout duration of message in seconds, 0 value indicates no timeout (i.e.
84      * the message must be manually cleared by the user).
85      */
86     QgsMessageBarItem *pushWidget( QWidget *widget SIP_TRANSFER, Qgis::MessageLevel level = Qgis::MessageLevel::Info, int duration = 0 );
87 
88     /**
89      * Remove the specified \a item from the bar, and display the next most recent one in the stack.
90      * If no messages remain in the stack, then the bar will be hidden.
91      *
92      * \param item previously added item to remove.
93      * \returns TRUE if \a item was removed, FALSE otherwise
94      */
95     bool popWidget( QgsMessageBarItem *item );
96 
97     /**
98      * Creates message bar item widget containing a message \a text to be displayed on the bar.
99      *
100      * The caller takes ownership of the returned item.
101      *
102      * \note This is a low-level API call. Users are recommended to use the high-level pushMessage() API call
103      * instead.
104      */
105     static QgsMessageBarItem *createMessage( const QString &text, QWidget *parent = nullptr ) SIP_FACTORY;
106 
107     /**
108      * Creates message bar item widget containing a \a title and message \a text to be displayed on the bar.
109      *
110      * The caller takes ownership of the returned item.
111      *
112      * \note This is a low-level API call. Users are recommended to use the high-level pushMessage() API call
113      * instead.
114      */
115     static QgsMessageBarItem *createMessage( const QString &title, const QString &text, QWidget *parent = nullptr ) SIP_FACTORY;
116 
117     /**
118      * Creates message bar item widget containing a custom \a widget to be displayed on the bar.
119      *
120      * The caller takes ownership of the returned item.
121      *
122      * \note This is a low-level API call. Users are recommended to use the high-level pushWidget() API call
123      * instead.
124      */
125     static QgsMessageBarItem *createMessage( QWidget *widget, QWidget *parent = nullptr ) SIP_FACTORY;
126 
127     /**
128      * A convenience method for pushing a message with the specified \a text to the bar.
129      *
130      * The \a level argument specifies the desired message level (severity) of the message, which controls
131      * how the message bar is styled.
132      *
133      * The optional \a duration argument can be used to specify the message timeout in seconds. If \a duration
134      * is set to 0, then the message must be manually dismissed by the user. Since QGIS 3.18, a duration of -1 indicates that
135      * the default timeout for the message \a level should be used.
136      */
137     void pushMessage( const QString &text, Qgis::MessageLevel level = Qgis::MessageLevel::Info, int duration = -1 );
138 
139     /**
140      * A convenience method for pushing a message with the specified \a title and \a text to the bar.
141      *
142      * The \a level argument specifies the desired message level (severity) of the message, which controls
143      * how the message bar is styled.
144      *
145      * The optional \a duration argument can be used to specify the message timeout in seconds. If \a duration
146      * is set to 0, then the message must be manually dismissed by the user. Since QGIS 3.18, a duration of -1 indicates that
147      * the default timeout for the message \a level should be used.
148      */
149     void pushMessage( const QString &title, const QString &text, Qgis::MessageLevel level = Qgis::MessageLevel::Info, int duration = -1 );
150 
151     /**
152      * A convenience method for pushing a message with the specified \a title and \a text to the bar. Additional
153      * message content specified via \a showMore will be shown when the user presses a "more" button.
154      *
155      * The \a level argument specifies the desired message level (severity) of the message, which controls
156      * how the message bar is styled.
157      *
158      * The optional \a duration argument can be used to specify the message timeout in seconds. If \a duration
159      * is set to 0, then the message must be manually dismissed by the user. Since QGIS 3.18, a duration of -1 indicates that
160      * the default timeout for the message \a level should be used.
161      */
162     void pushMessage( const QString &title, const QString &text, const QString &showMore, Qgis::MessageLevel level = Qgis::MessageLevel::Info, int duration = -1 );
163 
164     /**
165      * Returns the current visible item, or NULLPTR if no item is shown.
166      */
167     QgsMessageBarItem *currentItem();
168 
169     /**
170      * Returns a list of all items currently visible or queued for the bar.
171      *
172      * \since QGIS 3.14
173      */
174     QList<QgsMessageBarItem *> items();
175 
176     /**
177      * Returns the default timeout in seconds for timed messages of the specified \a level.
178      * \since QGIS 3.18
179      */
180     static int defaultMessageTimeout( Qgis::MessageLevel level = Qgis::MessageLevel::NoLevel );
181 
182   signals:
183 
184     /**
185      * Emitted whenever an \a item is added to the bar.
186      */
187     void widgetAdded( QgsMessageBarItem *item );
188 
189     /**
190      * Emitted whenever an \a item was removed from the bar.
191      */
192     void widgetRemoved( QgsMessageBarItem *item );
193 
194   public slots:
195 
196     /**
197      * Remove the currently displayed item from the bar and display the next item
198      * in the stack. If no remaining items are present, the bar will be hidden.
199      *
200      * \returns TRUE if the widget was removed, FALSE otherwise
201      */
202     bool popWidget();
203 
204     /**
205      * Removes all items from the bar.
206      *
207      * \returns TRUE if all items were removed, FALSE otherwise
208      */
209     bool clearWidgets();
210 
211     /**
212      * Pushes a success \a message with default timeout to the message bar.
213      *
214      * \param title title string for message
215      * \param message The message to be displayed
216      *
217      * \since QGIS 2.8
218      */
219     void pushSuccess( const QString &title, const QString &message );
220 
221     /**
222      * Pushes a information \a message with default timeout to the message bar.
223      *
224      * \param title title string for message
225      * \param message The message to be displayed
226      *
227      * \since QGIS 2.8
228      */
229     void pushInfo( const QString &title, const QString &message );
230 
231     /**
232      * Pushes a warning \a message that must be manually dismissed by the user. Before QGIS 3.18 the default timeout was used.
233      *
234      * \param title title string for message
235      * \param message The message to be displayed
236      *
237      * \since QGIS 2.8
238      */
239     void pushWarning( const QString &title, const QString &message );
240 
241     /**
242      * Pushes a critical warning \a message that must be manually dismissed by the user. Before QGIS 3.18 the default timeout was used.
243      *
244      * \param title title string for message
245      * \param message The message to be displayed
246      *
247      * \since QGIS 2.8
248      */
249     void pushCritical( const QString &title, const QString &message );
250 
251   protected:
252     void mousePressEvent( QMouseEvent *e ) override;
253 
254   private:
255     void popItem( QgsMessageBarItem *item );
256     void showItem( QgsMessageBarItem *item );
257     QgsMessageBarItem *mCurrentItem = nullptr;
258     QList<QgsMessageBarItem *> mItems;
259     QMenu *mCloseMenu = nullptr;
260     QToolButton *mCloseBtn = nullptr;
261     QGridLayout *mLayout = nullptr;
262     QLabel *mItemCount = nullptr;
263     QAction *mActionCloseAll = nullptr;
264     QTimer *mCountdownTimer = nullptr;
265     QProgressBar *mCountProgress = nullptr;
266     QString mCountStyleSheet;
267     Qgis::MessageLevel mPrevLevel = Qgis::MessageLevel::NoLevel;
268 
269     static constexpr int MAX_ITEMS = 100;
270 
271     void removeLowestPriorityOldestItem();
272 
273   private slots:
274     //! updates count of items in widget list
275     void updateItemCount();
276 
277     //! updates the countdown for widgets that have a timeout duration
278     void updateCountdown();
279     void resetCountdown();
280 
281     friend class TestQgsMessageBar;
282 };
283 
284 #endif
285