Warning, /plasma/plasma-desktop/applets/kicker/package/contents/ui/ItemListView.qml is written in an unsupported language. File is not indexed.
0001 /* 0002 SPDX-FileCopyrightText: 2013-2014 Eike Hein <hein@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 import QtQuick 2.15 0008 import QtQuick.Controls 0009 0010 import org.kde.kquickcontrolsaddons 2.0 0011 import org.kde.plasma.extras 2.0 as PlasmaExtras 0012 import org.kde.kirigami 2.20 as Kirigami 0013 0014 FocusScope { 0015 id: itemList 0016 0017 property real minimumWidth: Kirigami.Units.gridUnit * 14 0018 property real maximumWidth: minimumWidth * 2 0019 0020 width: minimumWidth 0021 height: listView.contentHeight 0022 0023 signal exited 0024 signal keyNavigationAtListEnd 0025 signal appendSearchText(string text) 0026 0027 property Item focusParent: null 0028 property QtObject dialog: null 0029 property QtObject childDialog: null 0030 property bool iconsEnabled: false 0031 property int itemHeight: Math.ceil((Math.max(Kirigami.Units.iconSizes.sizeForLabels, Kirigami.Units.iconSizes.small) 0032 + Math.max(highlightItemSvg.margins.top + highlightItemSvg.margins.bottom, 0033 listItemSvg.margins.top + listItemSvg.margins.bottom)) / 2) * 2 0034 property int separatorHeight: model.sorted === true ? 0 : lineSvg.horLineHeight + (2 * Kirigami.Units.smallSpacing) 0035 0036 property alias currentIndex: listView.currentIndex 0037 property alias currentItem: listView.currentItem 0038 property alias keyNavigationWraps: listView.keyNavigationWraps 0039 property alias showChildDialogs: listView.showChildDialogs 0040 property alias model: listView.model 0041 property alias count: listView.count 0042 property alias containsMouse: listener.containsMouse 0043 property alias resetOnExitDelay: resetIndexTimer.interval 0044 0045 onFocusParentChanged: { 0046 appendSearchText.connect(focusParent.appendSearchText); 0047 } 0048 0049 Timer { 0050 id: dialogSpawnTimer 0051 0052 property bool focusOnSpawn: false 0053 0054 interval: 70 0055 repeat: false 0056 0057 onTriggered: { 0058 if (!kicker.expanded || model === undefined || currentIndex == -1) { 0059 return; 0060 } 0061 0062 if (itemList.childDialog != null) { 0063 itemList.childDialog.delayedDestroy(); 0064 } 0065 0066 // Gets reenabled after the dialog spawn causes a focus-in on the dialog window. 0067 kicker.hideOnWindowDeactivate = false; 0068 0069 itemList.childDialog = itemListDialogComponent.createObject(itemList); 0070 itemList.childDialog.focusParent = itemList; 0071 itemList.childDialog.visualParent = listView.currentItem; 0072 itemList.childDialog.model = model.modelForRow(listView.currentIndex); 0073 itemList.childDialog.visible = true; 0074 0075 windowSystem.forceActive(itemList.childDialog.mainItem); 0076 itemList.childDialog.mainItem.focus = true; 0077 0078 if (focusOnSpawn) { 0079 itemList.childDialog.mainItem.showChildDialogs = false; 0080 itemList.childDialog.mainItem.currentIndex = 0; 0081 itemList.childDialog.mainItem.showChildDialogs = true; 0082 } 0083 } 0084 } 0085 0086 Timer { 0087 id: resetIndexTimer 0088 0089 interval: (dialog != null) ? 50 : 150 0090 repeat: false 0091 0092 onTriggered: { 0093 if (focus && (!itemList.childDialog || !itemList.childDialog.mainItem.containsMouse)) { 0094 currentIndex = -1; 0095 itemList.exited(); 0096 } 0097 } 0098 } 0099 0100 MouseEventListener { 0101 id: listener 0102 0103 anchors.fill: parent 0104 0105 hoverEnabled: true 0106 0107 onContainsMouseChanged: { 0108 listView.eligibleWidth = listView.width; 0109 0110 if (containsMouse) { 0111 resetIndexTimer.stop(); 0112 itemList.forceActiveFocus(); 0113 } else if ((!itemList.childDialog || !dialog) 0114 && (!currentItem || !currentItem.menu.opened)) { 0115 resetIndexTimer.start(); 0116 } 0117 } 0118 0119 ScrollView { 0120 anchors.fill: parent 0121 0122 focus: true 0123 0124 ListView { 0125 id: listView 0126 0127 property bool showChildDialogs: true 0128 property int eligibleWidth: width 0129 0130 currentIndex: -1 0131 0132 boundsBehavior: Flickable.StopAtBounds 0133 snapMode: ListView.SnapToItem 0134 spacing: 0 0135 keyNavigationWraps: (dialog != null) 0136 0137 delegate: ItemListDelegate { 0138 onFullTextWidthChanged: { 0139 if (fullTextWidth > itemList.width) itemList.width = Math.min(fullTextWidth, itemList.maximumWidth); 0140 } 0141 } 0142 0143 highlight: PlasmaExtras.Highlight { 0144 visible: !listView.currentItem.isSeparator 0145 pressed: listView.currentItem && listView.currentItem.pressed && !listView.currentItem.hasChildren 0146 active: listView.currentItem && listView.currentItem.hovered 0147 } 0148 0149 highlightMoveDuration: 0 0150 0151 onCountChanged: { 0152 currentIndex = -1; 0153 } 0154 0155 onCurrentIndexChanged: { 0156 if (currentIndex != -1) { 0157 if (itemList.childDialog) { 0158 if (currentItem && currentItem.hasChildren) { 0159 itemList.childDialog.mainItem.width = itemList.minimumWidth; 0160 itemList.childDialog.model = model.modelForRow(currentIndex); 0161 itemList.childDialog.visualParent = listView.currentItem; 0162 } else { 0163 itemList.childDialog.delayedDestroy(); 0164 } 0165 0166 return; 0167 } 0168 0169 if (currentItem == null || !currentItem.hasChildren || !kicker.expanded) { 0170 dialogSpawnTimer.stop(); 0171 0172 return; 0173 } 0174 0175 if (showChildDialogs) { 0176 dialogSpawnTimer.focusOnSpawn = false; 0177 dialogSpawnTimer.restart(); 0178 } 0179 } else if (itemList.childDialog != null) { 0180 itemList.childDialog.delayedDestroy(); 0181 itemList.childDialog = null; 0182 } 0183 } 0184 0185 onCurrentItemChanged: { 0186 if (currentItem) { 0187 currentItem.menu.closed.connect(resetIndexTimer.restart); 0188 } 0189 } 0190 } 0191 0192 Keys.onPressed: event => { 0193 if (event.key === Qt.Key_Up) { 0194 event.accepted = true; 0195 0196 if (!keyNavigationWraps && currentIndex == 0) { 0197 itemList.keyNavigationAtListEnd(); 0198 0199 return; 0200 } 0201 0202 showChildDialogs = false; 0203 listView.decrementCurrentIndex(); 0204 0205 if (currentItem.isSeparator) { 0206 listView.decrementCurrentIndex(); 0207 } 0208 0209 showChildDialogs = true; 0210 } else if (event.key === Qt.Key_Down) { 0211 event.accepted = true; 0212 0213 if (!keyNavigationWraps && currentIndex == count - 1) { 0214 itemList.keyNavigationAtListEnd(); 0215 0216 return; 0217 } 0218 0219 showChildDialogs = false; 0220 listView.incrementCurrentIndex(); 0221 0222 if (currentItem.isSeparator) { 0223 listView.incrementCurrentIndex(); 0224 } 0225 0226 showChildDialogs = true; 0227 } else if ((event.key === Qt.Key_Right || event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && itemList.childDialog != null) { 0228 windowSystem.forceActive(itemList.childDialog.mainItem); 0229 itemList.childDialog.mainItem.focus = true; 0230 itemList.childDialog.mainItem.currentIndex = 0; 0231 } else if ((event.key === Qt.Key_Right || event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && itemList.childDialog == null 0232 && currentItem != null && currentItem.hasChildren) { 0233 dialogSpawnTimer.focusOnSpawn = true; 0234 dialogSpawnTimer.restart(); 0235 } else if (event.key === Qt.Key_Left && dialog != null) { 0236 dialog.destroy(); 0237 } else if (event.key === Qt.Key_Escape) { 0238 kicker.expanded = false; 0239 } else if (event.key === Qt.Key_Tab) { 0240 //do nothing, and skip appending text 0241 } else if (event.text !== "") { 0242 if (/[\x00-\x1F\x7F]/.test(event.text)) { 0243 // We still want to focus it 0244 appendSearchText(""); 0245 } else { 0246 appendSearchText(event.text); 0247 } 0248 } 0249 } 0250 } 0251 } 0252 0253 Component.onCompleted: { 0254 windowSystem.monitorWindowFocus(itemList); 0255 0256 if (dialog == null) { 0257 appendSearchText.connect(root.appendSearchText); 0258 } 0259 } 0260 }