Warning, /plasma/plasma-desktop/applets/kickoff/package/contents/ui/AbstractKickoffItemDelegate.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: 2014 Sebastian Kügler <sebas@kde.org> 0005 SPDX-FileCopyrightText: 2015-2018 Eike Hein <hein@kde.org> 0006 SPDX-FileCopyrightText: 2021 Mikel Johnson <mikel5764@gmail.com> 0007 SPDX-FileCopyrightText: 2021 Noah Davis <noahadvs@gmail.com> 0008 SPDX-FileCopyrightText: 2022 Nate Graham <nate@kde.org> 0009 0010 SPDX-License-Identifier: GPL-2.0-or-later 0011 */ 0012 import QtQuick 2.15 0013 import QtQml 2.15 0014 import QtQuick.Layouts 1.15 0015 import QtQuick.Templates 2.15 as T 0016 import org.kde.plasma.core as PlasmaCore 0017 import org.kde.plasma.components 3.0 as PC3 0018 import org.kde.kirigami 2.20 as Kirigami 0019 import "code/tools.js" as Tools 0020 import org.kde.plasma.plasmoid 2.0 0021 0022 T.ItemDelegate { 0023 id: root 0024 0025 // model properties 0026 required property var model 0027 required property int index 0028 required property url url 0029 required property var decoration 0030 required property string description 0031 0032 readonly property Flickable view: ListView.view ?? GridView.view 0033 property bool isCategoryListItem: false 0034 readonly property bool hasActionList: model && (model.favoriteId !== null || ("hasActionList" in model && model.hasActionList === true)) 0035 property bool isSearchResult: false 0036 0037 readonly property bool isSeparator: model && (model.isSeparator === true) 0038 property int separatorHeight: KickoffSingleton.lineSvg.horLineHeight + (2 * Kirigami.Units.smallSpacing) 0039 property int itemHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, implicitContentHeight + topPadding + bottomPadding) 0040 0041 readonly property bool dragEnabled: enabled && !isCategoryListItem 0042 && Plasmoid.immutability !== PlasmaCore.Types.SystemImmutable 0043 0044 readonly property alias mouseArea: mouseArea 0045 0046 readonly property bool iconAndLabelsShouldlookSelected: isPressed && !isCategoryListItem 0047 0048 property bool labelTruncated: false 0049 property bool descriptionTruncated: false 0050 property bool descriptionVisible: true 0051 0052 property Item dragIconItem: null 0053 0054 // pressed: is read-only and we're not using it here because we have fancy 0055 // custom mouse handling 0056 readonly property bool isPressed: mouseArea.pressed 0057 0058 function openActionMenu(x = undefined, y = undefined) { 0059 if (!hasActionList) { return; } 0060 0061 let actions = model.actionList; 0062 const favoriteActions = Tools.createFavoriteActions( 0063 i18n, //i18n() function callback 0064 view.model.favoritesModel, 0065 model.favoriteId, 0066 ); 0067 if (favoriteActions) { 0068 if (actions && actions.length > 0) { 0069 actions.push({ "type": "separator" }, ...favoriteActions); 0070 } else { 0071 actions = favoriteActions; 0072 } 0073 } 0074 0075 if (actions && actions.length > 0) { 0076 ActionMenu.plasmoid = kickoff; 0077 ActionMenu.menu.visualParent = root; 0078 ActionMenu.actionList = actions; 0079 if (x !== undefined && y !== undefined) { 0080 ActionMenu.menu.open(x, y); 0081 } else { 0082 ActionMenu.menu.openRelative(); 0083 } 0084 } 0085 } 0086 0087 // The default Z value for delegates is 1. The default Z value for the section delegate is 2. 0088 // The highlight gets a value of 3 while the drag is active and then goes back to the default value of 0. 0089 z: Drag.active ? 4 : 1 0090 0091 implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, 0092 implicitContentWidth + leftPadding + rightPadding) 0093 implicitHeight: isSeparator ? separatorHeight : itemHeight 0094 0095 spacing: KickoffSingleton.fontMetrics.descent 0096 0097 enabled: !isSeparator && !model.disabled 0098 hoverEnabled: false 0099 0100 text: model.name ?? model.displayWrapped ?? model.display 0101 Accessible.role: Accessible.ListItem 0102 Accessible.description: root.description !== root.text ? root.description : "" 0103 Accessible.onPressAction: { 0104 root.forceActiveFocus() // trigger is focus guarded 0105 action.trigger() 0106 } 0107 0108 // Using an action so that it can be replaced or manually triggered 0109 // using `model` () instead of `root.model` leads to errors about 0110 // `model` not having the trigger() function 0111 action: T.Action { 0112 onTriggered: { 0113 // Unless we're showing search results, eat the activation if we 0114 // don't have focus, to prevent the return/enter key from 0115 // inappropriately activating unfocused items 0116 if (!root.activeFocus && !root.isSearchResult) { 0117 return; 0118 } 0119 view.currentIndex = index 0120 // if successfully triggered, close popup 0121 if (view.model.trigger && view.model.trigger(index, "", null)) { 0122 if (kickoff.hideOnWindowDeactivate) { 0123 kickoff.expanded = false; 0124 } 0125 } 0126 } 0127 } 0128 0129 Drag.active: mouseArea.drag.active 0130 Drag.dragType: Drag.Automatic 0131 Drag.mimeData: { "text/uri-list" : root.url } 0132 Drag.onDragFinished: Drag.imageSource = "" 0133 0134 MouseArea { 0135 id: mouseArea 0136 property bool dragEnabled: false 0137 parent: root 0138 anchors.fill: parent 0139 anchors.margins: 1 0140 // Flickable margins are not mirrored, so disable layout mirroring 0141 LayoutMirroring.enabled: false 0142 // Only for ListView since extending margins for GridView is hard 0143 anchors.leftMargin: root.view instanceof ListView ? -root.view.leftMargin : anchors.margins 0144 anchors.rightMargin: root.view instanceof ListView ? -root.view.rightMargin : anchors.margins 0145 hoverEnabled: root.view 0146 // When the movedWithWheel condition is broken, this ensures that 0147 // onEntered is called again without moving the mouse. 0148 && !root.view.movedWithWheel 0149 // Fix VerticalStackView animation causing view currentIndex 0150 // to change while delegates are moving under the mouse cursor 0151 && kickoff.fullRepresentationItem && !kickoff.fullRepresentationItem.contentItem.busy && !kickoff.fullRepresentationItem.blockingHoverFocus 0152 acceptedButtons: Qt.LeftButton | Qt.RightButton 0153 drag { 0154 axis: Drag.XAndYAxis 0155 target: root.dragEnabled && mouseArea.dragEnabled ? dragItem : undefined 0156 } 0157 // Using this Item fixes drag and drop causing delegates 0158 // to reset to a 0 X position and overlapping each other. 0159 Item { id: dragItem } 0160 0161 onEntered: { 0162 // When the movedWithKeyboard condition is broken, we do not want to 0163 // select the hovered item without moving the mouse. 0164 if (root.view.movedWithKeyboard) { 0165 return 0166 } 0167 // Don't highlight separators. 0168 if (root.isSeparator) { 0169 return; 0170 } 0171 0172 // forceActiveFocus() touches multiple items, so check for 0173 // activeFocus first to be more efficient. 0174 if (!root.activeFocus) { 0175 root.forceActiveFocus(Qt.MouseFocusReason) 0176 } 0177 // No need to check currentIndex first because it's 0178 // built into QQuickListView::setCurrentIndex() already 0179 root.view.currentIndex = index 0180 } 0181 onPressed: mouse => { 0182 // Select and focus on press to improve responsiveness and touch feedback 0183 view.currentIndex = index 0184 root.forceActiveFocus(Qt.MouseFocusReason) 0185 0186 // Only enable drag and drop with a mouse. 0187 // We don't have a good way to handle it and drag scrolling with touch. 0188 mouseArea.dragEnabled = mouse.source === Qt.MouseEventNotSynthesized 0189 0190 // We normally try to open right click menus on press like Qt Widgets 0191 if (mouse.button === Qt.RightButton) { 0192 root.openActionMenu(mouseX, mouseY) 0193 } else if (mouseArea.dragEnabled && mouse.button === Qt.LeftButton 0194 && root.dragEnabled && root.dragIconItem && root.Drag.imageSource.toString() === "" 0195 ) { 0196 root.dragIconItem.grabToImage(result => { 0197 root.Drag.imageSource = result.url 0198 }) 0199 } 0200 } 0201 onClicked: mouse => { 0202 if (mouse.button === Qt.LeftButton) { 0203 root.action.trigger() 0204 } 0205 } 0206 // MouseEvents for pressAndHold use Qt.MouseEventSynthesizedByQt for mouse.source, 0207 // which makes checking mouse.source for whether or not touch input is used useless. 0208 onPressAndHold: mouse => { 0209 if (mouse.button === Qt.LeftButton) { 0210 root.openActionMenu(mouseX, mouseY) 0211 } 0212 } 0213 } 0214 0215 PC3.ToolTip.text: { 0216 if (root.labelTruncated && root.descriptionTruncated) { 0217 return `${text} (${description})` 0218 } else if (root.descriptionTruncated || !root.descriptionVisible) { 0219 return description 0220 } 0221 return "" 0222 } 0223 PC3.ToolTip.visible: mouseArea.containsMouse && PC3.ToolTip.text.length > 0 0224 PC3.ToolTip.delay: Kirigami.Units.toolTipDelay 0225 0226 background: null 0227 }