Warning, /plasma/plasma-workspace/krunner/qml/RunCommand.qml is written in an unsupported language. File is not indexed.
0001 /* 0002 SPDX-FileCopyrightText: 2014 Marco Martin <mart@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 import QtQuick 2.15 0008 import QtQuick.Layouts 1.1 0009 import QtQuick.Window 2.1 0010 0011 import org.kde.kquickcontrolsaddons 2.0 // For KCMShell 0012 import org.kde.plasma.core 2.0 as PlasmaCore 0013 import org.kde.plasma.components 3.0 as PlasmaComponents3 0014 import org.kde.plasma.extras 2.0 as PlasmaExtras 0015 import org.kde.milou 0.1 as Milou 0016 0017 ColumnLayout { 0018 id: root 0019 property string query 0020 property string runner 0021 property bool showHistory: false 0022 property alias runnerManager: results.runnerManager 0023 0024 LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft 0025 LayoutMirroring.childrenInherit: true 0026 0027 onQueryChanged: { 0028 queryField.text = query; 0029 } 0030 0031 Connections { 0032 target: runnerWindow 0033 function onVisibleChanged() { 0034 if (runnerWindow.visible) { 0035 queryField.forceActiveFocus(); 0036 listView.currentIndex = -1 0037 if (runnerManager.retainPriorSearch) { 0038 // If we manually specified a query(D-Bus invocation) we don't want to retain the prior search 0039 if (!query) { 0040 queryField.text = runnerManager.priorSearch 0041 queryField.select(root.query.length, 0) 0042 } 0043 } 0044 } else { 0045 if (runnerManager.retainPriorSearch) { 0046 runnerManager.priorSearch = root.query 0047 } 0048 root.runner = "" 0049 root.query = "" 0050 root.showHistory = false 0051 } 0052 } 0053 } 0054 0055 Connections { 0056 target: root 0057 function onShowHistoryChanged() { 0058 if (showHistory) { 0059 // we store 50 entries in the history but only show 20 in the UI so it doesn't get too huge 0060 listView.model = runnerManager.history.slice(0, 20) 0061 } else { 0062 listView.model = [] 0063 } 0064 } 0065 } 0066 0067 RowLayout { 0068 Layout.alignment: Qt.AlignTop 0069 PlasmaComponents3.ToolButton { 0070 icon.name: "configure" 0071 onClicked: { 0072 runnerWindow.visible = false 0073 runnerWindow.displayConfiguration() 0074 } 0075 Accessible.name: i18n("Configure") 0076 Accessible.description: i18n("Configure KRunner Behavior") 0077 visible: KCMShell.authorize("kcm_krunnersettings.desktop").length > 0 0078 PlasmaComponents3.ToolTip { 0079 text: i18n("Configure KRunner…") 0080 } 0081 } 0082 PlasmaExtras.SearchField { 0083 id: queryField 0084 property bool allowCompletion: false 0085 0086 Layout.minimumWidth: PlasmaCore.Units.gridUnit * 25 0087 Layout.maximumWidth: PlasmaCore.Units.gridUnit * 25 0088 0089 activeFocusOnPress: true 0090 placeholderText: results.runnerName ? i18nc("Textfield placeholder text, query specific KRunner plugin", 0091 "Search '%1'…", results.runnerName) 0092 : i18nc("Textfield placeholder text", "Search…") 0093 0094 PlasmaComponents3.BusyIndicator { 0095 anchors { 0096 right: parent.right 0097 top: parent.top 0098 bottom: parent.bottom 0099 margins: PlasmaCore.Units.smallSpacing 0100 rightMargin: height 0101 } 0102 0103 Timer { 0104 id: queryTimer 0105 property bool queryDisplay: false 0106 running: results.querying 0107 repeat: true 0108 onRunningChanged: if (queryDisplay && !running) { 0109 queryDisplay = false 0110 } 0111 onTriggered: if (!queryDisplay) { 0112 queryDisplay = true 0113 } 0114 interval: 500 0115 } 0116 0117 running: queryTimer.queryDisplay 0118 } 0119 function move_up() { 0120 if (length === 0) { 0121 root.showHistory = true; 0122 } else if (results.count > 0) { 0123 results.decrementCurrentIndex(); 0124 } 0125 focusCurrentListView() 0126 } 0127 0128 function move_down() { 0129 if (length === 0) { 0130 root.showHistory = true; 0131 } else if (results.count > 0) { 0132 results.incrementCurrentIndex(); 0133 } 0134 focusCurrentListView() 0135 } 0136 0137 function focusCurrentListView() { 0138 if (listView.count > 0) { 0139 listView.forceActiveFocus(); 0140 } else if (results.count > 0) { 0141 results.forceActiveFocus(); 0142 } 0143 } 0144 0145 onTextChanged: { 0146 root.query = queryField.text 0147 if (allowCompletion && length > 0 && runnerManager.historyEnabled) { 0148 var oldText = text 0149 var suggestedText = runnerManager.getHistorySuggestion(text); 0150 if (suggestedText.length > 0) { 0151 text = text + suggestedText.substr(oldText.length) 0152 select(text.length, oldText.length) 0153 } 0154 } 0155 } 0156 Keys.onPressed: { 0157 allowCompletion = (event.key !== Qt.Key_Backspace && event.key !== Qt.Key_Delete) 0158 0159 if (event.modifiers & Qt.ControlModifier) { 0160 if (event.key === Qt.Key_J) { 0161 move_down() 0162 event.accepted = true; 0163 } else if (event.key === Qt.Key_K) { 0164 move_up() 0165 event.accepted = true; 0166 } 0167 } 0168 // We only need to handle the Key_End case, the first item is focused by default 0169 if (event.key === Qt.Key_End && results.count > 0 && cursorPosition === text.length) { 0170 results.currentIndex = results.count - 1 0171 event.accepted = true; 0172 focusCurrentListView() 0173 } 0174 } 0175 Keys.onUpPressed: move_up() 0176 Keys.onDownPressed: move_down() 0177 function closeOrRun(event) { 0178 // Close KRunner if no text was typed and enter was pressed, FEATURE: 211225 0179 if (!root.query) { 0180 runnerWindow.visible = false 0181 } else { 0182 results.runCurrentIndex(event) 0183 } 0184 } 0185 Keys.onEnterPressed: closeOrRun(event) 0186 Keys.onReturnPressed: closeOrRun(event) 0187 0188 Keys.onEscapePressed: { 0189 runnerWindow.visible = false 0190 } 0191 0192 PlasmaCore.SvgItem { 0193 anchors { 0194 right: parent.right 0195 rightMargin: 6 // from PlasmaStyle TextFieldStyle 0196 verticalCenter: parent.verticalCenter 0197 } 0198 // match clear button 0199 width: Math.max(parent.height * 0.8, PlasmaCore.Units.iconSizes.small) 0200 height: width 0201 svg: PlasmaCore.Svg { 0202 imagePath: "widgets/arrows" 0203 colorGroup: PlasmaCore.Theme.ButtonColorGroup 0204 } 0205 elementId: "down-arrow" 0206 visible: queryField.length === 0 && runnerManager.historyEnabled 0207 0208 MouseArea { 0209 anchors.fill: parent 0210 onPressed: { 0211 root.showHistory = !root.showHistory 0212 if (root.showHistory) { 0213 listView.forceActiveFocus(); // is the history list 0214 } else { 0215 queryField.forceActiveFocus(); 0216 } 0217 } 0218 } 0219 } 0220 } 0221 PlasmaComponents3.ToolButton { 0222 visible: runnerWindow.helpEnabled 0223 checkable: true 0224 checked: root.query.startsWith("?") 0225 // Reset if out quers starts with "?", otherwise set it to "?" 0226 onClicked: root.query = root.query.startsWith("?") ? "" : "?" 0227 icon.name: "question" 0228 Accessible.name: i18n("Show Usage Help") 0229 Accessible.description: i18n("Show Usage Help") 0230 PlasmaComponents3.ToolTip { 0231 text: i18n("Show Usage Help") 0232 } 0233 } 0234 PlasmaComponents3.ToolButton { 0235 checkable: true 0236 checked: runnerWindow.pinned 0237 onToggled: runnerWindow.pinned = checked 0238 icon.name: "window-pin" 0239 Accessible.name: i18n("Pin") 0240 Accessible.description: i18n("Pin Search") 0241 PlasmaComponents3.ToolTip { 0242 text: i18n("Keep Open") 0243 } 0244 } 0245 } 0246 0247 PlasmaComponents3.ScrollView { 0248 Layout.alignment: Qt.AlignTop 0249 visible: results.count > 0 0250 enabled: visible 0251 Layout.fillWidth: true 0252 Layout.preferredHeight: Math.min(Screen.height, results.contentHeight) 0253 // HACK: workaround for https://bugreports.qt.io/browse/QTBUG-83890 0254 PlasmaComponents3.ScrollBar.horizontal.policy: PlasmaComponents3.ScrollBar.AlwaysOff 0255 0256 Milou.ResultsView { 0257 id: results 0258 queryString: root.query 0259 runner: root.runner 0260 0261 Keys.onPressed: { 0262 var ctrl = event.modifiers & Qt.ControlModifier; 0263 if (ctrl && event.key === Qt.Key_J) { 0264 incrementCurrentIndex() 0265 } else if (ctrl && event.key === Qt.Key_K) { 0266 decrementCurrentIndex() 0267 } else if (event.key === Qt.Key_Home) { 0268 results.currentIndex = 0 0269 } else if (event.key === Qt.Key_End) { 0270 results.currentIndex = results.count - 1 0271 } else if (event.text !== "") { 0272 // This prevents unprintable control characters from being inserted 0273 if (!/[\x00-\x1F\x7F]/.test(event.text)) { 0274 queryField.text += event.text; 0275 } 0276 queryField.cursorPosition = queryField.text.length 0277 queryField.focus = true; 0278 } 0279 } 0280 0281 Keys.onEscapePressed: { 0282 runnerWindow.visible = false 0283 } 0284 0285 onActivated: { 0286 if (!runnerWindow.pinned) { 0287 runnerWindow.visible = false 0288 } 0289 } 0290 0291 onUpdateQueryString: { 0292 queryField.text = text 0293 queryField.select(cursorPosition, root.query.length) 0294 queryField.focus = true; 0295 } 0296 } 0297 } 0298 0299 PlasmaComponents3.ScrollView { 0300 Layout.alignment: Qt.AlignTop 0301 Layout.fillWidth: true 0302 visible: root.query.length === 0 && listView.count > 0 0303 // don't accept keyboard input when not visible so the keys propagate to the other list 0304 enabled: visible 0305 Layout.preferredHeight: Math.min(Screen.height, listView.contentHeight) 0306 // HACK: workaround for https://bugreports.qt.io/browse/QTBUG-83890 0307 PlasmaComponents3.ScrollBar.horizontal.policy: PlasmaComponents3.ScrollBar.AlwaysOff 0308 0309 ListView { 0310 id: listView // needs this id so the delegate can access it 0311 keyNavigationWraps: true 0312 highlight: PlasmaExtras.Highlight {} 0313 highlightMoveDuration: 0 0314 activeFocusOnTab: true 0315 model: [] 0316 reuseItems: true 0317 delegate: Milou.ResultDelegate { 0318 id: resultDelegate 0319 width: listView.width 0320 typeText: index === 0 ? i18n("Recent Queries") : "" 0321 additionalActions: [{ 0322 icon: "list-remove", 0323 text: i18n("Remove") 0324 }] 0325 Accessible.description: i18n("Recent Queries") 0326 } 0327 0328 onActiveFocusChanged: { 0329 if (!activeFocus && currentIndex == listView.count-1) { 0330 currentIndex = 0; 0331 } 0332 } 0333 Keys.onReturnPressed: runCurrentIndex(event) 0334 Keys.onEnterPressed: runCurrentIndex(event) 0335 0336 Keys.onTabPressed: { 0337 if (currentIndex == listView.count-1) { 0338 listView.nextItemInFocusChain(true).forceActiveFocus(); 0339 } else { 0340 incrementCurrentIndex() 0341 } 0342 } 0343 Keys.onBacktabPressed: { 0344 if (currentIndex == 0) { 0345 listView.nextItemInFocusChain(false).forceActiveFocus(); 0346 } else { 0347 decrementCurrentIndex() 0348 } 0349 } 0350 Keys.onPressed: { 0351 var ctrl = event.modifiers & Qt.ControlModifier; 0352 if (ctrl && event.key === Qt.Key_J) { 0353 incrementCurrentIndex() 0354 } else if (ctrl && event.key === Qt.Key_K) { 0355 decrementCurrentIndex() 0356 } else if (event.key === Qt.Key_Home) { 0357 currentIndex = 0 0358 } else if (event.key === Qt.Key_End) { 0359 currentIndex = count - 1 0360 } else if (event.text !== "") { 0361 // This prevents unprintable control characters from being inserted 0362 if (event.key == Qt.Key_Escape) { 0363 root.showHistory = false 0364 } else if (!/[\x00-\x1F\x7F]/.test(event.text)) { 0365 queryField.text += event.text; 0366 } 0367 queryField.focus = true; 0368 } 0369 } 0370 0371 Keys.onUpPressed: decrementCurrentIndex() 0372 Keys.onDownPressed: incrementCurrentIndex() 0373 0374 function runCurrentIndex(event) { 0375 var entry = runnerManager.history[currentIndex] 0376 if (entry) { 0377 // If user presses Shift+Return to invoke an action, invoke the first runner action 0378 if (event && event.modifiers === Qt.ShiftModifier 0379 && currentItem.additionalActions && currentItem.additionalActions.length > 0) { 0380 runAction(0); 0381 return 0382 } 0383 0384 queryField.text = entry 0385 queryField.forceActiveFocus(); 0386 } 0387 } 0388 0389 function runAction(actionIndex) { 0390 if (actionIndex === 0) { 0391 // QStringList changes just reset the model, so we'll remember the index and set it again 0392 var currentIndex = listView.currentIndex 0393 runnerManager.removeFromHistory(currentIndex) 0394 model = runnerManager.history 0395 listView.currentIndex = currentIndex 0396 } 0397 } 0398 } 0399 0400 } 0401 }