File indexing completed on 2024-03-24 04:02:22

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 2007 Urs Wolfer <uwolfer at kde.org>
0004     SPDX-FileCopyrightText: 2008, 2019 Friedrich W. H. Kossebau <kossebau@kde.org>
0005     SPDX-FileCopyrightText: 2010 Teo Mrnjavac <teo@kde.org>
0006 
0007     Parts of this class have been take from the KAboutApplication class, which was
0008     SPDX-FileCopyrightText: 2000 Waldo Bastian <bastian@kde.org>
0009     SPDX-FileCopyrightText: 2000 Espen Sand <espen@kde.org>
0010 
0011     SPDX-License-Identifier: LGPL-2.0-only
0012 */
0013 
0014 #include "kabstractaboutdialog_p.h"
0015 
0016 #include "kaboutapplicationcomponentlistdelegate_p.h"
0017 #include "kaboutapplicationcomponentmodel_p.h"
0018 #include "kaboutapplicationlistview_p.h"
0019 #include "kaboutapplicationpersonlistdelegate_p.h"
0020 #include "kaboutapplicationpersonmodel_p.h"
0021 #include "klicensedialog_p.h"
0022 #include <kxmlgui_version.h>
0023 // KF
0024 #include <KLocalizedString>
0025 #include <KTitleWidget>
0026 // Qt
0027 #include <QApplication>
0028 #include <QCheckBox>
0029 #include <QDialogButtonBox>
0030 #include <QIcon>
0031 #include <QLabel>
0032 #include <QVBoxLayout>
0033 
0034 QWidget *KAbstractAboutDialogPrivate::createTitleWidget(const QIcon &icon, const QString &displayName, const QString &version, QWidget *parent)
0035 {
0036     KTitleWidget *titleWidget = new KTitleWidget(parent);
0037 
0038     titleWidget->setIconSize(QSize(48, 48));
0039     titleWidget->setIcon(icon, KTitleWidget::ImageLeft);
0040     titleWidget->setText(
0041         QLatin1String("<html><font size=\"5\">%1</font><br />%2</html>").arg(displayName, i18nc("Version version-number", "Version %1", version)));
0042     return titleWidget;
0043 }
0044 
0045 QWidget *KAbstractAboutDialogPrivate::createAboutWidget(const QString &shortDescription,
0046                                                         const QString &otherText,
0047                                                         const QString &copyrightStatement,
0048                                                         const QString &homepage,
0049                                                         const QList<KAboutLicense> &licenses,
0050                                                         QWidget *parent)
0051 {
0052     QWidget *aboutWidget = new QWidget(parent);
0053     QVBoxLayout *aboutLayout = new QVBoxLayout(aboutWidget);
0054 
0055     QString aboutPageText = shortDescription + QLatin1Char('\n');
0056 
0057     if (!otherText.isEmpty()) {
0058         aboutPageText += QLatin1Char('\n') + otherText + QLatin1Char('\n');
0059     }
0060 
0061     if (!copyrightStatement.isEmpty()) {
0062         aboutPageText += QLatin1Char('\n') + copyrightStatement + QLatin1Char('\n');
0063     }
0064 
0065     if (!homepage.isEmpty()) {
0066         aboutPageText += QLatin1Char('\n') + QStringLiteral("<a href=\"%1\">%1</a>").arg(homepage) + QLatin1Char('\n');
0067     }
0068     aboutPageText = aboutPageText.trimmed();
0069 
0070     QLabel *aboutLabel = new QLabel;
0071     aboutLabel->setWordWrap(true);
0072     aboutLabel->setOpenExternalLinks(true);
0073     aboutLabel->setText(aboutPageText.replace(QLatin1Char('\n'), QStringLiteral("<br />")));
0074     aboutLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
0075 
0076     aboutLayout->addStretch();
0077     aboutLayout->addWidget(aboutLabel);
0078 
0079     const int licenseCount = licenses.count();
0080     for (int i = 0; i < licenseCount; ++i) {
0081         const KAboutLicense &license = licenses.at(i);
0082 
0083         QLabel *showLicenseLabel = new QLabel;
0084         showLicenseLabel->setText(QStringLiteral("<a href=\"%1\">%2</a>").arg(QString::number(i), i18n("License: %1", license.name(KAboutLicense::FullName))));
0085         showLicenseLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
0086         QObject::connect(showLicenseLabel, &QLabel::linkActivated, parent, [license, parent]() {
0087             auto *dialog = new KLicenseDialog(license, parent);
0088             dialog->show();
0089         });
0090 
0091         aboutLayout->addWidget(showLicenseLabel);
0092     }
0093 
0094     aboutLayout->addStretch();
0095 
0096     return aboutWidget;
0097 }
0098 
0099 QWidget *KAbstractAboutDialogPrivate::createComponentWidget(const QList<KAboutComponent> &components, QWidget *parent)
0100 {
0101     QWidget *componentWidget = new QWidget(parent);
0102     QVBoxLayout *componentLayout = new QVBoxLayout(componentWidget);
0103     componentLayout->setContentsMargins(0, 0, 0, 0);
0104 
0105     QList<KAboutComponent> allComponents = components;
0106     allComponents.prepend(KAboutComponent(i18n("The <em>%1</em> windowing system", QGuiApplication::platformName())));
0107     allComponents.prepend(KAboutComponent(i18n("Qt"),
0108                                           QString(),
0109                                           i18n("%1 (built against %2)", QString::fromLocal8Bit(qVersion()), QStringLiteral(QT_VERSION_STR)),
0110                                           QStringLiteral("https://www.qt.io/")));
0111     allComponents.prepend(KAboutComponent(i18n("KDE Frameworks"),
0112                                           QString(),
0113                                           QStringLiteral(KXMLGUI_VERSION_STRING),
0114                                           QStringLiteral("https://develop.kde.org/products/frameworks/")));
0115 
0116     KDEPrivate::KAboutApplicationComponentModel *componentModel = new KDEPrivate::KAboutApplicationComponentModel(allComponents, componentWidget);
0117 
0118     KDEPrivate::KAboutApplicationListView *componentView = new KDEPrivate::KAboutApplicationListView(componentWidget);
0119 
0120     KDEPrivate::KAboutApplicationComponentListDelegate *componentDelegate =
0121         new KDEPrivate::KAboutApplicationComponentListDelegate(componentView, componentView);
0122 
0123     componentView->setModel(componentModel);
0124     componentView->setItemDelegate(componentDelegate);
0125     componentView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
0126     componentLayout->addWidget(componentView);
0127 
0128     return componentWidget;
0129 }
0130 
0131 static QWidget *createAvatarCheck(QWidget *parent, KDEPrivate::KAboutApplicationPersonModel *model)
0132 {
0133     // Add in a checkbox to allow people to switch the avatar fetch
0134     // (off-by-default to avoid unwarned online activity)
0135     QCheckBox *avatarsCheck = new QCheckBox(parent);
0136     avatarsCheck->setText(i18n("Show author photos"));
0137     avatarsCheck->setToolTip(i18n("Enabling this will fetch images from an online location"));
0138     avatarsCheck->setVisible(model->hasAnyAvatars());
0139     QObject::connect(model, &KDEPrivate::KAboutApplicationPersonModel::hasAnyAvatarsChanged, parent, [avatarsCheck, model]() {
0140         avatarsCheck->setVisible(model->hasAnyAvatars());
0141     });
0142     QObject::connect(avatarsCheck, &QCheckBox::stateChanged, parent, [model](int state) {
0143         switch (state) {
0144         case Qt::Checked:
0145         case Qt::PartiallyChecked:
0146             // tell model to use avatars
0147             model->setShowRemoteAvatars(true);
0148             break;
0149         case Qt::Unchecked:
0150         default:
0151             // tell model not to use avatars
0152             model->setShowRemoteAvatars(false);
0153             break;
0154         }
0155     });
0156     return avatarsCheck;
0157 }
0158 
0159 QWidget *KAbstractAboutDialogPrivate::createAuthorsWidget(const QList<KAboutPerson> &authors,
0160                                                           bool customAuthorTextEnabled,
0161                                                           const QString &customAuthorRichText,
0162                                                           const QString &bugAddress,
0163                                                           QWidget *parent)
0164 {
0165     QWidget *authorWidget = new QWidget(parent);
0166     QVBoxLayout *authorLayout = new QVBoxLayout(authorWidget);
0167     authorLayout->setContentsMargins(0, 0, 0, 0);
0168 
0169     if (!customAuthorTextEnabled || !customAuthorRichText.isEmpty()) {
0170         QLabel *bugsLabel = new QLabel(authorWidget);
0171         bugsLabel->setContentsMargins(4, 2, 0, 4);
0172         bugsLabel->setOpenExternalLinks(true);
0173         if (!customAuthorTextEnabled) {
0174             if (bugAddress.isEmpty() || bugAddress == QLatin1String("submit@bugs.kde.org")) {
0175                 bugsLabel->setText(i18nc("Reference to website",
0176                                          "Please use %1 to report bugs.\n",
0177                                          QLatin1String("<a href=\"https://bugs.kde.org\">https://bugs.kde.org</a>")));
0178             } else {
0179                 QUrl bugUrl(bugAddress);
0180                 if (bugUrl.scheme().isEmpty()) {
0181                     bugUrl.setScheme(QStringLiteral("mailto"));
0182                 }
0183                 bugsLabel->setText(i18nc("Reference to email address",
0184                                          "Please report bugs to %1.\n",
0185                                          QLatin1String("<a href=\"%1\">%2</a>").arg(bugUrl.toString(), bugAddress)));
0186             }
0187         } else {
0188             bugsLabel->setText(customAuthorRichText);
0189         }
0190         bugsLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
0191         authorLayout->addWidget(bugsLabel);
0192     }
0193 
0194     KDEPrivate::KAboutApplicationPersonModel *authorModel = new KDEPrivate::KAboutApplicationPersonModel(authors, authorWidget);
0195 
0196     KDEPrivate::KAboutApplicationListView *authorView = new KDEPrivate::KAboutApplicationListView(authorWidget);
0197 
0198     KDEPrivate::KAboutApplicationPersonListDelegate *authorDelegate = new KDEPrivate::KAboutApplicationPersonListDelegate(authorView, authorView);
0199 
0200     authorView->setModel(authorModel);
0201     authorView->setItemDelegate(authorDelegate);
0202     authorView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
0203     authorLayout->addWidget(createAvatarCheck(parent, authorModel));
0204     authorLayout->addWidget(authorView);
0205 
0206     return authorWidget;
0207 }
0208 
0209 QWidget *KAbstractAboutDialogPrivate::createCreditWidget(const QList<KAboutPerson> &credits, QWidget *parent)
0210 {
0211     QWidget *creditWidget = new QWidget(parent);
0212     QVBoxLayout *creditLayout = new QVBoxLayout(creditWidget);
0213     creditLayout->setContentsMargins(0, 0, 0, 0);
0214 
0215     KDEPrivate::KAboutApplicationPersonModel *creditModel = new KDEPrivate::KAboutApplicationPersonModel(credits, creditWidget);
0216 
0217     KDEPrivate::KAboutApplicationListView *creditView = new KDEPrivate::KAboutApplicationListView(creditWidget);
0218 
0219     KDEPrivate::KAboutApplicationPersonListDelegate *creditDelegate = new KDEPrivate::KAboutApplicationPersonListDelegate(creditView, creditView);
0220 
0221     creditView->setModel(creditModel);
0222     creditView->setItemDelegate(creditDelegate);
0223     creditView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
0224     creditLayout->addWidget(createAvatarCheck(parent, creditModel));
0225     creditLayout->addWidget(creditView);
0226 
0227     return creditWidget;
0228 }
0229 
0230 QWidget *KAbstractAboutDialogPrivate::createTranslatorsWidget(const QList<KAboutPerson> &translators, QWidget *parent)
0231 {
0232     QWidget *translatorWidget = new QWidget(parent);
0233     QVBoxLayout *translatorLayout = new QVBoxLayout(translatorWidget);
0234     translatorLayout->setContentsMargins(0, 0, 0, 0);
0235 
0236     KDEPrivate::KAboutApplicationPersonModel *translatorModel = new KDEPrivate::KAboutApplicationPersonModel(translators, translatorWidget);
0237 
0238     KDEPrivate::KAboutApplicationListView *translatorView = new KDEPrivate::KAboutApplicationListView(translatorWidget);
0239 
0240     KDEPrivate::KAboutApplicationPersonListDelegate *translatorDelegate = new KDEPrivate::KAboutApplicationPersonListDelegate(translatorView, translatorView);
0241 
0242     translatorView->setModel(translatorModel);
0243     translatorView->setItemDelegate(translatorDelegate);
0244     translatorView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
0245     translatorLayout->addWidget(createAvatarCheck(parent, translatorModel));
0246     translatorLayout->addWidget(translatorView);
0247 
0248     QString aboutTranslationTeam = KAboutData::aboutTranslationTeam();
0249     if (!aboutTranslationTeam.isEmpty()) {
0250         QLabel *translationTeamLabel = new QLabel(translatorWidget);
0251         translationTeamLabel->setContentsMargins(4, 2, 4, 4);
0252         translationTeamLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
0253         translationTeamLabel->setWordWrap(true);
0254         translationTeamLabel->setText(aboutTranslationTeam);
0255         translationTeamLabel->setOpenExternalLinks(true);
0256         translatorLayout->addWidget(translationTeamLabel);
0257         // TODO: this could be displayed as a view item to save space
0258     }
0259 
0260     return translatorWidget;
0261 }
0262 
0263 void KAbstractAboutDialogPrivate::createForm(QWidget *titleWidget, QWidget *tabWidget, QDialog *dialog)
0264 {
0265     QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog);
0266     buttonBox->setStandardButtons(QDialogButtonBox::Close);
0267     QObject::connect(buttonBox, &QDialogButtonBox::accepted, dialog, &QDialog::accept);
0268     QObject::connect(buttonBox, &QDialogButtonBox::rejected, dialog, &QDialog::reject);
0269 
0270     // And we jam everything together in a layout...
0271     QVBoxLayout *mainLayout = new QVBoxLayout(dialog);
0272     mainLayout->addWidget(titleWidget);
0273     mainLayout->addWidget(tabWidget);
0274     mainLayout->addWidget(buttonBox);
0275 }