| 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 |
| 19 | * \inmodule KWidgetsAddons |
| 20 | * |
| 21 | * \brief A widget to provide feedback or propose opportunistic interactions. |
| 22 | * |
| 23 | * KMessageWidget can be used to provide inline positive or negative |
| 24 | * feedback, or to implement opportunistic interactions. |
| 25 | * |
| 26 | * As a feedback widget, KMessageWidget provides a less intrusive alternative |
| 27 | * to "OK Only" message boxes. If you want to avoid a modal KMessageBox, |
| 28 | * consider using KMessageWidget instead. |
| 29 | * |
| 30 | * Examples of KMessageWidget look as follows, all of them having an icon set |
| 31 | * with setIcon(), and the first three show a close button: |
| 32 | * |
| 33 | * \image kmessagewidget.png "KMessageWidget with different message types" |
| 34 | * |
| 35 | * \section1 Negative feedback |
| 36 | * |
| 37 | * The KMessageWidget can be used as a secondary indicator of failure: the |
| 38 | * first indicator is usually the fact the action the user expected to happen |
| 39 | * did not happen. |
| 40 | * |
| 41 | * Example: User fills a form, clicks "Submit". |
| 42 | * \list |
| 43 | * \li Expected feedback: form closes |
| 44 | * \li First indicator of failure: form stays there |
| 45 | * \li Second indicator of failure: a KMessageWidget appears on top of the |
| 46 | * form, explaining the error condition |
| 47 | * \endlist |
| 48 | * |
| 49 | * When used to provide negative feedback, KMessageWidget should be placed |
| 50 | * close to its context. In the case of a form, it should appear on top of the |
| 51 | * form entries. |
| 52 | * |
| 53 | * KMessageWidget should get inserted in the existing layout. Space should not |
| 54 | * be reserved for it, otherwise it becomes "dead space", ignored by the user. |
| 55 | * KMessageWidget should also not appear as an overlay to prevent blocking |
| 56 | * access to elements the user needs to interact with to fix the failure. |
| 57 | * |
| 58 | * \section1 Positive feedback |
| 59 | * |
| 60 | * KMessageWidget can be used for positive feedback but it shouldn't be |
| 61 | * overused. It is often enough to provide feedback by simply showing the |
| 62 | * results of an action. |
| 63 | * |
| 64 | * Examples of acceptable uses: |
| 65 | * \list |
| 66 | * \li Confirm success of "critical" transactions |
| 67 | * \li Indicate completion of background tasks |
| 68 | * \endlist |
| 69 | * |
| 70 | * Example of unadapted uses: |
| 71 | * \list |
| 72 | * \li Indicate successful saving of a file |
| 73 | * \li Indicate a file has been successfully removed |
| 74 | * \endlist |
| 75 | * |
| 76 | * \section1 Opportunistic interaction |
| 77 | * |
| 78 | * Opportunistic interaction is the situation where the application suggests to |
| 79 | * the user an action he could be interested in perform, either based on an |
| 80 | * action the user just triggered or an event which the application noticed. |
| 81 | * |
| 82 | * Example of acceptable uses: |
| 83 | * \list |
| 84 | * \li A browser can propose remembering a recently entered password |
| 85 | * \li A music collection can propose ripping a CD which just got inserted |
| 86 | * \li A chat application may notify the user a "special friend" just connected |
| 87 | * \endlist |
| 88 | * |
| 89 | * \since 4.7 |
| 90 | */ |
| 91 | class KWIDGETSADDONS_EXPORT KMessageWidget : public QFrame |
| 92 | { |
| 93 | Q_OBJECT |
| 94 | |
| 95 | /*! |
| 96 | * \property KMessageWidget::text |
| 97 | */ |
| 98 | Q_PROPERTY(QString text READ text WRITE setText) |
| 99 | |
| 100 | /*! |
| 101 | * \property KMessageWidget::textFormat |
| 102 | */ |
| 103 | Q_PROPERTY(Qt::TextFormat textFormat READ textFormat WRITE setTextFormat) |
| 104 | |
| 105 | /*! |
| 106 | * \property KMessageWidget::wordWrap |
| 107 | */ |
| 108 | Q_PROPERTY(bool wordWrap READ wordWrap WRITE setWordWrap) |
| 109 | |
| 110 | /*! |
| 111 | * \property KMessageWidget::closeButtonVisible |
| 112 | */ |
| 113 | Q_PROPERTY(bool closeButtonVisible READ isCloseButtonVisible WRITE setCloseButtonVisible) |
| 114 | |
| 115 | /*! |
| 116 | * \property KMessageWidget::messageType |
| 117 | */ |
| 118 | Q_PROPERTY(MessageType messageType READ messageType WRITE setMessageType) |
| 119 | |
| 120 | /*! |
| 121 | * \property KMessageWidget::icon |
| 122 | */ |
| 123 | Q_PROPERTY(QIcon icon READ icon WRITE setIcon) |
| 124 | |
| 125 | /*! |
| 126 | * \property KMessageWidget::position |
| 127 | */ |
| 128 | Q_PROPERTY(Position position READ position WRITE setPosition) |
| 129 | public: |
| 130 | /*! |
| 131 | * Available message types. |
| 132 | * The background colors are chosen depending on the message type. |
| 133 | * |
| 134 | * \value Positive Positive message type |
| 135 | * \value Information Information message type |
| 136 | * \value Warning Warning message type |
| 137 | * \value Error Error message type |
| 138 | */ |
| 139 | enum MessageType { |
| 140 | Positive, |
| 141 | Information, |
| 142 | Warning, |
| 143 | Error, |
| 144 | }; |
| 145 | Q_ENUM(MessageType) |
| 146 | |
| 147 | /*! |
| 148 | * Position of the KMessageWidget |
| 149 | * |
| 150 | * This will update the look of the KMessageWidget to be appropriate to the position. |
| 151 | * |
| 152 | * \value Inline The message widget is display inside the content. |
| 153 | * \value Header The message widget is displayed as header. |
| 154 | * \value Footer The message widget is displayed as footer. |
| 155 | * |
| 156 | * \since 6.0 |
| 157 | */ |
| 158 | enum Position { |
| 159 | Inline, |
| 160 | , |
| 161 | , |
| 162 | }; |
| 163 | Q_ENUM(Position); |
| 164 | |
| 165 | /*! |
| 166 | * Constructs a KMessageWidget with the specified \a parent. |
| 167 | */ |
| 168 | explicit KMessageWidget(QWidget *parent = nullptr); |
| 169 | |
| 170 | /*! |
| 171 | * Constructs a KMessageWidget with the specified \a parent and |
| 172 | * contents \a text. |
| 173 | */ |
| 174 | explicit KMessageWidget(const QString &text, QWidget *parent = nullptr); |
| 175 | |
| 176 | /*! |
| 177 | * Destructor. |
| 178 | */ |
| 179 | ~KMessageWidget() override; |
| 180 | |
| 181 | /*! |
| 182 | * Get the position of this message. By default this is KMessageWidget::Inline. |
| 183 | * \sa setPosition() |
| 184 | * \since 6.0 |
| 185 | */ |
| 186 | Position position() const; |
| 187 | |
| 188 | /*! |
| 189 | * Get the text of this message widget. |
| 190 | * \sa setText() |
| 191 | */ |
| 192 | QString text() const; |
| 193 | |
| 194 | /*! |
| 195 | * Get the text format of the message widget's label. |
| 196 | * \sa QLabel::textFormat() |
| 197 | * \since 6.0 |
| 198 | */ |
| 199 | Qt::TextFormat textFormat() const; |
| 200 | |
| 201 | /*! |
| 202 | * Set the text format of the message widget's label. |
| 203 | * \sa QLabel::setTextFormat() |
| 204 | * \since 6.0 |
| 205 | */ |
| 206 | void setTextFormat(Qt::TextFormat textFormat); |
| 207 | |
| 208 | /*! |
| 209 | * Check whether word wrap is enabled. |
| 210 | * |
| 211 | * If word wrap is enabled, the message widget wraps the displayed text |
| 212 | * as required to the available width of the widget. This is useful to |
| 213 | * avoid breaking widget layouts. |
| 214 | * |
| 215 | * \sa setWordWrap() |
| 216 | */ |
| 217 | bool wordWrap() const; |
| 218 | |
| 219 | /*! |
| 220 | * Check whether the close button is visible. |
| 221 | * |
| 222 | * \sa setCloseButtonVisible() |
| 223 | */ |
| 224 | bool isCloseButtonVisible() const; |
| 225 | |
| 226 | /*! |
| 227 | * Get the type of this message. |
| 228 | * By default, the type is set to KMessageWidget::Information. |
| 229 | * |
| 230 | * \sa KMessageWidget::MessageType, setMessageType() |
| 231 | */ |
| 232 | MessageType messageType() const; |
| 233 | |
| 234 | /*! |
| 235 | * Add \a action to the message widget. |
| 236 | * |
| 237 | * For each action a button is added to the message widget in the |
| 238 | * order the actions were added. |
| 239 | * |
| 240 | * \a action the action to add |
| 241 | * \sa removeAction(), QWidget::actions() |
| 242 | */ |
| 243 | void addAction(QAction *action); |
| 244 | |
| 245 | /*! |
| 246 | * Remove \a action from the message widget. |
| 247 | * |
| 248 | * \a action the action to remove |
| 249 | * |
| 250 | * \sa KMessageWidget::MessageType, addAction(), setMessageType() |
| 251 | */ |
| 252 | void removeAction(QAction *action); |
| 253 | |
| 254 | /*! |
| 255 | * Clears all actions from the message widget. |
| 256 | * |
| 257 | * \sa KMessageWidget::MessageType, addAction() and removeAction() |
| 258 | * \since 5.100 |
| 259 | */ |
| 260 | void clearActions(); |
| 261 | |
| 262 | QSize sizeHint() const override; |
| 263 | |
| 264 | QSize minimumSizeHint() const override; |
| 265 | |
| 266 | int heightForWidth(int width) const override; |
| 267 | |
| 268 | /*! |
| 269 | * The icon shown on the left of the text. By default, no icon is shown. |
| 270 | * \since 4.11 |
| 271 | */ |
| 272 | QIcon icon() const; |
| 273 | |
| 274 | /*! |
| 275 | * Check whether the hide animation started by calling animatedHide() |
| 276 | * is still running. If animations are disabled, this function always |
| 277 | * returns \c false. |
| 278 | * |
| 279 | * \sa animatedHide(), hideAnimationFinished() |
| 280 | * \since 5.0 |
| 281 | */ |
| 282 | bool isHideAnimationRunning() const; |
| 283 | |
| 284 | /*! |
| 285 | * Check whether the show animation started by calling animatedShow() |
| 286 | * is still running. If animations are disabled, this function always |
| 287 | * returns \c false. |
| 288 | * |
| 289 | * \sa animatedShow(), showAnimationFinished() |
| 290 | * \since 5.0 |
| 291 | */ |
| 292 | bool isShowAnimationRunning() const; |
| 293 | |
| 294 | public Q_SLOTS: |
| 295 | /*! |
| 296 | * Set the text of the message widget to \a text. |
| 297 | * If the message widget is already visible, the text changes on the fly. |
| 298 | * |
| 299 | * \a text the text to display, rich text is allowed |
| 300 | * |
| 301 | * \sa text() |
| 302 | */ |
| 303 | void setText(const QString &text); |
| 304 | |
| 305 | /*! |
| 306 | * Set the position of this message |
| 307 | * \sa position() |
| 308 | * \since 6.0 |
| 309 | */ |
| 310 | void setPosition(Position position); |
| 311 | |
| 312 | /*! |
| 313 | * Set word wrap to \a wordWrap. If word wrap is enabled, the text() |
| 314 | * of the message widget is wrapped to fit the available width. |
| 315 | * If word wrap is disabled, the message widget's minimum size is |
| 316 | * such that the entire text fits. |
| 317 | * |
| 318 | * By default word wrap is disabled. |
| 319 | * |
| 320 | * \a wordWrap disable/enable word wrap |
| 321 | * \sa wordWrap() |
| 322 | */ |
| 323 | void setWordWrap(bool wordWrap); |
| 324 | |
| 325 | /*! |
| 326 | * Set the visibility of the close button. If \a visible is \c true, |
| 327 | * a close button is shown that calls animatedHide() if clicked. |
| 328 | * |
| 329 | * By default the close button is set to be visible. |
| 330 | * |
| 331 | * \sa closeButtonVisible(), animatedHide() |
| 332 | */ |
| 333 | void setCloseButtonVisible(bool visible); |
| 334 | |
| 335 | /*! |
| 336 | * Set the message type to \a type. |
| 337 | * By default, the message type is set to KMessageWidget::Information. |
| 338 | * Appropriate colors are chosen to mimic the appearance of Kirigami's |
| 339 | * InlineMessage. |
| 340 | * |
| 341 | * \sa messageType(), KMessageWidget::MessageType |
| 342 | */ |
| 343 | void setMessageType(KMessageWidget::MessageType type); |
| 344 | |
| 345 | /*! |
| 346 | * Show the widget using an animation. |
| 347 | */ |
| 348 | void animatedShow(); |
| 349 | |
| 350 | /*! |
| 351 | * Hide the widget using an animation. |
| 352 | */ |
| 353 | void animatedHide(); |
| 354 | |
| 355 | /*! |
| 356 | * Define an icon to be shown on the left of the text |
| 357 | * \since 4.11 |
| 358 | */ |
| 359 | void setIcon(const QIcon &icon); |
| 360 | |
| 361 | Q_SIGNALS: |
| 362 | /*! |
| 363 | * This signal is emitted when the user clicks a link in the text label. |
| 364 | * |
| 365 | * The URL referred to by the href anchor is passed in contents. |
| 366 | * |
| 367 | * \a contents text of the href anchor |
| 368 | * |
| 369 | * \sa QLabel::linkActivated() |
| 370 | * \since 4.10 |
| 371 | */ |
| 372 | void linkActivated(const QString &contents); |
| 373 | |
| 374 | /*! |
| 375 | * This signal is emitted when the user hovers over a link in the text label. |
| 376 | * |
| 377 | * The URL referred to by the href anchor is passed in contents. |
| 378 | * |
| 379 | * \a contents text of the href anchor |
| 380 | * |
| 381 | * \sa QLabel::linkHovered() |
| 382 | * \since 4.11 |
| 383 | */ |
| 384 | void linkHovered(const QString &contents); |
| 385 | |
| 386 | /*! |
| 387 | * This signal is emitted when the hide animation is finished, started by |
| 388 | * calling animatedHide(). If animations are disabled, this signal is |
| 389 | * emitted immediately after the message widget got hidden. |
| 390 | * |
| 391 | * \note This signal is not emitted if the widget was hidden by |
| 392 | * calling hide(), so this signal is only useful in conjunction |
| 393 | * with animatedHide(). |
| 394 | * |
| 395 | * \sa animatedHide() |
| 396 | * \since 5.0 |
| 397 | */ |
| 398 | void hideAnimationFinished(); |
| 399 | |
| 400 | /*! |
| 401 | * This signal is emitted when the show animation is finished, started by |
| 402 | * calling animatedShow(). If animations are disabled, this signal is |
| 403 | * emitted immediately after the message widget got shown. |
| 404 | * |
| 405 | * \note This signal is not emitted if the widget was shown by |
| 406 | * calling show(), so this signal is only useful in conjunction |
| 407 | * with animatedShow(). |
| 408 | * |
| 409 | * \sa animatedShow() |
| 410 | * \since 5.0 |
| 411 | */ |
| 412 | void showAnimationFinished(); |
| 413 | |
| 414 | protected: |
| 415 | void paintEvent(QPaintEvent *event) override; |
| 416 | |
| 417 | bool event(QEvent *event) override; |
| 418 | |
| 419 | void resizeEvent(QResizeEvent *event) override; |
| 420 | |
| 421 | private: |
| 422 | friend class KMessageWidgetPrivate; |
| 423 | std::unique_ptr<class KMessageWidgetPrivate> const d; |
| 424 | }; |
| 425 | |
| 426 | #endif /* KMESSAGEWIDGET_H */ |
| 427 | |