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