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