KWidgetsAddons

ktitlewidget.cpp
1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2007 Urs Wolfer <uwolfer@kde.org>
4 SPDX-FileCopyrightText: 2007 Michaƫl Larouche <larouche@kde.org>
5
6 SPDX-License-Identifier: LGPL-2.0-or-later
7*/
8
9#include "ktitlewidget.h"
10
11#include <QApplication>
12#include <QFrame>
13#include <QIcon>
14#include <QLabel>
15#include <QLayout>
16#include <QMouseEvent>
17#include <QStyle>
18#include <QTextDocument>
19#include <QTimer>
20
21class KTitleWidgetPrivate
22{
23public:
24 KTitleWidgetPrivate(KTitleWidget *parent)
25 : q(parent)
26 // use Left so updateIconAlignment(ImageRight) as called by constructor triggers the default layout
27 , iconAlignment(KTitleWidget::ImageLeft)
28 , autoHideTimeout(0)
29 , messageType(KTitleWidget::InfoMessage)
30 {
31 }
32
33 QString textStyleSheet() const
34 {
35 qreal factor;
36 switch (level) {
37 case 1:
38 factor = 1.35;
39 break;
40 case 2:
41 factor = 1.20;
42 break;
43 case 3:
44 factor = 1.15;
45 break;
46 case 4:
47 factor = 1.10;
48 break;
49 default:
50 factor = 1;
51 }
52 const double fontSize = QApplication::font().pointSize() * factor;
53 return QStringLiteral("QLabel { font-size: %1pt; color: %2 }").arg(QString::number(fontSize), q->palette().color(QPalette::WindowText).name());
54 }
55
56 QString commentStyleSheet() const
57 {
58 QString styleSheet;
59 switch (messageType) {
60 // FIXME: we need the usability color styles to implement different
61 // yet palette appropriate colours for the different use cases!
62 // also .. should we include an icon here,
63 // perhaps using the imageLabel?
67 styleSheet = QStringLiteral("QLabel { color: palette(%1); background: palette(%2); }")
68 .arg(q->palette().color(QPalette::HighlightedText).name(), q->palette().color(QPalette::Highlight).name());
69 break;
71 default:
72 break;
73 }
74 return styleSheet;
75 }
76
77 void updateIconAlignment(KTitleWidget::ImageAlignment newIconAlignment)
78 {
79 if (iconAlignment == newIconAlignment) {
80 return;
81 }
82
83 iconAlignment = newIconAlignment;
84
85 headerLayout->removeWidget(textLabel);
86 headerLayout->removeWidget(commentLabel);
87 headerLayout->removeWidget(imageLabel);
88
89 if (iconAlignment == KTitleWidget::ImageLeft) {
90 // swap the text and image labels around
91 headerLayout->addWidget(imageLabel, 0, 0, 2, 1);
92 headerLayout->addWidget(textLabel, 0, 1);
93 headerLayout->addWidget(commentLabel, 1, 1);
94 headerLayout->setColumnStretch(0, 0);
95 headerLayout->setColumnStretch(1, 1);
96 } else {
97 headerLayout->addWidget(textLabel, 0, 0);
98 headerLayout->addWidget(commentLabel, 1, 0);
99 headerLayout->addWidget(imageLabel, 0, 1, 2, 1);
100 headerLayout->setColumnStretch(1, 0);
101 headerLayout->setColumnStretch(0, 1);
102 }
103 }
104
105 void updatePixmap()
106 {
107 const QPixmap pixmap = icon.pixmap(q->iconSize());
108 imageLabel->setPixmap(pixmap);
109 }
110
111 int level = 1;
112 KTitleWidget *const q;
113 QGridLayout *headerLayout;
114 QLabel *imageLabel;
115 QLabel *textLabel;
116 QLabel *commentLabel;
117 QIcon icon;
118 QSize iconSize;
119 KTitleWidget::ImageAlignment iconAlignment;
120 int autoHideTimeout;
121 KTitleWidget::MessageType messageType;
122
123 /**
124 * @brief Get the icon name from the icon type
125 * @param type icon type from the enum
126 * @return named icon as QString
127 */
128 QString iconTypeToIconName(KTitleWidget::MessageType type);
129
130 void timeoutFinished()
131 {
132 q->setVisible(false);
133 }
134};
135
136QString KTitleWidgetPrivate::iconTypeToIconName(KTitleWidget::MessageType type)
137{
138 switch (type) {
140 return QStringLiteral("dialog-information");
142 return QStringLiteral("dialog-error");
144 return QStringLiteral("dialog-warning");
146 break;
147 }
148
149 return QString();
150}
151
153 : QWidget(parent)
154 , d(new KTitleWidgetPrivate(this))
155{
156 // default image / text part start
157 d->headerLayout = new QGridLayout();
158 d->headerLayout->setContentsMargins(0, 0, 0, 0);
159 d->headerLayout->setSizeConstraint(QLayout::SetFixedSize);
160
161 d->textLabel = new QLabel(this);
162 d->textLabel->setVisible(false);
163 d->textLabel->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse);
164
165 d->imageLabel = new QLabel(this);
166 d->imageLabel->setVisible(false);
167
168 d->commentLabel = new QLabel(this);
169 d->commentLabel->setVisible(false);
170 d->commentLabel->setOpenExternalLinks(true);
171 d->commentLabel->setWordWrap(true);
172 d->commentLabel->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse);
173
174 d->updateIconAlignment(ImageRight); // make sure d->iconAlignment is left, to trigger initial layout
175 // default image / text part end
176
177 // vertical centering of the complete header
178 auto *mainLayout = new QVBoxLayout(this);
179 mainLayout->addLayout(d->headerLayout);
180 // headerLayout's sizeConstraint being QLayout::SetFixedSize is ignored when added to a layout
181 // with default Qt::Alignment(). instead is stretched to match the whole size.
182 // Sadly QVBoxLayout::addLayout does not have a alignment argument, other than QVBoxLayout::addWidget,
183 // so set it afterwards onto the layout item generated.
184 mainLayout->itemAt(0)->setAlignment(Qt::AlignVCenter);
185 mainLayout->setContentsMargins(0, 0, 0, 0);
186}
187
188KTitleWidget::~KTitleWidget() = default;
189
190bool KTitleWidget::eventFilter(QObject *object, QEvent *event)
191{
192 // Hide message label on click
193 if (d->autoHideTimeout > 0 && event->type() == QEvent::MouseButtonPress) {
194 QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
195 if (mouseEvent && mouseEvent->button() == Qt::LeftButton) {
196 setVisible(false);
197 return true;
198 }
199 }
200
201 return QWidget::eventFilter(object, event);
202}
203
205{
206 d->headerLayout->addWidget(widget, 2, 0, 1, 2);
207}
208
209QString KTitleWidget::text() const
210{
211 return d->textLabel->text();
212}
213
214QString KTitleWidget::comment() const
215{
216 return d->commentLabel->text();
217}
218
220{
221 return d->icon;
222}
223
225{
226 if (d->iconSize.isValid()) {
227 return d->iconSize;
228 }
229 const int iconSizeExtent = style()->pixelMetric(QStyle::PM_MessageBoxIconSize);
230 return QSize(iconSizeExtent, iconSizeExtent);
231}
232
234{
235 d->textLabel->setBuddy(buddy);
236}
237
238void KTitleWidget::changeEvent(QEvent *e)
239{
242 d->textLabel->setStyleSheet(d->textStyleSheet());
243 d->commentLabel->setStyleSheet(d->commentStyleSheet());
244 d->updatePixmap();
245 } else if (e->type() == QEvent::StyleChange) {
246 if (!d->iconSize.isValid()) {
247 // relies on style's PM_MessageBoxIconSize
248 d->updatePixmap();
249 }
250 }
251}
252
253void KTitleWidget::setText(const QString &text, Qt::Alignment alignment)
254{
255 d->textLabel->setVisible(!text.isNull());
256
257 if (!Qt::mightBeRichText(text)) {
258 d->textLabel->setStyleSheet(d->textStyleSheet());
259 }
260
261 d->textLabel->setText(text);
262 d->textLabel->setAlignment(alignment);
263 show();
264}
265
267{
268 if (d->level == level) {
269 return;
270 }
271
272 d->level = level;
273
274 d->textLabel->setStyleSheet(d->textStyleSheet());
275}
276
278{
279 return d->level;
280}
281
283{
284 setIcon(type);
285 setText(text);
286}
287
289{
290 d->commentLabel->setVisible(!comment.isNull());
291
292 // TODO: should we override the current icon with the corresponding MessageType icon?
293 d->messageType = type;
294 d->commentLabel->setStyleSheet(d->commentStyleSheet());
295 d->commentLabel->setText(comment);
296 show();
297}
298
300{
301 d->icon = icon;
302
303 d->imageLabel->setVisible(!icon.isNull());
304
305 d->updateIconAlignment(alignment);
306
307 d->updatePixmap();
308}
309
310void KTitleWidget::setIconSize(const QSize &iconSize)
311{
312 if (d->iconSize == iconSize) {
313 return;
314 }
315
316 const QSize oldEffectiveIconSize = this->iconSize();
317
318 d->iconSize = iconSize;
319
320 if (oldEffectiveIconSize != this->iconSize()) {
321 d->updatePixmap();
322 }
323}
324
326{
327 setIcon(QIcon::fromTheme(d->iconTypeToIconName(type)), alignment);
328}
329
330int KTitleWidget::autoHideTimeout() const
331{
332 return d->autoHideTimeout;
333}
334
336{
337 d->autoHideTimeout = msecs;
338
339 if (msecs > 0) {
340 installEventFilter(this);
341 } else {
342 removeEventFilter(this);
343 }
344}
345
346void KTitleWidget::showEvent(QShowEvent *event)
347{
348 Q_UNUSED(event)
349 if (d->autoHideTimeout > 0) {
350 QTimer::singleShot(d->autoHideTimeout, this, [this] {
351 d->timeoutFinished();
352 });
353 }
354}
355
356#include "moc_ktitlewidget.cpp"
Standard title widget.
void setIcon(const QIcon &icon, ImageAlignment alignment=ImageRight)
Set the icon to display in the header.
void setIconSize(const QSize &iconSize)
Set the size of the icon to display in the header.
KTitleWidget(QWidget *parent=nullptr)
Constructs a title widget.
ImageAlignment
Possible title pixmap alignments.
@ ImageLeft
Display the pixmap on the left.
@ ImageRight
Display the pixmap on the right.
void setWidget(QWidget *widget)
void setBuddy(QWidget *buddy)
Sets this label's buddy to buddy.
void setText(const QString &text, Qt::Alignment alignment=Qt::AlignLeft|Qt::AlignVCenter)
void setLevel(int level)
Sets the level of this title, similar to HTML's h1 h2 h3... Follows the KDE HIG.
MessageType
Comment message types.
@ ErrorMessage
An error message.
@ InfoMessage
Information the user should be alerted to.
@ PlainMessage
Normal comment.
@ WarningMessage
A warning the user should be alerted to.
void setAutoHideTimeout(int msecs)
Set the autohide timeout of the label Set value to 0 to disable autohide, which is the default.
void setComment(const QString &comment, MessageType type=PlainMessage)
QFont font()
MouseButtonPress
Type type() const const
int pointSize() const const
void addWidget(QWidget *widget, int fromRow, int fromColumn, int rowSpan, int columnSpan, Qt::Alignment alignment)
void setColumnStretch(int column, int stretch)
QPixmap pixmap(QWindow *window, const QSize &size, Mode mode, State state) const const
QIcon fromTheme(const QString &name)
bool isNull() const const
void setPixmap(const QPixmap &)
void removeWidget(QWidget *widget)
virtual bool eventFilter(QObject *watched, QEvent *event)
void installEventFilter(QObject *filterObj)
void removeEventFilter(QObject *obj)
Qt::MouseButton button() const const
QString arg(Args &&... args) const const
bool isNull() const const
QString number(double n, char format, int precision)
PM_MessageBoxIconSize
virtual int pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const const=0
bool mightBeRichText(const QString &text)
AlignVCenter
LeftButton
TextSelectableByMouse
virtual void changeEvent(QEvent *event)
virtual bool event(QEvent *event) override
void show()
QStyle * style() const const
virtual void setVisible(bool visible)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Jul 26 2024 12:00:22 by doxygen 1.11.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.