File indexing completed on 2024-05-19 15:09:12
0001 /* 0002 This file is part of the KDE Libraries 0003 0004 SPDX-FileCopyrightText: 2000 Espen Sand <espen@kde.org> 0005 SPDX-FileCopyrightText: 2006 Nicolas GOUTTE <goutte@kde.org> 0006 SPDX-FileCopyrightText: 2008 Friedrich W. H. Kossebau <kossebau@kde.org> 0007 SPDX-FileCopyrightText: 2010 Teo Mrnjavac <teo@kde.org> 0008 SPDX-FileCopyrightText: 2017 Harald Sitter <sitter@kde.org> 0009 SPDX-FileCopyrightText: 2021 Julius Künzel <jk.kdedev@smartlab.uber.space> 0010 0011 SPDX-License-Identifier: LGPL-2.0-or-later 0012 */ 0013 0014 #include "kaboutdata.h" 0015 #include "kjsonutils.h" 0016 #include "kpluginmetadata.h" 0017 0018 #include <QCommandLineOption> 0019 #include <QCommandLineParser> 0020 #include <QCoreApplication> 0021 #include <QFile> 0022 #include <QHash> 0023 #include <QJsonObject> 0024 #include <QList> 0025 #include <QLoggingCategory> 0026 #include <QSharedData> 0027 #include <QStandardPaths> 0028 #include <QTextStream> 0029 #include <QUrl> 0030 0031 #include <algorithm> 0032 0033 Q_DECLARE_LOGGING_CATEGORY(KABOUTDATA) 0034 // logging category for this framework, default: log stuff >= warning 0035 Q_LOGGING_CATEGORY(KABOUTDATA, "kf.coreaddons.kaboutdata", QtWarningMsg) 0036 0037 class KAboutPersonPrivate : public QSharedData 0038 { 0039 public: 0040 QString _name; 0041 QString _task; 0042 QString _emailAddress; 0043 QString _webAddress; 0044 QString _ocsUsername; 0045 }; 0046 0047 KAboutPerson::KAboutPerson(const QString &_name, const QString &_task, const QString &_emailAddress, const QString &_webAddress, const QString &_ocsUsername) 0048 : d(new KAboutPersonPrivate) 0049 { 0050 d->_name = _name; 0051 d->_task = _task; 0052 d->_emailAddress = _emailAddress; 0053 d->_webAddress = _webAddress; 0054 d->_ocsUsername = _ocsUsername; 0055 } 0056 0057 KAboutPerson::KAboutPerson(const QString &_name, const QString &_email, bool) 0058 : d(new KAboutPersonPrivate) 0059 { 0060 d->_name = _name; 0061 d->_emailAddress = _email; 0062 } 0063 0064 KAboutPerson::KAboutPerson(const KAboutPerson &other) = default; 0065 0066 KAboutPerson::~KAboutPerson() = default; 0067 0068 QString KAboutPerson::name() const 0069 { 0070 return d->_name; 0071 } 0072 0073 QString KAboutPerson::task() const 0074 { 0075 return d->_task; 0076 } 0077 0078 QString KAboutPerson::emailAddress() const 0079 { 0080 return d->_emailAddress; 0081 } 0082 0083 QString KAboutPerson::webAddress() const 0084 { 0085 return d->_webAddress; 0086 } 0087 0088 QString KAboutPerson::ocsUsername() const 0089 { 0090 return d->_ocsUsername; 0091 } 0092 0093 KAboutPerson &KAboutPerson::operator=(const KAboutPerson &other) = default; 0094 0095 KAboutPerson KAboutPerson::fromJSON(const QJsonObject &obj) 0096 { 0097 const QString name = KJsonUtils::readTranslatedString(obj, QStringLiteral("Name")); 0098 const QString task = KJsonUtils::readTranslatedString(obj, QStringLiteral("Task")); 0099 const QString email = obj[QStringLiteral("Email")].toString(); 0100 const QString website = obj[QStringLiteral("Website")].toString(); 0101 const QString userName = obj[QStringLiteral("UserName")].toString(); 0102 return KAboutPerson(name, task, email, website, userName); 0103 } 0104 0105 class KAboutLicensePrivate : public QSharedData 0106 { 0107 public: 0108 KAboutLicensePrivate(KAboutLicense::LicenseKey licenseType, KAboutLicense::VersionRestriction versionRestriction, const KAboutData *aboutData); 0109 KAboutLicensePrivate(const KAboutLicensePrivate &other); 0110 0111 QString spdxID() const; 0112 0113 KAboutLicense::LicenseKey _licenseKey; 0114 QString _licenseText; 0115 QString _pathToLicenseTextFile; 0116 KAboutLicense::VersionRestriction _versionRestriction; 0117 // needed for access to the possibly changing copyrightStatement() 0118 const KAboutData *_aboutData; 0119 }; 0120 0121 KAboutLicensePrivate::KAboutLicensePrivate(KAboutLicense::LicenseKey licenseType, 0122 KAboutLicense::VersionRestriction versionRestriction, 0123 const KAboutData *aboutData) 0124 : QSharedData() 0125 , _licenseKey(licenseType) 0126 , _versionRestriction(versionRestriction) 0127 , _aboutData(aboutData) 0128 { 0129 } 0130 0131 KAboutLicensePrivate::KAboutLicensePrivate(const KAboutLicensePrivate &other) 0132 : QSharedData(other) 0133 , _licenseKey(other._licenseKey) 0134 , _licenseText(other._licenseText) 0135 , _pathToLicenseTextFile(other._pathToLicenseTextFile) 0136 , _versionRestriction(other._versionRestriction) 0137 , _aboutData(other._aboutData) 0138 { 0139 } 0140 0141 QString KAboutLicensePrivate::spdxID() const 0142 { 0143 switch (_licenseKey) { 0144 case KAboutLicense::GPL_V2: 0145 return QStringLiteral("GPL-2.0"); 0146 case KAboutLicense::LGPL_V2: 0147 return QStringLiteral("LGPL-2.0"); 0148 case KAboutLicense::BSDL: 0149 return QStringLiteral("BSD-2-Clause"); 0150 case KAboutLicense::Artistic: 0151 return QStringLiteral("Artistic-1.0"); 0152 case KAboutLicense::QPL_V1_0: 0153 return QStringLiteral("QPL-1.0"); 0154 case KAboutLicense::GPL_V3: 0155 return QStringLiteral("GPL-3.0"); 0156 case KAboutLicense::LGPL_V3: 0157 return QStringLiteral("LGPL-3.0"); 0158 case KAboutLicense::LGPL_V2_1: 0159 return QStringLiteral("LGPL-2.1"); 0160 case KAboutLicense::Custom: 0161 case KAboutLicense::File: 0162 case KAboutLicense::Unknown: 0163 return QString(); 0164 } 0165 return QString(); 0166 } 0167 0168 KAboutLicense::KAboutLicense() 0169 : d(new KAboutLicensePrivate(Unknown, {}, nullptr)) 0170 { 0171 } 0172 0173 KAboutLicense::KAboutLicense(LicenseKey licenseType, VersionRestriction versionRestriction, const KAboutData *aboutData) 0174 : d(new KAboutLicensePrivate(licenseType, versionRestriction, aboutData)) 0175 { 0176 } 0177 0178 KAboutLicense::KAboutLicense(LicenseKey licenseType, const KAboutData *aboutData) 0179 : d(new KAboutLicensePrivate(licenseType, OnlyThisVersion, aboutData)) 0180 { 0181 } 0182 0183 KAboutLicense::KAboutLicense(const KAboutData *aboutData) 0184 : d(new KAboutLicensePrivate(Unknown, OnlyThisVersion, aboutData)) 0185 { 0186 } 0187 0188 KAboutLicense::KAboutLicense(const KAboutLicense &other) 0189 : d(other.d) 0190 { 0191 } 0192 0193 KAboutLicense::~KAboutLicense() 0194 { 0195 } 0196 0197 void KAboutLicense::setLicenseFromPath(const QString &pathToFile) 0198 { 0199 d->_licenseKey = KAboutLicense::File; 0200 d->_pathToLicenseTextFile = pathToFile; 0201 } 0202 0203 void KAboutLicense::setLicenseFromText(const QString &licenseText) 0204 { 0205 d->_licenseKey = KAboutLicense::Custom; 0206 d->_licenseText = licenseText; 0207 } 0208 0209 QString KAboutLicense::text() const 0210 { 0211 QString result; 0212 0213 const QString lineFeed = QStringLiteral("\n\n"); 0214 0215 if (d->_aboutData && !d->_aboutData->copyrightStatement().isEmpty()) { 0216 result = d->_aboutData->copyrightStatement() + lineFeed; 0217 } 0218 0219 bool knownLicense = false; 0220 QString pathToFile; // rel path if known license 0221 switch (d->_licenseKey) { 0222 case KAboutLicense::File: 0223 pathToFile = d->_pathToLicenseTextFile; 0224 break; 0225 case KAboutLicense::GPL_V2: 0226 knownLicense = true; 0227 pathToFile = QStringLiteral("GPL_V2"); 0228 break; 0229 case KAboutLicense::LGPL_V2: 0230 knownLicense = true; 0231 pathToFile = QStringLiteral("LGPL_V2"); 0232 break; 0233 case KAboutLicense::BSDL: 0234 knownLicense = true; 0235 pathToFile = QStringLiteral("BSD"); 0236 break; 0237 case KAboutLicense::Artistic: 0238 knownLicense = true; 0239 pathToFile = QStringLiteral("ARTISTIC"); 0240 break; 0241 case KAboutLicense::QPL_V1_0: 0242 knownLicense = true; 0243 pathToFile = QStringLiteral("QPL_V1.0"); 0244 break; 0245 case KAboutLicense::GPL_V3: 0246 knownLicense = true; 0247 pathToFile = QStringLiteral("GPL_V3"); 0248 break; 0249 case KAboutLicense::LGPL_V3: 0250 knownLicense = true; 0251 pathToFile = QStringLiteral("LGPL_V3"); 0252 break; 0253 case KAboutLicense::LGPL_V2_1: 0254 knownLicense = true; 0255 pathToFile = QStringLiteral("LGPL_V21"); 0256 break; 0257 case KAboutLicense::Custom: 0258 if (!d->_licenseText.isEmpty()) { 0259 result = d->_licenseText; 0260 break; 0261 } 0262 Q_FALLTHROUGH(); 0263 // fall through 0264 default: 0265 result += QCoreApplication::translate("KAboutLicense", 0266 "No licensing terms for this program have been specified.\n" 0267 "Please check the documentation or the source for any\n" 0268 "licensing terms.\n"); 0269 } 0270 0271 if (knownLicense) { 0272 #ifndef Q_OS_ANDROID 0273 pathToFile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kf" QT_STRINGIFY(QT_VERSION_MAJOR) "/licenses/") + pathToFile); 0274 #else 0275 pathToFile = QStringLiteral("assets:/share/kf5/licenses/") + pathToFile; 0276 #endif 0277 result += QCoreApplication::translate("KAboutLicense", "This program is distributed under the terms of the %1.").arg(name(KAboutLicense::ShortName)); 0278 if (!pathToFile.isEmpty()) { 0279 result += lineFeed; 0280 } 0281 } 0282 0283 if (!pathToFile.isEmpty()) { 0284 QFile file(pathToFile); 0285 if (file.open(QIODevice::ReadOnly)) { 0286 QTextStream str(&file); 0287 result += str.readAll(); 0288 } 0289 } 0290 0291 return result; 0292 } 0293 0294 QString KAboutLicense::spdx() const 0295 { 0296 // SPDX licenses are comprised of an identifier (e.g. GPL-2.0), an optional + to denote 'or 0297 // later versions' and optional ' WITH $exception' to denote standardized exceptions from the 0298 // core license. As we do not offer exceptions we effectively only return GPL-2.0 or GPL-2.0+, 0299 // this may change in the future. To that end the documentation makes no assertions about the 0300 // actual content of the SPDX license expression we return. 0301 // Expressions can in theory also contain AND, OR and () to build constructs involving more than 0302 // one license. As this is outside the scope of a single license object we'll ignore this here 0303 // for now. 0304 // The expectation is that the return value is only run through spec-compliant parsers, so this 0305 // can potentially be changed. 0306 0307 auto id = d->spdxID(); 0308 if (id.isNull()) { // Guard against potential future changes which would allow 'Foo+' as input. 0309 return id; 0310 } 0311 return d->_versionRestriction == OrLaterVersions ? id.append(QLatin1Char('+')) : id; 0312 } 0313 0314 QString KAboutLicense::name(KAboutLicense::NameFormat formatName) const 0315 { 0316 QString licenseShort; 0317 QString licenseFull; 0318 0319 switch (d->_licenseKey) { 0320 case KAboutLicense::GPL_V2: 0321 licenseShort = QCoreApplication::translate("KAboutLicense", "GPL v2", "@item license (short name)"); 0322 licenseFull = QCoreApplication::translate("KAboutLicense", "GNU General Public License Version 2", "@item license"); 0323 break; 0324 case KAboutLicense::LGPL_V2: 0325 licenseShort = QCoreApplication::translate("KAboutLicense", "LGPL v2", "@item license (short name)"); 0326 licenseFull = QCoreApplication::translate("KAboutLicense", "GNU Lesser General Public License Version 2", "@item license"); 0327 break; 0328 case KAboutLicense::BSDL: 0329 licenseShort = QCoreApplication::translate("KAboutLicense", "BSD License", "@item license (short name)"); 0330 licenseFull = QCoreApplication::translate("KAboutLicense", "BSD License", "@item license"); 0331 break; 0332 case KAboutLicense::Artistic: 0333 licenseShort = QCoreApplication::translate("KAboutLicense", "Artistic License", "@item license (short name)"); 0334 licenseFull = QCoreApplication::translate("KAboutLicense", "Artistic License", "@item license"); 0335 break; 0336 case KAboutLicense::QPL_V1_0: 0337 licenseShort = QCoreApplication::translate("KAboutLicense", "QPL v1.0", "@item license (short name)"); 0338 licenseFull = QCoreApplication::translate("KAboutLicense", "Q Public License", "@item license"); 0339 break; 0340 case KAboutLicense::GPL_V3: 0341 licenseShort = QCoreApplication::translate("KAboutLicense", "GPL v3", "@item license (short name)"); 0342 licenseFull = QCoreApplication::translate("KAboutLicense", "GNU General Public License Version 3", "@item license"); 0343 break; 0344 case KAboutLicense::LGPL_V3: 0345 licenseShort = QCoreApplication::translate("KAboutLicense", "LGPL v3", "@item license (short name)"); 0346 licenseFull = QCoreApplication::translate("KAboutLicense", "GNU Lesser General Public License Version 3", "@item license"); 0347 break; 0348 case KAboutLicense::LGPL_V2_1: 0349 licenseShort = QCoreApplication::translate("KAboutLicense", "LGPL v2.1", "@item license (short name)"); 0350 licenseFull = QCoreApplication::translate("KAboutLicense", "GNU Lesser General Public License Version 2.1", "@item license"); 0351 break; 0352 case KAboutLicense::Custom: 0353 case KAboutLicense::File: 0354 licenseShort = licenseFull = QCoreApplication::translate("KAboutLicense", "Custom", "@item license"); 0355 break; 0356 default: 0357 licenseShort = licenseFull = QCoreApplication::translate("KAboutLicense", "Not specified", "@item license"); 0358 } 0359 0360 const QString result = (formatName == KAboutLicense::ShortName) ? licenseShort : (formatName == KAboutLicense::FullName) ? licenseFull : QString(); 0361 0362 return result; 0363 } 0364 0365 KAboutLicense &KAboutLicense::operator=(const KAboutLicense &other) 0366 { 0367 d = other.d; 0368 return *this; 0369 } 0370 0371 KAboutLicense::LicenseKey KAboutLicense::key() const 0372 { 0373 return d->_licenseKey; 0374 } 0375 0376 KAboutLicense KAboutLicense::byKeyword(const QString &rawKeyword) 0377 { 0378 // Setup keyword->enum dictionary on first call. 0379 // Use normalized keywords, by the algorithm below. 0380 static const QHash<QByteArray, KAboutLicense::LicenseKey> licenseDict{ 0381 {"gpl", KAboutLicense::GPL}, {"gplv2", KAboutLicense::GPL_V2}, 0382 {"gplv2+", KAboutLicense::GPL_V2}, {"gpl20", KAboutLicense::GPL_V2}, 0383 {"gpl20+", KAboutLicense::GPL_V2}, {"lgpl", KAboutLicense::LGPL}, 0384 {"lgplv2", KAboutLicense::LGPL_V2}, {"lgplv2+", KAboutLicense::LGPL_V2}, 0385 {"lgpl20", KAboutLicense::LGPL_V2}, {"lgpl20+", KAboutLicense::LGPL_V2}, 0386 {"bsd", KAboutLicense::BSDL}, {"bsd2clause", KAboutLicense::BSDL}, 0387 {"artistic", KAboutLicense::Artistic}, {"artistic10", KAboutLicense::Artistic}, 0388 {"qpl", KAboutLicense::QPL}, {"qplv1", KAboutLicense::QPL_V1_0}, 0389 {"qplv10", KAboutLicense::QPL_V1_0}, {"qpl10", KAboutLicense::QPL_V1_0}, 0390 {"gplv3", KAboutLicense::GPL_V3}, {"gplv3+", KAboutLicense::GPL_V3}, 0391 {"gpl30", KAboutLicense::GPL_V3}, {"gpl30+", KAboutLicense::GPL_V3}, 0392 {"lgplv3", KAboutLicense::LGPL_V3}, {"lgplv3+", KAboutLicense::LGPL_V3}, 0393 {"lgpl30", KAboutLicense::LGPL_V3}, {"lgpl30+", KAboutLicense::LGPL_V3}, 0394 {"lgplv21", KAboutLicense::LGPL_V2_1}, {"lgplv21+", KAboutLicense::LGPL_V2_1}, 0395 {"lgpl21", KAboutLicense::LGPL_V2_1}, {"lgpl21+", KAboutLicense::LGPL_V2_1}, 0396 }; 0397 0398 // Normalize keyword. 0399 QString keyword = rawKeyword; 0400 keyword = keyword.toLower(); 0401 keyword.replace(QLatin1String("-or-later"), QLatin1String("+")); 0402 keyword.remove(QLatin1Char(' ')); 0403 keyword.remove(QLatin1Char('.')); 0404 keyword.remove(QLatin1Char('-')); 0405 0406 LicenseKey license = licenseDict.value(keyword.toLatin1(), KAboutLicense::Custom); 0407 auto restriction = keyword.endsWith(QLatin1Char('+')) ? OrLaterVersions : OnlyThisVersion; 0408 return KAboutLicense(license, restriction, nullptr); 0409 } 0410 0411 class KAboutComponentPrivate : public QSharedData 0412 { 0413 public: 0414 QString _name; 0415 QString _description; 0416 QString _version; 0417 QString _webAddress; 0418 KAboutLicense _license; 0419 }; 0420 0421 KAboutComponent::KAboutComponent(const QString &_name, 0422 const QString &_description, 0423 const QString &_version, 0424 const QString &_webAddress, 0425 enum KAboutLicense::LicenseKey licenseType) 0426 : d(new KAboutComponentPrivate) 0427 { 0428 d->_name = _name; 0429 d->_description = _description; 0430 d->_version = _version; 0431 d->_webAddress = _webAddress; 0432 d->_license = KAboutLicense(licenseType, nullptr); 0433 } 0434 0435 KAboutComponent::KAboutComponent(const QString &_name, 0436 const QString &_description, 0437 const QString &_version, 0438 const QString &_webAddress, 0439 const QString &pathToLicenseFile) 0440 : d(new KAboutComponentPrivate) 0441 { 0442 d->_name = _name; 0443 d->_description = _description; 0444 d->_version = _version; 0445 d->_webAddress = _webAddress; 0446 d->_license = KAboutLicense(); 0447 d->_license.setLicenseFromPath(pathToLicenseFile); 0448 } 0449 0450 KAboutComponent::KAboutComponent(const KAboutComponent &other) = default; 0451 0452 KAboutComponent::~KAboutComponent() = default; 0453 0454 QString KAboutComponent::name() const 0455 { 0456 return d->_name; 0457 } 0458 0459 QString KAboutComponent::description() const 0460 { 0461 return d->_description; 0462 } 0463 0464 QString KAboutComponent::version() const 0465 { 0466 return d->_version; 0467 } 0468 0469 QString KAboutComponent::webAddress() const 0470 { 0471 return d->_webAddress; 0472 } 0473 0474 KAboutLicense KAboutComponent::license() const 0475 { 0476 return d->_license; 0477 } 0478 0479 KAboutComponent &KAboutComponent::operator=(const KAboutComponent &other) = default; 0480 0481 class KAboutDataPrivate 0482 { 0483 public: 0484 KAboutDataPrivate() 0485 : customAuthorTextEnabled(false) 0486 { 0487 } 0488 QString _componentName; 0489 QString _displayName; 0490 QString _shortDescription; 0491 QString _copyrightStatement; 0492 QString _otherText; 0493 QString _homepageAddress; 0494 QList<KAboutPerson> _authorList; 0495 QList<KAboutPerson> _creditList; 0496 QList<KAboutPerson> _translatorList; 0497 QList<KAboutComponent> _componentList; 0498 QList<KAboutLicense> _licenseList; 0499 #if KCOREADDONS_BUILD_DEPRECATED_SINCE(5, 2) 0500 QString programIconName; 0501 #endif 0502 QVariant programLogo; 0503 QString customAuthorPlainText, customAuthorRichText; 0504 bool customAuthorTextEnabled; 0505 0506 QString organizationDomain; 0507 QString _ocsProviderUrl; 0508 QString desktopFileName; 0509 0510 // Everything dr.konqi needs, we store as utf-8, so we 0511 // can just give it a pointer, w/o any allocations. 0512 QByteArray _internalProgramName; 0513 QByteArray _version; 0514 QByteArray _bugAddress; 0515 QByteArray productName; 0516 0517 static QList<KAboutPerson> parseTranslators(const QString &translatorName, const QString &translatorEmail); 0518 }; 0519 0520 KAboutData::KAboutData(const QString &_componentName, 0521 const QString &_displayName, 0522 const QString &_version, 0523 const QString &_shortDescription, 0524 enum KAboutLicense::LicenseKey licenseType, 0525 const QString &_copyrightStatement, 0526 const QString &text, 0527 const QString &homePageAddress, 0528 const QString &bugAddress) 0529 : d(new KAboutDataPrivate) 0530 { 0531 d->_componentName = _componentName; 0532 int p = d->_componentName.indexOf(QLatin1Char('/')); 0533 if (p >= 0) { 0534 d->_componentName = d->_componentName.mid(p + 1); 0535 } 0536 0537 d->_displayName = _displayName; 0538 if (!d->_displayName.isEmpty()) { // KComponentData("klauncher") gives empty program name 0539 d->_internalProgramName = _displayName.toUtf8(); 0540 } 0541 d->_version = _version.toUtf8(); 0542 d->_shortDescription = _shortDescription; 0543 d->_licenseList.append(KAboutLicense(licenseType, this)); 0544 d->_copyrightStatement = _copyrightStatement; 0545 d->_otherText = text; 0546 d->_homepageAddress = homePageAddress; 0547 d->_bugAddress = bugAddress.toUtf8(); 0548 0549 QUrl homePageUrl(homePageAddress); 0550 if (!homePageUrl.isValid() || homePageUrl.scheme().isEmpty()) { 0551 // Default domain if nothing else is better 0552 homePageUrl.setUrl(QStringLiteral("https://kde.org/")); 0553 } 0554 0555 const QChar dotChar(QLatin1Char('.')); 0556 QStringList hostComponents = homePageUrl.host().split(dotChar); 0557 0558 // Remove leading component unless 2 (or less) components are present 0559 if (hostComponents.size() > 2) { 0560 hostComponents.removeFirst(); 0561 } 0562 0563 d->organizationDomain = hostComponents.join(dotChar); 0564 0565 // KF6: do not set a default desktopFileName value here, but remove this code and leave it empty 0566 // see KAboutData::desktopFileName() for details 0567 0568 // desktop file name is reverse domain name 0569 std::reverse(hostComponents.begin(), hostComponents.end()); 0570 hostComponents.append(_componentName); 0571 0572 d->desktopFileName = hostComponents.join(dotChar); 0573 } 0574 0575 KAboutData::KAboutData(const QString &_componentName, const QString &_displayName, const QString &_version) 0576 : d(new KAboutDataPrivate) 0577 { 0578 d->_componentName = _componentName; 0579 int p = d->_componentName.indexOf(QLatin1Char('/')); 0580 if (p >= 0) { 0581 d->_componentName = d->_componentName.mid(p + 1); 0582 } 0583 0584 d->_displayName = _displayName; 0585 if (!d->_displayName.isEmpty()) { // KComponentData("klauncher") gives empty program name 0586 d->_internalProgramName = _displayName.toUtf8(); 0587 } 0588 d->_version = _version.toUtf8(); 0589 0590 // match behaviour of other constructors 0591 d->_licenseList.append(KAboutLicense(KAboutLicense::Unknown, this)); 0592 d->_bugAddress = "submit@bugs.kde.org"; 0593 d->organizationDomain = QStringLiteral("kde.org"); 0594 // KF6: do not set a default desktopFileName value here, but remove this code and leave it empty 0595 // see KAboutData::desktopFileName() for details 0596 d->desktopFileName = QLatin1String("org.kde.") + d->_componentName; 0597 } 0598 0599 KAboutData::~KAboutData() = default; 0600 0601 KAboutData::KAboutData(const KAboutData &other) 0602 : d(new KAboutDataPrivate) 0603 { 0604 *d = *other.d; 0605 for (KAboutLicense &al : d->_licenseList) { 0606 al.d.detach(); 0607 al.d->_aboutData = this; 0608 } 0609 } 0610 0611 KAboutData &KAboutData::operator=(const KAboutData &other) 0612 { 0613 if (this != &other) { 0614 *d = *other.d; 0615 for (KAboutLicense &al : d->_licenseList) { 0616 al.d.detach(); 0617 al.d->_aboutData = this; 0618 } 0619 } 0620 return *this; 0621 } 0622 0623 #if KCOREADDONS_BUILD_DEPRECATED_SINCE(5, 65) 0624 KAboutData KAboutData::fromPluginMetaData(const KPluginMetaData &plugin) 0625 { 0626 KAboutData ret(plugin.pluginId(), 0627 plugin.name(), 0628 plugin.version(), 0629 plugin.description(), 0630 KAboutLicense::byKeyword(plugin.license()).key(), 0631 plugin.copyrightText(), 0632 plugin.extraInformation(), 0633 plugin.website()); 0634 #if KCOREADDONS_BUILD_DEPRECATED_SINCE(5, 2) 0635 ret.d->programIconName = plugin.iconName(); 0636 #endif 0637 ret.d->_authorList = plugin.authors(); 0638 ret.d->_translatorList = plugin.translators(); 0639 ret.d->_creditList = plugin.otherContributors(); 0640 return ret; 0641 } 0642 #endif 0643 0644 KAboutData &KAboutData::addAuthor(const QString &name, const QString &task, const QString &emailAddress, const QString &webAddress, const QString &ocsUsername) 0645 { 0646 d->_authorList.append(KAboutPerson(name, task, emailAddress, webAddress, ocsUsername)); 0647 return *this; 0648 } 0649 0650 KAboutData &KAboutData::addCredit(const QString &name, const QString &task, const QString &emailAddress, const QString &webAddress, const QString &ocsUsername) 0651 { 0652 d->_creditList.append(KAboutPerson(name, task, emailAddress, webAddress, ocsUsername)); 0653 return *this; 0654 } 0655 0656 KAboutData &KAboutData::setTranslator(const QString &name, const QString &emailAddress) 0657 { 0658 d->_translatorList = KAboutDataPrivate::parseTranslators(name, emailAddress); 0659 return *this; 0660 } 0661 0662 KAboutData &KAboutData::addComponent(const QString &name, 0663 const QString &description, 0664 const QString &version, 0665 const QString &webAddress, 0666 KAboutLicense::LicenseKey licenseKey) 0667 { 0668 d->_componentList.append(KAboutComponent(name, description, version, webAddress, licenseKey)); 0669 return *this; 0670 } 0671 0672 KAboutData & 0673 KAboutData::addComponent(const QString &name, const QString &description, const QString &version, const QString &webAddress, const QString &pathToLicenseFile) 0674 { 0675 d->_componentList.append(KAboutComponent(name, description, version, webAddress, pathToLicenseFile)); 0676 return *this; 0677 } 0678 0679 KAboutData &KAboutData::setLicenseText(const QString &licenseText) 0680 { 0681 d->_licenseList[0] = KAboutLicense(this); 0682 d->_licenseList[0].setLicenseFromText(licenseText); 0683 return *this; 0684 } 0685 0686 KAboutData &KAboutData::addLicenseText(const QString &licenseText) 0687 { 0688 // if the default license is unknown, overwrite instead of append 0689 KAboutLicense &firstLicense = d->_licenseList[0]; 0690 KAboutLicense newLicense(this); 0691 newLicense.setLicenseFromText(licenseText); 0692 if (d->_licenseList.count() == 1 && firstLicense.d->_licenseKey == KAboutLicense::Unknown) { 0693 firstLicense = newLicense; 0694 } else { 0695 d->_licenseList.append(newLicense); 0696 } 0697 0698 return *this; 0699 } 0700 0701 KAboutData &KAboutData::setLicenseTextFile(const QString &pathToFile) 0702 { 0703 d->_licenseList[0] = KAboutLicense(this); 0704 d->_licenseList[0].setLicenseFromPath(pathToFile); 0705 return *this; 0706 } 0707 0708 KAboutData &KAboutData::addLicenseTextFile(const QString &pathToFile) 0709 { 0710 // if the default license is unknown, overwrite instead of append 0711 KAboutLicense &firstLicense = d->_licenseList[0]; 0712 KAboutLicense newLicense(this); 0713 newLicense.setLicenseFromPath(pathToFile); 0714 if (d->_licenseList.count() == 1 && firstLicense.d->_licenseKey == KAboutLicense::Unknown) { 0715 firstLicense = newLicense; 0716 } else { 0717 d->_licenseList.append(newLicense); 0718 } 0719 return *this; 0720 } 0721 0722 KAboutData &KAboutData::setComponentName(const QString &componentName) 0723 { 0724 d->_componentName = componentName; 0725 return *this; 0726 } 0727 0728 KAboutData &KAboutData::setDisplayName(const QString &_displayName) 0729 { 0730 d->_displayName = _displayName; 0731 d->_internalProgramName = _displayName.toUtf8(); 0732 return *this; 0733 } 0734 0735 KAboutData &KAboutData::setOcsProvider(const QString &_ocsProviderUrl) 0736 { 0737 d->_ocsProviderUrl = _ocsProviderUrl; 0738 return *this; 0739 } 0740 0741 KAboutData &KAboutData::setVersion(const QByteArray &_version) 0742 { 0743 d->_version = _version; 0744 return *this; 0745 } 0746 0747 KAboutData &KAboutData::setShortDescription(const QString &_shortDescription) 0748 { 0749 d->_shortDescription = _shortDescription; 0750 return *this; 0751 } 0752 0753 KAboutData &KAboutData::setLicense(KAboutLicense::LicenseKey licenseKey) 0754 { 0755 return setLicense(licenseKey, KAboutLicense::OnlyThisVersion); 0756 } 0757 0758 KAboutData &KAboutData::setLicense(KAboutLicense::LicenseKey licenseKey, KAboutLicense::VersionRestriction versionRestriction) 0759 { 0760 d->_licenseList[0] = KAboutLicense(licenseKey, versionRestriction, this); 0761 return *this; 0762 } 0763 0764 KAboutData &KAboutData::addLicense(KAboutLicense::LicenseKey licenseKey) 0765 { 0766 return addLicense(licenseKey, KAboutLicense::OnlyThisVersion); 0767 } 0768 0769 KAboutData &KAboutData::addLicense(KAboutLicense::LicenseKey licenseKey, KAboutLicense::VersionRestriction versionRestriction) 0770 { 0771 // if the default license is unknown, overwrite instead of append 0772 KAboutLicense &firstLicense = d->_licenseList[0]; 0773 if (d->_licenseList.count() == 1 && firstLicense.d->_licenseKey == KAboutLicense::Unknown) { 0774 firstLicense = KAboutLicense(licenseKey, versionRestriction, this); 0775 } else { 0776 d->_licenseList.append(KAboutLicense(licenseKey, versionRestriction, this)); 0777 } 0778 return *this; 0779 } 0780 0781 KAboutData &KAboutData::setCopyrightStatement(const QString &_copyrightStatement) 0782 { 0783 d->_copyrightStatement = _copyrightStatement; 0784 return *this; 0785 } 0786 0787 KAboutData &KAboutData::setOtherText(const QString &_otherText) 0788 { 0789 d->_otherText = _otherText; 0790 return *this; 0791 } 0792 0793 KAboutData &KAboutData::setHomepage(const QString &homepage) 0794 { 0795 d->_homepageAddress = homepage; 0796 return *this; 0797 } 0798 0799 KAboutData &KAboutData::setBugAddress(const QByteArray &_bugAddress) 0800 { 0801 d->_bugAddress = _bugAddress; 0802 return *this; 0803 } 0804 0805 KAboutData &KAboutData::setOrganizationDomain(const QByteArray &domain) 0806 { 0807 d->organizationDomain = QString::fromLatin1(domain.data()); 0808 return *this; 0809 } 0810 0811 KAboutData &KAboutData::setProductName(const QByteArray &_productName) 0812 { 0813 d->productName = _productName; 0814 return *this; 0815 } 0816 0817 QString KAboutData::componentName() const 0818 { 0819 return d->_componentName; 0820 } 0821 0822 QString KAboutData::productName() const 0823 { 0824 if (!d->productName.isEmpty()) { 0825 return QString::fromUtf8(d->productName); 0826 } 0827 return componentName(); 0828 } 0829 0830 const char *KAboutData::internalProductName() const 0831 { 0832 return d->productName.isEmpty() ? nullptr : d->productName.constData(); 0833 } 0834 0835 QString KAboutData::displayName() const 0836 { 0837 if (!d->_displayName.isEmpty()) { 0838 return d->_displayName; 0839 } 0840 return componentName(); 0841 } 0842 0843 /// @internal 0844 /// Return the program name. It is always pre-allocated. 0845 /// Needed for KCrash in particular. 0846 const char *KAboutData::internalProgramName() const 0847 { 0848 return d->_internalProgramName.constData(); 0849 } 0850 0851 #if KCOREADDONS_BUILD_DEPRECATED_SINCE(5, 2) 0852 QString KAboutData::programIconName() const 0853 { 0854 return d->programIconName.isEmpty() ? componentName() : d->programIconName; 0855 } 0856 0857 KAboutData &KAboutData::setProgramIconName(const QString &iconName) 0858 { 0859 d->programIconName = iconName; 0860 return *this; 0861 } 0862 #endif 0863 0864 QVariant KAboutData::programLogo() const 0865 { 0866 return d->programLogo; 0867 } 0868 0869 KAboutData &KAboutData::setProgramLogo(const QVariant &image) 0870 { 0871 d->programLogo = image; 0872 return *this; 0873 } 0874 0875 QString KAboutData::ocsProviderUrl() const 0876 { 0877 return d->_ocsProviderUrl; 0878 } 0879 0880 QString KAboutData::version() const 0881 { 0882 return QString::fromUtf8(d->_version.data()); 0883 } 0884 0885 /// @internal 0886 /// Return the untranslated and uninterpreted (to UTF8) string 0887 /// for the version information. Used in particular for KCrash. 0888 const char *KAboutData::internalVersion() const 0889 { 0890 return d->_version.constData(); 0891 } 0892 0893 QString KAboutData::shortDescription() const 0894 { 0895 return d->_shortDescription; 0896 } 0897 0898 QString KAboutData::homepage() const 0899 { 0900 return d->_homepageAddress; 0901 } 0902 0903 QString KAboutData::bugAddress() const 0904 { 0905 return QString::fromUtf8(d->_bugAddress.constData()); 0906 } 0907 0908 QString KAboutData::organizationDomain() const 0909 { 0910 return d->organizationDomain; 0911 } 0912 0913 /// @internal 0914 /// Return the untranslated and uninterpreted (to UTF8) string 0915 /// for the bug mail address. Used in particular for KCrash. 0916 const char *KAboutData::internalBugAddress() const 0917 { 0918 if (d->_bugAddress.isEmpty()) { 0919 return nullptr; 0920 } 0921 return d->_bugAddress.constData(); 0922 } 0923 0924 QList<KAboutPerson> KAboutData::authors() const 0925 { 0926 return d->_authorList; 0927 } 0928 0929 QList<KAboutPerson> KAboutData::credits() const 0930 { 0931 return d->_creditList; 0932 } 0933 0934 QList<KAboutPerson> KAboutDataPrivate::parseTranslators(const QString &translatorName, const QString &translatorEmail) 0935 { 0936 if (translatorName.isEmpty() || translatorName == QLatin1String("Your names")) { 0937 return {}; 0938 } 0939 0940 const QStringList nameList(translatorName.split(QLatin1Char(','))); 0941 0942 QStringList emailList; 0943 if (!translatorEmail.isEmpty() && translatorEmail != QLatin1String("Your emails")) { 0944 emailList = translatorEmail.split(QLatin1Char(','), Qt::KeepEmptyParts); 0945 } 0946 0947 QList<KAboutPerson> personList; 0948 personList.reserve(nameList.size()); 0949 0950 auto eit = emailList.constBegin(); 0951 0952 for (const QString &name : nameList) { 0953 QString email; 0954 if (eit != emailList.constEnd()) { 0955 email = *eit; 0956 ++eit; 0957 } 0958 0959 personList.append(KAboutPerson(name.trimmed(), email.trimmed(), true)); 0960 } 0961 0962 return personList; 0963 } 0964 0965 QList<KAboutPerson> KAboutData::translators() const 0966 { 0967 return d->_translatorList; 0968 } 0969 0970 QString KAboutData::aboutTranslationTeam() 0971 { 0972 return QCoreApplication::translate("KAboutData", 0973 "<p>KDE is translated into many languages thanks to the work " 0974 "of the translation teams all over the world.</p>" 0975 "<p>For more information on KDE internationalization " 0976 "visit <a href=\"https://l10n.kde.org\">https://l10n.kde.org</a></p>", 0977 "replace this with information about your translation team"); 0978 } 0979 0980 QString KAboutData::otherText() const 0981 { 0982 return d->_otherText; 0983 } 0984 0985 QList<KAboutComponent> KAboutData::components() const 0986 { 0987 return d->_componentList; 0988 } 0989 0990 QList<KAboutLicense> KAboutData::licenses() const 0991 { 0992 return d->_licenseList; 0993 } 0994 0995 QString KAboutData::copyrightStatement() const 0996 { 0997 return d->_copyrightStatement; 0998 } 0999 1000 QString KAboutData::customAuthorPlainText() const 1001 { 1002 return d->customAuthorPlainText; 1003 } 1004 1005 QString KAboutData::customAuthorRichText() const 1006 { 1007 return d->customAuthorRichText; 1008 } 1009 1010 bool KAboutData::customAuthorTextEnabled() const 1011 { 1012 return d->customAuthorTextEnabled; 1013 } 1014 1015 KAboutData &KAboutData::setCustomAuthorText(const QString &plainText, const QString &richText) 1016 { 1017 d->customAuthorPlainText = plainText; 1018 d->customAuthorRichText = richText; 1019 1020 d->customAuthorTextEnabled = true; 1021 1022 return *this; 1023 } 1024 1025 KAboutData &KAboutData::unsetCustomAuthorText() 1026 { 1027 d->customAuthorPlainText = QString(); 1028 d->customAuthorRichText = QString(); 1029 1030 d->customAuthorTextEnabled = false; 1031 1032 return *this; 1033 } 1034 1035 KAboutData &KAboutData::setDesktopFileName(const QString &desktopFileName) 1036 { 1037 d->desktopFileName = desktopFileName; 1038 1039 return *this; 1040 } 1041 1042 QString KAboutData::desktopFileName() const 1043 { 1044 return d->desktopFileName; 1045 // KF6: switch to this code and adapt API dox 1046 #if 0 1047 // if desktopFileName has been explicitly set, use that value 1048 if (!d->desktopFileName.isEmpty()) { 1049 return d->desktopFileName; 1050 } 1051 1052 // return a string calculated on-the-fly from the current org domain & component name 1053 const QChar dotChar(QLatin1Char('.')); 1054 QStringList hostComponents = d->organizationDomain.split(dotChar); 1055 1056 // desktop file name is reverse domain name 1057 std::reverse(hostComponents.begin(), hostComponents.end()); 1058 hostComponents.append(componentName()); 1059 1060 return hostComponents.join(dotChar); 1061 #endif 1062 } 1063 1064 class KAboutDataRegistry 1065 { 1066 public: 1067 KAboutDataRegistry() 1068 : m_appData(nullptr) 1069 { 1070 } 1071 ~KAboutDataRegistry() 1072 { 1073 delete m_appData; 1074 #if KCOREADDONS_BUILD_DEPRECATED_SINCE(5, 76) 1075 qDeleteAll(m_pluginData); 1076 #endif 1077 } 1078 KAboutDataRegistry(const KAboutDataRegistry &) = delete; 1079 KAboutDataRegistry &operator=(const KAboutDataRegistry &) = delete; 1080 1081 KAboutData *m_appData; 1082 #if KCOREADDONS_BUILD_DEPRECATED_SINCE(5, 76) 1083 QHash<QString, KAboutData *> m_pluginData; 1084 #endif 1085 }; 1086 1087 Q_GLOBAL_STATIC(KAboutDataRegistry, s_registry) 1088 1089 namespace 1090 { 1091 void warnIfOutOfSync(const char *aboutDataString, const QString &aboutDataValue, const char *appDataString, const QString &appDataValue) 1092 { 1093 if (aboutDataValue != appDataValue) { 1094 qCWarning(KABOUTDATA) << appDataString << appDataValue << "is out-of-sync with" << aboutDataString << aboutDataValue; 1095 } 1096 } 1097 1098 } 1099 1100 KAboutData KAboutData::applicationData() 1101 { 1102 QCoreApplication *app = QCoreApplication::instance(); 1103 1104 KAboutData *aboutData = s_registry->m_appData; 1105 1106 // not yet existing 1107 if (!aboutData) { 1108 // init from current Q*Application data 1109 aboutData = new KAboutData(QCoreApplication::applicationName(), QString(), QString()); 1110 // Unset the default (KDE) bug address, this is likely a third-party app. https://bugs.kde.org/show_bug.cgi?id=473517 1111 aboutData->setBugAddress(QByteArray()); 1112 // For applicationDisplayName & desktopFileName, which are only properties of QGuiApplication, 1113 // we have to try to get them via the property system, as the static getter methods are 1114 // part of QtGui only. Disadvantage: requires an app instance. 1115 // Either get all or none of the properties & warn about it 1116 if (app) { 1117 aboutData->setOrganizationDomain(QCoreApplication::organizationDomain().toUtf8()); 1118 aboutData->setVersion(QCoreApplication::applicationVersion().toUtf8()); 1119 aboutData->setDisplayName(app->property("applicationDisplayName").toString()); 1120 aboutData->setDesktopFileName(app->property("desktopFileName").toString()); 1121 } else { 1122 qCWarning(KABOUTDATA) << "Could not initialize the properties of KAboutData::applicationData by the equivalent properties from Q*Application: no " 1123 "app instance (yet) existing."; 1124 } 1125 1126 s_registry->m_appData = aboutData; 1127 } else { 1128 // check if in-sync with Q*Application metadata, as their setters could have been called 1129 // after the last KAboutData::setApplicationData, with different values 1130 warnIfOutOfSync("KAboutData::applicationData().componentName", 1131 aboutData->componentName(), 1132 "QCoreApplication::applicationName", 1133 QCoreApplication::applicationName()); 1134 warnIfOutOfSync("KAboutData::applicationData().version", 1135 aboutData->version(), 1136 "QCoreApplication::applicationVersion", 1137 QCoreApplication::applicationVersion()); 1138 warnIfOutOfSync("KAboutData::applicationData().organizationDomain", 1139 aboutData->organizationDomain(), 1140 "QCoreApplication::organizationDomain", 1141 QCoreApplication::organizationDomain()); 1142 if (app) { 1143 warnIfOutOfSync("KAboutData::applicationData().displayName", 1144 aboutData->displayName(), 1145 "QGuiApplication::applicationDisplayName", 1146 app->property("applicationDisplayName").toString()); 1147 warnIfOutOfSync("KAboutData::applicationData().desktopFileName", 1148 aboutData->desktopFileName(), 1149 "QGuiApplication::desktopFileName", 1150 app->property("desktopFileName").toString()); 1151 } 1152 } 1153 1154 return *aboutData; 1155 } 1156 1157 void KAboutData::setApplicationData(const KAboutData &aboutData) 1158 { 1159 if (s_registry->m_appData) { 1160 *s_registry->m_appData = aboutData; 1161 } else { 1162 s_registry->m_appData = new KAboutData(aboutData); 1163 } 1164 1165 // For applicationDisplayName & desktopFileName, which are only properties of QGuiApplication, 1166 // we have to try to set them via the property system, as the static getter methods are 1167 // part of QtGui only. Disadvantage: requires an app instance. 1168 // So set either all or none of the properties & warn about it 1169 QCoreApplication *app = QCoreApplication::instance(); 1170 if (app) { 1171 app->setApplicationVersion(aboutData.version()); 1172 app->setApplicationName(aboutData.componentName()); 1173 app->setOrganizationDomain(aboutData.organizationDomain()); 1174 app->setProperty("applicationDisplayName", aboutData.displayName()); 1175 app->setProperty("desktopFileName", aboutData.desktopFileName()); 1176 } else { 1177 qCWarning(KABOUTDATA) << "Could not initialize the equivalent properties of Q*Application: no instance (yet) existing."; 1178 } 1179 1180 // KF6: Rethink the current relation between KAboutData::applicationData and the Q*Application metadata 1181 // Always overwriting the Q*Application metadata here, but not updating back the KAboutData 1182 // in applicationData() is unbalanced and can result in out-of-sync data if the Q*Application 1183 // setters have been called meanwhile 1184 // Options are to remove the overlapping properties of KAboutData for cleancode, or making the 1185 // overlapping properties official shadow properties of their Q*Application countparts, though 1186 // that increases behavioural complexity a little. 1187 } 1188 1189 #if KCOREADDONS_BUILD_DEPRECATED_SINCE(5, 76) 1190 void KAboutData::registerPluginData(const KAboutData &aboutData) 1191 { 1192 auto &data = s_registry->m_pluginData[aboutData.componentName()]; 1193 if (data) { 1194 // silently ignore double registration, assuming it's for the same plugin 1195 // all of this is getting deprecated anyways, we just don't want to leak anything 1196 return; 1197 } 1198 data = new KAboutData(aboutData); 1199 } 1200 #endif 1201 1202 #if KCOREADDONS_BUILD_DEPRECATED_SINCE(5, 76) 1203 KAboutData *KAboutData::pluginData(const QString &componentName) 1204 { 1205 KAboutData *ad = s_registry->m_pluginData.value(componentName); 1206 return ad; 1207 } 1208 #endif 1209 1210 // only for KCrash (no memory allocation allowed) 1211 const KAboutData *KAboutData::applicationDataPointer() 1212 { 1213 if (s_registry.exists()) { 1214 return s_registry->m_appData; 1215 } 1216 return nullptr; 1217 } 1218 1219 bool KAboutData::setupCommandLine(QCommandLineParser *parser) 1220 { 1221 if (!d->_shortDescription.isEmpty()) { 1222 parser->setApplicationDescription(d->_shortDescription); 1223 } 1224 1225 parser->addHelpOption(); 1226 1227 QCoreApplication *app = QCoreApplication::instance(); 1228 if (app && !app->applicationVersion().isEmpty()) { 1229 parser->addVersionOption(); 1230 } 1231 1232 return parser->addOption(QCommandLineOption(QStringLiteral("author"), QCoreApplication::translate("KAboutData CLI", "Show author information."))) 1233 && parser->addOption(QCommandLineOption(QStringLiteral("license"), QCoreApplication::translate("KAboutData CLI", "Show license information."))) 1234 && parser->addOption(QCommandLineOption(QStringLiteral("desktopfile"), 1235 QCoreApplication::translate("KAboutData CLI", "The base file name of the desktop entry for this application."), 1236 QCoreApplication::translate("KAboutData CLI", "file name"))); 1237 } 1238 1239 void KAboutData::processCommandLine(QCommandLineParser *parser) 1240 { 1241 bool foundArgument = false; 1242 if (parser->isSet(QStringLiteral("author"))) { 1243 foundArgument = true; 1244 if (d->_authorList.isEmpty()) { 1245 printf("%s\n", 1246 qPrintable(QCoreApplication::translate("KAboutData CLI", "This application was written by somebody who wants to remain anonymous."))); 1247 } else { 1248 printf("%s\n", qPrintable(QCoreApplication::translate("KAboutData CLI", "%1 was written by:").arg(qAppName()))); 1249 for (const KAboutPerson &person : std::as_const(d->_authorList)) { 1250 QString authorData = QLatin1String(" ") + person.name(); 1251 if (!person.emailAddress().isEmpty()) { 1252 authorData.append(QLatin1String(" <") + person.emailAddress() + QLatin1Char('>')); 1253 } 1254 printf("%s\n", qPrintable(authorData)); 1255 } 1256 } 1257 if (!customAuthorTextEnabled()) { 1258 if (bugAddress() == QLatin1String("submit@bugs.kde.org")) { 1259 printf("%s\n", qPrintable(QCoreApplication::translate("KAboutData CLI", "Please use https://bugs.kde.org to report bugs."))); 1260 } else if (!bugAddress().isEmpty()) { 1261 printf("%s\n", qPrintable(QCoreApplication::translate("KAboutData CLI", "Please report bugs to %1.").arg(bugAddress()))); 1262 } 1263 } else { 1264 printf("%s\n", qPrintable(customAuthorPlainText())); 1265 } 1266 } else if (parser->isSet(QStringLiteral("license"))) { 1267 foundArgument = true; 1268 for (const KAboutLicense &license : std::as_const(d->_licenseList)) { 1269 printf("%s\n", qPrintable(license.text())); 1270 } 1271 } 1272 1273 const QString desktopFileName = parser->value(QStringLiteral("desktopfile")); 1274 if (!desktopFileName.isEmpty()) { 1275 d->desktopFileName = desktopFileName; 1276 } 1277 1278 if (foundArgument) { 1279 ::exit(EXIT_SUCCESS); 1280 } 1281 } 1282 1283 template<class T> 1284 QVariantList listToVariant(const QList<T> &values) 1285 { 1286 QVariantList ret; 1287 ret.reserve(values.count()); 1288 for (const auto &value : values) { 1289 ret << QVariant::fromValue(value); 1290 } 1291 return ret; 1292 } 1293 1294 QVariantList KAboutData::licensesVariant() const 1295 { 1296 return listToVariant(d->_licenseList); 1297 } 1298 1299 QVariantList KAboutData::authorsVariant() const 1300 { 1301 return listToVariant(d->_authorList); 1302 } 1303 1304 QVariantList KAboutData::creditsVariant() const 1305 { 1306 return listToVariant(d->_creditList); 1307 } 1308 1309 QVariantList KAboutData::translatorsVariant() const 1310 { 1311 return listToVariant(d->_translatorList); 1312 } 1313 1314 QVariantList KAboutData::componentsVariant() const 1315 { 1316 return listToVariant(d->_componentList); 1317 } 1318 1319 #include "moc_kaboutdata.cpp"