Warning, /plasma/milou/lib/qml/ResultsView.qml is written in an unsupported language. File is not indexed.

0001 /*
0002  * This file is part of the KDE Milou Project
0003  * SPDX-FileCopyrightText: 2013-2014 Vishesh Handa <me@vhanda.in>
0004  *
0005  * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0006  *
0007  */
0008 
0009 import QtQuick
0010 import QtQuick.Templates as T
0011 
0012 import org.kde.plasma.extras 2.0 as PlasmaExtras
0013 import org.kde.kirigami 2.20 as Kirigami
0014 import org.kde.milou 0.3 as Milou
0015 
0016 ListView {
0017     id: listView
0018     property alias queryString: resultModel.queryString
0019     property alias singleRunner: resultModel.singleRunner
0020     property alias runnerManager: resultModel.runnerManager
0021 
0022     property alias singleRunnerMetaData: resultModel.singleRunnerMetaData
0023     property alias querying: resultModel.querying
0024     property alias limit: resultModel.limit
0025     property bool reversed
0026     signal activated
0027     signal updateQueryString(string text, int cursorPosition)
0028 
0029     // NOTE this also flips increment/decrementCurrentIndex (Bug 360789)
0030     verticalLayoutDirection: reversed ? ListView.BottomToTop : ListView.TopToBottom
0031     keyNavigationWraps: true
0032     highlight: PlasmaExtras.Highlight {
0033         pressed: (listView.currentItem as T.AbstractButton)?.down ?? false
0034     }
0035     highlightMoveDuration: 0
0036     activeFocusOnTab: true
0037     Accessible.role: Accessible.List
0038 
0039     section {
0040         criteria: ViewSection.FullString
0041         property: "category"
0042     }
0043 
0044     // This is used to keep track if the user has pressed enter before
0045     // the first result has been shown, in the case the first result should
0046     // be run when the model is populated
0047     property bool runAutomatically
0048 
0049     // This is used to disable mouse selection if the user interacts only with keyboard
0050     property bool moved: false
0051     property point savedMousePosition: Milou.MouseHelper.globalMousePosition()
0052     function mouseMovedGlobally() {
0053         return savedMousePosition != Milou.MouseHelper.globalMousePosition();
0054     }
0055 
0056     model: Milou.ResultsModel {
0057         id: resultModel
0058         limit: 15
0059         onQueryStringChangeRequested: {
0060             listView.updateQueryString(queryString, pos)
0061         }
0062         onQueryStringChanged: () => {
0063             resetView();
0064             // Do not run the results automatically, if the query changed since we pressed enter
0065             // BUG: 459859
0066             runAutomatically = false;
0067         }
0068         onModelReset: resetView()
0069 
0070         onRowsInserted: {
0071             // Keep the selection at the top as items inserted to the beginning will shift it downwards
0072             // ListView will update its view after this signal is processed and then our callLater will set it back
0073             if (listView.currentIndex === 0) {
0074                 Qt.callLater(function() {
0075                     listView.currentIndex = 0;
0076                 });
0077             }
0078 
0079             if (runAutomatically) {
0080                 // This needs to be delayed as running a result may close the window and clear the query
0081                 // having us reset the model whilst in the middle of processing the insertion.
0082                 // The proxy model chain that comes after us really doesn't like this.
0083                 Qt.callLater(function() {
0084                     resultModel.run(resultModel.index(0, 0));
0085                     listView.activated();
0086                 });
0087 
0088                 runAutomatically = false;
0089             }
0090         }
0091 
0092         function resetView() {
0093             listView.currentIndex = 0;
0094             listView.moved = false;
0095             listView.savedMousePosition = Milou.MouseHelper.globalMousePosition();
0096         }
0097     }
0098 
0099     delegate: ResultDelegate {
0100         id: resultDelegate
0101         width: listView.width
0102         reversed: listView.reversed
0103     }
0104 
0105     //
0106     // vHanda: Ideally this should have gotten handled in the delagte's onReturnPressed
0107     // code, but the ListView doesn't seem forward keyboard events to the delgate when
0108     // it is not in activeFocus. Even manually adding Keys.forwardTo: resultDelegate
0109     // doesn't make any difference!
0110     Keys.onReturnPressed: event => runCurrentIndex(event);
0111     Keys.onEnterPressed: event => runCurrentIndex(event);
0112 
0113     function runCurrentIndex(event) {
0114         if (!currentItem) {
0115             runAutomatically = true
0116             return;
0117         } else {
0118             // If user presses Shift+Return to invoke an action, invoke the first runner action
0119             if (event && event.modifiers === Qt.ShiftModifier
0120                     && currentItem.additionalActions && currentItem.additionalActions.length > 0) {
0121                 runAction(0)
0122                 return
0123             }
0124 
0125             if (currentItem.activeAction > -1) {
0126                 runAction(currentItem.activeAction)
0127                 return
0128             }
0129 
0130             if (resultModel.run(resultModel.index(currentIndex, 0))) {
0131                 activated()
0132             }
0133             runAutomatically = false
0134         }
0135     }
0136 
0137     function runAction(index) {
0138         if (resultModel.runAction(resultModel.index(currentIndex, 0), index)) {
0139             activated()
0140         }
0141     }
0142 
0143     onActiveFocusChanged: {
0144         if (!activeFocus && currentIndex == listView.count-1) {
0145             currentIndex = 0;
0146         }
0147     }
0148 
0149     Keys.onTabPressed: {
0150         if (!currentItem || !currentItem.activateNextAction()) {
0151             if (reversed) {
0152                 if (currentIndex == 0) {
0153                     listView.nextItemInFocusChain(false).forceActiveFocus();
0154                     return;
0155                 }
0156                 decrementCurrentIndex()
0157             } else {
0158                 if (currentIndex == listView.count-1) {
0159                     listView.nextItemInFocusChain(true).forceActiveFocus();
0160                     return;
0161                 }
0162                 incrementCurrentIndex()
0163             }
0164         }
0165     }
0166     Keys.onBacktabPressed: {
0167         if (!currentItem || !currentItem.activatePreviousAction()) {
0168             if (reversed) {
0169                 if (currentIndex == listView.count-1) {
0170                     listView.nextItemInFocusChain(true).forceActiveFocus();
0171                     return;
0172                 }
0173                 incrementCurrentIndex()
0174             } else {
0175                 if (currentIndex == 0) {
0176                     listView.nextItemInFocusChain(false).forceActiveFocus();
0177                     return;
0178                 }
0179                 decrementCurrentIndex()
0180             }
0181 
0182             // activate previous action cannot know whether we want to back tab from an action
0183             // to the main result or back tab from another search result, so we explicitly highlight
0184             // the last action here to provide a consistent navigation experience
0185             if (currentItem) {
0186                 currentItem.activateLastAction()
0187             }
0188         }
0189     }
0190     Keys.onUpPressed: reversed ? incrementCurrentIndex() : decrementCurrentIndex();
0191     Keys.onDownPressed: reversed ? decrementCurrentIndex() : incrementCurrentIndex();
0192 
0193     boundsBehavior: Flickable.StopAtBounds
0194 
0195     function loadSettings() {
0196         resultModel.loadSettings()
0197     }
0198 
0199     function setQueryString(queryString) {
0200         resultModel.queryString = queryString
0201         runAutomatically = false
0202     }
0203 
0204     // Save drag data
0205     Item {
0206         id: dragHelper
0207         Drag.dragType: Drag.Automatic
0208         Drag.supportedActions: Qt.CopyAction | Qt.LinkAction
0209         Drag.onDragFinished: {
0210             Drag.mimeData = {};
0211             Drag.imageSource = "";
0212         }
0213     }
0214 }