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 | |
34 | QWidget *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 | |
45 | QWidget *KAbstractAboutDialogPrivate::createAboutWidget(const QString &shortDescription, |
46 | const QString &otherText, |
47 | const QString ©rightStatement, |
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 | |
99 | QWidget *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 | |
131 | static 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 | |
159 | QWidget *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 | |
209 | QWidget *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 | |
230 | QWidget *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 | |
263 | void 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 | |