MauiKit Controls

icon.cpp
1/*
2 * SPDX-FileCopyrightText: 2011 Marco Martin <mart@kde.org>
3 * SPDX-FileCopyrightText: 2014 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
4 *
5 * SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7
8#include "icon.h"
9#include "platformtheme.h"
10#include "managedtexturenode.h"
11
12#include <QBitmap>
13#include <QDebug>
14#include <QGuiApplication>
15#include <QIcon>
16#include <QPainter>
17#include <QQuickImageProvider>
18#include <QQuickWindow>
19#include <QSGSimpleTextureNode>
20#include <QSGTexture>
21#include <QScreen>
22#include <QtQml>
23
24Q_GLOBAL_STATIC(ImageTexturesCache, s_iconImageCache)
25
26Icon::Icon(QQuickItem *parent)
27 : QQuickItem(parent)
28 , m_changed(false)
29 , m_active(false)
30 , m_selected(false)
31 , m_isMask(false)
32{
33 setFlag(ItemHasContents, true);
34 // Using 32 because Icon used to redefine implicitWidth and implicitHeight and hardcode them to 32
35 setImplicitSize(32, 32);
36 // FIXME: not necessary anymore
40
41}
42
43Icon::~Icon()
44{
45}
46
47void Icon::setSource(const QVariant &icon)
48{
49 if (m_source == icon) {
50 return;
51 }
52 m_source = icon;
53 m_monochromeHeuristics.clear();
54
55 if (!m_theme) {
56 m_theme = static_cast<Maui::PlatformTheme *>(qmlAttachedPropertiesObject<Maui::PlatformTheme>(this, true));
57 Q_ASSERT(m_theme);
58
59 connect(m_theme, &Maui::PlatformTheme::PlatformTheme::colorsChanged, this, &QQuickItem::polish);
60 }
61
62 if (icon.type() == QVariant::String) {
63 const QString iconSource = icon.toString();
64 m_isMaskHeuristic = (iconSource.endsWith(QLatin1String("-symbolic")) //
65 || iconSource.endsWith(QLatin1String("-symbolic-rtl")) //
66 || iconSource.endsWith(QLatin1String("-symbolic-ltr")));
67 Q_EMIT isMaskChanged();
68 }
69
70 if (m_networkReply) {
71 // if there was a network query going on, interrupt it
72 m_networkReply->close();
73 }
74 m_loadedImage = QImage();
75 setStatus(Loading);
76
77 polish();
78 Q_EMIT sourceChanged();
79 Q_EMIT validChanged();
80}
81
83{
84 return m_source;
85}
86
87void Icon::setActive(const bool active)
88{
89 if (active == m_active) {
90 return;
91 }
92 m_active = active;
93 polish();
94 Q_EMIT activeChanged();
95}
96
97bool Icon::active() const
98{
99 return m_active;
100}
101
102bool Icon::valid() const
103{
104 // TODO: should this be return m_status == Ready?
105 // Consider an empty URL invalid, even though isNull() will say false
106 if (m_source.canConvert<QUrl>() && m_source.toUrl().isEmpty()) {
107 return false;
108 }
109
110 return !m_source.isNull();
111}
112
113void Icon::setSelected(const bool selected)
114{
115 if (selected == m_selected) {
116 return;
117 }
118 m_selected = selected;
119 polish();
120 Q_EMIT selectedChanged();
121}
122
123bool Icon::selected() const
124{
125 return m_selected;
126}
127
128void Icon::setIsMask(bool mask)
129{
130 if (m_isMask == mask) {
131 return;
132 }
133
134 m_isMask = mask;
135 m_isMaskHeuristic = mask;
136 polish();
137 Q_EMIT isMaskChanged();
138}
139
140bool Icon::isMask() const
141{
142 return m_isMask || m_isMaskHeuristic;
143}
144
145void Icon::setColor(const QColor &color)
146{
147 if (m_color == color) {
148 return;
149 }
150
151 m_color = color;
152 polish();
153 Q_EMIT colorChanged();
154}
155
156QColor Icon::color() const
157{
158 return m_color;
159}
160
161QSGNode *Icon::updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNodeData * /*data*/)
162{
163 if (m_source.isNull() || qFuzzyIsNull(width()) || qFuzzyIsNull(height())) {
164 delete node;
165 return Q_NULLPTR;
166 }
167
168 if (m_changed || node == nullptr) {
169 const QSize itemSize(width(), height());
170 QRect nodeRect(QPoint(0, 0), itemSize);
171
172 ManagedTextureNode *mNode = dynamic_cast<ManagedTextureNode *>(node);
173 if (!mNode) {
174 delete node;
175 mNode = new ManagedTextureNode;
176 }
177 if (itemSize.width() != 0 && itemSize.height() != 0) {
178 mNode->setTexture(s_iconImageCache->loadTexture(window(), m_icon, QQuickWindow::TextureCanUseAtlas));
179 if (m_icon.size() != itemSize) {
180 // At this point, the image will already be scaled, but we need to output it in
181 // the correct aspect ratio, painted centered in the viewport. So:
182 QRect destination(QPoint(0, 0), m_icon.size().scaled(itemSize, Qt::KeepAspectRatio));
183 destination.moveCenter(nodeRect.center());
184 nodeRect = destination;
185 }
186 }
187 mNode->setRect(nodeRect);
188 node = mNode;
189 if (smooth()) {
191 }
192 m_changed = false;
193 }
194
195 return node;
196}
197
198void Icon::refresh()
199{
200 this->polish();
201}
202
203#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
204void Icon::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
205{
206 QQuickItem::geometryChanged(newGeometry, oldGeometry);
207#else
208void Icon::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
209{
210 QQuickItem::geometryChange(newGeometry, oldGeometry);
211#endif
212 if (newGeometry.size() != oldGeometry.size()) {
213 polish();
214 }
215}
216
217void Icon::handleRedirect(QNetworkReply *reply)
218{
219 QNetworkAccessManager *qnam = reply->manager();
220 if (reply->error() != QNetworkReply::NoError) {
221 return;
222 }
223 const QUrl possibleRedirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
224 if (!possibleRedirectUrl.isEmpty()) {
225 const QUrl redirectUrl = reply->url().resolved(possibleRedirectUrl);
226 if (redirectUrl == reply->url()) {
227 // no infinite redirections thank you very much
228 reply->deleteLater();
229 return;
230 }
231 reply->deleteLater();
232 QNetworkRequest request(possibleRedirectUrl);
234 m_networkReply = qnam->get(request);
235 connect(m_networkReply.data(), &QNetworkReply::finished, this, [this]() {
236 handleFinished(m_networkReply);
237 });
238 }
239}
240
241void Icon::handleFinished(QNetworkReply *reply)
242{
243 if (!reply) {
244 return;
245 }
246
247 reply->deleteLater();
249 handleRedirect(reply);
250 return;
251 }
252
253 m_loadedImage = QImage();
254
255 const QString filename = reply->url().fileName();
256 if (!m_loadedImage.load(reply, filename.mid(filename.indexOf(QLatin1Char('.'))).toLatin1().constData())) {
257 qWarning() << "received broken image" << reply->url();
258
259 // broken image from data, inform the user of this with some useful broken-image thing...
260 const QIcon icon = QIcon::fromTheme(m_fallback);
261 m_loadedImage = icon.pixmap(window(), icon.actualSize(size().toSize()), iconMode(), QIcon::On).toImage();
262 }
263
264 polish();
265}
266
267void Icon::updatePolish()
268{
270
271 if (m_source.isNull()) {
272 setStatus(Ready);
273 updatePaintedGeometry();
274 update();
275 return;
276 }
277
278 const QSize itemSize(width(), height());
279 if (itemSize.width() != 0 && itemSize.height() != 0) {
281 ? 1
282 : (window() ? window()->effectiveDevicePixelRatio() : qGuiApp->devicePixelRatio());
283 const QSize size = itemSize * multiplier;
284
285 switch (m_source.type()) {
286 case QVariant::Pixmap:
287 m_icon = m_source.value<QPixmap>().toImage();
288 break;
289 case QVariant::Image:
290 m_icon = m_source.value<QImage>();
291 break;
292 case QVariant::Bitmap:
293 m_icon = m_source.value<QBitmap>().toImage();
294 break;
295 case QVariant::Icon: {
296 const QIcon icon = m_source.value<QIcon>();
297 m_icon = icon.pixmap(window(), icon.actualSize(itemSize), iconMode(), QIcon::On).toImage();
298 break;
299 }
300 case QVariant::Url:
301 case QVariant::String:
302 m_icon = findIcon(size);
303 break;
304 case QVariant::Brush:
305 // todo: fill here too?
306 case QVariant::Color:
308 m_icon.fill(m_source.value<QColor>());
309 break;
310 default:
311 break;
312 }
313
314 if (m_icon.isNull()) {
316 m_icon.fill(Qt::transparent);
317 }
318
319 const QColor tintColor = //
320 !m_color.isValid() || m_color == Qt::transparent //
321 ? (m_selected ? m_theme->highlightedTextColor() : m_theme->textColor())
322 : m_color;
323
324 // TODO: initialize m_isMask with icon.isMask()
325 if (tintColor.alpha() > 0 && (isMask() || guessMonochrome(m_icon))) {
326 QPainter p(&m_icon);
327 p.setCompositionMode(QPainter::CompositionMode_SourceIn);
328 p.fillRect(m_icon.rect(), tintColor);
329 p.end();
330 }
331 }
332 m_changed = true;
333 updatePaintedGeometry();
334 update();
335}
336
337QImage Icon::findIcon(const QSize &size)
338{
339 QImage img;
340 QString iconSource = m_source.toString();
341
342 if (iconSource.startsWith(QLatin1String("image://"))) {
344 ? (window() ? window()->effectiveDevicePixelRatio() : qGuiApp->devicePixelRatio())
345 : 1;
346 QUrl iconUrl(iconSource);
347 QString iconProviderId = iconUrl.host();
348 // QUrl path has the "/" prefix while iconId does not
349 QString iconId = iconUrl.path().remove(0, 1);
350
352 QQuickImageProvider *imageProvider = dynamic_cast<QQuickImageProvider *>(qmlEngine(this)->imageProvider(iconProviderId));
353 if (!imageProvider) {
354 return img;
355 }
356 switch (imageProvider->imageType()) {
358 img = imageProvider->requestImage(iconId, &actualSize, size * multiplier);
359 if (!img.isNull()) {
360 setStatus(Ready);
361 }
362 break;
364 img = imageProvider->requestPixmap(iconId, &actualSize, size * multiplier).toImage();
365 if (!img.isNull()) {
366 setStatus(Ready);
367 }
368 break;
370 if (!m_loadedImage.isNull()) {
371 setStatus(Ready);
373 }
374 QQuickAsyncImageProvider *provider = dynamic_cast<QQuickAsyncImageProvider *>(imageProvider);
375 auto response = provider->requestImageResponse(iconId, size * multiplier);
376 connect(response, &QQuickImageResponse::finished, this, [iconId, response, this]() {
377 if (response->errorString().isEmpty()) {
378 QQuickTextureFactory *textureFactory = response->textureFactory();
379 if (textureFactory) {
380 m_loadedImage = textureFactory->image();
381 delete textureFactory;
382 }
383 if (m_loadedImage.isNull()) {
384 // broken image from data, inform the user of this with some useful broken-image thing...
385 const QIcon icon = QIcon::fromTheme(m_fallback);
386 m_loadedImage = icon.pixmap(window(), icon.actualSize(QSize(width(), height())), iconMode(), QIcon::On).toImage();
387 setStatus(Error);
388 } else {
389 setStatus(Ready);
390 }
391 polish();
392 }
393 response->deleteLater();
394 });
395 // Temporary icon while we wait for the real image to load...
396 const QIcon icon = QIcon::fromTheme(m_placeholder);
397 img = icon.pixmap(window(), icon.actualSize(size), iconMode(), QIcon::On).toImage();
398 break;
399 }
401 QQuickTextureFactory *textureFactory = imageProvider->requestTexture(iconId, &actualSize, size * multiplier);
402 if (textureFactory) {
403 img = textureFactory->image();
404 }
405 if (img.isNull()) {
406 // broken image from data, or the texture factory wasn't healthy, inform the user of this with some useful broken-image thing...
407 const QIcon icon = QIcon::fromTheme(m_fallback);
408 img = icon.pixmap(window(), icon.actualSize(QSize(width(), height())), iconMode(), QIcon::On).toImage();
409 setStatus(Error);
410 } else {
411 setStatus(Ready);
412 }
413 break;
414 }
416 // will have to investigate this more
417 setStatus(Error);
418 break;
419 }
420 } else if (iconSource.startsWith(QLatin1String("http://")) || iconSource.startsWith(QLatin1String("https://"))) {
421 if (!m_loadedImage.isNull()) {
422 setStatus(Ready);
424 }
425 const auto url = m_source.toUrl();
426 QQmlEngine *engine = qmlEngine(this);
428 if (engine && (qnam = engine->networkAccessManager()) && (!m_networkReply || m_networkReply->url() != url)) {
429 QNetworkRequest request(url);
431 m_networkReply = qnam->get(request);
432 connect(m_networkReply.data(), &QNetworkReply::finished, this, [this]() {
433 handleFinished(m_networkReply);
434 });
435 }
436 // Temporary icon while we wait for the real image to load...
437 const QIcon icon = QIcon::fromTheme(m_placeholder);
438 img = icon.pixmap(window(), icon.actualSize(size), iconMode(), QIcon::On).toImage();
439 } else {
440 if (iconSource.startsWith(QLatin1String("qrc:/"))) {
441 iconSource = iconSource.mid(3);
442 } else if (iconSource.startsWith(QLatin1String("file:/"))) {
443 iconSource = QUrl(iconSource).path();
444 }
445
446 QIcon icon;
447 const bool isPath = iconSource.contains(QLatin1String("/"));
448 if (isPath) {
449 icon = QIcon(iconSource);
450 } else {
451 if (icon.isNull()) {
452 icon = m_theme->iconFromTheme(iconSource, m_color);
453 }
454 }
455 if (!icon.isNull()) {
456 img = icon.pixmap(window(), icon.actualSize(window(), size), iconMode(), QIcon::On).toImage();
457
458 setStatus(Ready);
459 /*const QColor tintColor = !m_color.isValid() || m_color == Qt::transparent ? (m_selected ? m_theme->highlightedTextColor() : m_theme->textColor())
460 : m_color;
461
462 if (m_isMask || icon.isMask() || iconSource.endsWith(QLatin1String("-symbolic")) || iconSource.endsWith(QLatin1String("-symbolic-rtl")) ||
463 iconSource.endsWith(QLatin1String("-symbolic-ltr")) || guessMonochrome(img)) { //
464 QPainter p(&img);
465 p.setCompositionMode(QPainter::CompositionMode_SourceIn);
466 p.fillRect(img.rect(), tintColor);
467 p.end();
468 }*/
469 }
470 }
471
472 if (!iconSource.isEmpty() && img.isNull()) {
473 setStatus(Error);
474 const QIcon icon = QIcon::fromTheme(m_fallback);
475 img = icon.pixmap(window(), icon.actualSize(size), iconMode(), QIcon::On).toImage();
476 }
477 return img;
478}
479
480QIcon::Mode Icon::iconMode() const
481{
482 if (!isEnabled()) {
483 return QIcon::Disabled;
484 } else if (m_selected) {
485 return QIcon::Selected;
486 } else if (m_active) {
487 return QIcon::Active;
488 }
489 return QIcon::Normal;
490}
491
492bool Icon::guessMonochrome(const QImage &img)
493{
494 // don't try for too big images
495 if (img.width() >= 256 || m_theme->supportsIconColoring()) {
496 return false;
497 }
498 // round size to a standard size. hardcode as we can't use KIconLoader
499 int stdSize;
500 if (img.width() <= 16) {
501 stdSize = 16;
502 } else if (img.width() <= 22) {
503 stdSize = 22;
504 } else if (img.width() <= 24) {
505 stdSize = 24;
506 } else if (img.width() <= 32) {
507 stdSize = 32;
508 } else if (img.width() <= 48) {
509 stdSize = 48;
510 } else if (img.width() <= 64) {
511 stdSize = 64;
512 } else {
513 stdSize = 128;
514 }
515
516 auto findIt = m_monochromeHeuristics.constFind(stdSize);
517 if (findIt != m_monochromeHeuristics.constEnd()) {
518 return findIt.value();
519 }
520
521 QHash<int, int> dist;
522 int transparentPixels = 0;
523 int saturatedPixels = 0;
524 for (int x = 0; x < img.width(); x++) {
525 for (int y = 0; y < img.height(); y++) {
526 QColor color = QColor::fromRgba(qUnpremultiply(img.pixel(x, y)));
527 if (color.alpha() < 100) {
528 ++transparentPixels;
529 continue;
530 } else if (color.saturation() > 84) {
531 ++saturatedPixels;
532 }
533 dist[qGray(color.rgb())]++;
534 }
535 }
536
537 QMultiMap<int, int> reverseDist;
538 auto it = dist.constBegin();
539 qreal entropy = 0;
540 while (it != dist.constEnd()) {
541 reverseDist.insert(it.value(), it.key());
542 qreal probability = qreal(it.value()) / qreal(img.size().width() * img.size().height() - transparentPixels);
543 entropy -= probability * log(probability) / log(255);
544 ++it;
545 }
546
547 // Arbitrarily low values of entropy and colored pixels
548 m_monochromeHeuristics[stdSize] = saturatedPixels <= (img.size().width() * img.size().height() - transparentPixels) * 0.3 && entropy <= 0.3;
549 return m_monochromeHeuristics[stdSize];
550}
551
553{
554 return m_fallback;
555}
556
557void Icon::setFallback(const QString &fallback)
558{
559 if (m_fallback != fallback) {
560 m_fallback = fallback;
561 Q_EMIT fallbackChanged(fallback);
562 }
563}
564
566{
567 return m_placeholder;
568}
569
570void Icon::setPlaceholder(const QString &placeholder)
571{
572 if (m_placeholder != placeholder) {
573 m_placeholder = placeholder;
574 Q_EMIT placeholderChanged(placeholder);
575 }
576}
577
578void Icon::setStatus(Status status)
579{
580 if (status == m_status) {
581 return;
582 }
583
584 m_status = status;
585 Q_EMIT statusChanged();
586}
587
589{
590 return m_status;
591}
592
593qreal Icon::paintedWidth() const
594{
595 return m_paintedWidth;
596}
597
598qreal Icon::paintedHeight() const
599{
600 return m_paintedHeight;
601}
602
603void Icon::updatePaintedGeometry()
604{
605 qreal newWidth = 0.0;
606 qreal newHeight = 0.0;
607 if (!m_icon.width() || !m_icon.height()) {
608 newWidth = newHeight = 0.0;
609 } else {
610 const qreal w = widthValid() ? width() : m_icon.size().width();
611 const qreal widthScale = w / m_icon.size().width();
612 const qreal h = heightValid() ? height() : m_icon.size().height();
613 const qreal heightScale = h / m_icon.size().height();
614 if (widthScale <= heightScale) {
615 newWidth = w;
616 newHeight = widthScale * m_icon.size().height();
617 } else if (heightScale < widthScale) {
618 newWidth = heightScale * m_icon.size().width();
619 newHeight = h;
620 }
621 }
622 if (newWidth != m_paintedWidth || newHeight != m_paintedHeight) {
623 m_paintedWidth = newWidth;
624 m_paintedHeight = newHeight;
625 Q_EMIT paintedAreaChanged();
626 }
627}
628
629void Icon::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value)
630{
632 polish();
633 }
634 QQuickItem::itemChange(change, value);
635}
636
637#include "moc_icon.cpp"
qreal paintedHeight
The height of the painted area measured in pixels.
Definition icon.h:154
QString placeholder
The name of an icon from the icon theme to show while the icon set in source is being loaded.
Definition icon.h:79
qreal paintedWidth
The width of the painted area measured in pixels.
Definition icon.h:146
bool selected
Whether this icon will use the QIcon::Selected mode when drawing the icon, resulting in a graphical e...
Definition icon.h:113
bool valid
Whether this icon's source is valid and it is being used.
Definition icon.h:99
QColor color
The color to use when drawing this icon when isMask is enabled.
Definition icon.h:130
Icon::Status status
Whether the icon is correctly loaded, is asynchronously loading or there was an error.
Definition icon.h:138
Status
Definition icon.h:156
@ Ready
No icon has been set.
Definition icon.h:158
@ Loading
The icon loaded correctly.
Definition icon.h:159
QString fallback
The name of a fallback icon to load from the icon theme when the source cannot be found.
Definition icon.h:66
QVariant source
The source of this icon.
Definition icon.h:56
bool isMask
Whether this icon will be treated as a mask.
Definition icon.h:122
bool active
Whether this icon will use the QIcon::Active mode when drawing the icon, resulting in a graphical eff...
Definition icon.h:94
This class is the base for color management in Maui, different platforms can reimplement this class t...
QColor highlightedTextColor
Color for text that has been highlighted, often is a light color while normal text is dark.
QColor textColor
Color for normal foregrounds, usually text, but not limited to it, anything that should be painted wi...
Q_SCRIPTABLE CaptureState status()
QAction * actualSize(const QObject *recvr, const char *slot, QObject *parent)
int alpha() const const
QColor fromRgba(QRgb rgba)
bool isValid() const const
QRgb rgb() const const
int saturation() const const
QCoreApplication * instance()
bool testAttribute(Qt::ApplicationAttribute attribute)
void paletteChanged(const QPalette &palette)
void clear()
const_iterator constBegin() const const
const_iterator constEnd() const const
const_iterator constFind(const Key &key) const const
QSize actualSize(QWindow *window, const QSize &size, Mode mode, State state) const const
QPixmap pixmap(QWindow *window, const QSize &size, Mode mode, State state) const const
QIcon fromTheme(const QString &name)
bool isNull() const const
int height() const const
bool isNull() const const
bool load(QIODevice *device, const char *format)
QRgb pixel(const QPoint &position) const const
QImage scaled(const QSize &size, Qt::AspectRatioMode aspectRatioMode, Qt::TransformationMode transformMode) const const
QSize size() const const
int width() const const
iterator insert(const Key &key, const T &value)
QNetworkReply * get(const QNetworkRequest &request)
QVariant attribute(QNetworkRequest::Attribute code) const const
NetworkError error() const const
QNetworkAccessManager * manager() const const
QUrl url() const const
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void deleteLater()
CompositionMode_SourceIn
QImage toImage() const const
T * data() const const
QNetworkAccessManager * networkAccessManager() const const
virtual QQuickImageResponse * requestImageResponse(const QString &id, const QSize &requestedSize)=0
virtual ImageType imageType() const const override
virtual QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize)
virtual QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize)
virtual QQuickTextureFactory * requestTexture(const QString &id, QSize *size, const QSize &requestedSize)
void enabledChanged()
virtual void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
bool heightValid() const const
virtual void itemChange(ItemChange change, const ItemChangeData &value)
void polish()
QSizeF size() const const
void smoothChanged(bool)
void update()
virtual void updatePolish()
bool widthValid() const const
QQuickWindow * window() const const
virtual QImage image() const const
qreal effectiveDevicePixelRatio() const const
QSizeF size() const const
void setFiltering(QSGTexture::Filtering filtering)
void setRect(const QRectF &r)
int height() const const
QSize scaled(const QSize &s, Qt::AspectRatioMode mode) const const
int width() const const
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
qsizetype indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
QString mid(qsizetype position, qsizetype n) const const
QString & remove(QChar ch, Qt::CaseSensitivity cs)
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
AA_UseHighDpiPixmaps
KeepAspectRatio
transparent
SmoothTransformation
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QString fileName(ComponentFormattingOptions options) const const
bool isEmpty() const const
QString path(ComponentFormattingOptions options) const const
QUrl resolved(const QUrl &relative) const const
Type type() const const
bool canConvert() const const
bool isNull() const const
QString toString() const const
QUrl toUrl() const const
T value() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri May 3 2024 11:47:05 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.