Warning, /plasma/plasma-desktop/applets/kickoff/package/contents/ui/main.qml is written in an unsupported language. File is not indexed.
0001 /*
0002 SPDX-FileCopyrightText: 2011 Martin Gräßlin <mgraesslin@kde.org>
0003 SPDX-FileCopyrightText: 2012 Gregor Taetzner <gregor@freenet.de>
0004 SPDX-FileCopyrightText: 2012 Marco Martin <mart@kde.org>
0005 SPDX-FileCopyrightText: 2013 David Edmundson <davidedmundson@kde.org>
0006 SPDX-FileCopyrightText: 2015 Eike Hein <hein@kde.org>
0007 SPDX-FileCopyrightText: 2021 Mikel Johnson <mikel5764@gmail.com>
0008 SPDX-FileCopyrightText: 2021 Noah Davis <noahadvs@gmail.com>
0009
0010 SPDX-License-Identifier: GPL-2.0-or-later
0011 */
0012 import QtQuick 2.15
0013 import QtQuick.Layouts 1.15
0014 import QtQuick.Window 2.15
0015 import QtQml 2.15
0016 import org.kde.plasma.plasmoid 2.0
0017 import org.kde.plasma.core as PlasmaCore
0018 import org.kde.ksvg 1.0 as KSvg
0019 import org.kde.plasma.components 3.0 as PC3
0020 import org.kde.plasma.private.kicker 0.1 as Kicker
0021 import org.kde.kirigami 2.20 as Kirigami
0022
0023 import "code/tools.js" as Tools
0024
0025 PlasmoidItem {
0026 id: kickoff
0027
0028 // The properties are defined here instead of the singleton because each
0029 // instance of Kickoff requires different instances of these properties
0030
0031 readonly property bool inPanel: [
0032 PlasmaCore.Types.TopEdge,
0033 PlasmaCore.Types.RightEdge,
0034 PlasmaCore.Types.BottomEdge,
0035 PlasmaCore.Types.LeftEdge,
0036 ].includes(Plasmoid.location)
0037 readonly property bool vertical: Plasmoid.formFactor === PlasmaCore.Types.Vertical
0038
0039 // Used to prevent the width from changing frequently when the scrollbar appears or disappears
0040 readonly property bool mayHaveGridWithScrollBar: Plasmoid.configuration.applicationsDisplay === 0
0041 || (Plasmoid.configuration.favoritesDisplay === 0 && kickoff.rootModel.favoritesModel.count > minimumGridRowCount * minimumGridRowCount)
0042
0043 //BEGIN Models
0044 readonly property Kicker.RootModel rootModel: Kicker.RootModel {
0045 autoPopulate: false
0046
0047 // TODO: appletInterface property now can be ported to "applet" and have the real Applet* assigned directly
0048 appletInterface: kickoff
0049
0050 flat: true // have categories, but no subcategories
0051 sorted: Plasmoid.configuration.alphaSort
0052 showSeparators: true
0053 showTopLevelItems: true
0054
0055 showAllApps: true
0056 showAllAppsCategorized: false
0057 showRecentApps: false
0058 showRecentDocs: false
0059 showPowerSession: false
0060 showFavoritesPlaceholder: true
0061
0062 Component.onCompleted: {
0063 favoritesModel.initForClient("org.kde.plasma.kickoff.favorites.instance-" + Plasmoid.id)
0064
0065 if (!Plasmoid.configuration.favoritesPortedToKAstats) {
0066 if (favoritesModel.count < 1) {
0067 favoritesModel.portOldFavorites(Plasmoid.configuration.favorites);
0068 }
0069 Plasmoid.configuration.favoritesPortedToKAstats = true;
0070 }
0071 }
0072 }
0073
0074 readonly property Kicker.RunnerModel runnerModel: Kicker.RunnerModel {
0075 query: kickoff.searchField ? kickoff.searchField.text : ""
0076 onRequestUpdateQuery: query => {
0077 if (kickoff.searchField) {
0078 kickoff.searchField.text = query;
0079 }
0080 }
0081 appletInterface: kickoff
0082 mergeResults: true
0083 favoritesModel: rootModel.favoritesModel
0084 }
0085
0086 readonly property Kicker.ComputerModel computerModel: Kicker.ComputerModel {
0087 appletInterface: kickoff
0088 favoritesModel: rootModel.favoritesModel
0089 systemApplications: Plasmoid.configuration.systemApplications
0090 Component.onCompleted: {
0091 //systemApplications = Plasmoid.configuration.systemApplications;
0092 }
0093 }
0094
0095 readonly property Kicker.RecentUsageModel recentUsageModel: Kicker.RecentUsageModel {
0096 favoritesModel: rootModel.favoritesModel
0097 }
0098
0099 readonly property Kicker.RecentUsageModel frequentUsageModel: Kicker.RecentUsageModel {
0100 favoritesModel: rootModel.favoritesModel
0101 ordering: 1 // Popular / Frequently Used
0102 }
0103 //END
0104
0105 //BEGIN UI elements
0106 // Set in FullRepresentation.qml
0107 property Item header: null
0108
0109 // Set in Header.qml
0110 property PC3.TextField searchField: null
0111
0112 // Set in FullRepresentation.qml, ApplicationPage.qml, PlacesPage.qml
0113 property Item sideBar: null // is null when searching
0114 property Item contentArea: null // is searchView when searching
0115
0116 // Set in NormalPage.qml
0117 property Item footer: null
0118
0119 // True when central pane (and header) LayoutMirroring diverges from global
0120 // LayoutMirroring, in order to achieve the desired sidebar position
0121 readonly property bool paneSwap: Plasmoid.configuration.paneSwap
0122 readonly property bool sideBarOnRight: (Qt.application.layoutDirection == Qt.RightToLeft) != paneSwap
0123 // References to items according to their focus chain order
0124 readonly property Item firstHeaderItem: header ? (paneSwap ? header.pinButton : header.avatar) : null
0125 readonly property Item lastHeaderItem: header ? (paneSwap ? header.avatar : header.pinButton) : null
0126 readonly property Item firstCentralPane: paneSwap ? contentArea : sideBar
0127 readonly property Item lastCentralPane: paneSwap ? sideBar : contentArea
0128 //END
0129
0130 //BEGIN Metrics
0131 readonly property KSvg.FrameSvgItem backgroundMetrics: KSvg.FrameSvgItem {
0132 // Inset defaults to a negative value when not set by margin hints
0133 readonly property real leftPadding: margins.left - Math.max(inset.left, 0)
0134 readonly property real rightPadding: margins.right - Math.max(inset.right, 0)
0135 readonly property real topPadding: margins.top - Math.max(inset.top, 0)
0136 readonly property real bottomPadding: margins.bottom - Math.max(inset.bottom, 0)
0137 readonly property real spacing: leftPadding
0138 visible: false
0139 imagePath: Plasmoid.formFactor === PlasmaCore.Types.Planar ? "widgets/background" : "dialogs/background"
0140 }
0141
0142 // This is here rather than in the singleton with the other metrics items
0143 // because the list delegate's height depends on a configuration setting
0144 // and the singleton can't access those
0145 readonly property real listDelegateHeight: listDelegate.height
0146 KickoffListDelegate {
0147 id: listDelegate
0148 visible: false
0149 enabled: false
0150 model: null
0151 index: -1
0152 text: "asdf"
0153 url: ""
0154 decoration: "start-here-kde"
0155 description: "asdf"
0156 action: null
0157 indicator: null
0158 }
0159
0160 // Used to show smaller Kickoff on small screens
0161 readonly property int minimumGridRowCount: Math.min(Screen.desktopAvailableWidth, Screen.desktopAvailableHeight) * Screen.devicePixelRatio < KickoffSingleton.gridCellSize * 4 + (fullRepresentationItem ? fullRepresentationItem.normalPage.preferredSideBarWidth : KickoffSingleton.gridCellSize * 2) ? 2 : 4
0162 //END
0163
0164 Plasmoid.icon: Plasmoid.configuration.icon
0165
0166 switchWidth: fullRepresentationItem ? fullRepresentationItem.Layout.minimumWidth : -1
0167 switchHeight: fullRepresentationItem ? fullRepresentationItem.Layout.minimumHeight : -1
0168
0169 preferredRepresentation: compactRepresentation
0170
0171 fullRepresentation: FullRepresentation { focus: true }
0172
0173 // Only exists because the default CompactRepresentation doesn't:
0174 // - open on drag
0175 // - allow defining a custom drop handler
0176 // - expose the ability to show text below or beside the icon
0177 // TODO remove once it gains those features
0178 compactRepresentation: MouseArea {
0179 id: compactRoot
0180
0181 // Taken from DigitalClock to ensure uniform sizing when next to each other
0182 readonly property bool tooSmall: Plasmoid.formFactor === PlasmaCore.Types.Horizontal && Math.round(2 * (compactRoot.height / 5)) <= Kirigami.Theme.smallFont.pixelSize
0183
0184 readonly property bool shouldHaveIcon: Plasmoid.formFactor === PlasmaCore.Types.Vertical || Plasmoid.icon !== ""
0185 readonly property bool shouldHaveLabel: Plasmoid.formFactor !== PlasmaCore.Types.Vertical && Plasmoid.configuration.menuLabel !== ""
0186
0187 readonly property int iconSize: 48
0188
0189 readonly property var sizing: {
0190 const displayedIcon = buttonIcon.valid ? buttonIcon : buttonIconFallback;
0191
0192 let impWidth = 0;
0193 if (shouldHaveIcon) {
0194 impWidth += displayedIcon.width;
0195 }
0196 if (shouldHaveLabel) {
0197 impWidth += labelTextField.contentWidth + labelTextField.Layout.leftMargin + labelTextField.Layout.rightMargin;
0198 }
0199 const impHeight = displayedIcon.height > 0 ? displayedIcon.height : iconSize
0200
0201 // at least square, but can be wider/taller
0202 if (kickoff.inPanel) {
0203 if (kickoff.vertical) {
0204 return {
0205 preferredWidth: iconSize,
0206 preferredHeight: impHeight
0207 };
0208 } else { // horizontal
0209 return {
0210 preferredWidth: impWidth,
0211 preferredHeight: iconSize
0212 };
0213 }
0214 } else {
0215 return {
0216 preferredWidth: impWidth,
0217 preferredHeight: Kirigami.Units.iconSizes.small,
0218 };
0219 }
0220 }
0221
0222 implicitWidth: iconSize
0223 implicitHeight: iconSize
0224
0225 Layout.preferredWidth: sizing.preferredWidth
0226 Layout.preferredHeight: sizing.preferredHeight
0227 Layout.minimumWidth: Layout.preferredWidth
0228 Layout.minimumHeight: Layout.preferredHeight
0229
0230 hoverEnabled: true
0231
0232 property bool wasExpanded
0233
0234 Accessible.name: Plasmoid.title
0235
0236 onPressed: wasExpanded = kickoff.expanded
0237 onClicked: kickoff.expanded = !wasExpanded
0238
0239 DropArea {
0240 id: compactDragArea
0241 anchors.fill: parent
0242 }
0243
0244 Timer {
0245 id: expandOnDragTimer
0246 // this is an interaction and not an animation, so we want it as a constant
0247 interval: 250
0248 running: compactDragArea.containsDrag
0249 onTriggered: kickoff.expanded = true
0250 }
0251
0252 RowLayout {
0253 id: iconLabelRow
0254 anchors.fill: parent
0255 spacing: 0
0256
0257 Kirigami.Icon {
0258 id: buttonIcon
0259
0260 Layout.fillWidth: kickoff.vertical
0261 Layout.fillHeight: !kickoff.vertical
0262 Layout.preferredWidth: kickoff.vertical ? -1 : height / (implicitHeight / implicitWidth)
0263 Layout.preferredHeight: !kickoff.vertical ? -1 : width * (implicitHeight / implicitWidth)
0264 Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
0265 source: Tools.iconOrDefault(Plasmoid.formFactor, Plasmoid.icon)
0266 active: compactRoot.containsMouse || compactDragArea.containsDrag
0267 roundToIconSize: implicitHeight === implicitWidth
0268 visible: valid
0269 }
0270
0271 Kirigami.Icon {
0272 id: buttonIconFallback
0273 // fallback is assumed to be square
0274 Layout.fillWidth: kickoff.vertical
0275 Layout.fillHeight: !kickoff.vertical
0276 Layout.preferredWidth: kickoff.vertical ? -1 : height
0277 Layout.preferredHeight: !kickoff.vertical ? -1 : width
0278 Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
0279
0280 source: buttonIcon.valid ? null : Tools.defaultIconName
0281 active: compactRoot.containsMouse || compactDragArea.containsDrag
0282 visible: !buttonIcon.valid && Plasmoid.icon !== ""
0283 }
0284
0285 PC3.Label {
0286 id: labelTextField
0287
0288 Layout.fillHeight: true
0289 Layout.leftMargin: Kirigami.Units.smallSpacing
0290 Layout.rightMargin: Kirigami.Units.smallSpacing
0291
0292 text: Plasmoid.configuration.menuLabel
0293 textFormat: Text.PlainText
0294 horizontalAlignment: Text.AlignLeft
0295 verticalAlignment: Text.AlignVCenter
0296 wrapMode: Text.NoWrap
0297 fontSizeMode: Text.VerticalFit
0298 font.pixelSize: compactRoot.tooSmall ? Kirigami.Theme.defaultFont.pixelSize : Kirigami.Units.iconSizes.roundedIconSize(Kirigami.Units.gridUnit * 2)
0299 minimumPointSize: Kirigami.Theme.smallFont.pointSize
0300 visible: compactRoot.shouldHaveLabel
0301 }
0302 }
0303 }
0304
0305 Kicker.ProcessRunner {
0306 id: processRunner;
0307 }
0308
0309 Plasmoid.contextualActions: [
0310 PlasmaCore.Action {
0311 text: i18n("Edit Applications…")
0312 icon.name: "kmenuedit"
0313 visible: Plasmoid.immutability !== PlasmaCore.Types.SystemImmutable
0314 onTriggered: processRunner.runMenuEditor()
0315 }
0316 ]
0317
0318 Component.onCompleted: {
0319 if (Plasmoid.hasOwnProperty("activationTogglesExpanded")) {
0320 Plasmoid.activationTogglesExpanded = true
0321 }
0322 }
0323 } // root