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");
174 return QStringLiteral("MPL-2.0");
178 return QString();
179 }
180 return QString();
181}
182
184 : d(new KAboutLicensePrivate(Unknown, {}, nullptr))
185{
186}
187
188KAboutLicense::KAboutLicense(LicenseKey licenseType, VersionRestriction versionRestriction, const KAboutData *aboutData)
189 : d(new KAboutLicensePrivate(licenseType, versionRestriction, aboutData))
190{
191}
192
193KAboutLicense::KAboutLicense(LicenseKey licenseType, const KAboutData *aboutData)
194 : d(new KAboutLicensePrivate(licenseType, OnlyThisVersion, aboutData))
195{
196}
197
199 : d(new KAboutLicensePrivate(Unknown, OnlyThisVersion, aboutData))
200{
201}
202
204 : d(other.d)
205{
206}
207
208KAboutLicense::~KAboutLicense()
209{
210}
211
212void KAboutLicense::setLicenseFromPath(const QString &pathToFile)
213{
214 d->_licenseKey = KAboutLicense::File;
215 d->_pathToLicenseTextFile = pathToFile;
216}
217
218void KAboutLicense::setLicenseFromText(const QString &licenseText)
219{
220 d->_licenseKey = KAboutLicense::Custom;
221 d->_licenseText = licenseText;
222}
223
224QString KAboutLicense::text() const
225{
226 QString result;
227
228 const QString lineFeed = QStringLiteral("\n\n");
229
230 if (d->_aboutData && !d->_aboutData->copyrightStatement().isEmpty()
231 && (d->_licenseKey == KAboutLicense::BSD_2_Clause || d->_licenseKey == KAboutLicense::BSD_3_Clause || d->_licenseKey == KAboutLicense::MIT
232 || d->_licenseKey == KAboutLicense::Artistic)) {
233 result = d->_aboutData->copyrightStatement() + lineFeed;
234 }
235
236 bool knownLicense = false;
237 QString pathToFile; // rel path if known license
238 switch (d->_licenseKey) {
240 pathToFile = d->_pathToLicenseTextFile;
241 break;
243 knownLicense = true;
244 pathToFile = QStringLiteral("GPL_V2");
245 break;
247 knownLicense = true;
248 pathToFile = QStringLiteral("LGPL_V2");
249 break;
251 knownLicense = true;
252 pathToFile = QStringLiteral("BSD");
253 break;
255 knownLicense = true;
256 pathToFile = QStringLiteral("ARTISTIC");
257 break;
259 knownLicense = true;
260 pathToFile = QStringLiteral("GPL_V3");
261 break;
263 knownLicense = true;
264 pathToFile = QStringLiteral("LGPL_V3");
265 break;
267 knownLicense = true;
268 pathToFile = QStringLiteral("LGPL_V21");
269 break;
271 knownLicense = true;
272 pathToFile = QStringLiteral("MIT");
273 break;
281 knownLicense = true;
282 result += QCoreApplication::translate("KAboutLicense", "This program is distributed under the terms of the %1.").arg(name(KAboutLicense::ShortName))
283 + u"\n\n"_s
284 + QCoreApplication::translate("KAboutLicense", "You can find the full term <a href=\"https://spdx.org/licenses/%1.html\">the SPDX website</a>")
285 .arg(d->spdxID());
286 break;
288 if (!d->_licenseText.isEmpty()) {
289 result = d->_licenseText;
290 break;
291 }
292 Q_FALLTHROUGH();
293 // fall through
294 default:
295 result += QCoreApplication::translate("KAboutLicense",
296 "No licensing terms for this program have been specified.\n"
297 "Please check the documentation or the source for any\n"
298 "licensing terms.\n");
299 }
300
301 if (knownLicense) {
302 pathToFile = QStringLiteral(":/org.kde.kcoreaddons/licenses/") + pathToFile;
303 result += QCoreApplication::translate("KAboutLicense", "This program is distributed under the terms of the %1.").arg(name(KAboutLicense::ShortName));
304 if (!pathToFile.isEmpty()) {
305 result += lineFeed;
306 }
307 }
308
309 if (!pathToFile.isEmpty()) {
310 QFile file(pathToFile);
311 if (file.open(QIODevice::ReadOnly)) {
312 QTextStream str(&file);
313 result += str.readAll();
314 }
315 }
316
317 return result;
318}
319
320QString KAboutLicense::spdx() const
321{
322 // SPDX licenses are comprised of an identifier (e.g. GPL-2.0), an optional + to denote 'or
323 // later versions' and optional ' WITH $exception' to denote standardized exceptions from the
324 // core license. As we do not offer exceptions we effectively only return GPL-2.0 or GPL-2.0+,
325 // this may change in the future. To that end the documentation makes no assertions about the
326 // actual content of the SPDX license expression we return.
327 // Expressions can in theory also contain AND, OR and () to build constructs involving more than
328 // one license. As this is outside the scope of a single license object we'll ignore this here
329 // for now.
330 // The expectation is that the return value is only run through spec-compliant parsers, so this
331 // can potentially be changed.
332
333 auto id = d->spdxID();
334 if (id.isNull()) { // Guard against potential future changes which would allow 'Foo+' as input.
335 return id;
336 }
337 return d->_versionRestriction == OrLaterVersions ? id.append(QLatin1Char('+')) : id;
338}
339
340QString KAboutLicense::name(KAboutLicense::NameFormat formatName) const
341{
342 QString licenseShort;
343 QString licenseFull;
344
345 switch (d->_licenseKey) {
347 licenseShort = QCoreApplication::translate("KAboutLicense", "GPL v2", "@item license (short name)");
348 licenseFull = QCoreApplication::translate("KAboutLicense", "GNU General Public License Version 2", "@item license");
349 break;
351 licenseShort = QCoreApplication::translate("KAboutLicense", "LGPL v2", "@item license (short name)");
352 licenseFull = QCoreApplication::translate("KAboutLicense", "GNU Lesser General Public License Version 2", "@item license");
353 break;
355 licenseShort = QCoreApplication::translate("KAboutLicense", "BSD License", "@item license (short name)");
356 licenseFull = QCoreApplication::translate("KAboutLicense", "BSD License", "@item license");
357 break;
359 licenseShort = QCoreApplication::translate("KAboutLicense", "Artistic License", "@item license (short name)");
360 licenseFull = QCoreApplication::translate("KAboutLicense", "Artistic License", "@item license");
361 break;
363 licenseShort = QCoreApplication::translate("KAboutLicense", "GPL v3", "@item license (short name)");
364 licenseFull = QCoreApplication::translate("KAboutLicense", "GNU General Public License Version 3", "@item license");
365 break;
367 licenseShort = QCoreApplication::translate("KAboutLicense", "LGPL v3", "@item license (short name)");
368 licenseFull = QCoreApplication::translate("KAboutLicense", "GNU Lesser General Public License Version 3", "@item license");
369 break;
371 licenseShort = QCoreApplication::translate("KAboutLicense", "LGPL v2.1", "@item license (short name)");
372 licenseFull = QCoreApplication::translate("KAboutLicense", "GNU Lesser General Public License Version 2.1", "@item license");
373 break;
375 licenseShort = QCoreApplication::translate("KAboutLicense", "MIT License", "@item license (short name)");
376 licenseFull = QCoreApplication::translate("KAboutLicense", "MIT License", "@item license");
377 break;
379 licenseShort = QCoreApplication::translate("KAboutLicense", "CC0", "@item license (short name)");
380 licenseFull = QCoreApplication::translate("KAboutLicense", "Creative Commons Zero", "@item license");
381 break;
383 licenseShort = QCoreApplication::translate("KAboutLicense", "ODbL v1.0", "@item license (short name)");
384 licenseFull = QCoreApplication::translate("KAboutLicense", "Open Data Commons Open Database License v1.0", "@item license");
385 break;
387 licenseShort = QCoreApplication::translate("KAboutLicense", "Apache 2.0", "@item license (short name)");
388 licenseFull = QCoreApplication::translate("KAboutLicense", "Apache License 2.0", "@item license");
389 break;
391 licenseShort = QCoreApplication::translate("KAboutLicense", "FTL", "@item license (short name)");
392 licenseFull = QCoreApplication::translate("KAboutLicense", "Freetype Project License", "@item license");
393 break;
395 licenseShort = QCoreApplication::translate("KAboutLicense", "Boost License", "@item license (short name)");
396 licenseFull = QCoreApplication::translate("KAboutLicense", "Boost Software License 1.0", "@item license");
397 break;
399 licenseShort = QCoreApplication::translate("KAboutLicense", "BSD-3-Clause", "@item license (short name)");
400 licenseFull = QCoreApplication::translate("KAboutLicense", "BSD 3-Clause \"New\" or \"Revised\" License", "@item license");
402 licenseShort = QCoreApplication::translate("KAboutLicense", "MPL 2.0", "@item license (short name)");
403 licenseFull = QCoreApplication::translate("KAboutLicense", "Mozilla Public License 2.0", "@item license");
404 break;
405 break;
408 licenseShort = licenseFull = QCoreApplication::translate("KAboutLicense", "Custom", "@item license");
409 break;
410 default:
411 licenseShort = licenseFull = QCoreApplication::translate("KAboutLicense", "Not specified", "@item license");
412 }
413
414 const QString result = (formatName == KAboutLicense::ShortName) ? licenseShort : (formatName == KAboutLicense::FullName) ? licenseFull : QString();
415
416 return result;
417}
418
420{
421 d = other.d;
422 return *this;
423}
424
425KAboutLicense::LicenseKey KAboutLicense::key() const
426{
427 return d->_licenseKey;
428}
429
431{
432 // Setup keyword->enum dictionary on first call.
433 // Use normalized keywords, by the algorithm below.
434 static const QHash<QByteArray, KAboutLicense::LicenseKey> licenseDict{
435 {"gpl", KAboutLicense::GPL}, {"gplv2", KAboutLicense::GPL_V2},
436 {"gplv2+", KAboutLicense::GPL_V2}, {"gpl20", KAboutLicense::GPL_V2},
437 {"gpl20+", KAboutLicense::GPL_V2}, {"lgpl", KAboutLicense::LGPL},
438 {"lgplv2", KAboutLicense::LGPL_V2}, {"lgplv2+", KAboutLicense::LGPL_V2},
439 {"lgpl20", KAboutLicense::LGPL_V2}, {"lgpl20+", KAboutLicense::LGPL_V2},
441 {"apache", KAboutLicense::Apache_V2}, {"bsd3clause", KAboutLicense::BSD_3_Clause},
442 {"artistic", KAboutLicense::Artistic}, {"artistic10", KAboutLicense::Artistic},
443 {"gplv3", KAboutLicense::GPL_V3}, {"gplv3+", KAboutLicense::GPL_V3},
444 {"gpl30", KAboutLicense::GPL_V3}, {"gpl30+", KAboutLicense::GPL_V3},
445 {"lgplv3", KAboutLicense::LGPL_V3}, {"lgplv3+", KAboutLicense::LGPL_V3},
446 {"lgpl30", KAboutLicense::LGPL_V3}, {"lgpl30+", KAboutLicense::LGPL_V3},
447 {"lgplv21", KAboutLicense::LGPL_V2_1}, {"lgplv21+", KAboutLicense::LGPL_V2_1},
448 {"lgpl21", KAboutLicense::LGPL_V2_1}, {"lgpl21+", KAboutLicense::LGPL_V2_1},
449 {"mit", KAboutLicense::MIT},
450 };
451
452 // Normalize keyword.
453 QString keyword = rawKeyword;
454 keyword = keyword.toLower();
455 keyword.replace(QLatin1StringView("-or-later"), QLatin1StringView("+"));
456 keyword.remove(QLatin1Char(' '));
457 keyword.remove(QLatin1Char('.'));
458 keyword.remove(QLatin1Char('-'));
459
460 LicenseKey license = licenseDict.value(keyword.toLatin1(), KAboutLicense::Custom);
461 auto restriction = keyword.endsWith(QLatin1Char('+')) ? OrLaterVersions : OnlyThisVersion;
462 return KAboutLicense(license, restriction, nullptr);
463}
464
465class KAboutComponentPrivate : public QSharedData
466{
467public:
468 QString _name;
469 QString _description;
470 QString _version;
471 QString _webAddress;
472 KAboutLicense _license;
473};
474
476 const QString &_description,
477 const QString &_version,
478 const QString &_webAddress,
479 enum KAboutLicense::LicenseKey licenseType)
480 : d(new KAboutComponentPrivate)
481{
482 d->_name = _name;
483 d->_description = _description;
484 d->_version = _version;
485 d->_webAddress = _webAddress;
486 d->_license = KAboutLicense(licenseType, nullptr);
487}
488
490 const QString &_description,
491 const QString &_version,
492 const QString &_webAddress,
493 const QString &pathToLicenseFile)
494 : d(new KAboutComponentPrivate)
495{
496 d->_name = _name;
497 d->_description = _description;
498 d->_version = _version;
499 d->_webAddress = _webAddress;
500 d->_license = KAboutLicense();
501 d->_license.setLicenseFromPath(pathToLicenseFile);
502}
503
505
506KAboutComponent::~KAboutComponent() = default;
507
508QString KAboutComponent::name() const
509{
510 return d->_name;
511}
512
513QString KAboutComponent::description() const
514{
515 return d->_description;
516}
517
518QString KAboutComponent::version() const
519{
520 return d->_version;
521}
522
523QString KAboutComponent::webAddress() const
524{
525 return d->_webAddress;
526}
527
529{
530 return d->_license;
531}
532
534
535class KAboutDataPrivate
536{
537public:
538 KAboutDataPrivate()
539 : customAuthorTextEnabled(false)
540 {
541 }
542 QString _componentName;
543 QString _displayName;
544 QString _shortDescription;
545 QString _copyrightStatement;
546 QString _otherText;
547 QString _homepageAddress;
548 QList<KAboutPerson> _authorList;
549 QList<KAboutPerson> _creditList;
550 QList<KAboutPerson> _translatorList;
551 QList<KAboutComponent> _componentList;
552 QList<KAboutLicense> _licenseList;
553 QVariant programLogo;
554 QString customAuthorPlainText, customAuthorRichText;
555 bool customAuthorTextEnabled;
556
557 QString organizationDomain;
558 QString desktopFileName;
559
560 // Everything dr.konqi needs, we store as utf-8, so we
561 // can just give it a pointer, w/o any allocations.
562 QByteArray _internalProgramName;
563 QByteArray _version;
564 QByteArray _bugAddress;
565 QByteArray productName;
566
567 static QList<KAboutPerson> parseTranslators(const QString &translatorName, const QString &translatorEmail);
568};
569
570KAboutData::KAboutData(const QString &_componentName,
571 const QString &_displayName,
572 const QString &_version,
573 const QString &_shortDescription,
574 enum KAboutLicense::LicenseKey licenseType,
575 const QString &_copyrightStatement,
576 const QString &text,
577 const QString &homePageAddress,
578 const QString &bugAddress)
579 : d(new KAboutDataPrivate)
580{
581 d->_componentName = _componentName;
582 int p = d->_componentName.indexOf(QLatin1Char('/'));
583 if (p >= 0) {
584 d->_componentName = d->_componentName.mid(p + 1);
585 }
586
587 d->_displayName = _displayName;
588 if (!d->_displayName.isEmpty()) { // KComponentData("klauncher") gives empty program name
589 d->_internalProgramName = _displayName.toUtf8();
590 }
591 d->_version = _version.toUtf8();
592 d->_shortDescription = _shortDescription;
593 d->_licenseList.append(KAboutLicense(licenseType, this));
594 d->_copyrightStatement = _copyrightStatement;
595 d->_otherText = text;
596 d->_homepageAddress = homePageAddress;
597 d->_bugAddress = bugAddress.toUtf8();
598
599 QUrl homePageUrl(homePageAddress);
600 if (!homePageUrl.isValid() || homePageUrl.scheme().isEmpty()) {
601 // Default domain if nothing else is better
602 homePageUrl.setUrl(QStringLiteral("https://kde.org/"));
603 }
604
605 const QChar dotChar(QLatin1Char('.'));
606 QStringList hostComponents = homePageUrl.host().split(dotChar);
607
608 // Remove leading component unless 2 (or less) components are present
609 if (hostComponents.size() > 2) {
610 hostComponents.removeFirst();
611 }
612
613 d->organizationDomain = hostComponents.join(dotChar);
614
615 // KF6: do not set a default desktopFileName value here, but remove this code and leave it empty
616 // see KAboutData::desktopFileName() for details
617
618 // desktop file name is reverse domain name
619 std::reverse(hostComponents.begin(), hostComponents.end());
620 hostComponents.append(_componentName);
621
622 d->desktopFileName = hostComponents.join(dotChar);
623}
624
625KAboutData::KAboutData(const QString &_componentName, const QString &_displayName, const QString &_version)
626 : d(new KAboutDataPrivate)
627{
628 d->_componentName = _componentName;
629 int p = d->_componentName.indexOf(QLatin1Char('/'));
630 if (p >= 0) {
631 d->_componentName = d->_componentName.mid(p + 1);
632 }
633
634 d->_displayName = _displayName;
635 if (!d->_displayName.isEmpty()) { // KComponentData("klauncher") gives empty program name
636 d->_internalProgramName = _displayName.toUtf8();
637 }
638 d->_version = _version.toUtf8();
639
640 // match behaviour of other constructors
641 d->_licenseList.append(KAboutLicense(KAboutLicense::Unknown, this));
642 d->_bugAddress = "submit@bugs.kde.org";
643 d->organizationDomain = QStringLiteral("kde.org");
644 // KF6: do not set a default desktopFileName value here, but remove this code and leave it empty
645 // see KAboutData::desktopFileName() for details
646 d->desktopFileName = QLatin1String("org.kde.") + d->_componentName;
647}
648
649KAboutData::~KAboutData() = default;
650
652 : d(new KAboutDataPrivate)
653{
654 *d = *other.d;
655 for (KAboutLicense &al : d->_licenseList) {
656 al.d.detach();
657 al.d->_aboutData = this;
658 }
659}
660
662{
663 if (this != &other) {
664 *d = *other.d;
665 for (KAboutLicense &al : d->_licenseList) {
666 al.d.detach();
667 al.d->_aboutData = this;
668 }
669 }
670 return *this;
671}
672
673KAboutData &KAboutData::addAuthor(const QString &name, const QString &task, const QString &emailAddress, const QString &webAddress, const QUrl &avatarUrl)
674{
675 d->_authorList.append(KAboutPerson(name, task, emailAddress, webAddress, avatarUrl));
676 return *this;
677}
678
680{
681 d->_authorList.append(author);
682 return *this;
683}
684
686{
687 d->_creditList.append(person);
688 return *this;
689}
690
691KAboutData &KAboutData::addCredit(const QString &name, const QString &task, const QString &emailAddress, const QString &webAddress, const QUrl &avatarUrl)
692{
693 d->_creditList.append(KAboutPerson(name, task, emailAddress, webAddress, avatarUrl));
694 return *this;
695}
696
697KAboutData &KAboutData::setTranslator(const QString &name, const QString &emailAddress)
698{
699 d->_translatorList = KAboutDataPrivate::parseTranslators(name, emailAddress);
700 return *this;
701}
702
704{
705 d->_componentList.append(component);
706 return *this;
707}
708
710 const QString &description,
711 const QString &version,
712 const QString &webAddress,
713 KAboutLicense::LicenseKey licenseKey)
714{
715 d->_componentList.append(KAboutComponent(name, description, version, webAddress, licenseKey));
716 return *this;
717}
718
720KAboutData::addComponent(const QString &name, const QString &description, const QString &version, const QString &webAddress, const QString &pathToLicenseFile)
721{
722 d->_componentList.append(KAboutComponent(name, description, version, webAddress, pathToLicenseFile));
723 return *this;
724}
725
727{
728 d->_licenseList[0] = KAboutLicense(this);
729 d->_licenseList[0].setLicenseFromText(licenseText);
730 return *this;
731}
732
734{
735 // if the default license is unknown, overwrite instead of append
736 KAboutLicense &firstLicense = d->_licenseList[0];
737 KAboutLicense newLicense(this);
738 newLicense.setLicenseFromText(licenseText);
739 if (d->_licenseList.count() == 1 && firstLicense.d->_licenseKey == KAboutLicense::Unknown) {
740 firstLicense = newLicense;
741 } else {
742 d->_licenseList.append(newLicense);
743 }
744
745 return *this;
746}
747
749{
750 d->_licenseList[0] = KAboutLicense(this);
751 d->_licenseList[0].setLicenseFromPath(pathToFile);
752 return *this;
753}
754
756{
757 // if the default license is unknown, overwrite instead of append
758 KAboutLicense &firstLicense = d->_licenseList[0];
759 KAboutLicense newLicense(this);
760 newLicense.setLicenseFromPath(pathToFile);
761 if (d->_licenseList.count() == 1 && firstLicense.d->_licenseKey == KAboutLicense::Unknown) {
762 firstLicense = newLicense;
763 } else {
764 d->_licenseList.append(newLicense);
765 }
766 return *this;
767}
768
770{
771 d->_componentName = componentName;
772 return *this;
773}
774
776{
777 d->_displayName = _displayName;
778 d->_internalProgramName = _displayName.toUtf8();
779 return *this;
780}
781
783{
784 d->_version = _version;
785 return *this;
786}
787
789{
790 d->_shortDescription = _shortDescription;
791 return *this;
792}
793
795{
796 return setLicense(licenseKey, KAboutLicense::OnlyThisVersion);
797}
798
800{
801 d->_licenseList[0] = KAboutLicense(licenseKey, versionRestriction, this);
802 return *this;
803}
804
806{
807 return addLicense(licenseKey, KAboutLicense::OnlyThisVersion);
808}
809
811{
812 // if the default license is unknown, overwrite instead of append
813 KAboutLicense &firstLicense = d->_licenseList[0];
814 if (d->_licenseList.count() == 1 && firstLicense.d->_licenseKey == KAboutLicense::Unknown) {
815 firstLicense = KAboutLicense(licenseKey, versionRestriction, this);
816 } else {
817 d->_licenseList.append(KAboutLicense(licenseKey, versionRestriction, this));
818 }
819 return *this;
820}
821
823{
824 d->_copyrightStatement = _copyrightStatement;
825 return *this;
826}
827
829{
830 d->_otherText = _otherText;
831 return *this;
832}
833
835{
836 d->_homepageAddress = homepage;
837 return *this;
838}
839
841{
842 d->_bugAddress = _bugAddress;
843 return *this;
844}
845
847{
849 return *this;
850}
851
853{
854 d->productName = _productName;
855 return *this;
856}
857
858QString KAboutData::componentName() const
859{
860 return d->_componentName;
861}
862
863QString KAboutData::productName() const
864{
865 if (!d->productName.isEmpty()) {
866 return QString::fromUtf8(d->productName);
867 }
868 return componentName();
869}
870
872{
873 return d->productName.isEmpty() ? nullptr : d->productName.constData();
874}
875
876QString KAboutData::displayName() const
877{
878 return d->_displayName;
879}
880
881/// @internal
882/// Return the program name. It is always pre-allocated.
883/// Needed for KCrash in particular.
885{
886 return d->_internalProgramName.constData();
887}
888
889QVariant KAboutData::programLogo() const
890{
891 return d->programLogo;
892}
893
895{
896 d->programLogo = image;
897 return *this;
898}
899
900QString KAboutData::version() const
901{
902 return QString::fromUtf8(d->_version.data());
903}
904
905/// @internal
906/// Return the untranslated and uninterpreted (to UTF8) string
907/// for the version information. Used in particular for KCrash.
909{
910 return d->_version.constData();
911}
912
913QString KAboutData::shortDescription() const
914{
915 return d->_shortDescription;
916}
917
918QString KAboutData::homepage() const
919{
920 return d->_homepageAddress;
921}
922
923QString KAboutData::bugAddress() const
924{
925 return QString::fromUtf8(d->_bugAddress.constData());
926}
927
929{
930 return d->organizationDomain;
931}
932
933/// @internal
934/// Return the untranslated and uninterpreted (to UTF8) string
935/// for the bug mail address. Used in particular for KCrash.
937{
938 if (d->_bugAddress.isEmpty()) {
939 return nullptr;
940 }
941 return d->_bugAddress.constData();
942}
943
944QList<KAboutPerson> KAboutData::authors() const
945{
946 return d->_authorList;
947}
948
949QList<KAboutPerson> KAboutData::credits() const
950{
951 return d->_creditList;
952}
953
954QList<KAboutPerson> KAboutDataPrivate::parseTranslators(const QString &translatorName, const QString &translatorEmail)
955{
956 if (translatorName.isEmpty() || translatorName == QLatin1String("Your names")) {
957 return {};
958 }
959
960 // use list of string views to delay creating new QString instances after the white-space trimming
961 const QList<QStringView> nameList = QStringView(translatorName).split(QLatin1Char(','));
962
963 QList<QStringView> emailList;
964 if (!translatorEmail.isEmpty() && translatorEmail != QLatin1String("Your emails")) {
965 emailList = QStringView(translatorEmail).split(QLatin1Char(','), Qt::KeepEmptyParts);
966 }
967
968 QList<KAboutPerson> personList;
969 personList.reserve(nameList.size());
970
971 auto eit = emailList.constBegin();
972
973 for (const QStringView &name : nameList) {
974 QStringView email;
975 if (eit != emailList.constEnd()) {
976 email = *eit;
977 ++eit;
978 }
979
980 personList.append(KAboutPerson(name.trimmed().toString(), email.trimmed().toString(), true));
981 }
982
983 return personList;
984}
985
986QList<KAboutPerson> KAboutData::translators() const
987{
988 return d->_translatorList;
989}
990
992{
993 return QCoreApplication::translate("KAboutData",
994 "<p>KDE is translated into many languages thanks to the work "
995 "of the translation teams all over the world.</p>"
996 "<p>For more information on KDE internationalization "
997 "visit <a href=\"https://l10n.kde.org\">https://l10n.kde.org</a></p>",
998 "replace this with information about your translation team");
999}
1000
1001QString KAboutData::otherText() const
1002{
1003 return d->_otherText;
1004}
1005
1006QList<KAboutComponent> KAboutData::components() const
1007{
1008 return d->_componentList;
1009}
1010
1011QList<KAboutLicense> KAboutData::licenses() const
1012{
1013 return d->_licenseList;
1014}
1015
1016QString KAboutData::copyrightStatement() const
1017{
1018 return d->_copyrightStatement;
1019}
1020
1022{
1023 return d->customAuthorPlainText;
1024}
1025
1027{
1028 return d->customAuthorRichText;
1029}
1030
1032{
1033 return d->customAuthorTextEnabled;
1034}
1035
1037{
1038 d->customAuthorPlainText = plainText;
1039 d->customAuthorRichText = richText;
1040
1041 d->customAuthorTextEnabled = true;
1042
1043 return *this;
1044}
1045
1047{
1049 d->customAuthorRichText = QString();
1050
1051 d->customAuthorTextEnabled = false;
1052
1053 return *this;
1054}
1055
1057{
1058 d->desktopFileName = desktopFileName;
1059
1060 return *this;
1061}
1062
1063QString KAboutData::desktopFileName() const
1064{
1065 return d->desktopFileName;
1066 // KF6: switch to this code and adapt API dox
1067#if 0
1068 // if desktopFileName has been explicitly set, use that value
1069 if (!d->desktopFileName.isEmpty()) {
1070 return d->desktopFileName;
1071 }
1072
1073 // return a string calculated on-the-fly from the current org domain & component name
1074 const QChar dotChar(QLatin1Char('.'));
1075 QStringList hostComponents = d->organizationDomain.split(dotChar);
1076
1077 // desktop file name is reverse domain name
1078 std::reverse(hostComponents.begin(), hostComponents.end());
1079 hostComponents.append(componentName());
1080
1081 return hostComponents.join(dotChar);
1082#endif
1083}
1084
1085class KAboutDataRegistry
1086{
1087public:
1088 KAboutDataRegistry()
1089 : m_appData(nullptr)
1090 {
1091 }
1092 ~KAboutDataRegistry()
1093 {
1094 delete m_appData;
1095 }
1096 KAboutDataRegistry(const KAboutDataRegistry &) = delete;
1097 KAboutDataRegistry &operator=(const KAboutDataRegistry &) = delete;
1098
1099 KAboutData *m_appData;
1100};
1101
1102Q_GLOBAL_STATIC(KAboutDataRegistry, s_registry)
1103
1104namespace
1105{
1106void warnIfOutOfSync(const char *aboutDataString, const QString &aboutDataValue, const char *appDataString, const QString &appDataValue)
1107{
1108 if (aboutDataValue != appDataValue) {
1109 qCWarning(KABOUTDATA) << appDataString << appDataValue << "is out-of-sync with" << aboutDataString << aboutDataValue;
1110 }
1111}
1112
1113}
1114
1116{
1118
1119 KAboutData *aboutData = s_registry->m_appData;
1120
1121 // not yet existing
1122 if (!aboutData) {
1123 // init from current Q*Application data
1125 // Unset the default (KDE) bug address, this is likely a third-party app. https://bugs.kde.org/show_bug.cgi?id=473517
1126 aboutData->setBugAddress(QByteArray());
1127 // For applicationDisplayName & desktopFileName, which are only properties of QGuiApplication,
1128 // we have to try to get them via the property system, as the static getter methods are
1129 // part of QtGui only. Disadvantage: requires an app instance.
1130 // Either get all or none of the properties & warn about it
1131 if (app) {
1133 aboutData->setVersion(QCoreApplication::applicationVersion().toUtf8());
1134 aboutData->setDisplayName(app->property("applicationDisplayName").toString());
1135 aboutData->setDesktopFileName(app->property("desktopFileName").toString());
1136 } else {
1137 qCWarning(KABOUTDATA) << "Could not initialize the properties of KAboutData::applicationData by the equivalent properties from Q*Application: no "
1138 "app instance (yet) existing.";
1139 }
1140
1141 s_registry->m_appData = aboutData;
1142 } else {
1143 // check if in-sync with Q*Application metadata, as their setters could have been called
1144 // after the last KAboutData::setApplicationData, with different values
1145 warnIfOutOfSync("KAboutData::applicationData().componentName",
1146 aboutData->componentName(),
1147 "QCoreApplication::applicationName",
1149 warnIfOutOfSync("KAboutData::applicationData().version",
1150 aboutData->version(),
1151 "QCoreApplication::applicationVersion",
1153 warnIfOutOfSync("KAboutData::applicationData().organizationDomain",
1154 aboutData->organizationDomain(),
1155 "QCoreApplication::organizationDomain",
1157 if (app) {
1158 warnIfOutOfSync("KAboutData::applicationData().displayName",
1159 aboutData->displayName(),
1160 "QGuiApplication::applicationDisplayName",
1161 app->property("applicationDisplayName").toString());
1162 warnIfOutOfSync("KAboutData::applicationData().desktopFileName",
1163 aboutData->desktopFileName(),
1164 "QGuiApplication::desktopFileName",
1165 app->property("desktopFileName").toString());
1166 }
1167 }
1168
1169 return *aboutData;
1170}
1171
1173{
1174 if (s_registry->m_appData) {
1175 *s_registry->m_appData = aboutData;
1176 } else {
1177 s_registry->m_appData = new KAboutData(aboutData);
1178 }
1179
1180 // For applicationDisplayName & desktopFileName, which are only properties of QGuiApplication,
1181 // we have to try to set them via the property system, as the static getter methods are
1182 // part of QtGui only. Disadvantage: requires an app instance.
1183 // So set either all or none of the properties & warn about it
1185 if (app) {
1186 app->setApplicationVersion(aboutData.version());
1187 app->setApplicationName(aboutData.componentName());
1188 app->setOrganizationDomain(aboutData.organizationDomain());
1189 app->setProperty("applicationDisplayName", aboutData.displayName());
1190 app->setProperty("desktopFileName", aboutData.desktopFileName());
1191 } else {
1192 qCWarning(KABOUTDATA) << "Could not initialize the equivalent properties of Q*Application: no instance (yet) existing.";
1193 }
1194
1195 // KF6: Rethink the current relation between KAboutData::applicationData and the Q*Application metadata
1196 // Always overwriting the Q*Application metadata here, but not updating back the KAboutData
1197 // in applicationData() is unbalanced and can result in out-of-sync data if the Q*Application
1198 // setters have been called meanwhile
1199 // Options are to remove the overlapping properties of KAboutData for cleancode, or making the
1200 // overlapping properties official shadow properties of their Q*Application countparts, though
1201 // that increases behavioural complexity a little.
1202}
1203
1204// only for KCrash (no memory allocation allowed)
1205const KAboutData *KAboutData::applicationDataPointer()
1206{
1207 if (s_registry.exists()) {
1208 return s_registry->m_appData;
1209 }
1210 return nullptr;
1211}
1212
1214{
1215 if (!d->_shortDescription.isEmpty()) {
1216 parser->setApplicationDescription(d->_shortDescription);
1217 }
1218
1219 parser->addHelpOption();
1220
1222 if (app && !app->applicationVersion().isEmpty()) {
1223 parser->addVersionOption();
1224 }
1225
1226 return parser->addOption(QCommandLineOption(QStringLiteral("author"), QCoreApplication::translate("KAboutData CLI", "Show author information.")))
1227 && parser->addOption(QCommandLineOption(QStringLiteral("license"), QCoreApplication::translate("KAboutData CLI", "Show license information.")))
1228 && parser->addOption(QCommandLineOption(QStringLiteral("desktopfile"),
1229 QCoreApplication::translate("KAboutData CLI", "The base file name of the desktop entry for this application."),
1230 QCoreApplication::translate("KAboutData CLI", "file name")));
1231}
1232
1234{
1235 bool foundArgument = false;
1236 if (parser->isSet(QStringLiteral("author"))) {
1237 foundArgument = true;
1238 if (d->_authorList.isEmpty()) {
1239 printf("%s\n",
1240 qPrintable(QCoreApplication::translate("KAboutData CLI", "This application was written by somebody who wants to remain anonymous.")));
1241 } else {
1242 printf("%s\n", qPrintable(QCoreApplication::translate("KAboutData CLI", "%1 was written by:").arg(qAppName())));
1243 for (const KAboutPerson &person : std::as_const(d->_authorList)) {
1244 QString authorData = QLatin1String(" ") + person.name();
1245 if (!person.emailAddress().isEmpty()) {
1246 authorData.append(QLatin1String(" <") + person.emailAddress() + QLatin1Char('>'));
1247 }
1248 printf("%s\n", qPrintable(authorData));
1249 }
1250 }
1251 if (!customAuthorTextEnabled()) {
1252 if (bugAddress() == QLatin1String("submit@bugs.kde.org")) {
1253 printf("%s\n", qPrintable(QCoreApplication::translate("KAboutData CLI", "Please use https://bugs.kde.org to report bugs.")));
1254 } else if (!bugAddress().isEmpty()) {
1255 printf("%s\n", qPrintable(QCoreApplication::translate("KAboutData CLI", "Please report bugs to %1.").arg(bugAddress())));
1256 }
1257 } else {
1258 printf("%s\n", qPrintable(customAuthorPlainText()));
1259 }
1260 } else if (parser->isSet(QStringLiteral("license"))) {
1261 foundArgument = true;
1262 for (const KAboutLicense &license : std::as_const(d->_licenseList)) {
1263 printf("%s\n", qPrintable(license.text()));
1264 }
1265 }
1266
1267 const QString desktopFileName = parser->value(QStringLiteral("desktopfile"));
1268 if (!desktopFileName.isEmpty()) {
1269 d->desktopFileName = desktopFileName;
1270 }
1271
1272 if (foundArgument) {
1273 ::exit(EXIT_SUCCESS);
1274 }
1275}
1276
1277#include "moc_kaboutdata.cpp"
This class is used to store information about a third party component.
Definition kaboutdata.h:391
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:558
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
@ MPL_V2
MPL_V2.
Definition kaboutdata.h:223
@ 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:239
static KAboutLicense byKeyword(const QString &keyword)
Fetch a known license by a keyword/spdx ID.
NameFormat
Format of the license name.
Definition kaboutdata.h:230
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)
QByteArray & append(QByteArrayView data)
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)
qsizetype indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const const
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
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-2025 The KDE developers.
Generated on Fri Jan 24 2025 11:55:52 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.