1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2007 Urs Wolfer <uwolfer at kde.org>
4 SPDX-FileCopyrightText: 2008, 2019 Friedrich W. H. Kossebau <kossebau@kde.org>
5 SPDX-FileCopyrightText: 2010 Teo Mrnjavac <teo@kde.org>
6
7 Parts of this class have been take from the KAboutApplication class, which was
8 SPDX-FileCopyrightText: 2000 Waldo Bastian <bastian@kde.org>
9 SPDX-FileCopyrightText: 2000 Espen Sand <espen@kde.org>
10
11 SPDX-License-Identifier: LGPL-2.0-only
12*/
13
14#include "kabstractaboutdialog_p.h"
15
16#include "kaboutapplicationcomponentlistdelegate_p.h"
17#include "kaboutapplicationcomponentmodel_p.h"
18#include "kaboutapplicationlistview_p.h"
19#include "kaboutapplicationpersonlistdelegate_p.h"
20#include "kaboutapplicationpersonmodel_p.h"
21#include "klicensedialog_p.h"
22#include <kxmlgui_version.h>
23// KF
24#include <KLocalizedString>
25#include <KTitleWidget>
26// Qt
27#include <QApplication>
28#include <QCheckBox>
29#include <QDialogButtonBox>
30#include <QIcon>
31#include <QLabel>
32#include <QVBoxLayout>
33
34QWidget *KAbstractAboutDialogPrivate::createTitleWidget(const QIcon &icon, const QString &displayName, const QString &version, QWidget *parent)
35{
36 KTitleWidget *titleWidget = new KTitleWidget(parent);
37
38 titleWidget->setIconSize(QSize(48, 48));
39 titleWidget->setIcon(icon, alignment: KTitleWidget::ImageLeft);
40 titleWidget->setText(
41 text: QLatin1String("<html><font size=\"5\">%1</font><br />%2</html>").arg(args: displayName, i18nc("Version version-number", "Version %1", version)));
42 return titleWidget;
43}
44
45QWidget *KAbstractAboutDialogPrivate::createAboutWidget(const QString &shortDescription,
46 const QString &otherText,
47 const QString &copyrightStatement,
48 const QString &homepage,
49 const QList<KAboutLicense> &licenses,
50 QWidget *parent)
51{
52 QWidget *aboutWidget = new QWidget(parent);
53 QVBoxLayout *aboutLayout = new QVBoxLayout(aboutWidget);
54
55 QString aboutPageText = shortDescription + QLatin1Char('\n');
56
57 if (!otherText.isEmpty()) {
58 aboutPageText += QLatin1Char('\n') + otherText + QLatin1Char('\n');
59 }
60
61 if (!copyrightStatement.isEmpty()) {
62 aboutPageText += QLatin1Char('\n') + copyrightStatement + QLatin1Char('\n');
63 }
64
65 if (!homepage.isEmpty()) {
66 aboutPageText += QLatin1Char('\n') + QStringLiteral("<a href=\"%1\">%1</a>").arg(a: homepage) + QLatin1Char('\n');
67 }
68 aboutPageText = aboutPageText.trimmed();
69
70 QLabel *aboutLabel = new QLabel;
71 aboutLabel->setWordWrap(true);
72 aboutLabel->setOpenExternalLinks(true);
73 aboutLabel->setText(aboutPageText.replace(c: QLatin1Char('\n'), QStringLiteral("<br />")));
74 aboutLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
75
76 aboutLayout->addStretch();
77 aboutLayout->addWidget(aboutLabel);
78
79 const int licenseCount = licenses.count();
80 for (int i = 0; i < licenseCount; ++i) {
81 const KAboutLicense &license = licenses.at(i);
82
83 QLabel *showLicenseLabel = new QLabel;
84 showLicenseLabel->setText(QStringLiteral("<a href=\"%1\">%2</a>").arg(args: QString::number(i), i18n("License: %1", license.name(KAboutLicense::FullName))));
85 showLicenseLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
86 QObject::connect(sender: showLicenseLabel, signal: &QLabel::linkActivated, context: parent, slot: [license, parent]() {
87 auto *dialog = new KLicenseDialog(license, parent);
88 dialog->show();
89 });
90
91 aboutLayout->addWidget(showLicenseLabel);
92 }
93
94 aboutLayout->addStretch();
95
96 return aboutWidget;
97}
98
99QWidget *KAbstractAboutDialogPrivate::createComponentWidget(const QList<KAboutComponent> &components, QWidget *parent)
100{
101 QWidget *componentWidget = new QWidget(parent);
102 QVBoxLayout *componentLayout = new QVBoxLayout(componentWidget);
103 componentLayout->setContentsMargins(left: 0, top: 0, right: 0, bottom: 0);
104
105 QList<KAboutComponent> allComponents = components;
106 allComponents.prepend(t: KAboutComponent(i18n("The <em>%1</em> windowing system", QGuiApplication::platformName())));
107 allComponents.prepend(t: KAboutComponent(i18n("Qt"),
108 QString(),
109 i18n("%1 (built against %2)", QString::fromLocal8Bit(qVersion()), QStringLiteral(QT_VERSION_STR)),
110 QStringLiteral("https://www.qt.io/")));
111 allComponents.prepend(t: KAboutComponent(i18n("KDE Frameworks"),
112 QString(),
113 QStringLiteral(KXMLGUI_VERSION_STRING),
114 QStringLiteral("https://develop.kde.org/products/frameworks/")));
115
116 KDEPrivate::KAboutApplicationComponentModel *componentModel = new KDEPrivate::KAboutApplicationComponentModel(allComponents, componentWidget);
117
118 KDEPrivate::KAboutApplicationListView *componentView = new KDEPrivate::KAboutApplicationListView(componentWidget);
119
120 KDEPrivate::KAboutApplicationComponentListDelegate *componentDelegate =
121 new KDEPrivate::KAboutApplicationComponentListDelegate(componentView, componentView);
122
123 componentView->setModel(componentModel);
124 componentView->setItemDelegate(componentDelegate);
125 componentView->setSizePolicy(hor: QSizePolicy::Expanding, ver: QSizePolicy::Expanding);
126 componentLayout->addWidget(componentView);
127
128 return componentWidget;
129}
130
131static QWidget *createAvatarCheck(QWidget *parent, KDEPrivate::KAboutApplicationPersonModel *model)
132{
133 // Add in a checkbox to allow people to switch the avatar fetch
134 // (off-by-default to avoid unwarned online activity)
135 QCheckBox *avatarsCheck = new QCheckBox(parent);
136 avatarsCheck->setText(i18n("Show author photos"));
137 avatarsCheck->setToolTip(i18n("Enabling this will fetch images from an online location"));
138 avatarsCheck->setVisible(model->hasAnyAvatars());
139 QObject::connect(sender: model, signal: &KDEPrivate::KAboutApplicationPersonModel::hasAnyAvatarsChanged, context: parent, slot: [avatarsCheck, model]() {
140 avatarsCheck->setVisible(model->hasAnyAvatars());
141 });
142 QObject::connect(sender: avatarsCheck, signal: &QCheckBox::stateChanged, context: parent, slot: [model](int state) {
143 switch (state) {
144 case Qt::Checked:
145 case Qt::PartiallyChecked:
146 // tell model to use avatars
147 model->setShowRemoteAvatars(true);
148 break;
149 case Qt::Unchecked:
150 default:
151 // tell model not to use avatars
152 model->setShowRemoteAvatars(false);
153 break;
154 }
155 });
156 return avatarsCheck;
157}
158
159QWidget *KAbstractAboutDialogPrivate::createAuthorsWidget(const QList<KAboutPerson> &authors,
160 bool customAuthorTextEnabled,
161 const QString &customAuthorRichText,
162 const QString &bugAddress,
163 QWidget *parent)
164{
165 QWidget *authorWidget = new QWidget(parent);
166 QVBoxLayout *authorLayout = new QVBoxLayout(authorWidget);
167 authorLayout->setContentsMargins(left: 0, top: 0, right: 0, bottom: 0);
168
169 if (!customAuthorTextEnabled || !customAuthorRichText.isEmpty()) {
170 QLabel *bugsLabel = new QLabel(authorWidget);
171 bugsLabel->setContentsMargins(left: 4, top: 2, right: 0, bottom: 4);
172 bugsLabel->setOpenExternalLinks(true);
173 if (!customAuthorTextEnabled) {
174 if (bugAddress.isEmpty() || bugAddress == QLatin1String("submit@bugs.kde.org")) {
175 bugsLabel->setText(i18nc("Reference to website",
176 "Please use %1 to report bugs.\n",
177 QLatin1String("<a href=\"https://bugs.kde.org\">https://bugs.kde.org</a>")));
178 } else {
179 QUrl bugUrl(bugAddress);
180 if (bugUrl.scheme().isEmpty()) {
181 bugUrl.setScheme(QStringLiteral("mailto"));
182 }
183 bugsLabel->setText(i18nc("Reference to email address",
184 "Please report bugs to %1.\n",
185 QLatin1String("<a href=\"%1\">%2</a>").arg(bugUrl.toString(), bugAddress)));
186 }
187 } else {
188 bugsLabel->setText(customAuthorRichText);
189 }
190 bugsLabel->setSizePolicy(hor: QSizePolicy::Expanding, ver: QSizePolicy::Minimum);
191 authorLayout->addWidget(bugsLabel);
192 }
193
194 KDEPrivate::KAboutApplicationPersonModel *authorModel = new KDEPrivate::KAboutApplicationPersonModel(authors, authorWidget);
195
196 KDEPrivate::KAboutApplicationListView *authorView = new KDEPrivate::KAboutApplicationListView(authorWidget);
197
198 KDEPrivate::KAboutApplicationPersonListDelegate *authorDelegate = new KDEPrivate::KAboutApplicationPersonListDelegate(authorView, authorView);
199
200 authorView->setModel(authorModel);
201 authorView->setItemDelegate(authorDelegate);
202 authorView->setSizePolicy(hor: QSizePolicy::Expanding, ver: QSizePolicy::Expanding);
203 authorLayout->addWidget(createAvatarCheck(parent, model: authorModel));
204 authorLayout->addWidget(authorView);
205
206 return authorWidget;
207}
208
209QWidget *KAbstractAboutDialogPrivate::createCreditWidget(const QList<KAboutPerson> &credits, QWidget *parent)
210{
211 QWidget *creditWidget = new QWidget(parent);
212 QVBoxLayout *creditLayout = new QVBoxLayout(creditWidget);
213 creditLayout->setContentsMargins(left: 0, top: 0, right: 0, bottom: 0);
214
215 KDEPrivate::KAboutApplicationPersonModel *creditModel = new KDEPrivate::KAboutApplicationPersonModel(credits, creditWidget);
216
217 KDEPrivate::KAboutApplicationListView *creditView = new KDEPrivate::KAboutApplicationListView(creditWidget);
218
219 KDEPrivate::KAboutApplicationPersonListDelegate *creditDelegate = new KDEPrivate::KAboutApplicationPersonListDelegate(creditView, creditView);
220
221 creditView->setModel(creditModel);
222 creditView->setItemDelegate(creditDelegate);
223 creditView->setSizePolicy(hor: QSizePolicy::Expanding, ver: QSizePolicy::Expanding);
224 creditLayout->addWidget(createAvatarCheck(parent, model: creditModel));
225 creditLayout->addWidget(creditView);
226
227 return creditWidget;
228}
229
230QWidget *KAbstractAboutDialogPrivate::createTranslatorsWidget(const QList<KAboutPerson> &translators, QWidget *parent)
231{
232 QWidget *translatorWidget = new QWidget(parent);
233 QVBoxLayout *translatorLayout = new QVBoxLayout(translatorWidget);
234 translatorLayout->setContentsMargins(left: 0, top: 0, right: 0, bottom: 0);
235
236 KDEPrivate::KAboutApplicationPersonModel *translatorModel = new KDEPrivate::KAboutApplicationPersonModel(translators, translatorWidget);
237
238 KDEPrivate::KAboutApplicationListView *translatorView = new KDEPrivate::KAboutApplicationListView(translatorWidget);
239
240 KDEPrivate::KAboutApplicationPersonListDelegate *translatorDelegate = new KDEPrivate::KAboutApplicationPersonListDelegate(translatorView, translatorView);
241
242 translatorView->setModel(translatorModel);
243 translatorView->setItemDelegate(translatorDelegate);
244 translatorView->setSizePolicy(hor: QSizePolicy::Expanding, ver: QSizePolicy::Expanding);
245 translatorLayout->addWidget(createAvatarCheck(parent, model: translatorModel));
246 translatorLayout->addWidget(translatorView);
247
248 QString aboutTranslationTeam = KAboutData::aboutTranslationTeam();
249 if (!aboutTranslationTeam.isEmpty()) {
250 QLabel *translationTeamLabel = new QLabel(translatorWidget);
251 translationTeamLabel->setContentsMargins(left: 4, top: 2, right: 4, bottom: 4);
252 translationTeamLabel->setSizePolicy(hor: QSizePolicy::Expanding, ver: QSizePolicy::Minimum);
253 translationTeamLabel->setWordWrap(true);
254 translationTeamLabel->setText(aboutTranslationTeam);
255 translationTeamLabel->setOpenExternalLinks(true);
256 translatorLayout->addWidget(translationTeamLabel);
257 // TODO: this could be displayed as a view item to save space
258 }
259
260 return translatorWidget;
261}
262
263void KAbstractAboutDialogPrivate::createForm(QWidget *titleWidget, QWidget *tabWidget, QDialog *dialog)
264{
265 QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog);
266 buttonBox->setStandardButtons(QDialogButtonBox::Close);
267 QObject::connect(sender: buttonBox, signal: &QDialogButtonBox::accepted, context: dialog, slot: &QDialog::accept);
268 QObject::connect(sender: buttonBox, signal: &QDialogButtonBox::rejected, context: dialog, slot: &QDialog::reject);
269
270 // And we jam everything together in a layout...
271 QVBoxLayout *mainLayout = new QVBoxLayout(dialog);
272 mainLayout->addWidget(titleWidget);
273 mainLayout->addWidget(tabWidget);
274 mainLayout->addWidget(buttonBox);
275}
276

source code of kxmlgui/src/kabstractaboutdialog_p.cpp