KCoreAddons

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

KDE's Doxygen guidelines are available online.