/* This file is part of the KDE libraries SPDX-FileCopyrightText: 2007 Urs Wolfer SPDX-FileCopyrightText: 2008, 2019 Friedrich W. H. Kossebau SPDX-FileCopyrightText: 2010 Teo Mrnjavac Parts of this class have been take from the KAboutApplication class, which was SPDX-FileCopyrightText: 2000 Waldo Bastian SPDX-FileCopyrightText: 2000 Espen Sand SPDX-License-Identifier: LGPL-2.0-only */ #include "kabstractaboutdialog_p.h" #include "klicensedialog_p.h" #include #include // KF #include #include #include #include // Qt #include #include #include #include #include #include #include #include #include #include #include using namespace Qt::StringLiterals; QWidget *KAbstractAboutDialogPrivate::createTitleWidget(const QIcon &icon, const QString &displayName, const QString &version, QWidget *parent) { KTitleWidget *titleWidget = new KTitleWidget(parent); titleWidget->setIconSize(QSize(48, 48)); titleWidget->setIcon(icon, KTitleWidget::ImageLeft); titleWidget->setText( QLatin1String("%1
%2").arg(displayName, i18nc("Version version-number", "Version %1", version))); return titleWidget; } QWidget *KAbstractAboutDialogPrivate::createAboutWidget(const QString &shortDescription, const QString &otherText, const QString ©rightStatement, const QString &homepage, const QList &licenses, QWidget *parent) { auto wrapper = new KAdjustingScrollArea(parent); auto aboutWidget = new QWidget(parent); wrapper->setWidget(aboutWidget); auto aboutLayout = new QVBoxLayout(aboutWidget); QString aboutPageText = shortDescription + QLatin1Char('\n'); if (!otherText.isEmpty()) { aboutPageText += QLatin1Char('\n') + otherText + QLatin1Char('\n'); } if (!copyrightStatement.isEmpty()) { aboutPageText += QLatin1Char('\n') + copyrightStatement + QLatin1Char('\n'); } if (!homepage.isEmpty()) { aboutPageText += QLatin1Char('\n') + QStringLiteral("%1").arg(homepage) + QLatin1Char('\n'); } aboutPageText = aboutPageText.trimmed(); QLabel *aboutLabel = new QLabel; aboutLabel->setWordWrap(true); aboutLabel->setOpenExternalLinks(true); aboutLabel->setText(aboutPageText.replace(QLatin1Char('\n'), QStringLiteral("
"))); aboutLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); aboutLayout->addWidget(aboutLabel); const int licenseCount = licenses.count(); for (int i = 0; i < licenseCount; ++i) { const KAboutLicense &license = licenses.at(i); QLabel *showLicenseLabel = new QLabel; showLicenseLabel->setText(QStringLiteral("%2").arg(QString::number(i), i18n("License: %1", license.name(KAboutLicense::FullName)))); showLicenseLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); QObject::connect(showLicenseLabel, &QLabel::linkActivated, parent, [license, parent]() { auto *dialog = new KLicenseDialog(license, parent); dialog->show(); }); aboutLayout->addWidget(showLicenseLabel); } aboutLayout->addStretch(); return wrapper; } QWidget *KAbstractAboutDialogPrivate::createComponentWidget(const QList &components, QWidget *parent) { auto wrapper = new KAdjustingScrollArea(parent); auto componentWidget = new QWidget; auto componentLayout = new QVBoxLayout(componentWidget); wrapper->setWidget(componentWidget); QList allComponents = components; QString platformName; auto platform = QGuiApplication::platformName(); platform.replace(0, 1, platform[0].toUpper()); if (platform == u"Wayland"_s || platform == u"Xcb"_s) { platform = i18nc("@info Platform name", "%1 (%2)", QSysInfo::prettyProductName(), platform); } else { platform = QSysInfo::prettyProductName(); } allComponents.append(KAboutComponent(i18n("KDE Frameworks"), i18nc("@info", "Collection of libraries created by the KDE Community to extend Qt."), QStringLiteral(KXMLGUI_VERSION_STRING), QStringLiteral("https://develop.kde.org/products/frameworks/"), KAboutLicense::LGPL_V2_1)); allComponents.append(KAboutComponent(i18n("Qt"), i18nc("@info", "Cross-platform application development framework."), i18n("Using %1 and built against %2", QString::fromLocal8Bit(qVersion()), QStringLiteral(QT_VERSION_STR)), QStringLiteral("https://www.qt.io/"), KAboutLicense::LGPL_V3)); allComponents.append(KAboutComponent(platform, i18nc("@info", "Underlying platform."))); for (qsizetype i = 0, count = allComponents.count(); i < count; i++) { const auto &component = allComponents[i]; QVBoxLayout *col = nullptr; QHBoxLayout *row = nullptr; auto name = new QLabel(u""_s + component.name() + u""_s + (!component.version().isEmpty() ? (u" (" + component.version() + u')') : QString{})); if (!component.description().isEmpty()) { col = new QVBoxLayout; col->setSpacing(0); auto description = new QLabel(component.description()); auto palette = description->palette(); auto foregroundColor = palette.color(QPalette::WindowText); foregroundColor.setAlphaF(0.85); palette.setColor(QPalette::WindowText, foregroundColor); description->setPalette(palette); col->addWidget(name); col->addWidget(description); } if (!component.webAddress().isEmpty()) { row = new QHBoxLayout; const auto url = QUrl(component.webAddress()); auto webAction = new QAction(QIcon::fromTheme(u"internet-services-symbolic"_s), i18nc("@action:button", "Visit component's homepage")); webAction->setToolTip(i18nc("@info:tooltip", "Visit components's homepage\n%1", component.webAddress())); QObject::connect(webAction, &QAction::triggered, webAction, [url]() { QDesktopServices::openUrl(QUrl(url)); }); auto web = new QToolButton; web->setDefaultAction(webAction); web->setToolButtonStyle(Qt::ToolButtonIconOnly); web->setAutoRaise(true); if (col) { row->addLayout(col); } else { row->addWidget(name); } row->addWidget(web); } if (row) { componentLayout->addLayout(row); } else if (col) { componentLayout->addLayout(col); } else { componentLayout->addWidget(name); } if (i + 1 != count) { auto separator = new KSeparator; separator->setEnabled(false); componentLayout->addWidget(separator); } } componentLayout->addSpacing(parent->style()->pixelMetric(QStyle::PM_LayoutVerticalSpacing)); auto copyButton = new QPushButton(QIcon::fromTheme(u"edit-copy-symbolic"_s), i18nc("@action:button", "Copy to Clipboard"), parent); copyButton->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); QObject::connect(copyButton, &QPushButton::clicked, copyButton, [allComponents]() { auto aboutData = KAboutData::applicationData(); QString info = aboutData.displayName() + u": "_s + aboutData.version() + u'\n'; for (const auto &component : allComponents) { info += component.name(); if (!component.version().isEmpty()) { info += u": "_s + component.version(); } info += u'\n'; } info += u"Build ABI: "_s + QSysInfo::buildAbi() + u'\n'; info += u"Kernel: "_s + QSysInfo::kernelType() + u' ' + QSysInfo::kernelVersion() + u'\n'; QClipboard *clipboard = QGuiApplication::clipboard(); clipboard->setText(info); }); componentLayout->addWidget(copyButton); componentLayout->addStretch(); return wrapper; } static void createPersonLayout(QVBoxLayout *layout, const QList &persons) { for (qsizetype i = 0, count = persons.count(); i < count; i++) { const auto &person = persons[i]; QVBoxLayout *col = nullptr; QHBoxLayout *row = nullptr; auto name = new QLabel(person.name()); auto font = name->font(); font.setWeight(QFont::DemiBold); name->setFont(font); if (!person.task().isEmpty()) { col = new QVBoxLayout; col->setSpacing(0); auto task = new QLabel(person.task()); auto palette = task->palette(); auto foregroundColor = palette.color(QPalette::WindowText); foregroundColor.setAlphaF(0.85); palette.setColor(QPalette::WindowText, foregroundColor); task->setPalette(palette); col->addWidget(name); col->addWidget(task); } if (!person.webAddress().isEmpty()) { row = new QHBoxLayout; const auto url = QUrl(person.webAddress()); auto webAction = new QAction(QIcon::fromTheme(u"internet-services-symbolic"_s), i18nc("@action:button", "Visit author's homepage")); webAction->setToolTip(i18nc("@info:tooltip", "Visit author's homepage\n%1", person.webAddress())); QObject::connect(webAction, &QAction::triggered, webAction, [url]() { QDesktopServices::openUrl(url); }); auto web = new QToolButton; web->setDefaultAction(webAction); web->setAutoRaise(true); web->setToolButtonStyle(Qt::ToolButtonIconOnly); if (col) { row->addLayout(col); } else { row->addWidget(name); } row->addWidget(web); } if (!person.emailAddress().isEmpty()) { if (!row) { row = new QHBoxLayout; } const auto url = person.emailAddress(); auto webAction = new QAction(QIcon::fromTheme(u"mail-send-symbolic"_s), i18nc("@action:button Send an email to a contributor", "Email contributor")); webAction->setToolTip(i18nc("@info:tooltip", "Email contributor: %1", person.emailAddress())); QObject::connect(webAction, &QAction::triggered, webAction, [url]() { QDesktopServices::openUrl(QUrl(u"mailto:"_s + url)); }); auto web = new QToolButton; web->setDefaultAction(webAction); web->setToolButtonStyle(Qt::ToolButtonIconOnly); web->setAutoRaise(true); if (col) { row->addLayout(col); } else { row->addWidget(name); } row->addWidget(web); } if (row) { layout->addLayout(row); } else if (col) { layout->addLayout(col); } else { layout->addWidget(name); } if (i + 1 != count) { auto separator = new KSeparator; separator->setEnabled(false); layout->addWidget(separator); } } layout->addStretch(); } QWidget *KAbstractAboutDialogPrivate::createAuthorsWidget(const QList &authors, bool customAuthorTextEnabled, const QString &customAuthorRichText, const QString &bugAddress, QWidget *parent) { auto wrapper = new KAdjustingScrollArea; auto authorWidget = new QWidget(parent); wrapper->setWidget(authorWidget); auto authorLayout = new QVBoxLayout(authorWidget); if (!customAuthorTextEnabled || !customAuthorRichText.isEmpty()) { QLabel *bugsLabel = new QLabel(authorWidget); bugsLabel->setOpenExternalLinks(true); if (!customAuthorTextEnabled) { if (bugAddress.isEmpty() || bugAddress == QLatin1String("submit@bugs.kde.org")) { bugsLabel->setText(i18nc("Reference to website", "Please use %1 to report bugs.\n", QLatin1String("https://bugs.kde.org"))); } else { QUrl bugUrl(bugAddress); if (bugUrl.scheme().isEmpty()) { bugUrl.setScheme(QStringLiteral("mailto")); } bugsLabel->setText(i18nc("Reference to email address", "Please report bugs to %1.\n", QLatin1String("%2").arg(bugUrl.toString(), bugAddress))); } } else { bugsLabel->setText(customAuthorRichText); } bugsLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); authorLayout->addWidget(bugsLabel); } createPersonLayout(authorLayout, authors); return wrapper; } QWidget *KAbstractAboutDialogPrivate::createCreditWidget(const QList &credits, QWidget *parent) { auto wrapper = new KAdjustingScrollArea; auto creditWidget = new QWidget(parent); wrapper->setWidget(creditWidget); auto creditLayout = new QVBoxLayout(creditWidget); createPersonLayout(creditLayout, credits); return wrapper; } QWidget *KAbstractAboutDialogPrivate::createTranslatorsWidget(const QList &translators, QWidget *parent) { auto wrapper = new KAdjustingScrollArea; auto translatorWidget = new QWidget(parent); wrapper->setWidget(translatorWidget); auto translatorLayout = new QVBoxLayout(translatorWidget); createPersonLayout(translatorLayout, translators); QString aboutTranslationTeam = KAboutData::aboutTranslationTeam(); if (!aboutTranslationTeam.isEmpty()) { QLabel *translationTeamLabel = new QLabel(translatorWidget); translationTeamLabel->setContentsMargins(4, 2, 4, 4); translationTeamLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); translationTeamLabel->setWordWrap(true); translationTeamLabel->setText(aboutTranslationTeam); translationTeamLabel->setOpenExternalLinks(true); translatorLayout->addWidget(translationTeamLabel); // TODO: this could be displayed as a view item to save space } return wrapper; } void KAbstractAboutDialogPrivate::createForm(QWidget *titleWidget, QWidget *tabWidget, QDialog *dialog) { QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog); buttonBox->setStandardButtons(QDialogButtonBox::Close); QObject::connect(buttonBox, &QDialogButtonBox::accepted, dialog, &QDialog::accept); QObject::connect(buttonBox, &QDialogButtonBox::rejected, dialog, &QDialog::reject); // And we jam everything together in a layout... QVBoxLayout *mainLayout = new QVBoxLayout(dialog); mainLayout->addWidget(titleWidget); mainLayout->addWidget(tabWidget); mainLayout->addWidget(buttonBox); }