Warning, /frameworks/kirigami/src/controls/AboutItem.qml is written in an unsupported language. File is not indexed.

0001 /*
0002  *  SPDX-FileCopyrightText: 2018 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
0003  *
0004  *  SPDX-License-Identifier: LGPL-2.0-or-later
0005  */
0006 
0007 import QtQuick 2.1
0008 import QtQuick.Controls 2.4 as QQC2
0009 import QtQuick.Window 2.15
0010 import QtQuick.Layouts 1.3
0011 import org.kde.kirigami 2.20 as Kirigami
0012 
0013 //TODO: Kf6: move somewhere else which can depend from KAboutData?
0014 /**
0015  * @brief This component is an "About" item that displays data about the application.
0016  *
0017  * It allows showing the defind copyright notice of the application together
0018  * with the contributors and some information of which platform it's running on.
0019  *
0020  * @see <a href="https://develop.kde.org/docs/getting-started/kirigami/advanced-add_about_page">About Page in Kirigami</a>
0021  * @see <a href="https://develop.kde.org/hig/components/assistance/aboutview">KDE Human Interface Guidelines on Application Information</a>
0022  * @see kirigami::AboutPage
0023  * @since KDE Frameworks 5.87
0024  * @since org.kde.kirigami 2.19
0025  */
0026 Item {
0027     id: aboutItem
0028     /**
0029      * @brief This property holds information that this component displays.
0030      *
0031      * The stored JSON information object has the same structure as KAboutData.
0032      *
0033      * Example usage:
0034      * @code{.json}
0035      * aboutData: {
0036      *    "displayName" : "KirigamiApp",
0037      *    "productName" : "kirigami/app",
0038      *    "componentName" : "kirigamiapp",
0039      *    "shortDescription" : "A Kirigami example",
0040      *    "homepage" : "",
0041      *    "bugAddress" : "submit@bugs.kde.org",
0042      *    "version" : "5.14.80",
0043      *    "otherText" : "",
0044      *    "authors" : [
0045      *        {
0046      *            "name" : "...",
0047      *            "task" : "",
0048      *            "emailAddress" : "somebody@kde.org",
0049      *            "webAddress" : "",
0050      *            "ocsUsername" : ""
0051      *        }
0052      *    ],
0053      *    "credits" : [],
0054      *    "translators" : [],
0055      *    "licenses" : [
0056      *        {
0057      *            "name" : "GPL v2",
0058      *            "text" : "long, boring, license text",
0059      *            "spdx" : "GPL-2.0"
0060      *        }
0061      *    ],
0062      *    "copyrightStatement" : "© 2010-2018 Plasma Development Team",
0063      *    "desktopFileName" : "org.kde.kirigamiapp"
0064      * }
0065      * @endcode
0066      *
0067      * @see KAboutData
0068      */
0069     property var aboutData
0070 
0071     /**
0072      * @brief This property holds a link to a "Get Involved" page.
0073      *
0074      * default: `"https://community.kde.org/Get_Involved" when application id starts with "org.kde.", otherwise it is empty.`
0075      */
0076     property url getInvolvedUrl: aboutData.desktopFileName.startsWith("org.kde.") ? "https://community.kde.org/Get_Involved" : ""
0077 
0078     /**
0079      * @brief This property holds a link to a "Donate" page.
0080      *
0081      * default: `"https://kde.org/community/donations" when application id starts with "org.kde.", otherwise it is empty.`
0082      */
0083     property url donateUrl: aboutData.desktopFileName.startsWith("org.kde.") ? "https://kde.org/community/donations" : ""
0084 
0085     /** @internal */
0086     property bool _usePageStack: false
0087 
0088     /**
0089      * @brief This property specifies whether about item is in wide mode.
0090      * @see kirigami::FormLayout::wideMode
0091      * @property bool wideMode
0092      */
0093     property alias wideMode: form.wideMode
0094 
0095     /** @internal */
0096     default property alias _content: form.data
0097 
0098     implicitHeight: form.implicitHeight
0099     implicitWidth: form.implicitWidth
0100 
0101     Component {
0102         id: personDelegate
0103 
0104         RowLayout {
0105             Layout.fillWidth: true
0106             property bool hasRemoteAvatar: (typeof(modelData.ocsUsername) !== "undefined" && modelData.ocsUsername.length > 0)
0107 
0108             spacing: Kirigami.Units.smallSpacing * 2
0109 
0110             Kirigami.Icon {
0111                 id: avatarIcon
0112 
0113                 implicitWidth: Kirigami.Units.iconSizes.medium
0114                 implicitHeight: implicitWidth
0115 
0116                 fallback: "user"
0117                 source: hasRemoteAvatar && remoteAvatars.checked ? "https://store.kde.org/avatar/%1?s=%2".arg(modelData.ocsUsername).arg(width) : "user"
0118                 visible: status !== Kirigami.Icon.Loading
0119             }
0120 
0121             // So it's clear that something is happening while avatar images are loaded
0122             QQC2.BusyIndicator {
0123                 implicitWidth: Kirigami.Units.iconSizes.medium
0124                 implicitHeight: implicitWidth
0125 
0126                 visible: avatarIcon.status === Kirigami.Icon.Loading
0127                 running: visible
0128             }
0129 
0130             QQC2.Label {
0131                 Layout.fillWidth: true
0132                 readonly property bool withTask: typeof(modelData.task) !== "undefined" && modelData.task.length > 0
0133                 text: withTask ? qsTr("%1 (%2)").arg(modelData.name).arg(modelData.task) : modelData.name
0134                 wrapMode: Text.WordWrap
0135             }
0136 
0137             QQC2.ToolButton {
0138                 visible: typeof(modelData.ocsUsername) !== "undefined" && modelData.ocsUsername.length > 0
0139                 icon.name: "get-hot-new-stuff"
0140                 QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
0141                 QQC2.ToolTip.visible: hovered
0142                 QQC2.ToolTip.text: qsTr("Visit %1's KDE Store page").arg(modelData.name)
0143                 onClicked: Qt.openUrlExternally("https://store.kde.org/u/%1".arg(modelData.ocsUsername))
0144             }
0145 
0146             QQC2.ToolButton {
0147                 visible: typeof(modelData.emailAddress) !== "undefined" && modelData.emailAddress.length > 0
0148                 icon.name: "mail-sent"
0149                 QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
0150                 QQC2.ToolTip.visible: hovered
0151                 QQC2.ToolTip.text: qsTr("Send an email to %1").arg(modelData.emailAddress)
0152                 onClicked: Qt.openUrlExternally("mailto:%1".arg(modelData.emailAddress))
0153             }
0154 
0155             QQC2.ToolButton {
0156                 visible: typeof(modelData.webAddress) !== "undefined" && modelData.webAddress.length > 0
0157                 icon.name: "globe"
0158                 QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
0159                 QQC2.ToolTip.visible: hovered
0160                 QQC2.ToolTip.text: (typeof(modelData.webAddress) === "undefined" && modelData.webAddress.length > 0) ? "" : modelData.webAddress
0161                 onClicked: Qt.openUrlExternally(modelData.webAddress)
0162             }
0163         }
0164     }
0165 
0166     Kirigami.FormLayout {
0167         id: form
0168 
0169         anchors.fill: parent
0170 
0171         GridLayout {
0172             columns: 2
0173             Layout.fillWidth: true
0174 
0175             Kirigami.Icon {
0176                 Layout.rowSpan: 3
0177                 Layout.preferredHeight: Kirigami.Units.iconSizes.huge
0178                 Layout.preferredWidth: height
0179                 Layout.maximumWidth: aboutItem.width / 3;
0180                 Layout.rightMargin: Kirigami.Units.largeSpacing
0181                 source: Kirigami.Settings.applicationWindowIcon || aboutItem.aboutData.programLogo || aboutItem.aboutData.programIconName || aboutItem.aboutData.componentName
0182             }
0183 
0184             Kirigami.Heading {
0185                 Layout.fillWidth: true
0186                 text: aboutItem.aboutData.displayName + " " + aboutItem.aboutData.version
0187                 wrapMode: Text.WordWrap
0188             }
0189 
0190             Kirigami.Heading {
0191                 Layout.fillWidth: true
0192                 level: 2
0193                 wrapMode: Text.WordWrap
0194                 text: aboutItem.aboutData.shortDescription
0195             }
0196 
0197             RowLayout {
0198                 spacing: Kirigami.Units.largeSpacing * 2
0199 
0200                 UrlButton {
0201                     text: qsTr("Get Involved")
0202                     url: aboutItem.getInvolvedUrl
0203                     visible: url !== ""
0204                 }
0205 
0206                 UrlButton {
0207                     text: qsTr("Donate")
0208                     url: aboutItem.donateUrl
0209                     visible: url !== ""
0210                 }
0211 
0212                 UrlButton {
0213                     readonly property string theUrl: {
0214                         if (page.aboutData.bugAddress !== "submit@bugs.kde.org") {
0215                             return page.aboutData.bugAddress
0216                         }
0217                         const elements = page.aboutData.productName.split('/');
0218                         let url = `https://bugs.kde.org/enter_bug.cgi?format=guided&product=${elements[0]}&version=${page.aboutData.version}`;
0219                         if (elements.length === 2) {
0220                             url += "&component=" + elements[1];
0221                         }
0222                         return url;
0223                     }
0224                     text: qsTr("Report a Bug")
0225                     url: theUrl
0226                     visible: theUrl !== ""
0227                 }
0228             }
0229         }
0230 
0231         Separator {
0232             Layout.fillWidth: true
0233         }
0234 
0235         Kirigami.Heading {
0236             Kirigami.FormData.isSection: true
0237             text: qsTr("Copyright")
0238         }
0239 
0240         QQC2.Label {
0241             Layout.leftMargin: Kirigami.Units.gridUnit
0242             text: aboutData.otherText
0243             visible: text.length > 0
0244             wrapMode: Text.WordWrap
0245             Layout.fillWidth: true
0246         }
0247 
0248         QQC2.Label {
0249             Layout.leftMargin: Kirigami.Units.gridUnit
0250             text: aboutData.copyrightStatement
0251             visible: text.length > 0
0252             wrapMode: Text.WordWrap
0253             Layout.fillWidth: true
0254         }
0255 
0256         UrlButton {
0257             Layout.leftMargin: Kirigami.Units.gridUnit
0258             url: aboutData.homepage
0259             visible: url.length > 0
0260             wrapMode: Text.WordWrap
0261             Layout.fillWidth: true
0262         }
0263 
0264         OverlaySheet {
0265             id: licenseSheet
0266             property alias text: bodyLabel.text
0267 
0268             contentItem: SelectableLabel {
0269                 id: bodyLabel
0270                 text: licenseSheet.text
0271                 wrapMode: Text.Wrap
0272             }
0273         }
0274 
0275         Component {
0276             id: licenseLinkButton
0277 
0278             RowLayout {
0279                 Layout.leftMargin: Kirigami.Units.smallSpacing
0280 
0281                 QQC2.Label { text: qsTr("License:") }
0282 
0283                 LinkButton {
0284                     Layout.fillWidth: true
0285                     wrapMode: Text.WordWrap
0286                     text: modelData.name
0287                     onClicked: mouse => {
0288                         licenseSheet.text = modelData.text
0289                         licenseSheet.title = modelData.name
0290                         licenseSheet.open()
0291                     }
0292                 }
0293             }
0294         }
0295 
0296         Component {
0297             id: licenseTextItem
0298 
0299             QQC2.Label {
0300                 Layout.leftMargin: Kirigami.Units.smallSpacing
0301                 Layout.fillWidth: true
0302                 wrapMode: Text.WordWrap
0303                 text: qsTr("License: %1").arg(modelData.name)
0304             }
0305         }
0306 
0307         Repeater {
0308             model: aboutData.licenses
0309             delegate: _usePageStack ? licenseLinkButton : licenseTextItem
0310         }
0311 
0312         Kirigami.Heading {
0313             Kirigami.FormData.isSection: visible
0314             text: qsTr("Libraries in use")
0315             Layout.fillWidth: true
0316             wrapMode: Text.WordWrap
0317             visible: Kirigami.Settings.information
0318         }
0319 
0320         Repeater {
0321             model: Kirigami.Settings.information
0322             delegate: QQC2.Label {
0323                 Layout.leftMargin: Kirigami.Units.gridUnit
0324                 Layout.fillWidth: true
0325                 wrapMode: Text.WordWrap
0326                 id: libraries
0327                 text: modelData
0328             }
0329         }
0330 
0331         Repeater {
0332             model: aboutData.components
0333             delegate: QQC2.Label {
0334                 Layout.fillWidth: true
0335                 wrapMode: Text.WordWrap
0336                 Layout.leftMargin: Kirigami.Units.gridUnit
0337                 text: modelData.name + (modelData.version === "" ? "" : " %1".arg(modelData.version))
0338             }
0339         }
0340 
0341         Kirigami.Heading {
0342             Layout.fillWidth: true
0343             Kirigami.FormData.isSection: visible
0344             text: qsTr("Authors")
0345             wrapMode: Text.WordWrap
0346             visible: aboutData.authors.length > 0
0347         }
0348 
0349         QQC2.CheckBox {
0350             id: remoteAvatars
0351             visible: authorsRepeater.hasAnyRemoteAvatars
0352             checked: false
0353             text: qsTr("Show author photos")
0354 
0355             Timer {
0356                 id: remotesThrottle
0357                 repeat: false
0358                 interval: 1
0359                 onTriggered: {
0360                     let hasAnyRemotes = false;
0361                     for (let i = 0; i < authorsRepeater.count; ++i) {
0362                         const itm = authorsRepeater.itemAt(i);
0363                         if (itm.hasRemoteAvatar) {
0364                             hasAnyRemotes = true;
0365                             break;
0366                         }
0367                     }
0368                     authorsRepeater.hasAnyRemoteAvatars = hasAnyRemotes;
0369                 }
0370             }
0371         }
0372 
0373         Repeater {
0374             id: authorsRepeater
0375             model: aboutData.authors
0376             property bool hasAnyRemoteAvatars
0377             delegate: personDelegate
0378             onCountChanged: remotesThrottle.start()
0379         }
0380 
0381         Kirigami.Heading {
0382             height: visible ? implicitHeight : 0
0383             Kirigami.FormData.isSection: visible
0384             text: qsTr("Credits")
0385             visible: repCredits.count > 0
0386         }
0387 
0388         Repeater {
0389             id: repCredits
0390             model: aboutData.credits
0391             delegate: personDelegate
0392         }
0393 
0394         Kirigami.Heading {
0395             height: visible ? implicitHeight : 0
0396             Kirigami.FormData.isSection: visible
0397             text: qsTr("Translators")
0398             visible: repTranslators.count > 0
0399         }
0400 
0401         Repeater {
0402             id: repTranslators
0403             model: aboutData.translators
0404             delegate: personDelegate
0405         }
0406     }
0407 }