1 /*
2     This file is part of the KDE libraries
3 
4     SPDX-FileCopyrightText: 2011 Aurélien Gâteau <agateau@kde.org>
5     SPDX-FileCopyrightText: 2014 Dominik Haumann <dhaumann@kde.org>
6 
7     SPDX-License-Identifier: LGPL-2.1-or-later
8 */
9 #ifndef KMESSAGEWIDGET_H
10 #define KMESSAGEWIDGET_H
11 
12 #include <kwidgetsaddons_export.h>
13 
14 #include <QFrame>
15 #include <memory>
16 
17 /**
18  * @class KMessageWidget kmessagewidget.h KMessageWidget
19  *
20  * @short A widget to provide feedback or propose opportunistic interactions.
21  *
22  * KMessageWidget can be used to provide inline positive or negative
23  * feedback, or to implement opportunistic interactions.
24  *
25  * As a feedback widget, KMessageWidget provides a less intrusive alternative
26  * to "OK Only" message boxes. If you want to avoid a modal KMessageBox,
27  * consider using KMessageWidget instead.
28  *
29  * Examples of KMessageWidget look as follows, all of them having an icon set
30  * with setIcon(), and the first three show a close button:
31  *
32  * \image html kmessagewidget.png "KMessageWidget with different message types"
33  *
34  * <b>Negative feedback</b>
35  *
36  * The KMessageWidget can be used as a secondary indicator of failure: the
37  * first indicator is usually the fact the action the user expected to happen
38  * did not happen.
39  *
40  * Example: User fills a form, clicks "Submit".
41  *
42  * @li Expected feedback: form closes
43  * @li First indicator of failure: form stays there
44  * @li Second indicator of failure: a KMessageWidget appears on top of the
45  * form, explaining the error condition
46  *
47  * When used to provide negative feedback, KMessageWidget should be placed
48  * close to its context. In the case of a form, it should appear on top of the
49  * form entries.
50  *
51  * KMessageWidget should get inserted in the existing layout. Space should not
52  * be reserved for it, otherwise it becomes "dead space", ignored by the user.
53  * KMessageWidget should also not appear as an overlay to prevent blocking
54  * access to elements the user needs to interact with to fix the failure.
55  *
56  * <b>Positive feedback</b>
57  *
58  * KMessageWidget can be used for positive feedback but it shouldn't be
59  * overused. It is often enough to provide feedback by simply showing the
60  * results of an action.
61  *
62  * Examples of acceptable uses:
63  *
64  * @li Confirm success of "critical" transactions
65  * @li Indicate completion of background tasks
66  *
67  * Example of unadapted uses:
68  *
69  * @li Indicate successful saving of a file
70  * @li Indicate a file has been successfully removed
71  *
72  * <b>Opportunistic interaction</b>
73  *
74  * Opportunistic interaction is the situation where the application suggests to
75  * the user an action he could be interested in perform, either based on an
76  * action the user just triggered or an event which the application noticed.
77  *
78  * Example of acceptable uses:
79  *
80  * @li A browser can propose remembering a recently entered password
81  * @li A music collection can propose ripping a CD which just got inserted
82  * @li A chat application may notify the user a "special friend" just connected
83  *
84  * @author Aurélien Gâteau <agateau@kde.org>
85  * @since 4.7
86  */
87 class KWIDGETSADDONS_EXPORT KMessageWidget : public QFrame
88 {
89     Q_OBJECT
90 
91     Q_PROPERTY(QString text READ text WRITE setText)
92     Q_PROPERTY(bool wordWrap READ wordWrap WRITE setWordWrap)
93     Q_PROPERTY(bool closeButtonVisible READ isCloseButtonVisible WRITE setCloseButtonVisible)
94     Q_PROPERTY(MessageType messageType READ messageType WRITE setMessageType)
95     Q_PROPERTY(QIcon icon READ icon WRITE setIcon)
96 public:
97     /**
98      * Available message types.
99      * The background colors are chosen depending on the message type.
100      */
101     enum MessageType {
102         Positive,
103         Information,
104         Warning,
105         Error,
106     };
107     Q_ENUM(MessageType)
108 
109     /**
110      * Constructs a KMessageWidget with the specified @p parent.
111      */
112     explicit KMessageWidget(QWidget *parent = nullptr);
113 
114     /**
115      * Constructs a KMessageWidget with the specified @p parent and
116      * contents @p text.
117      */
118     explicit KMessageWidget(const QString &text, QWidget *parent = nullptr);
119 
120     /**
121      * Destructor.
122      */
123     ~KMessageWidget() override;
124 
125     /**
126      * Get the text of this message widget.
127      * @see setText()
128      */
129     QString text() const;
130 
131     /**
132      * Check whether word wrap is enabled.
133      *
134      * If word wrap is enabled, the message widget wraps the displayed text
135      * as required to the available width of the widget. This is useful to
136      * avoid breaking widget layouts.
137      *
138      * @see setWordWrap()
139      */
140     bool wordWrap() const;
141 
142     /**
143      * Check whether the close button is visible.
144      *
145      * @see setCloseButtonVisible()
146      */
147     bool isCloseButtonVisible() const;
148 
149     /**
150      * Get the type of this message.
151      * By default, the type is set to KMessageWidget::Information.
152      *
153      * @see KMessageWidget::MessageType, setMessageType()
154      */
155     MessageType messageType() const;
156 
157     /**
158      * Add @p action to the message widget.
159      * For each action a button is added to the message widget in the
160      * order the actions were added.
161      *
162      * @param action the action to add
163      * @see removeAction(), QWidget::actions()
164      */
165     void addAction(QAction *action);
166 
167     /**
168      * Remove @p action from the message widget.
169      *
170      * @param action the action to remove
171      * @see KMessageWidget::MessageType, addAction(), setMessageType()
172      */
173     void removeAction(QAction *action);
174 
175     /**
176      * Returns the preferred size of the message widget.
177      */
178     QSize sizeHint() const override;
179 
180     /**
181      * Returns the minimum size of the message widget.
182      */
183     QSize minimumSizeHint() const override;
184 
185     /**
186      * Returns the required height for @p width.
187      * @param width the width in pixels
188      */
189     int heightForWidth(int width) const override;
190 
191     /**
192      * The icon shown on the left of the text. By default, no icon is shown.
193      * @since 4.11
194      */
195     QIcon icon() const;
196 
197     /**
198      * Check whether the hide animation started by calling animatedHide()
199      * is still running. If animations are disabled, this function always
200      * returns @e false.
201      *
202      * @see animatedHide(), hideAnimationFinished()
203      * @since 5.0
204      */
205     bool isHideAnimationRunning() const;
206 
207     /**
208      * Check whether the show animation started by calling animatedShow()
209      * is still running. If animations are disabled, this function always
210      * returns @e false.
211      *
212      * @see animatedShow(), showAnimationFinished()
213      * @since 5.0
214      */
215     bool isShowAnimationRunning() const;
216 
217 public Q_SLOTS:
218     /**
219      * Set the text of the message widget to @p text.
220      * If the message widget is already visible, the text changes on the fly.
221      *
222      * @param text the text to display, rich text is allowed
223      * @see text()
224      */
225     void setText(const QString &text);
226 
227     /**
228      * Set word wrap to @p wordWrap. If word wrap is enabled, the text()
229      * of the message widget is wrapped to fit the available width.
230      * If word wrap is disabled, the message widget's minimum size is
231      * such that the entire text fits.
232      *
233      * By default word wrap is disabled.
234      *
235      * @param wordWrap disable/enable word wrap
236      * @see wordWrap()
237      */
238     void setWordWrap(bool wordWrap);
239 
240     /**
241      * Set the visibility of the close button. If @p visible is @e true,
242      * a close button is shown that calls animatedHide() if clicked.
243      *
244      * By default the close button is set to be visible.
245      *
246      * @see closeButtonVisible(), animatedHide()
247      */
248     void setCloseButtonVisible(bool visible);
249 
250     /**
251      * Set the message type to @p type.
252      * By default, the message type is set to KMessageWidget::Information.
253      * Appropriate colors are chosen to mimic the appearance of Kirigami's
254      * InlineMessage.
255      *
256      * @see messageType(), KMessageWidget::MessageType
257      */
258     void setMessageType(KMessageWidget::MessageType type);
259 
260     /**
261      * Show the widget using an animation.
262      */
263     void animatedShow();
264 
265     /**
266      * Hide the widget using an animation.
267      */
268     void animatedHide();
269 
270     /**
271      * Define an icon to be shown on the left of the text
272      * @since 4.11
273      */
274     void setIcon(const QIcon &icon);
275 
276 Q_SIGNALS:
277     /**
278      * This signal is emitted when the user clicks a link in the text label.
279      * The URL referred to by the href anchor is passed in contents.
280      * @param contents text of the href anchor
281      * @see QLabel::linkActivated()
282      * @since 4.10
283      */
284     void linkActivated(const QString &contents);
285 
286     /**
287      * This signal is emitted when the user hovers over a link in the text label.
288      * The URL referred to by the href anchor is passed in contents.
289      * @param contents text of the href anchor
290      * @see QLabel::linkHovered()
291      * @since 4.11
292      */
293     void linkHovered(const QString &contents);
294 
295     /**
296      * This signal is emitted when the hide animation is finished, started by
297      * calling animatedHide(). If animations are disabled, this signal is
298      * emitted immediately after the message widget got hidden.
299      *
300      * @note This signal is @e not emitted if the widget was hidden by
301      *       calling hide(), so this signal is only useful in conjunction
302      *       with animatedHide().
303      *
304      * @see animatedHide()
305      * @since 5.0
306      */
307     void hideAnimationFinished();
308 
309     /**
310      * This signal is emitted when the show animation is finished, started by
311      * calling animatedShow(). If animations are disabled, this signal is
312      * emitted immediately after the message widget got shown.
313      *
314      * @note This signal is @e not emitted if the widget was shown by
315      *       calling show(), so this signal is only useful in conjunction
316      *       with animatedShow().
317      *
318      * @see animatedShow()
319      * @since 5.0
320      */
321     void showAnimationFinished();
322 
323 protected:
324     void paintEvent(QPaintEvent *event) override;
325 
326     bool event(QEvent *event) override;
327 
328     void resizeEvent(QResizeEvent *event) override;
329 
330 private:
331     friend class KMessageWidgetPrivate;
332     std::unique_ptr<class KMessageWidgetPrivate> const d;
333 };
334 
335 #endif /* KMESSAGEWIDGET_H */
336