Warning, /frameworks/qqc2-desktop-style/org.kde.desktop/private/TextFieldContextMenu.qml is written in an unsupported language. File is not indexed.
0001 /* 0002 SPDX-FileCopyrightText: 2020 Devin Lin <espidev@gmail.com> 0003 SPDX-FileCopyrightText: 2021 Carl Schwan <carlschwan@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 pragma Singleton 0009 0010 import QtQuick 2.6 0011 import QtQml 2.2 0012 import QtQuick.Controls 2.15 0013 import org.kde.kirigami 2.5 as Kirigami 0014 0015 Menu { 0016 id: contextMenu 0017 0018 property Item target 0019 property bool deselectWhenMenuClosed: true 0020 property int restoredCursorPosition: 0 0021 property int restoredSelectionStart 0022 property int restoredSelectionEnd 0023 property bool persistentSelectionSetting 0024 property var spellcheckhighlighter: null 0025 property var spellcheckhighlighterLoader: null 0026 property var suggestions: [] 0027 Component.onCompleted: persistentSelectionSetting = persistentSelectionSetting // break binding 0028 0029 property var runOnMenuClose: () => {} 0030 0031 parent: Overlay.overlay 0032 0033 function storeCursorAndSelection() { 0034 contextMenu.restoredCursorPosition = target.cursorPosition; 0035 contextMenu.restoredSelectionStart = target.selectionStart; 0036 contextMenu.restoredSelectionEnd = target.selectionEnd; 0037 } 0038 0039 // target is pressed with mouse 0040 function targetClick(handlerPoint, newTarget, spellcheckhighlighter, mousePosition) { 0041 if (handlerPoint.pressedButtons === Qt.RightButton) { // only accept just right click 0042 if (contextMenu.visible) { 0043 deselectWhenMenuClosed = false; // don't deselect text if menu closed by right click on textfield 0044 dismiss(); 0045 } else { 0046 contextMenu.target = newTarget; 0047 contextMenu.target.persistentSelection = true; // persist selection when menu is opened 0048 contextMenu.spellcheckhighlighterLoader = spellcheckhighlighter; 0049 if (spellcheckhighlighter && spellcheckhighlighter.active) { 0050 contextMenu.spellcheckhighlighter = spellcheckhighlighter.item; 0051 contextMenu.suggestions = mousePosition ? spellcheckhighlighter.item.suggestions(mousePosition) : []; 0052 } else { 0053 contextMenu.spellcheckhighlighter = null; 0054 contextMenu.suggestions = []; 0055 } 0056 storeCursorAndSelection(); 0057 popup(contextMenu.target); 0058 // slightly locate context menu away from mouse so no item is selected when menu is opened 0059 x += 1 0060 y += 1 0061 } 0062 } else { 0063 dismiss(); 0064 } 0065 } 0066 0067 // context menu keyboard key 0068 function targetKeyPressed(event, newTarget) { 0069 if (event.modifiers === Qt.NoModifier && event.key === Qt.Key_Menu) { 0070 contextMenu.target = newTarget; 0071 target.persistentSelection = true; // persist selection when menu is opened 0072 storeCursorAndSelection(); 0073 popup(contextMenu.target); 0074 } 0075 } 0076 0077 readonly property bool targetIsPassword: target !== null && (target.echoMode === TextInput.PasswordEchoOnEdit || target.echoMode === TextInput.Password) 0078 0079 onAboutToShow: { 0080 if (Overlay.overlay) { 0081 let tempZ = 0 0082 for (let i in Overlay.overlay.visibleChildren) { 0083 tempZ = Math.max(tempZ, Overlay.overlay.visibleChildren[i].z) 0084 } 0085 z = tempZ + 1 0086 } 0087 } 0088 0089 // deal with whether or not text should be deselected 0090 onClosed: { 0091 // restore text field's original persistent selection setting 0092 target.persistentSelection = persistentSelectionSetting 0093 // deselect text field text if menu is closed not because of a right click on the text field 0094 if (deselectWhenMenuClosed) { 0095 target.deselect(); 0096 } 0097 deselectWhenMenuClosed = true; 0098 0099 // restore cursor position 0100 target.forceActiveFocus(); 0101 target.cursorPosition = restoredCursorPosition; 0102 target.select(restoredSelectionStart, restoredSelectionEnd); 0103 0104 // run action, and free memory 0105 runOnMenuClose(); 0106 runOnMenuClose = () => {}; 0107 } 0108 0109 onOpened: { 0110 runOnMenuClose = () => {}; 0111 } 0112 0113 Instantiator { 0114 active: target !== null && !target.readOnly && spellcheckhighlighter !== null && spellcheckhighlighter.active && spellcheckhighlighter.wordIsMisspelled 0115 model: suggestions 0116 delegate: MenuItem { 0117 text: modelData 0118 onClicked: { 0119 deselectWhenMenuClosed = false; 0120 runOnMenuClose = () => spellcheckhighlighter.replaceWord(modelData); 0121 } 0122 } 0123 onObjectAdded: { 0124 contextMenu.insertItem(0, object) 0125 } 0126 onObjectRemoved: contextMenu.removeItem(0) 0127 } 0128 0129 MenuItem { 0130 visible: target !== null && !target.readOnly && spellcheckhighlighter !== null && spellcheckhighlighter.active && spellcheckhighlighter.wordIsMisspelled && suggestions.length === 0 0131 action: Action { 0132 text: spellcheckhighlighter ? qsTr("No suggestions for \"%1\"").arg(spellcheckhighlighter.wordUnderMouse) : '' 0133 enabled: false 0134 } 0135 } 0136 0137 MenuItem { 0138 visible: target !== null && !target.readOnly && spellcheckhighlighter !== null && spellcheckhighlighter.active && spellcheckhighlighter.wordIsMisspelled 0139 action: Action { 0140 text: spellcheckhighlighter ? qsTr("Add \"%1\" to dictionary").arg(spellcheckhighlighter.wordUnderMouse) : '' 0141 onTriggered: { 0142 deselectWhenMenuClosed = false; 0143 runOnMenuClose = () => spellcheckhighlighter.addWordToDictionary(spellcheckhighlighter.wordUnderMouse); 0144 } 0145 } 0146 } 0147 0148 MenuItem { 0149 visible: target !== null && !target.readOnly && spellcheckhighlighter !== null && spellcheckhighlighter.active && spellcheckhighlighter.wordIsMisspelled 0150 action: Action { 0151 text: qsTr("Ignore") 0152 onTriggered: { 0153 deselectWhenMenuClosed = false; 0154 runOnMenuClose = () => spellcheckhighlighter.ignoreWord(spellcheckhighlighter.wordUnderMouse); 0155 } 0156 } 0157 } 0158 0159 MenuItem { 0160 visible: target !== null && !target.readOnly && spellcheckhighlighterLoader && spellcheckhighlighterLoader.activable 0161 checkable: true 0162 checked: spellcheckhighlighter ? spellcheckhighlighter.active : false 0163 text: qsTr("Enable Spellchecker") 0164 onCheckedChanged: { 0165 spellcheckhighlighterLoader.active = checked; 0166 spellcheckhighlighter = spellcheckhighlighterLoader.item; 0167 } 0168 } 0169 0170 MenuSeparator { 0171 visible: target !== null && !target.readOnly && ((spellcheckhighlighter !== null && spellcheckhighlighter.active && spellcheckhighlighter.wordIsMisspelled) || (spellcheckhighlighterLoader && spellcheckhighlighterLoader.activable)) 0172 } 0173 0174 MenuItem { 0175 visible: target !== null && !target.readOnly && !targetIsPassword 0176 action: Action { 0177 icon.name: "edit-undo-symbolic" 0178 text: qsTr("Undo") 0179 shortcut: StandardKey.Undo 0180 } 0181 enabled: target !== null && target.canUndo 0182 onTriggered: { 0183 deselectWhenMenuClosed = false; 0184 runOnMenuClose = () => target.undo(); 0185 } 0186 } 0187 MenuItem { 0188 visible: target !== null && !target.readOnly && !targetIsPassword 0189 action: Action { 0190 icon.name: "edit-redo-symbolic" 0191 text: qsTr("Redo") 0192 shortcut: StandardKey.Redo 0193 } 0194 enabled: target !== null && target.canRedo 0195 onTriggered: { 0196 deselectWhenMenuClosed = false; 0197 runOnMenuClose = () => target.redo(); 0198 } 0199 } 0200 MenuSeparator { 0201 visible: target !== null && !target.readOnly && !targetIsPassword 0202 } 0203 MenuItem { 0204 visible: target !== null && !target.readOnly && !targetIsPassword 0205 action: Action { 0206 icon.name: "edit-cut-symbolic" 0207 text: qsTr("Cut") 0208 shortcut: StandardKey.Cut 0209 } 0210 enabled: target !== null && target.selectedText 0211 onTriggered: { 0212 deselectWhenMenuClosed = false; 0213 runOnMenuClose = () => target.cut(); 0214 } 0215 } 0216 MenuItem { 0217 action: Action { 0218 icon.name: "edit-copy-symbolic" 0219 text: qsTr("Copy") 0220 shortcut: StandardKey.Copy 0221 } 0222 enabled: target !== null && target.selectedText 0223 visible: !targetIsPassword 0224 onTriggered: { 0225 deselectWhenMenuClosed = false; 0226 runOnMenuClose = () => target.copy(); 0227 } 0228 } 0229 MenuItem { 0230 visible: target !== null && !target.readOnly 0231 action: Action { 0232 icon.name: "edit-paste-symbolic" 0233 text: qsTr("Paste") 0234 shortcut: StandardKey.Paste 0235 } 0236 enabled: target !== null && target.canPaste 0237 onTriggered: { 0238 deselectWhenMenuClosed = false; 0239 runOnMenuClose = () => target.paste(); 0240 } 0241 } 0242 MenuItem { 0243 visible: target !== null && !target.readOnly 0244 action: Action { 0245 icon.name: "edit-delete-symbolic" 0246 text: qsTr("Delete") 0247 shortcut: StandardKey.Delete 0248 } 0249 enabled: target !== null && target.selectedText 0250 onTriggered: { 0251 deselectWhenMenuClosed = false; 0252 runOnMenuClose = () => target.remove(target.selectionStart, target.selectionEnd); 0253 } 0254 } 0255 MenuSeparator { 0256 visible: !targetIsPassword 0257 } 0258 MenuItem { 0259 action: Action { 0260 icon.name: "edit-select-all-symbolic" 0261 text: qsTr("Select All") 0262 shortcut: StandardKey.SelectAll 0263 } 0264 visible: !targetIsPassword 0265 onTriggered: { 0266 deselectWhenMenuClosed = false; 0267 runOnMenuClose = () => target.selectAll(); 0268 } 0269 } 0270 }