Warning, /plasma/plasma-desktop/applets/kicker/package/contents/ui/DashboardRepresentation.qml is written in an unsupported language. File is not indexed.
0001 /* 0002 SPDX-FileCopyrightText: 2015 Eike Hein <hein@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 import QtQuick 2.15 0008 import Qt5Compat.GraphicalEffects 0009 // Deliberately imported after QtQuick to avoid missing restoreMode property in Binding. Fix in Qt 6. 0010 import QtQml 2.15 0011 0012 import org.kde.kquickcontrolsaddons 2.0 0013 import org.kde.kwindowsystem 1.0 0014 import org.kde.plasma.components as PlasmaComponents 0015 import org.kde.plasma.extras 2.0 as PlasmaExtras 0016 import org.kde.plasma.core as PlasmaCore 0017 import org.kde.ksvg 1.0 as KSvg 0018 import org.kde.plasma.private.shell 2.0 0019 import org.kde.kirigami 2.20 as Kirigami 0020 0021 import org.kde.plasma.plasmoid 2.0 0022 import org.kde.plasma.private.kicker 0.1 as Kicker 0023 0024 import "code/tools.js" as Tools 0025 0026 /* TODO 0027 * Reverse middleRow layout + keyboard nav + filter list text alignment in rtl locales. 0028 * Keep cursor column when arrow'ing down past non-full trailing rows into a lower grid. 0029 * Make DND transitions cleaner by performing an item swap instead of index reinsertion. 0030 */ 0031 0032 Kicker.DashboardWindow { 0033 id: root 0034 0035 property bool smallScreen: ((Math.floor(width / Kirigami.Units.iconSizes.huge) <= 22) || (Math.floor(height / Kirigami.Units.iconSizes.huge) <= 14)) 0036 0037 property int iconSize: smallScreen ? Kirigami.Units.iconSizes.large : Kirigami.Units.iconSizes.huge 0038 property int cellSize: iconSize + (2 * Kirigami.Units.iconSizes.sizeForLabels) 0039 + (2 * Kirigami.Units.smallSpacing) 0040 + (2 * Math.max(highlightItemSvg.margins.top + highlightItemSvg.margins.bottom, 0041 highlightItemSvg.margins.left + highlightItemSvg.margins.right)) 0042 property int columns: Math.floor(((smallScreen ? 85 : 80)/100) * Math.ceil(width / cellSize)) 0043 property bool searching: searchField.text !== "" 0044 0045 keyEventProxy: searchField 0046 backgroundColor: Qt.rgba(0, 0, 0, 0.737) 0047 0048 onKeyEscapePressed: { 0049 if (searching) { 0050 searchField.clear(); 0051 } else { 0052 root.toggle(); 0053 } 0054 } 0055 0056 onVisibleChanged: { 0057 reset(); 0058 0059 if (visible) { 0060 preloadAllAppsTimer.restart(); 0061 } 0062 } 0063 0064 onSearchingChanged: { 0065 if (!searching) { 0066 reset(); 0067 } else { 0068 filterList.currentIndex = -1; 0069 } 0070 } 0071 0072 function reset() { 0073 searchField.clear(); 0074 globalFavoritesGrid.currentIndex = -1; 0075 systemFavoritesGrid.currentIndex = -1; 0076 filterList.currentIndex = 0; 0077 funnelModel.sourceModel = rootModel.modelForRow(0); 0078 mainGrid.model = funnelModel; 0079 mainGrid.currentIndex = -1; 0080 filterListScrollArea.focus = true; 0081 filterList.model = rootModel; 0082 } 0083 0084 mainItem: MouseArea { 0085 id: rootItem 0086 0087 anchors.fill: parent 0088 0089 acceptedButtons: Qt.LeftButton | Qt.RightButton 0090 0091 LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft 0092 LayoutMirroring.childrenInherit: true 0093 0094 Connections { 0095 target: kicker 0096 0097 function onReset() { 0098 if (!root.searching) { 0099 filterList.applyFilter(); 0100 funnelModel.reset(); 0101 } 0102 } 0103 0104 function onDragSourceChanged() { 0105 if (!kicker.dragSource) { 0106 // FIXME TODO HACK: Reset all views post-DND to work around 0107 // mouse grab bug despite QQuickWindow::mouseGrabberItem==0x0. 0108 // Needs a more involved hunt through Qt Quick sources later since 0109 // it's not happening with near-identical code in the menu repr. 0110 rootModel.refresh(); 0111 } 0112 } 0113 } 0114 0115 Connections { 0116 target: Plasmoid 0117 function onUserConfiguringChanged() { 0118 if (Plasmoid.userConfiguring) { 0119 root.hide() 0120 } 0121 } 0122 } 0123 0124 PlasmaExtras.Menu { 0125 id: contextMenu 0126 0127 PlasmaExtras.MenuItem { 0128 action: Plasmoid.internalAction("configure") 0129 } 0130 } 0131 0132 Kirigami.Heading { 0133 id: dummyHeading 0134 0135 visible: false 0136 0137 width: 0 0138 0139 level: 1 0140 textFormat: Text.PlainText 0141 } 0142 0143 TextMetrics { 0144 id: headingMetrics 0145 0146 font: dummyHeading.font 0147 } 0148 0149 Kicker.FunnelModel { 0150 id: funnelModel 0151 0152 onSourceModelChanged: { 0153 if (mainColumn.visible) { 0154 mainGrid.currentIndex = -1; 0155 mainGrid.forceLayout(); 0156 } 0157 } 0158 } 0159 0160 Timer { 0161 id: preloadAllAppsTimer 0162 0163 property bool done: false 0164 0165 interval: 1000 0166 repeat: false 0167 0168 onTriggered: { 0169 if (done || root.searching) { 0170 return; 0171 } 0172 0173 for (var i = 0; i < rootModel.count; ++i) { 0174 var model = rootModel.modelForRow(i); 0175 0176 if (model.description === "KICKER_ALL_MODEL") { 0177 allAppsGrid.model = model; 0178 done = true; 0179 break; 0180 } 0181 } 0182 } 0183 0184 function defer() { 0185 if (running && !done) { 0186 restart(); 0187 } 0188 } 0189 } 0190 0191 Kicker.ContainmentInterface { 0192 id: containmentInterface 0193 } 0194 0195 TextEdit { 0196 id: searchField 0197 0198 width: 0 0199 height: 0 0200 0201 visible: false 0202 0203 persistentSelection: true 0204 0205 onTextChanged: { 0206 runnerModel.query = searchField.text; 0207 } 0208 0209 function clear() { 0210 text = ""; 0211 } 0212 0213 onSelectionStartChanged: Qt.callLater(searchHeading.updateSelection) 0214 onSelectionEndChanged: Qt.callLater(searchHeading.updateSelection) 0215 } 0216 0217 TextEdit { 0218 id: searchHeading 0219 0220 anchors { 0221 horizontalCenter: parent.horizontalCenter 0222 } 0223 0224 y: (middleRow.anchors.topMargin / 2) - (root.smallScreen ? (height/10) : 0) 0225 0226 font.pointSize: dummyHeading.font.pointSize * 1.5 0227 wrapMode: Text.NoWrap 0228 opacity: 1.0 0229 0230 selectByMouse: false 0231 cursorVisible: false 0232 0233 color: "white" 0234 0235 text: root.searching ? i18n("Searching for '%1'", searchField.text) : i18nc("@info:placeholder as in, 'start typing to initiate a search'", "Type to search…") 0236 0237 function updateSelection() { 0238 if (!searchField.selectedText) { 0239 return; 0240 } 0241 0242 var delta = text.lastIndexOf(searchField.text, text.length - 2); 0243 searchHeading.select(searchField.selectionStart + delta, searchField.selectionEnd + delta); 0244 } 0245 } 0246 0247 PlasmaComponents.ToolButton { 0248 id: cancelSearchButton 0249 0250 anchors { 0251 left: searchHeading.right 0252 leftMargin: Kirigami.Units.gridUnit 0253 verticalCenter: searchHeading.verticalCenter 0254 } 0255 0256 width: Kirigami.Units.iconSizes.large 0257 height: width 0258 0259 visible: (searchField.text !== "") 0260 0261 icon.name: "edit-clear" 0262 flat: false 0263 0264 onClicked: searchField.clear(); 0265 0266 Keys.onPressed: event => { 0267 if (event.key === Qt.Key_Tab) { 0268 event.accepted = true; 0269 0270 if (runnerModel.count) { 0271 mainColumn.tryActivate(0, 0); 0272 } else { 0273 systemFavoritesGrid.tryActivate(0, 0); 0274 } 0275 } else if (event.key === Qt.Key_Backtab) { 0276 event.accepted = true; 0277 0278 if (globalFavoritesGrid.enabled) { 0279 globalFavoritesGrid.tryActivate(0, 0); 0280 } else { 0281 systemFavoritesGrid.tryActivate(0, 0); 0282 } 0283 } 0284 } 0285 } 0286 0287 Row { 0288 id: middleRow 0289 0290 anchors { 0291 top: parent.top 0292 topMargin: Kirigami.Units.gridUnit * (smallScreen ? 8 : 10) 0293 bottom: parent.bottom 0294 bottomMargin: (Kirigami.Units.gridUnit * 2) 0295 horizontalCenter: parent.horizontalCenter 0296 } 0297 0298 width: (root.columns * root.cellSize) + (2 * spacing) 0299 0300 spacing: Kirigami.Units.gridUnit * 2 0301 0302 Item { 0303 id: favoritesColumn 0304 0305 anchors { 0306 top: parent.top 0307 bottom: parent.bottom 0308 } 0309 0310 width: (columns * root.cellSize) + Kirigami.Units.gridUnit 0311 0312 property int columns: 3 0313 0314 Kirigami.Heading { 0315 id: favoritesColumnLabel 0316 0317 anchors { 0318 top: parent.top 0319 } 0320 0321 x: Kirigami.Units.smallSpacing 0322 width: parent.width - x 0323 0324 elide: Text.ElideRight 0325 wrapMode: Text.NoWrap 0326 0327 color: "white" 0328 0329 level: 1 0330 0331 text: i18n("Favorites") 0332 textFormat: Text.PlainText 0333 0334 opacity: enabled ? 1.0 : 0.3 0335 0336 Behavior on opacity { SmoothedAnimation { duration: Kirigami.Units.longDuration; velocity: 0.01 } } 0337 } 0338 0339 KSvg.SvgItem { 0340 id: favoritesColumnLabelUnderline 0341 0342 anchors { 0343 top: favoritesColumnLabel.bottom 0344 } 0345 0346 width: parent.width - Kirigami.Units.gridUnit 0347 height: lineSvg.horLineHeight 0348 0349 svg: lineSvg 0350 elementId: "horizontal-line" 0351 0352 opacity: enabled ? 1.0 : 0.3 0353 0354 Behavior on opacity { SmoothedAnimation { duration: Kirigami.Units.longDuration; velocity: 0.01 } } 0355 } 0356 0357 ItemGridView { 0358 id: globalFavoritesGrid 0359 0360 anchors { 0361 top: favoritesColumnLabelUnderline.bottom 0362 topMargin: Kirigami.Units.gridUnit 0363 } 0364 0365 Kirigami.Theme.colorSet: Kirigami.Theme.Complementary 0366 Kirigami.Theme.inherit: false 0367 0368 property int rows: (Math.floor((parent.height - favoritesColumnLabel.height 0369 - favoritesColumnLabelUnderline.height - Kirigami.Units.gridUnit) / root.cellSize) 0370 - systemFavoritesGrid.rows) 0371 0372 width: parent.width 0373 height: rows * root.cellSize 0374 0375 cellWidth: root.cellSize 0376 cellHeight: root.cellSize 0377 iconSize: root.iconSize 0378 0379 model: globalFavorites 0380 0381 dropEnabled: true 0382 0383 opacity: enabled ? 1.0 : 0.3 0384 0385 Behavior on opacity { SmoothedAnimation { duration: Kirigami.Units.longDuration; velocity: 0.01 } } 0386 0387 onCurrentIndexChanged: { 0388 preloadAllAppsTimer.defer(); 0389 } 0390 0391 onKeyNavRight: { 0392 mainColumn.tryActivate(currentRow(), 0); 0393 } 0394 0395 onKeyNavDown: { 0396 systemFavoritesGrid.tryActivate(0, currentCol()); 0397 } 0398 0399 Keys.onPressed: event => { 0400 if (event.key === Qt.Key_Tab) { 0401 event.accepted = true; 0402 0403 if (root.searching) { 0404 cancelSearchButton.focus = true; 0405 } else { 0406 mainColumn.tryActivate(0, 0); 0407 } 0408 } else if (event.key === Qt.Key_Backtab) { 0409 event.accepted = true; 0410 systemFavoritesGrid.tryActivate(0, 0); 0411 } 0412 } 0413 0414 Binding { 0415 target: globalFavorites 0416 property: "iconSize" 0417 value: root.iconSize 0418 restoreMode: Binding.RestoreBinding 0419 } 0420 } 0421 0422 ItemGridView { 0423 id: systemFavoritesGrid 0424 Kirigami.Theme.colorSet: Kirigami.Theme.Complementary 0425 Kirigami.Theme.inherit: false 0426 anchors { 0427 top: globalFavoritesGrid.bottom 0428 } 0429 0430 property int rows: Math.ceil(count / Math.floor(width / root.cellSize)) 0431 0432 width: parent.width 0433 height: rows * root.cellSize 0434 0435 cellWidth: root.cellSize 0436 cellHeight: root.cellSize 0437 iconSize: root.iconSize 0438 0439 model: systemFavorites 0440 0441 dropEnabled: true 0442 0443 onCurrentIndexChanged: { 0444 preloadAllAppsTimer.defer(); 0445 } 0446 0447 onKeyNavRight: { 0448 mainColumn.tryActivate(globalFavoritesGrid.rows + currentRow(), 0); 0449 } 0450 0451 onKeyNavUp: { 0452 globalFavoritesGrid.tryActivate(globalFavoritesGrid.rows - 1, currentCol()); 0453 } 0454 0455 Keys.onPressed: event => { 0456 if (event.key === Qt.Key_Tab) { 0457 event.accepted = true; 0458 0459 if (globalFavoritesGrid.enabled) { 0460 globalFavoritesGrid.tryActivate(0, 0); 0461 } else if (root.searching && !runnerModel.count) { 0462 cancelSearchButton.focus = true; 0463 } else { 0464 mainColumn.tryActivate(0, 0); 0465 } 0466 } else if (event.key === Qt.Key_Backtab) { 0467 event.accepted = true; 0468 0469 if (filterList.enabled) { 0470 filterList.forceActiveFocus(); 0471 } else if (root.searching && !runnerModel.count) { 0472 cancelSearchButton.focus = true; 0473 } else { 0474 mainColumn.tryActivate(0, 0); 0475 } 0476 } 0477 } 0478 } 0479 } 0480 0481 Item { 0482 id: mainColumn 0483 0484 anchors.top: parent.top 0485 0486 width: (columns * root.cellSize) + Kirigami.Units.gridUnit 0487 height: Math.floor(parent.height / root.cellSize) * root.cellSize + mainGridContainer.headerHeight 0488 0489 Kirigami.Theme.colorSet: Kirigami.Theme.Complementary 0490 Kirigami.Theme.inherit: false 0491 0492 property int columns: root.columns - favoritesColumn.columns - filterListColumn.columns 0493 property Item visibleGrid: mainGrid 0494 0495 function tryActivate(row, col) { 0496 if (visibleGrid) { 0497 visibleGrid.tryActivate(row, col); 0498 } 0499 } 0500 0501 Item { 0502 id: mainGridContainer 0503 0504 anchors.fill: parent 0505 z: (opacity === 1.0) ? 1 : 0 0506 0507 visible: opacity !== 0.0 0508 0509 property int headerHeight: mainColumnLabel.height + mainColumnLabelUnderline.height + Kirigami.Units.gridUnit 0510 0511 opacity: { 0512 if (root.searching) { 0513 return 0.0; 0514 } 0515 0516 if (filterList.allApps) { 0517 return 0.0; 0518 } 0519 0520 return 1.0; 0521 } 0522 0523 onOpacityChanged: { 0524 if (opacity === 1.0) { 0525 mainColumn.visibleGrid = mainGrid; 0526 } 0527 } 0528 0529 Kirigami.Heading { 0530 id: mainColumnLabel 0531 0532 anchors { 0533 top: parent.top 0534 } 0535 0536 x: Kirigami.Units.smallSpacing 0537 width: parent.width - x 0538 0539 elide: Text.ElideRight 0540 wrapMode: Text.NoWrap 0541 opacity: 1.0 0542 0543 color: "white" 0544 0545 level: 1 0546 0547 text: funnelModel.description 0548 textFormat: Text.PlainText 0549 } 0550 0551 KSvg.SvgItem { 0552 id: mainColumnLabelUnderline 0553 0554 visible: mainGrid.count 0555 0556 anchors { 0557 top: mainColumnLabel.bottom 0558 } 0559 0560 width: parent.width - Kirigami.Units.gridUnit 0561 height: lineSvg.horLineHeight 0562 0563 svg: lineSvg 0564 elementId: "horizontal-line" 0565 } 0566 0567 ItemGridView { 0568 id: mainGrid 0569 0570 anchors { 0571 top: mainColumnLabelUnderline.bottom 0572 topMargin: Kirigami.Units.gridUnit 0573 } 0574 0575 width: parent.width 0576 height: systemFavoritesGrid.y + systemFavoritesGrid.height - mainGridContainer.headerHeight 0577 0578 cellWidth: root.cellSize 0579 cellHeight: cellWidth 0580 iconSize: root.iconSize 0581 0582 model: funnelModel 0583 0584 onCurrentIndexChanged: { 0585 preloadAllAppsTimer.defer(); 0586 } 0587 0588 onKeyNavLeft: { 0589 var row = currentRow(); 0590 var target = row + 1 > globalFavoritesGrid.rows ? systemFavoritesGrid : globalFavoritesGrid; 0591 var targetRow = row + 1 > globalFavoritesGrid.rows ? row - globalFavoritesGrid.rows : row; 0592 target.tryActivate(targetRow, favoritesColumn.columns - 1); 0593 } 0594 0595 onKeyNavRight: { 0596 filterListScrollArea.focus = true; 0597 } 0598 } 0599 } 0600 0601 ItemMultiGridView { 0602 id: allAppsGrid 0603 0604 anchors { 0605 top: parent.top 0606 } 0607 0608 z: (opacity === 1.0) ? 1 : 0 0609 width: parent.width 0610 height: systemFavoritesGrid.y + systemFavoritesGrid.height 0611 0612 visible: opacity !== 0.0 0613 0614 opacity: filterList.allApps ? 1.0 : 0.0 0615 0616 onOpacityChanged: { 0617 if (opacity === 1.0) { 0618 allAppsGrid.flickableItem.contentY = 0; 0619 mainColumn.visibleGrid = allAppsGrid; 0620 } 0621 } 0622 0623 onKeyNavLeft: { 0624 var row = 0; 0625 0626 for (var i = 0; i < subGridIndex; i++) { 0627 row += subGridAt(i).lastRow() + 2; // Header counts as one. 0628 } 0629 0630 row += subGridAt(subGridIndex).currentRow(); 0631 0632 var target = row + 1 > globalFavoritesGrid.rows ? systemFavoritesGrid : globalFavoritesGrid; 0633 var targetRow = row + 1 > globalFavoritesGrid.rows ? row - globalFavoritesGrid.rows : row; 0634 target.tryActivate(targetRow, favoritesColumn.columns - 1); 0635 } 0636 0637 onKeyNavRight: { 0638 filterListScrollArea.focus = true; 0639 } 0640 } 0641 0642 ItemMultiGridView { 0643 id: runnerGrid 0644 0645 anchors { 0646 top: parent.top 0647 } 0648 0649 z: (opacity === 1.0) ? 1 : 0 0650 width: parent.width 0651 height: Math.min(implicitHeight, systemFavoritesGrid.y + systemFavoritesGrid.height) 0652 0653 visible: opacity !== 0.0 0654 0655 model: runnerModel 0656 0657 grabFocus: true 0658 0659 opacity: root.searching ? 1.0 : 0.0 0660 0661 onOpacityChanged: { 0662 if (opacity === 1.0) { 0663 mainColumn.visibleGrid = runnerGrid; 0664 } 0665 } 0666 0667 onKeyNavLeft: { 0668 var row = 0; 0669 0670 for (var i = 0; i < subGridIndex; i++) { 0671 row += subGridAt(i).lastRow() + 2; // Header counts as one. 0672 } 0673 0674 row += subGridAt(subGridIndex).currentRow(); 0675 0676 var target = row + 1 > globalFavoritesGrid.rows ? systemFavoritesGrid : globalFavoritesGrid; 0677 var targetRow = row + 1 > globalFavoritesGrid.rows ? row - globalFavoritesGrid.rows : row; 0678 target.tryActivate(targetRow, favoritesColumn.columns - 1); 0679 } 0680 } 0681 0682 Keys.onPressed: event => { 0683 if (event.key === Qt.Key_Tab) { 0684 event.accepted = true; 0685 0686 if (filterList.enabled) { 0687 filterList.forceActiveFocus(); 0688 } else { 0689 systemFavoritesGrid.tryActivate(0, 0); 0690 } 0691 } else if (event.key === Qt.Key_Backtab) { 0692 event.accepted = true; 0693 0694 if (root.searching) { 0695 cancelSearchButton.focus = true; 0696 } else if (globalFavoritesGrid.enabled) { 0697 globalFavoritesGrid.tryActivate(0, 0); 0698 } else { 0699 systemFavoritesGrid.tryActivate(0, 0); 0700 } 0701 } 0702 } 0703 } 0704 0705 Item { 0706 id: filterListColumn 0707 0708 anchors { 0709 top: parent.top 0710 topMargin: mainColumnLabelUnderline.y + mainColumnLabelUnderline.height + Kirigami.Units.gridUnit 0711 bottom: parent.bottom 0712 } 0713 0714 width: columns * root.cellSize 0715 0716 property int columns: 3 0717 0718 PlasmaComponents.ScrollView { 0719 id: filterListScrollArea 0720 0721 x: root.visible ? 0 : Kirigami.Units.gridUnit 0722 0723 Behavior on x { SmoothedAnimation { duration: Kirigami.Units.longDuration; velocity: 0.01 } } 0724 0725 width: parent.width 0726 height: mainGrid.height 0727 0728 enabled: !root.searching 0729 0730 property alias currentIndex: filterList.currentIndex 0731 0732 opacity: root.visible ? (root.searching ? 0.30 : 1.0) : 0.3 0733 0734 Behavior on opacity { SmoothedAnimation { duration: Kirigami.Units.longDuration; velocity: 0.01 } } 0735 0736 PlasmaComponents.ScrollBar.vertical.policy: (opacity === 1.0) ? PlasmaComponents.ScrollBar.AsNeeded : PlasmaComponents.ScrollBar.AlwaysOff 0737 0738 onEnabledChanged: { 0739 if (!enabled) { 0740 filterList.currentIndex = -1; 0741 } 0742 } 0743 0744 onCurrentIndexChanged: { 0745 focus = (currentIndex !== -1); 0746 } 0747 0748 ListView { 0749 id: filterList 0750 0751 focus: true 0752 0753 property bool allApps: false 0754 property int eligibleWidth: width 0755 property int hItemMargins: Math.max(highlightItemSvg.margins.left + highlightItemSvg.margins.right, 0756 listItemSvg.margins.left + listItemSvg.margins.right) 0757 0758 model: rootModel 0759 0760 boundsBehavior: Flickable.StopAtBounds 0761 snapMode: ListView.SnapToItem 0762 spacing: 0 0763 keyNavigationWraps: true 0764 0765 delegate: MouseArea { 0766 id: item 0767 0768 signal actionTriggered(string actionId, variant actionArgument) 0769 signal aboutToShowActionMenu(variant actionMenu) 0770 0771 property var m: model 0772 property int textWidth: label.contentWidth 0773 property int mouseCol 0774 property bool hasActionList: ((model.favoriteId !== null) 0775 || (("hasActionList" in model) && (model.hasActionList === true))) 0776 property Item menu: actionMenu 0777 0778 width: ListView.view.width 0779 height: Math.ceil((label.paintedHeight 0780 + Math.max(highlightItemSvg.margins.top + highlightItemSvg.margins.bottom, 0781 listItemSvg.margins.top + listItemSvg.margins.bottom)) / 2) * 2 0782 0783 Accessible.role: Accessible.MenuItem 0784 Accessible.name: model.display 0785 0786 acceptedButtons: Qt.LeftButton | Qt.RightButton 0787 0788 hoverEnabled: true 0789 0790 onContainsMouseChanged: { 0791 if (!containsMouse) { 0792 updateCurrentItemTimer.stop(); 0793 } 0794 } 0795 0796 onPositionChanged: mouse => { // Lazy menu implementation. 0797 mouseCol = mouse.x; 0798 0799 if (justOpenedTimer.running || ListView.view.currentIndex === 0 || index === ListView.view.currentIndex) { 0800 updateCurrentItem(); 0801 } else if ((index === ListView.view.currentIndex - 1) && mouse.y < (height - 6) 0802 || (index === ListView.view.currentIndex + 1) && mouse.y > 5) { 0803 0804 if (mouse.x > ListView.view.eligibleWidth - 5) { 0805 updateCurrentItem(); 0806 } 0807 } else if (mouse.x > ListView.view.eligibleWidth) { 0808 updateCurrentItem(); 0809 } 0810 0811 updateCurrentItemTimer.restart(); 0812 } 0813 0814 onPressed: mouse => { 0815 if (mouse.buttons & Qt.RightButton) { 0816 if (hasActionList) { 0817 openActionMenu(item, mouse.x, mouse.y); 0818 } 0819 } 0820 } 0821 0822 onClicked: mouse => { 0823 if (mouse.button === Qt.LeftButton) { 0824 updateCurrentItem(); 0825 } 0826 } 0827 0828 onAboutToShowActionMenu: { 0829 var actionList = hasActionList ? model.actionList : []; 0830 Tools.fillActionMenu(i18n, actionMenu, actionList, ListView.view.model.favoritesModel, model.favoriteId); 0831 } 0832 0833 onActionTriggered: { 0834 if (Tools.triggerAction(ListView.view.model, model.index, actionId, actionArgument) === true) { 0835 kicker.expanded = false; 0836 } 0837 } 0838 0839 function openActionMenu(visualParent, x, y) { 0840 aboutToShowActionMenu(actionMenu); 0841 actionMenu.visualParent = visualParent; 0842 actionMenu.open(x, y); 0843 } 0844 0845 function updateCurrentItem() { 0846 ListView.view.currentIndex = index; 0847 ListView.view.eligibleWidth = Math.min(width, mouseCol); 0848 } 0849 0850 ActionMenu { 0851 id: actionMenu 0852 0853 onActionClicked: { 0854 actionTriggered(actionId, actionArgument); 0855 } 0856 } 0857 0858 Timer { 0859 id: updateCurrentItemTimer 0860 0861 interval: 50 0862 repeat: false 0863 0864 onTriggered: parent.updateCurrentItem() 0865 } 0866 0867 Kirigami.Heading { 0868 id: label 0869 0870 anchors { 0871 fill: parent 0872 leftMargin: highlightItemSvg.margins.left 0873 rightMargin: highlightItemSvg.margins.right 0874 } 0875 0876 elide: Text.ElideRight 0877 wrapMode: Text.NoWrap 0878 opacity: 1.0 0879 0880 color: "white" 0881 0882 level: 1 0883 0884 text: model.display 0885 textFormat: Text.PlainText 0886 } 0887 } 0888 0889 highlight: PlasmaExtras.Highlight { 0890 x: filterList.currentItem ? filterList.currentItem.x : 0 0891 y: filterList.currentItem ? filterList.currentItem.y : 0 0892 height: filterList.currentItem ? filterList.currentItem.height : 0 0893 width: (highlightItemSvg.margins.left 0894 + (filterList.currentItem ? filterList.currentItem.textWidth : 0) 0895 + highlightItemSvg.margins.right 0896 + Kirigami.Units.smallSpacing) 0897 0898 visible: filterList.currentItem 0899 active: filterListScrollArea.focus 0900 pressed: filterList.currentItem && filterList.currentItem.pressed 0901 } 0902 0903 highlightFollowsCurrentItem: false 0904 highlightMoveDuration: 0 0905 highlightResizeDuration: 0 0906 0907 onCurrentIndexChanged: applyFilter() 0908 0909 onCountChanged: { 0910 var width = 0; 0911 0912 for (var i = 0; i < rootModel.count; ++i) { 0913 headingMetrics.text = rootModel.labelForRow(i); 0914 0915 if (headingMetrics.width > width) { 0916 width = headingMetrics.width; 0917 } 0918 } 0919 0920 filterListColumn.columns = Math.ceil(width / root.cellSize); 0921 filterListScrollArea.width = width + hItemMargins + (Kirigami.Units.gridUnit * 2); 0922 } 0923 0924 function applyFilter() { 0925 if (!root.searching && currentIndex >= 0) { 0926 if (preloadAllAppsTimer.running) { 0927 preloadAllAppsTimer.stop(); 0928 } 0929 0930 var model = rootModel.modelForRow(currentIndex); 0931 0932 if (model.description === "KICKER_ALL_MODEL") { 0933 allAppsGrid.model = model; 0934 allApps = true; 0935 funnelModel.sourceModel = null; 0936 preloadAllAppsTimer.done = true; 0937 } else { 0938 funnelModel.sourceModel = model; 0939 allApps = false; 0940 } 0941 } else { 0942 funnelModel.sourceModel = null; 0943 allApps = false; 0944 } 0945 } 0946 0947 Keys.onPressed: event => { 0948 if (event.key === Qt.Key_Left) { 0949 event.accepted = true; 0950 0951 const currentRow = Math.max(0, Math.ceil(currentItem.y / mainGrid.cellHeight) - 1); 0952 mainColumn.tryActivate(currentRow, mainColumn.columns - 1); 0953 } else if (event.key === Qt.Key_Tab) { 0954 event.accepted = true; 0955 systemFavoritesGrid.tryActivate(0, 0); 0956 } else if (event.key === Qt.Key_Backtab) { 0957 event.accepted = true; 0958 mainColumn.tryActivate(0, 0); 0959 } 0960 } 0961 } 0962 } 0963 } 0964 } 0965 0966 onPressed: mouse => { 0967 if (mouse.button === Qt.RightButton) { 0968 contextMenu.open(mouse.x, mouse.y); 0969 } 0970 } 0971 0972 onClicked: mouse => { 0973 if (mouse.button === Qt.LeftButton) { 0974 root.toggle(); 0975 } 0976 } 0977 } 0978 0979 Component.onCompleted: { 0980 rootModel.refresh(); 0981 } 0982 }