KCoreAddons

kaboutdata.cpp
1/*
2 This file is part of the KDE Libraries
3
4 SPDX-FileCopyrightText: 2000 Espen Sand <espen@kde.org>
5 SPDX-FileCopyrightText: 2006 Nicolas GOUTTE <goutte@kde.org>
6 SPDX-FileCopyrightText: 2008 Friedrich W. H. Kossebau <kossebau@kde.org>
7 SPDX-FileCopyrightText: 2010 Teo Mrnjavac <teo@kde.org>
8 SPDX-FileCopyrightText: 2017 Harald Sitter <sitter@kde.org>
9 SPDX-FileCopyrightText: 2021 Julius Künzel <jk.kdedev@smartlab.uber.space>
10
11 SPDX-License-Identifier: LGPL-2.0-or-later
12*/
13
14#include "kaboutdata.h"
15#include "kjsonutils.h"
16
17#include <QCommandLineOption>
18#include <QCommandLineParser>
19#include <QCoreApplication>
20#include <QFile>
21#include <QHash>
22#include <QJsonObject>
23#include <QList>
24#include <QLoggingCategory>
25#include <QSharedData>
26#include <QStandardPaths>
27#include <QTextStream>
28#include <QUrl>
29
30#include <algorithm>
31
32using namespace Qt::StringLiterals;
33
34Q_DECLARE_LOGGING_CATEGORY(KABOUTDATA)
35// logging category for this framework, default: log stuff >= warning
36Q_LOGGING_CATEGORY(KABOUTDATA, "kf.coreaddons.kaboutdata", QtWarningMsg)
37
38class KAboutPersonPrivate : public QSharedData
39{
40public:
41 QString _name;
42 QString _task;
43 QString _emailAddress;
44 QString _webAddress;
45 QUrl _avatarUrl;
46};
47
48KAboutPerson::KAboutPerson(const QString &_name, const QString &_task, const QString &_emailAddress, const QString &_webAddress, const QUrl &avatarUrl)
49 : d(new KAboutPersonPrivate)
50{
51 d->_name = _name;
52 d->_task = _task;
53 d->_emailAddress = _emailAddress;
54 d->_webAddress = _webAddress;
55 d->_avatarUrl = avatarUrl;
56}
57
58KAboutPerson::KAboutPerson(const QString &_name, const QString &_email, bool)
59 : d(new KAboutPersonPrivate)
60{
61 d->_name = _name;
62 d->_emailAddress = _email;
63}
64
65KAboutPerson::KAboutPerson(const KAboutPerson &other) = default;
66
67KAboutPerson::~KAboutPerson() = default;
68
69QString KAboutPerson::name() const
70{
71 return d->_name;
72}
73
74QString KAboutPerson::task() const
75{
76 return d->_task;
77}
78
79QString KAboutPerson::emailAddress() const
80{
81 return d->_emailAddress;
82}
83
84QString KAboutPerson::webAddress() const
85{
86 return d->_webAddress;
87}
88
89QUrl KAboutPerson::avatarUrl() const
90{
91 return d->_avatarUrl;
92}
93
95
97{
98 const QString name = KJsonUtils::readTranslatedString(obj, QStringLiteral("Name"));
99 const QString task = KJsonUtils::readTranslatedString(obj, QStringLiteral("Task"));
100 const QString email = obj.value(QLatin1String("Email")).toString();
101 const QString website = obj.value(QLatin1String("Website")).toString();
102 const QUrl avatarUrl = obj.value(QLatin1String("AvatarUrl")).toVariant().toUrl();
103 return KAboutPerson(name, task, email, website, avatarUrl);
104}
105
106class KAboutLicensePrivate : public QSharedData
107{
108public:
109 KAboutLicensePrivate(KAboutLicense::LicenseKey licenseType, KAboutLicense::VersionRestriction versionRestriction, const KAboutData *aboutData);
110 KAboutLicensePrivate(const KAboutLicensePrivate &other);
111
112 QString spdxID() const;
113
114 KAboutLicense::LicenseKey _licenseKey;
115 QString _licenseText;
116 QString _pathToLicenseTextFile;
117 KAboutLicense::VersionRestriction _versionRestriction;
118 // needed for access to the possibly changing copyrightStatement()
119 const KAboutData *_aboutData;
120};
121
122KAboutLicensePrivate::KAboutLicensePrivate(KAboutLicense::LicenseKey licenseType,
123 KAboutLicense::VersionRestriction versionRestriction,
124 const KAboutData *aboutData)
125 : QSharedData()
126 , _licenseKey(licenseType)
127 , _versionRestriction(versionRestriction)
128 , _aboutData(aboutData)
129{
130}
131
132KAboutLicensePrivate::KAboutLicensePrivate(const KAboutLicensePrivate &other)
133 : QSharedData(other)
134 , _licenseKey(other._licenseKey)
135 , _licenseText(other._licenseText)
136 , _pathToLicenseTextFile(other._pathToLicenseTextFile)
137 , _versionRestriction(other._versionRestriction)
138 , _aboutData(other._aboutData)
139{
140}
141
142QString KAboutLicensePrivate::spdxID() const
143{
144 switch (_licenseKey) {
146 return QStringLiteral("GPL-2.0");
148 return QStringLiteral("LGPL-2.0");
150 return QStringLiteral("BSD-2-Clause");
152 return QStringLiteral("BSD-3-Clause");
154 return QStringLiteral("Artistic-1.0");
156 return QStringLiteral("GPL-3.0");
158 return QStringLiteral("LGPL-3.0");
160 return QStringLiteral("LGPL-2.1");
162 return QStringLiteral("MIT");
164 return QStringLiteral("ODbL-1.0");
166 return QStringLiteral("Apache-2.0");
168 return QStringLiteral("FTL");
170 return QStringLiteral("BSL-1.0");
172 return QStringLiteral("CC0-1.0");
176 return QString();
177 }
178 return QString();
179}
180
182 : d(new KAboutLicensePrivate(Unknown, {}, nullptr))
183{
184}
185
186KAboutLicense::KAboutLicense(LicenseKey licenseType, VersionRestriction versionRestriction, const KAboutData *aboutData)
187 : d(new KAboutLicensePrivate(licenseType, versionRestriction, aboutData))
188{
189}
190
191KAboutLicense::KAboutLicense(LicenseKey licenseType, const KAboutData *aboutData)
192 : d(new KAboutLicensePrivate(licenseType, OnlyThisVersion, aboutData))
193{
194}
195
197 : d(new KAboutLicensePrivate(Unknown, OnlyThisVersion, aboutData))
198{
199}
200
202 : d(other.d)
203{
204}
205
206KAboutLicense::~KAboutLicense()
207{
208}
209
210void KAboutLicense::setLicenseFromPath(const QString &pathToFile)
211{
212 d->_licenseKey = KAboutLicense::File;
213 d->_pathToLicenseTextFile = pathToFile;
214}
215
216void KAboutLicense::setLicenseFromText(const QString &licenseText)
217{
218 d->_licenseKey = KAboutLicense::Custom;
219 d->_licenseText = licenseText;
220}
221
222QString KAboutLicense::text() const
223{
224 QString result;
225
226 const QString lineFeed = QStringLiteral("\n\n");
227
228 if (d->_aboutData && !d->_aboutData->copyrightStatement().isEmpty()
229 && (d->_licenseKey == KAboutLicense::BSD_2_Clause || d->_licenseKey == KAboutLicense::BSD_3_Clause || d->_licenseKey == KAboutLicense::MIT
230 || d->_licenseKey == KAboutLicense::Artistic)) {
231 result = d->_aboutData->copyrightStatement() + lineFeed;
232 }
233
234 bool knownLicense = false;
235 QString pathToFile; // rel path if known license
236 switch (d->_licenseKey) {
238 pathToFile = d->_pathToLicenseTextFile;
239 break;
241 knownLicense = true;
242 pathToFile = QStringLiteral("GPL_V2");
243 break;
245 knownLicense = true;
246 pathToFile = QStringLiteral("LGPL_V2");
247 break;
249 knownLicense = true;
250 pathToFile = QStringLiteral("BSD");
251 break;
253 knownLicense = true;
254 pathToFile = QStringLiteral("ARTISTIC");
255 break;
257 knownLicense = true;
258 pathToFile = QStringLiteral("GPL_V3");
259 break;
261 knownLicense = true;
262 pathToFile = QStringLiteral("LGPL_V3");
263 break;
265 knownLicense = true;
266 pathToFile = QStringLiteral("LGPL_V21");
267 break;
269 knownLicense = true;
270 pathToFile = QStringLiteral("MIT");
271 break;
278 knownLicense = true;
279 result += QCoreApplication::translate("KAboutLicense", "This program is distributed under the terms of the %1.").arg(name(KAboutLicense::ShortName))
280 + u"\n\n"_s
281 + QCoreApplication::translate("KAboutLicense", "You can find the full term <a href=\"https://spdx.org/licenses/%1.html\">the SPDX website</a>")
282 .arg(d->spdxID());
283 break;
285 if (!d->_licenseText.isEmpty()) {
286 result = d->_licenseText;
287 break;
288 }
289 Q_FALLTHROUGH();
290 // fall through
291 default:
292 result += QCoreApplication::translate("KAboutLicense",
293 "No licensing terms for this program have been specified.\n"
294 "Please check the documentation or the source for any\n"
295 "licensing terms.\n");
296 }
297
298 if (knownLicense) {
299 pathToFile = QStringLiteral(":/org.kde.kcoreaddons/licenses/") + pathToFile;
300 result += QCoreApplication::translate("KAboutLicense", "This program is distributed under the terms of the %1.").arg(name(KAboutLicense::ShortName));
301 if (!pathToFile.isEmpty()) {
302 result += lineFeed;
303 }
304 }
305
306 if (!pathToFile.isEmpty()) {
307 QFile file(pathToFile);
308 if (file.open(QIODevice::ReadOnly)) {
309 QTextStream str(&file);
310 result += str.readAll();
311 }
312 }
313
314 return result;
315}
316
317QString KAboutLicense::spdx() const
318{
319 // SPDX licenses are comprised of an identifier (e.g. GPL-2.0), an optional + to denote 'or
320 // later versions' and optional ' WITH $exception' to denote standardized exceptions from the
321 // core license. As we do not offer exceptions we effectively only return GPL-2.0 or GPL-2.0+,
322 // this may change in the future. To that end the documentation makes no assertions about the
323 // actual content of the SPDX license expression we return.
324 // Expressions can in theory also contain AND, OR and () to build constructs involving more than
325 // one license. As this is outside the scope of a single license object we'll ignore this here
326 // for now.
327 // The expectation is that the return value is only run through spec-compliant parsers, so this
328 // can potentially be changed.
329
330 auto id = d->spdxID();
331 if (id.isNull()) { // Guard against potential future changes which would allow 'Foo+' as input.
332 return id;
333 }
334 return d->_versionRestriction == OrLaterVersions ? id.append(QLatin1Char('+')) : id;
335}
336
337QString KAboutLicense::name(KAboutLicense::NameFormat formatName) const
338{
339 QString licenseShort;
340 QString licenseFull;
341
342 switch (d->_licenseKey) {
344 licenseShort = QCoreApplication::translate("KAboutLicense", "GPL v2", "@item license (short name)");
345 licenseFull = QCoreApplication::translate("KAboutLicense", "GNU General Public License Version 2", "@item license");
346 break;
348 licenseShort = QCoreApplication::translate("KAboutLicense", "LGPL v2", "@item license (short name)");
349 licenseFull = QCoreApplication::translate("KAboutLicense", "GNU Lesser General Public License Version 2", "@item license");
350 break;
352 licenseShort = QCoreApplication::translate("KAboutLicense", "BSD License", "@item license (short name)");
353 licenseFull = QCoreApplication::translate("KAboutLicense", "BSD License", "@item license");
354 break;
356 licenseShort = QCoreApplication::translate("KAboutLicense", "Artistic License", "@item license (short name)");
357 licenseFull = QCoreApplication::translate("KAboutLicense", "Artistic License", "@item license");
358 break;
360 licenseShort = QCoreApplication::translate("KAboutLicense", "GPL v3", "@item license (short name)");
361 licenseFull = QCoreApplication::translate("KAboutLicense", "GNU General Public License Version 3", "@item license");
362 break;
364 licenseShort = QCoreApplication::translate("KAboutLicense", "LGPL v3", "@item license (short name)");
365 licenseFull = QCoreApplication::translate("KAboutLicense", "GNU Lesser General Public License Version 3", "@item license");
366 break;
368 licenseShort = QCoreApplication::translate("KAboutLicense", "LGPL v2.1", "@item license (short name)");
369 licenseFull = QCoreApplication::translate("KAboutLicense", "GNU Lesser General Public License Version 2.1", "@item license");
370 break;
372 licenseShort = QCoreApplication::translate("KAboutLicense", "MIT License", "@item license (short name)");
373 licenseFull = QCoreApplication::translate("KAboutLicense", "MIT License", "@item license");
374 break;
376 licenseShort = QCoreApplication::translate("KAboutLicense", "CC0", "@item license (short name)");
377 licenseFull = QCoreApplication::translate("KAboutLicense", "Creative Commons Zero", "@item license");
378 break;
380 licenseShort = QCoreApplication::translate("KAboutLicense", "ODbL v1.0", "@item license (short name)");
381 licenseFull = QCoreApplication::translate("KAboutLicense", "Open Data Commons Open Database License v1.0", "@item license");
382 break;
384 licenseShort = QCoreApplication::translate("KAboutLicense", "Apache 2.0", "@item license (short name)");
385 licenseFull = QCoreApplication::translate("KAboutLicense", "Apache License 2.0", "@item license");
386 break;
388 licenseShort = QCoreApplication::translate("KAboutLicense", "FTL", "@item license (short name)");
389 licenseFull = QCoreApplication::translate("KAboutLicense", "Freetype Project License", "@item license");
390 break;
392 licenseShort = QCoreApplication::translate("KAboutLicense", "Boost License", "@item license (short name)");
393 licenseFull = QCoreApplication::translate("KAboutLicense", "Boost Software License 1.0", "@item license");
394 break;
396 licenseShort = QCoreApplication::translate("KAboutLicense", "BSD-3-Clause", "@item license (short name)");
397 licenseFull = QCoreApplication::translate("KAboutLicense", "BSD 3-Clause \"New\" or \"Revised\" License", "@item license");
398 break;
401 licenseShort = licenseFull = QCoreApplication::translate("KAboutLicense", "Custom", "@item license");
402 break;
403 default:
404 licenseShort = licenseFull = QCoreApplication::translate("KAboutLicense", "Not specified", "@item license");
405 }
406
407 const QString result = (formatName == KAboutLicense::ShortName) ? licenseShort : (formatName == KAboutLicense::FullName) ? licenseFull : QString();
408
409 return result;
410}
411
413{
414 d = other.d;
415 return *this;
416}
417
418KAboutLicense::LicenseKey KAboutLicense::key() const
419{
420 return d->_licenseKey;
421}
422
424{
425 // Setup keyword->enum dictionary on first call.
426 // Use normalized keywords, by the algorithm below.
427 static const QHash<QByteArray, KAboutLicense::LicenseKey> licenseDict{
428 {"gpl", KAboutLicense::GPL}, {"gplv2", KAboutLicense::GPL_V2},
429 {"gplv2+", KAboutLicense::GPL_V2}, {"gpl20", KAboutLicense::GPL_V2},
430 {"gpl20+", KAboutLicense::GPL_V2}, {"lgpl", KAboutLicense::LGPL},
431 {"lgplv2", KAboutLicense::LGPL_V2}, {"lgplv2+", KAboutLicense::LGPL_V2},
432 {"lgpl20", KAboutLicense::LGPL_V2}, {"lgpl20+", KAboutLicense::LGPL_V2},
434 {"apache", KAboutLicense::Apache_V2}, {"bsd3clause", KAboutLicense::BSD_3_Clause},
435 {"artistic", KAboutLicense::Artistic}, {"artistic10", KAboutLicense::Artistic},
436 {"gplv3", KAboutLicense::GPL_V3}, {"gplv3+", KAboutLicense::GPL_V3},
437 {"gpl30", KAboutLicense::GPL_V3}, {"gpl30+", KAboutLicense::GPL_V3},
438 {"lgplv3", KAboutLicense::LGPL_V3}, {"lgplv3+", KAboutLicense::LGPL_V3},
439 {"lgpl30", KAboutLicense::LGPL_V3}, {"lgpl30+", KAboutLicense::LGPL_V3},
440 {"lgplv21", KAboutLicense::LGPL_V2_1}, {"lgplv21+", KAboutLicense::LGPL_V2_1},
441 {"lgpl21", KAboutLicense::LGPL_V2_1}, {"lgpl21+", KAboutLicense::LGPL_V2_1},
442 {"mit", KAboutLicense::MIT},
443 };
444
445 // Normalize keyword.
446 QString keyword = rawKeyword;
447 keyword = keyword.toLower();
448 keyword.replace(QLatin1StringView("-or-later"), QLatin1StringView("+"));
449 keyword.remove(QLatin1Char(' '));
450 keyword.remove(QLatin1Char('.'));
451 keyword.remove(QLatin1Char('-'));
452
453 LicenseKey license = licenseDict.value(keyword.toLatin1(), KAboutLicense::Custom);
454 auto restriction = keyword.endsWith(QLatin1Char('+')) ? OrLaterVersions : OnlyThisVersion;
455 return KAboutLicense(license, restriction, nullptr);
456}
457
458class KAboutComponentPrivate : public QSharedData
459{
460public:
461 QString _name;
462 QString _description;
463 QString _version;
464 QString _webAddress;
465 KAboutLicense _license;
466};
467
469 const QString &_description,
470 const QString &_version,
471 const QString &_webAddress,
472 enum KAboutLicense::LicenseKey licenseType)
473 : d(new KAboutComponentPrivate)
474{
475 d->_name = _name;
476 d->_description = _description;
477 d->_version = _version;
478 d->_webAddress = _webAddress;
479 d->_license = KAboutLicense(licenseType, nullptr);
480}
481
483 const QString &_description,
484 const QString &_version,
485 const QString &_webAddress,
486 const QString &pathToLicenseFile)
487 : d(new KAboutComponentPrivate)
488{
489 d->_name = _name;
490 d->_description = _description;
491 d->_version = _version;
492 d->_webAddress = _webAddress;
493 d->_license = KAboutLicense();
494 d->_license.setLicenseFromPath(pathToLicenseFile);
495}
496
498
499KAboutComponent::~KAboutComponent() = default;
500
501QString KAboutComponent::name() const
502{
503 return d->_name;
504}
505
506QString KAboutComponent::description() const
507{
508 return d->_description;
509}
510
511QString KAboutComponent::version() const
512{
513 return d->_version;
514}
515
516QString KAboutComponent::webAddress() const
517{
518 return d->_webAddress;
519}
520
522{
523 return d->_license;
524}
525
527
528class KAboutDataPrivate
529{
530public:
531 KAboutDataPrivate()
532 : customAuthorTextEnabled(false)
533 {
534 }
535 QString _componentName;
536 QString _displayName;
537 QString _shortDescription;
538 QString _copyrightStatement;
539 QString _otherText;
540 QString _homepageAddress;
541 QList<KAboutPerson> _authorList;
542 QList<KAboutPerson> _creditList;
543 QList<KAboutPerson> _translatorList;
544 QList<KAboutComponent> _componentList;
545 QList<KAboutLicense> _licenseList;
546 QVariant programLogo;
547 QString customAuthorPlainText, customAuthorRichText;
548 bool customAuthorTextEnabled;
549
550 QString organizationDomain;
551 QString desktopFileName;
552
553 // Everything dr.konqi needs, we store as utf-8, so we
554 // can just give it a pointer, w/o any allocations.
555 QByteArray _internalProgramName;
556 QByteArray _version;
557 QByteArray _bugAddress;
558 QByteArray productName;
559
560 static QList<KAboutPerson> parseTranslators(const QString &translatorName, const QString &translatorEmail);
561};
562
563KAboutData::KAboutData(const QString &_componentName,
564 const QString &_displayName,
565 const QString &_version,
566 const QString &_shortDescription,
567 enum KAboutLicense::LicenseKey licenseType,
568 const QString &_copyrightStatement,
569 const QString &text,
570 const QString &homePageAddress,
571 const QString &bugAddress)
572 : d(new KAboutDataPrivate)
573{
574 d->_componentName = _componentName;
575 int p = d->_componentName.indexOf(QLatin1Char('/'));
576 if (p >= 0) {
577 d->_componentName = d->_componentName.mid(p + 1);
578 }
579
580 d->_displayName = _displayName;
581 if (!d->_displayName.isEmpty()) { // KComponentData("klauncher") gives empty program name
582 d->_internalProgramName = _displayName.toUtf8();
583 }
584 d->_version = _version.toUtf8();
585 d->_shortDescription = _shortDescription;
586 d->_licenseList.append(KAboutLicense(licenseType, this));
587 d->_copyrightStatement = _copyrightStatement;
588 d->_otherText = text;
589 d->_homepageAddress = homePageAddress;
590 d->_bugAddress = bugAddress.toUtf8();
591
592 QUrl homePageUrl(homePageAddress);
593 if (!homePageUrl.isValid() || homePageUrl.scheme().isEmpty()) {
594 // Default domain if nothing else is better
595 homePageUrl.setUrl(QStringLiteral("https://kde.org/"));
596 }
597
598 const QChar dotChar(QLatin1Char('.'));
599 QStringList hostComponents = homePageUrl.host().split(dotChar);
600
601 // Remove leading component unless 2 (or less) components are present
602 if (hostComponents.size() > 2) {
603 hostComponents.removeFirst();
604 }
605
606 d->organizationDomain = hostComponents.join(dotChar);
607
608 // KF6: do not set a default desktopFileName value here, but remove this code and leave it empty
609 // see KAboutData::desktopFileName() for details
610
611 // desktop file name is reverse domain name
612 std::reverse(hostComponents.begin(), hostComponents.end());
613 hostComponents.append(_componentName);
614
615 d->desktopFileName = hostComponents.join(dotChar);
616}
617
618KAboutData::KAboutData(const QString &_componentName, const QString &_displayName, const QString &_version)
619 : d(new KAboutDataPrivate)
620{
621 d->_componentName = _componentName;
622 int p = d->_componentName.indexOf(QLatin1Char('/'));
623 if (p >= 0) {
624 d->_componentName = d->_componentName.mid(p + 1);
625 }
626
627 d->_displayName = _displayName;
628 if (!d->_displayName.isEmpty()) { // KComponentData("klauncher") gives empty program name
629 d->_internalProgramName = _displayName.toUtf8();
630 }
631 d->_version = _version.toUtf8();
632
633 // match behaviour of other constructors
634 d->_licenseList.append(KAboutLicense(KAboutLicense::Unknown, this));
635 d->_bugAddress = "submit@bugs.kde.org";
636 d->organizationDomain = QStringLiteral("kde.org");
637 // KF6: do not set a default desktopFileName value here, but remove this code and leave it empty
638 // see KAboutData::desktopFileName() for details
639 d->desktopFileName = QLatin1String("org.kde.") + d->_componentName;
640}
641
642KAboutData::~KAboutData() = default;
643
645 : d(new KAboutDataPrivate)
646{
647 *d = *other.d;
648 for (KAboutLicense &al : d->_licenseList) {
649 al.d.detach();
650 al.d->_aboutData = this;
651 }
652}
653
655{
656 if (this != &other) {
657 *d = *other.d;
658 for (KAboutLicense &al : d->_licenseList) {
659 al.d.detach();
660 al.d->_aboutData = this;
661 }
662 }
663 return *this;
664}
665
666KAboutData &KAboutData::addAuthor(const QString &name, const QString &task, const QString &emailAddress, const QString &webAddress, const QUrl &avatarUrl)
667{
668 d->_authorList.append(KAboutPerson(name, task, emailAddress, webAddress, avatarUrl));
669 return *this;
670}
671
673{
674 d->_authorList.append(author);
675 return *this;
676}
677
679{
680 d->_creditList.append(person);
681 return *this;
682}
683
684KAboutData &KAboutData::addCredit(const QString &name, const QString &task, const QString &emailAddress, const QString &webAddress, const QUrl &avatarUrl)
685{
686 d->_creditList.append(KAboutPerson(name, task, emailAddress, webAddress, avatarUrl));
687 return *this;
688}
689
690KAboutData &KAboutData::setTranslator(const QString &name, const QString &emailAddress)
691{
692 d->_translatorList = KAboutDataPrivate::parseTranslators(name, emailAddress);
693 return *this;
694}
695
697{
698 d->_componentList.append(component);
699 return *this;
700}
701
703 const QString &description,
704 const QString &version,
705 const QString &webAddress,
706 KAboutLicense::LicenseKey licenseKey)
707{
708 d->_componentList.append(KAboutComponent(name, description, version, webAddress, licenseKey));
709 return *this;
710}
711
713KAboutData::addComponent(const QString &name, const QString &description, const QString &version, const QString &webAddress, const QString &pathToLicenseFile)
714{
715 d->_componentList.append(KAboutComponent(name, description, version, webAddress, pathToLicenseFile));
716 return *this;
717}
718
720{
721 d->_licenseList[0] = KAboutLicense(this);
722 d->_licenseList[0].setLicenseFromText(licenseText);
723 return *this;
724}
725
727{
728 // if the default license is unknown, overwrite instead of append
729 KAboutLicense &firstLicense = d->_licenseList[0];
730 KAboutLicense newLicense(this);
731 newLicense.setLicenseFromText(licenseText);
732 if (d->_licenseList.count() == 1 && firstLicense.d->_licenseKey == KAboutLicense::Unknown) {
733 firstLicense = newLicense;
734 } else {
735 d->_licenseList.append(newLicense);
736 }
737
738 return *this;
739}
740
742{
743 d->_licenseList[0] = KAboutLicense(this);
744 d->_licenseList[0].setLicenseFromPath(pathToFile);
745 return *this;
746}
747
749{
750 // if the default license is unknown, overwrite instead of append
751 KAboutLicense &firstLicense = d->_licenseList[0];
752 KAboutLicense newLicense(this);
753 newLicense.setLicenseFromPath(pathToFile);
754 if (d->_licenseList.count() == 1 && firstLicense.d->_licenseKey == KAboutLicense::Unknown) {
755 firstLicense = newLicense;
756 } else {
757 d->_licenseList.append(newLicense);
758 }
759 return *this;
760}
761
763{
764 d->_componentName = componentName;
765 return *this;
766}
767
769{
770 d->_displayName = _displayName;
771 d->_internalProgramName = _displayName.toUtf8();
772 return *this;
773}
774
776{
777 d->_version = _version;
778 return *this;
779}
780
782{
783 d->_shortDescription = _shortDescription;
784 return *this;
785}
786
788{
789 return setLicense(licenseKey, KAboutLicense::OnlyThisVersion);
790}
791
793{
794 d->_licenseList[0] = KAboutLicense(licenseKey, versionRestriction, this);
795 return *this;
796}
797
799{
800 return addLicense(licenseKey, KAboutLicense::OnlyThisVersion);
801}
802
804{
805 // if the default license is unknown, overwrite instead of append
806 KAboutLicense &firstLicense = d->_licenseList[0];
807 if (d->_licenseList.count() == 1 && firstLicense.d->_licenseKey == KAboutLicense::Unknown) {
808 firstLicense = KAboutLicense(licenseKey, versionRestriction, this);
809 } else {
810 d->_licenseList.append(KAboutLicense(licenseKey, versionRestriction, this));
811 }
812 return *this;
813}
814
816{
817 d->_copyrightStatement = _copyrightStatement;
818 return *this;
819}
820
822{
823 d->_otherText = _otherText;
824 return *this;
825}
826
828{
829 d->_homepageAddress = homepage;
830 return *this;
831}
832
834{
835 d->_bugAddress = _bugAddress;
836 return *this;
837}
838
840{
841 d->organizationDomain = QString::fromLatin1(domain.data());
842 return *this;
843}
844
846{
847 d->productName = _productName;
848 return *this;
849}
850
851QString KAboutData::componentName() const
852{
853 return d->_componentName;
854}
855
856QString KAboutData::productName() const
857{
858 if (!d->productName.isEmpty()) {
859 return QString::fromUtf8(d->productName);
860 }
861 return componentName();
862}
863
865{
866 return d->productName.isEmpty() ? nullptr : d->productName.constData();
867}
868
869QString KAboutData::displayName() const
870{
871 return d->_displayName;
872}
873
874/// @internal
875/// Return the program name. It is always pre-allocated.
876/// Needed for KCrash in particular.
878{
879 return d->_internalProgramName.constData();
880}
881
882QVariant KAboutData::programLogo() const
883{
884 return d->programLogo;
885}
886
888{
889 d->programLogo = image;
890 return *this;
891}
892
893QString KAboutData::version() const
894{
895 return QString::fromUtf8(d->_version.data());
896}
897
898/// @internal
899/// Return the untranslated and uninterpreted (to UTF8) string
900/// for the version information. Used in particular for KCrash.
902{
903 return d->_version.constData();
904}
905
906QString KAboutData::shortDescription() const
907{
908 return d->_shortDescription;
909}
910
911QString KAboutData::homepage() const
912{
913 return d->_homepageAddress;
914}
915
916QString KAboutData::bugAddress() const
917{
918 return QString::fromUtf8(d->_bugAddress.constData());
919}
920
922{
923 return d->organizationDomain;
924}
925
926/// @internal
927/// Return the untranslated and uninterpreted (to UTF8) string
928/// for the bug mail address. Used in particular for KCrash.
930{
931 if (d->_bugAddress.isEmpty()) {
932 return nullptr;
933 }
934 return d->_bugAddress.constData();
935}
936
937QList<KAboutPerson> KAboutData::authors() const
938{
939 return d->_authorList;
940}
941
942QList<KAboutPerson> KAboutData::credits() const
943{
944 return d->_creditList;
945}
946
947QList<KAboutPerson> KAboutDataPrivate::parseTranslators(const QString &translatorName, const QString &translatorEmail)
948{
949 if (translatorName.isEmpty() || translatorName == QLatin1String("Your names")) {
950 return {};
951 }
952
953 // use list of string views to delay creating new QString instances after the white-space trimming
954 const QList<QStringView> nameList = QStringView(translatorName).split(QLatin1Char(','));
955
956 QList<QStringView> emailList;
957 if (!translatorEmail.isEmpty() && translatorEmail != QLatin1String("Your emails")) {
958 emailList = QStringView(translatorEmail).split(QLatin1Char(','), Qt::KeepEmptyParts);
959 }
960
961 QList<KAboutPerson> personList;
962 personList.reserve(nameList.size());
963
964 auto eit = emailList.constBegin();
965
966 for (const QStringView &name : nameList) {
967 QStringView email;
968 if (eit != emailList.constEnd()) {
969 email = *eit;
970 ++eit;
971 }
972
973 personList.append(KAboutPerson(name.trimmed().toString(), email.trimmed().toString(), true));
974 }
975
976 return personList;
977}
978
979QList<KAboutPerson> KAboutData::translators() const
980{
981 return d->_translatorList;
982}
983
985{
986 return QCoreApplication::translate("KAboutData",
987 "<p>KDE is translated into many languages thanks to the work "
988 "of the translation teams all over the world.</p>"
989 "<p>For more information on KDE internationalization "
990 "visit <a href=\"https://l10n.kde.org\">https://l10n.kde.org</a></p>",
991 "replace this with information about your translation team");
992}
993
994QString KAboutData::otherText() const
995{
996 return d->_otherText;
997}
998
999QList<KAboutComponent> KAboutData::components() const
1000{
1001 return d->_componentList;
1002}
1003
1004QList<KAboutLicense> KAboutData::licenses() const
1005{
1006 return d->_licenseList;
1007}
1008
1009QString KAboutData::copyrightStatement() const
1010{
1011 return d->_copyrightStatement;
1012}
1013
1015{
1016 return d->customAuthorPlainText;
1017}
1018
1020{
1021 return d->customAuthorRichText;
1022}
1023
1025{
1026 return d->customAuthorTextEnabled;
1027}
1028
1030{
1031 d->customAuthorPlainText = plainText;
1032 d->customAuthorRichText = richText;
1033
1034 d->customAuthorTextEnabled = true;
1035
1036 return *this;
1037}
1038
1040{
1041 d->customAuthorPlainText = QString();
1042 d->customAuthorRichText = QString();
1043
1044 d->customAuthorTextEnabled = false;
1045
1046 return *this;
1047}
1048
1050{
1051 d->desktopFileName = desktopFileName;
1052
1053 return *this;
1054}
1055
1056QString KAboutData::desktopFileName() const
1057{
1058 return d->desktopFileName;
1059 // KF6: switch to this code and adapt API dox
1060#if 0
1061 // if desktopFileName has been explicitly set, use that value
1062 if (!d->desktopFileName.isEmpty()) {
1063 return d->desktopFileName;
1064 }
1065
1066 // return a string calculated on-the-fly from the current org domain & component name
1067 const QChar dotChar(QLatin1Char('.'));
1068 QStringList hostComponents = d->organizationDomain.split(dotChar);
1069
1070 // desktop file name is reverse domain name
1071 std::reverse(hostComponents.begin(), hostComponents.end());
1072 hostComponents.append(componentName());
1073
1074 return hostComponents.join(dotChar);
1075#endif
1076}
1077
1078class KAboutDataRegistry
1079{
1080public:
1081 KAboutDataRegistry()
1082 : m_appData(nullptr)
1083 {
1084 }
1085 ~KAboutDataRegistry()
1086 {
1087 delete m_appData;
1088 }
1089 KAboutDataRegistry(const KAboutDataRegistry &) = delete;
1090 KAboutDataRegistry &operator=(const KAboutDataRegistry &) = delete;
1091
1092 KAboutData *m_appData;
1093};
1094
1095Q_GLOBAL_STATIC(KAboutDataRegistry, s_registry)
1096
1097namespace
1098{
1099void warnIfOutOfSync(const char *aboutDataString, const QString &aboutDataValue, const char *appDataString, const QString &appDataValue)
1100{
1101 if (aboutDataValue != appDataValue) {
1102 qCWarning(KABOUTDATA) << appDataString << appDataValue << "is out-of-sync with" << aboutDataString << aboutDataValue;
1103 }
1104}
1105
1106}
1107
1109{
1111
1112 KAboutData *aboutData = s_registry->m_appData;
1113
1114 // not yet existing
1115 if (!aboutData) {
1116 // init from current Q*Application data
1118 // Unset the default (KDE) bug address, this is likely a third-party app. https://bugs.kde.org/show_bug.cgi?id=473517
1119 aboutData->setBugAddress(QByteArray());
1120 // For applicationDisplayName & desktopFileName, which are only properties of QGuiApplication,
1121 // we have to try to get them via the property system, as the static getter methods are
1122 // part of QtGui only. Disadvantage: requires an app instance.
1123 // Either get all or none of the properties & warn about it
1124 if (app) {
1126 aboutData->setVersion(QCoreApplication::applicationVersion().toUtf8());
1127 aboutData->setDisplayName(app->property("applicationDisplayName").toString());
1128 aboutData->setDesktopFileName(app->property("desktopFileName").toString());
1129 } else {
1130 qCWarning(KABOUTDATA) << "Could not initialize the properties of KAboutData::applicationData by the equivalent properties from Q*Application: no "
1131 "app instance (yet) existing.";
1132 }
1133
1134 s_registry->m_appData = aboutData;
1135 } else {
1136 // check if in-sync with Q*Application metadata, as their setters could have been called
1137 // after the last KAboutData::setApplicationData, with different values
1138 warnIfOutOfSync("KAboutData::applicationData().componentName",
1139 aboutData->componentName(),
1140 "QCoreApplication::applicationName",
1142 warnIfOutOfSync("KAboutData::applicationData().version",
1143 aboutData->version(),
1144 "QCoreApplication::applicationVersion",
1146 warnIfOutOfSync("KAboutData::applicationData().organizationDomain",
1147 aboutData->organizationDomain(),
1148 "QCoreApplication::organizationDomain",
1150 if (app) {
1151 warnIfOutOfSync("KAboutData::applicationData().displayName",
1152 aboutData->displayName(),
1153 "QGuiApplication::applicationDisplayName",
1154 app->property("applicationDisplayName").toString());
1155 warnIfOutOfSync("KAboutData::applicationData().desktopFileName",
1156 aboutData->desktopFileName(),
1157 "QGuiApplication::desktopFileName",
1158 app->property("desktopFileName").toString());
1159 }
1160 }
1161
1162 return *aboutData;
1163}
1164
1166{
1167 if (s_registry->m_appData) {
1168 *s_registry->m_appData = aboutData;
1169 } else {
1170 s_registry->m_appData = new KAboutData(aboutData);
1171 }
1172
1173 // For applicationDisplayName & desktopFileName, which are only properties of QGuiApplication,
1174 // we have to try to set them via the property system, as the static getter methods are
1175 // part of QtGui only. Disadvantage: requires an app instance.
1176 // So set either all or none of the properties & warn about it
1178 if (app) {
1179 app->setApplicationVersion(aboutData.version());
1180 app->setApplicationName(aboutData.componentName());
1181 app->setOrganizationDomain(aboutData.organizationDomain());
1182 app->setProperty("applicationDisplayName", aboutData.displayName());
1183 app->setProperty("desktopFileName", aboutData.desktopFileName());
1184 } else {
1185 qCWarning(KABOUTDATA) << "Could not initialize the equivalent properties of Q*Application: no instance (yet) existing.";
1186 }
1187
1188 // KF6: Rethink the current relation between KAboutData::applicationData and the Q*Application metadata
1189 // Always overwriting the Q*Application metadata here, but not updating back the KAboutData
1190 // in applicationData() is unbalanced and can result in out-of-sync data if the Q*Application
1191 // setters have been called meanwhile
1192 // Options are to remove the overlapping properties of KAboutData for cleancode, or making the
1193 // overlapping properties official shadow properties of their Q*Application countparts, though
1194 // that increases behavioural complexity a little.
1195}
1196
1197// only for KCrash (no memory allocation allowed)
1198const KAboutData *KAboutData::applicationDataPointer()
1199{
1200 if (s_registry.exists()) {
1201 return s_registry->m_appData;
1202 }
1203 return nullptr;
1204}
1205
1207{
1208 if (!d->_shortDescription.isEmpty()) {
1209 parser->setApplicationDescription(d->_shortDescription);
1210 }
1211
1212 parser->addHelpOption();
1213
1215 if (app && !app->applicationVersion().isEmpty()) {
1216 parser->addVersionOption();
1217 }
1218
1219 return parser->addOption(QCommandLineOption(QStringLiteral("author"), QCoreApplication::translate("KAboutData CLI", "Show author information.")))
1220 && parser->addOption(QCommandLineOption(QStringLiteral("license"), QCoreApplication::translate("KAboutData CLI", "Show license information.")))
1221 && parser->addOption(QCommandLineOption(QStringLiteral("desktopfile"),
1222 QCoreApplication::translate("KAboutData CLI", "The base file name of the desktop entry for this application."),
1223 QCoreApplication::translate("KAboutData CLI", "file name")));
1224}
1225
1227{
1228 bool foundArgument = false;
1229 if (parser->isSet(QStringLiteral("author"))) {
1230 foundArgument = true;
1231 if (d->_authorList.isEmpty()) {
1232 printf("%s\n",
1233 qPrintable(QCoreApplication::translate("KAboutData CLI", "This application was written by somebody who wants to remain anonymous.")));
1234 } else {
1235 printf("%s\n", qPrintable(QCoreApplication::translate("KAboutData CLI", "%1 was written by:").arg(qAppName())));
1236 for (const KAboutPerson &person : std::as_const(d->_authorList)) {
1237 QString authorData = QLatin1String(" ") + person.name();
1238 if (!person.emailAddress().isEmpty()) {
1239 authorData.append(QLatin1String(" <") + person.emailAddress() + QLatin1Char('>'));
1240 }
1241 printf("%s\n", qPrintable(authorData));
1242 }
1243 }
1244 if (!customAuthorTextEnabled()) {
1245 if (bugAddress() == QLatin1String("submit@bugs.kde.org")) {
1246 printf("%s\n", qPrintable(QCoreApplication::translate("KAboutData CLI", "Please use https://bugs.kde.org to report bugs.")));
1247 } else if (!bugAddress().isEmpty()) {
1248 printf("%s\n", qPrintable(QCoreApplication::translate("KAboutData CLI", "Please report bugs to %1.").arg(bugAddress())));
1249 }
1250 } else {
1251 printf("%s\n", qPrintable(customAuthorPlainText()));
1252 }
1253 } else if (parser->isSet(QStringLiteral("license"))) {
1254 foundArgument = true;
1255 for (const KAboutLicense &license : std::as_const(d->_licenseList)) {
1256 printf("%s\n", qPrintable(license.text()));
1257 }
1258 }
1259
1260 const QString desktopFileName = parser->value(QStringLiteral("desktopfile"));
1261 if (!desktopFileName.isEmpty()) {
1262 d->desktopFileName = desktopFileName;
1263 }
1264
1265 if (foundArgument) {
1266 ::exit(EXIT_SUCCESS);
1267 }
1268}
1269
1270#include "moc_kaboutdata.cpp"
This class is used to store information about a third party component.
Definition kaboutdata.h:390
KAboutLicense license() const
The component's license.
KAboutComponent & operator=(const KAboutComponent &other)
Assignment operator.
KAboutComponent(const QString &name=QString(), const QString &description=QString(), const QString &version=QString(), const QString &webAddress=QString(), enum KAboutLicense::LicenseKey licenseType=KAboutLicense::Unknown)
Convenience constructor.
This class is used to store information about a program or plugin.
Definition kaboutdata.h:557
KAboutData & setProductName(const QByteArray &name)
Defines the product name which will be used in the KBugReport dialog.
KAboutData & setLicenseText(const QString &license)
Defines a license text, which is translated.
KAboutData & setShortDescription(const QString &shortDescription)
Defines a short description of what the program does.
KAboutData & setHomepage(const QString &homepage)
Defines the program homepage.
KAboutData & setDesktopFileName(const QString &desktopFileName)
Sets the base name of the desktop entry for this application.
static QString aboutTranslationTeam()
Returns a message about the translation team.
KAboutData & addLicense(KAboutLicense::LicenseKey licenseKey)
Adds a license identifier.
const char * internalBugAddress() const
KAboutData & setLicenseTextFile(const QString &file)
Defines a license text by pointing to a file where it resides.
const char * internalProductName() const
QString customAuthorRichText() const
Returns the rich text displayed around the list of authors instead of the default message telling use...
KAboutData & setCopyrightStatement(const QString &copyrightStatement)
Defines the copyright statement to show when displaying the license.
const char * internalVersion() const
KAboutData & addComponent(const KAboutComponent &component)
Add a component that is used by the application.
bool customAuthorTextEnabled() const
Returns whether custom text should be displayed around the list of authors.
KAboutData & addAuthor(const KAboutPerson &author)
Add an author.
const char * internalProgramName() const
KAboutData & setProgramLogo(const QVariant &image)
Defines the program logo.
QString customAuthorPlainText() const
Returns the plain text displayed around the list of authors instead of the default message telling us...
KAboutData & setBugAddress(const QByteArray &bugAddress)
Defines the address where bug reports should be sent.
KAboutData & operator=(const KAboutData &other)
Assignment operator.
KAboutData & setTranslator(const QString &name, const QString &emailAddress)
Sets the name(s) of the translator(s) of the GUI.
KAboutData & addCredit(const KAboutPerson &person)
Add a person that deserves credit.
QString organizationDomain() const
Returns the domain name of the organization that wrote this application.
KAboutData & addLicenseText(const QString &license)
Adds a license text, which is translated.
KAboutData & setDisplayName(const QString &displayName)
Defines the displayable component name string.
static void setApplicationData(const KAboutData &aboutData)
Sets the application data for this application.
KAboutData & setVersion(const QByteArray &version)
Defines the program version string.
KAboutData & setOtherText(const QString &otherText)
Defines the additional text to show in the about dialog.
KAboutData & setCustomAuthorText(const QString &plainText, const QString &richText)
Sets the custom text displayed around the list of authors instead of the default message telling user...
KAboutData & setOrganizationDomain(const QByteArray &domain)
Defines the domain of the organization that wrote this application.
KAboutData(const QString &componentName, const QString &displayName, const QString &version, const QString &shortDescription, enum KAboutLicense::LicenseKey licenseType, const QString &copyrightStatement=QString(), const QString &otherText=QString(), const QString &homePageAddress=QString(), const QString &bugAddress=QStringLiteral("submit@bugs.kde.org"))
Constructor.
void processCommandLine(QCommandLineParser *parser)
Reads the processed parser and sees if any of the arguments are the ones set up from setupCommandLine...
KAboutData & unsetCustomAuthorText()
Clears any custom text displayed around the list of authors and falls back to the default message tel...
KAboutData & addLicenseTextFile(const QString &file)
Adds a license text by pointing to a file where it resides.
KAboutData & setLicense(KAboutLicense::LicenseKey licenseKey)
Defines the license identifier.
static KAboutData applicationData()
Returns the KAboutData for the application.
bool setupCommandLine(QCommandLineParser *parser)
Configures the parser command line parser to provide an authors entry with information about the deve...
KAboutData & setComponentName(const QString &componentName)
Defines the component name used internally.
This class is used to store information about a license.
Definition kaboutdata.h:187
LicenseKey
Describes the license of the software; for more information see: https://spdx.org/licenses/.
Definition kaboutdata.h:200
@ GPL_V3
GPL_V3, see https://spdx.org/licenses/GPL-3.0.html.
Definition kaboutdata.h:213
@ BSL_V1
BSL_V1.
Definition kaboutdata.h:220
@ CC0_V1
CC0_V1.
Definition kaboutdata.h:222
@ ODbL_V1
ODbL_V1.
Definition kaboutdata.h:217
@ Artistic
Artistic, see https://spdx.org/licenses/Artistic-2.0.html.
Definition kaboutdata.h:212
@ BSD_2_Clause
BSD_2_CLAUSE, see https://spdx.org/licenses/BSD-2-Clause.html.
Definition kaboutdata.h:211
@ LGPL_V2_1
LGPL_V2_1.
Definition kaboutdata.h:215
@ Unknown
Unknown license.
Definition kaboutdata.h:203
@ BSD_3_Clause
BSD_3_CLAUSE.
Definition kaboutdata.h:221
@ Custom
Custom license.
Definition kaboutdata.h:201
@ LGPL_V2
LGPL_V2, this has the same value as LicenseKey::LGPL, see https://spdx.org/licenses/LGPL-2....
Definition kaboutdata.h:207
@ GPL_V2
GPL_V2, this has the same value as LicenseKey::GPL, see https://spdx.org/licenses/GPL-2....
Definition kaboutdata.h:205
@ File
License set from text file, see setLicenseFromPath()
Definition kaboutdata.h:202
@ LGPL_V3
LGPL_V3, see https://spdx.org/licenses/LGPL-3.0-only.html.
Definition kaboutdata.h:214
@ Apache_V2
Apache_V2.
Definition kaboutdata.h:218
VersionRestriction
Whether later versions of the license are allowed.
Definition kaboutdata.h:238
static KAboutLicense byKeyword(const QString &keyword)
Fetch a known license by a keyword/spdx ID.
NameFormat
Format of the license name.
Definition kaboutdata.h:229
KAboutLicense & operator=(const KAboutLicense &other)
Assignment operator.
This class is used to store information about a person or developer.
Definition kaboutdata.h:64
static KAboutPerson fromJSON(const QJsonObject &obj)
Creates a KAboutPerson from a JSON object with the following structure:
KAboutPerson(const QString &name=QString(), const QString &task=QString(), const QString &emailAddress=QString(), const QString &webAddress=QString(), const QUrl &avatarUrl=QUrl())
Convenience constructor.
KAboutPerson & operator=(const KAboutPerson &other)
Assignment operator.
QString name(StandardAction id)
char * data()
QCommandLineOption addHelpOption()
bool addOption(const QCommandLineOption &option)
QCommandLineOption addVersionOption()
bool isSet(const QCommandLineOption &option) const const
void setApplicationDescription(const QString &description)
QString value(const QCommandLineOption &option) const const
QCoreApplication * instance()
QString translate(const char *context, const char *sourceText, const char *disambiguation, int n)
bool open(FILE *fh, OpenMode mode, FileHandleFlags handleFlags)
QJsonValue value(QLatin1StringView key) const const
QString toString() const const
QVariant toVariant() const const
void append(QList< T > &&value)
iterator begin()
const_iterator constBegin() const const
const_iterator constEnd() const const
iterator end()
void removeFirst()
void reserve(qsizetype size)
qsizetype size() const const
QVariant property(const char *name) const const
bool setProperty(const char *name, QVariant &&value)
QString & append(QChar ch)
QString arg(Args &&... args) const const
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
QString fromLatin1(QByteArrayView str)
QString fromUtf8(QByteArrayView str)
bool isEmpty() const const
QString & remove(QChar ch, Qt::CaseSensitivity cs)
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QByteArray toLatin1() const const
QString toLower() const const
QByteArray toUtf8() const const
QString trimmed() const const
QString join(QChar separator) const const
QList< QStringView > split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QString toString() const const
QStringView trimmed() const const
KeepEmptyParts
QString readAll()
QString host(ComponentFormattingOptions options) const const
bool isValid() const const
QString scheme() const const
void setUrl(const QString &url, ParsingMode parsingMode)
QString toString() const const
QUrl toUrl() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Dec 13 2024 11:49:19 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.