2 |
2 |
3 # Copyright (c) 2003 - 2013 Detlev Offenbach <detlev@die-offenbachs.de> |
3 # Copyright (c) 2003 - 2013 Detlev Offenbach <detlev@die-offenbachs.de> |
4 # |
4 # |
5 |
5 |
6 """ |
6 """ |
7 Module implementing a dialog for the configuration of eric5s keyboard shortcuts. |
7 Module implementing a dialog for the configuration of eric5's keyboard |
|
8 shortcuts. |
8 """ |
9 """ |
9 |
10 |
10 from PyQt4.QtCore import pyqtSignal, QRegExp, Qt, pyqtSlot |
11 from PyQt4.QtCore import pyqtSignal, QRegExp, Qt, pyqtSlot |
11 from PyQt4.QtGui import QKeySequence, QHeaderView, QDialog, QTreeWidgetItem |
12 from PyQt4.QtGui import QKeySequence, QHeaderView, QDialog, QTreeWidgetItem |
12 |
13 |
19 from Preferences import Shortcuts |
20 from Preferences import Shortcuts |
20 |
21 |
21 |
22 |
22 class ShortcutsDialog(QDialog, Ui_ShortcutsDialog): |
23 class ShortcutsDialog(QDialog, Ui_ShortcutsDialog): |
23 """ |
24 """ |
24 Class implementing a dialog for the configuration of eric5s keyboard shortcuts. |
25 Class implementing a dialog for the configuration of eric5's keyboard |
25 |
26 shortcuts. |
26 @signal updateShortcuts() emitted when the user pressed the dialogs OK button |
27 |
|
28 @signal updateShortcuts() emitted when the user pressed the dialogs OK |
|
29 button |
27 """ |
30 """ |
28 updateShortcuts = pyqtSignal() |
31 updateShortcuts = pyqtSignal() |
29 |
32 |
30 objectNameRole = Qt.UserRole |
33 objectNameRole = Qt.UserRole |
31 noCheckRole = Qt.UserRole + 1 |
34 noCheckRole = Qt.UserRole + 1 |
43 if name: |
46 if name: |
44 self.setObjectName(name) |
47 self.setObjectName(name) |
45 self.setModal(modal) |
48 self.setModal(modal) |
46 self.setupUi(self) |
49 self.setupUi(self) |
47 |
50 |
48 self.shortcutsList.headerItem().setText(self.shortcutsList.columnCount(), "") |
51 self.shortcutsList.headerItem().setText( |
|
52 self.shortcutsList.columnCount(), "") |
49 self.shortcutsList.header().setSortIndicator(0, Qt.AscendingOrder) |
53 self.shortcutsList.header().setSortIndicator(0, Qt.AscendingOrder) |
50 |
54 |
51 from .ShortcutDialog import ShortcutDialog |
55 from .ShortcutDialog import ShortcutDialog |
52 self.shortcutDialog = ShortcutDialog() |
56 self.shortcutDialog = ShortcutDialog() |
53 self.shortcutDialog.shortcutChanged.connect(self.__shortcutChanged) |
57 self.shortcutDialog.shortcutChanged.connect(self.__shortcutChanged) |
61 |
65 |
62 def __resizeColumns(self): |
66 def __resizeColumns(self): |
63 """ |
67 """ |
64 Private method to resize the list columns. |
68 Private method to resize the list columns. |
65 """ |
69 """ |
66 self.shortcutsList.header().resizeSections(QHeaderView.ResizeToContents) |
70 self.shortcutsList.header().resizeSections( |
|
71 QHeaderView.ResizeToContents) |
67 self.shortcutsList.header().setStretchLastSection(True) |
72 self.shortcutsList.header().setStretchLastSection(True) |
68 |
73 |
69 def __generateCategoryItem(self, title): |
74 def __generateCategoryItem(self, title): |
70 """ |
75 """ |
71 Private method to generate a category item. |
76 Private method to generate a category item. |
84 |
89 |
85 @param category reference to the category item (QTreeWidgetItem) |
90 @param category reference to the category item (QTreeWidgetItem) |
86 @param action reference to the keyboard action (E5Action) |
91 @param action reference to the keyboard action (E5Action) |
87 @keyparam noCheck flag indicating that no uniqueness check should |
92 @keyparam noCheck flag indicating that no uniqueness check should |
88 be performed (boolean) |
93 be performed (boolean) |
89 @keyparam objectType type of the object (string). Objects of the same type |
94 @keyparam objectType type of the object (string). Objects of the same |
90 are not checked for duplicate shortcuts. |
95 type are not checked for duplicate shortcuts. |
91 """ |
96 """ |
92 itm = QTreeWidgetItem(category, |
97 itm = QTreeWidgetItem(category, |
93 [action.iconText(), action.shortcut().toString(), |
98 [action.iconText(), action.shortcut().toString(), |
94 action.alternateShortcut().toString()]) |
99 action.alternateShortcut().toString()]) |
95 itm.setIcon(0, action.icon()) |
100 itm.setIcon(0, action.icon()) |
148 |
153 |
149 self.macroItem = self.__generateCategoryItem(self.trUtf8("Macro")) |
154 self.macroItem = self.__generateCategoryItem(self.trUtf8("Macro")) |
150 for act in e5App().getObject("ViewManager").getActions('macro'): |
155 for act in e5App().getObject("ViewManager").getActions('macro'): |
151 self.__generateShortcutItem(self.macroItem, act) |
156 self.__generateShortcutItem(self.macroItem, act) |
152 |
157 |
153 self.bookmarkItem = self.__generateCategoryItem(self.trUtf8("Bookmarks")) |
158 self.bookmarkItem = self.__generateCategoryItem( |
|
159 self.trUtf8("Bookmarks")) |
154 for act in e5App().getObject("ViewManager").getActions('bookmark'): |
160 for act in e5App().getObject("ViewManager").getActions('bookmark'): |
155 self.__generateShortcutItem(self.bookmarkItem, act) |
161 self.__generateShortcutItem(self.bookmarkItem, act) |
156 |
162 |
157 self.spellingItem = self.__generateCategoryItem(self.trUtf8("Spelling")) |
163 self.spellingItem = self.__generateCategoryItem( |
|
164 self.trUtf8("Spelling")) |
158 for act in e5App().getObject("ViewManager").getActions('spelling'): |
165 for act in e5App().getObject("ViewManager").getActions('spelling'): |
159 self.__generateShortcutItem(self.spellingItem, act) |
166 self.__generateShortcutItem(self.spellingItem, act) |
160 |
167 |
161 actions = e5App().getObject("ViewManager").getActions('window') |
168 actions = e5App().getObject("ViewManager").getActions('window') |
162 if actions: |
169 if actions: |
163 self.windowItem = self.__generateCategoryItem(self.trUtf8("Window")) |
170 self.windowItem = self.__generateCategoryItem( |
|
171 self.trUtf8("Window")) |
164 for act in actions: |
172 for act in actions: |
165 self.__generateShortcutItem(self.windowItem, act) |
173 self.__generateShortcutItem(self.windowItem, act) |
166 |
174 |
167 self.pluginCategoryItems = [] |
175 self.pluginCategoryItems = [] |
168 for category, ref in e5App().getPluginObjects(): |
176 for category, ref in e5App().getPluginObjects(): |
194 if itm.childCount(): |
202 if itm.childCount(): |
195 return |
203 return |
196 |
204 |
197 self.__editTopItem = itm.parent() |
205 self.__editTopItem = itm.parent() |
198 |
206 |
199 self.shortcutDialog.setKeys(QKeySequence(itm.text(1)), QKeySequence(itm.text(2)), |
207 self.shortcutDialog.setKeys( |
|
208 QKeySequence(itm.text(1)), |
|
209 QKeySequence(itm.text(2)), |
200 itm.data(0, self.noCheckRole), |
210 itm.data(0, self.noCheckRole), |
201 itm.data(0, self.objectTypeRole)) |
211 itm.data(0, self.objectTypeRole)) |
202 self.shortcutDialog.show() |
212 self.shortcutDialog.show() |
203 |
213 |
204 def on_shortcutsList_itemClicked(self, itm, column): |
214 def on_shortcutsList_itemClicked(self, itm, column): |
229 itm.setText(column, "") |
239 itm.setText(column, "") |
230 else: |
240 else: |
231 itm.setText(column, keystr) |
241 itm.setText(column, keystr) |
232 self.shortcutsList.closePersistentEditor(itm, column) |
242 self.shortcutsList.closePersistentEditor(itm, column) |
233 |
243 |
234 def __shortcutChanged(self, keysequence, altKeysequence, noCheck, objectType): |
244 def __shortcutChanged(self, keysequence, altKeysequence, noCheck, |
235 """ |
245 objectType): |
236 Private slot to handle the shortcutChanged signal of the shortcut dialog. |
246 """ |
|
247 Private slot to handle the shortcutChanged signal of the shortcut |
|
248 dialog. |
237 |
249 |
238 @param keysequence the keysequence of the changed action (QKeySequence) |
250 @param keysequence the keysequence of the changed action (QKeySequence) |
239 @param altKeysequence the alternative keysequence of the changed |
251 @param altKeysequence the alternative keysequence of the changed |
240 action (QKeySequence) |
252 action (QKeySequence) |
241 @param noCheck flag indicating that no uniqueness check should |
253 @param noCheck flag indicating that no uniqueness check should |
242 be performed (boolean) |
254 be performed (boolean) |
243 @param objectType type of the object (string). |
255 @param objectType type of the object (string). |
244 """ |
256 """ |
245 if not noCheck and \ |
257 if not noCheck and \ |
246 (not self.__checkShortcut(keysequence, objectType, self.__editTopItem) or \ |
258 (not self.__checkShortcut( |
247 not self.__checkShortcut(altKeysequence, objectType, self.__editTopItem)): |
259 keysequence, objectType, self.__editTopItem) or \ |
|
260 not self.__checkShortcut( |
|
261 altKeysequence, objectType, self.__editTopItem)): |
248 return |
262 return |
249 |
263 |
250 self.shortcutsList.currentItem().setText(1, keysequence.toString()) |
264 self.shortcutsList.currentItem().setText(1, keysequence.toString()) |
251 self.shortcutsList.currentItem().setText(2, altKeysequence.toString()) |
265 self.shortcutsList.currentItem().setText(2, altKeysequence.toString()) |
252 |
266 |
285 topItem != origTopItem: |
299 topItem != origTopItem: |
286 continue |
300 continue |
287 |
301 |
288 # 3. check key name |
302 # 3. check key name |
289 if itm.text(0) != keyname: |
303 if itm.text(0) != keyname: |
290 for col in [1, 2]: # check against primary, then alternative binding |
304 for col in [1, 2]: # check against primary, |
|
305 # then alternative binding |
291 itmseq = itm.text(col) |
306 itmseq = itm.text(col) |
292 # step 1: check if shortcut is already allocated |
307 # step 1: check if shortcut is already allocated |
293 if keystr == itmseq: |
308 if keystr == itmseq: |
294 res = E5MessageBox.yesNo(self, |
309 res = E5MessageBox.yesNo(self, |
295 self.trUtf8("Edit shortcuts"), |
310 self.trUtf8("Edit shortcuts"), |
296 self.trUtf8( |
311 self.trUtf8( |
297 """<p><b>{0}</b> has already been allocated""" |
312 """<p><b>{0}</b> has already been""" |
298 """ to the <b>{1}</b> action. """ |
313 """ allocated to the <b>{1}</b> action. """ |
299 """Remove this binding?</p>""") |
314 """Remove this binding?</p>""") |
300 .format(keystr, itm.text(0)), |
315 .format(keystr, itm.text(0)), |
301 icon=E5MessageBox.Warning) |
316 icon=E5MessageBox.Warning) |
302 if res: |
317 if res: |
303 itm.setText(col, "") |
318 itm.setText(col, "") |
311 # step 2: check if shortcut hides an already allocated |
326 # step 2: check if shortcut hides an already allocated |
312 if itmseq.startswith("{0}+".format(keystr)): |
327 if itmseq.startswith("{0}+".format(keystr)): |
313 res = E5MessageBox.yesNo(self, |
328 res = E5MessageBox.yesNo(self, |
314 self.trUtf8("Edit shortcuts"), |
329 self.trUtf8("Edit shortcuts"), |
315 self.trUtf8( |
330 self.trUtf8( |
316 """<p><b>{0}</b> hides the <b>{1}</b> action. """ |
331 """<p><b>{0}</b> hides the <b>{1}</b>""" |
317 """Remove this binding?</p>""") |
332 """ action. Remove this binding?</p>""") |
318 .format(keystr, itm.text(0)), |
333 .format(keystr, itm.text(0)), |
319 icon=E5MessageBox.Warning) |
334 icon=E5MessageBox.Warning) |
320 if res: |
335 if res: |
321 itm.setText(col, "") |
336 itm.setText(col, "") |
322 return True |
337 return True |
323 else: |
338 else: |
324 return False |
339 return False |
325 |
340 |
326 # step 3: check if shortcut is hidden by an already allocated |
341 # step 3: check if shortcut is hidden by an |
|
342 # already allocated |
327 if keystr.startswith("{0}+".format(itmseq)): |
343 if keystr.startswith("{0}+".format(itmseq)): |
328 res = E5MessageBox.yesNo(self, |
344 res = E5MessageBox.yesNo(self, |
329 self.trUtf8("Edit shortcuts"), |
345 self.trUtf8("Edit shortcuts"), |
330 self.trUtf8( |
346 self.trUtf8( |
331 """<p><b>{0}</b> is hidden by the """ |
347 """<p><b>{0}</b> is hidden by the """ |
352 itm = category.child(index) |
368 itm = category.child(index) |
353 txt = itm.data(0, self.objectNameRole) |
369 txt = itm.data(0, self.objectNameRole) |
354 for act in actions: |
370 for act in actions: |
355 if txt == act.objectName(): |
371 if txt == act.objectName(): |
356 act.setShortcut(QKeySequence(itm.text(1))) |
372 act.setShortcut(QKeySequence(itm.text(1))) |
357 act.setAlternateShortcut(QKeySequence(itm.text(2)), removeEmpty=True) |
373 act.setAlternateShortcut( |
|
374 QKeySequence(itm.text(2)), removeEmpty=True) |
358 break |
375 break |
359 |
376 |
360 def on_buttonBox_accepted(self): |
377 def on_buttonBox_accepted(self): |
361 """ |
378 """ |
362 Private slot to handle the OK button press. |
379 Private slot to handle the OK button press. |
414 topItem = self.shortcutsList.topLevelItem(topIndex) |
431 topItem = self.shortcutsList.topLevelItem(topIndex) |
415 childHiddenCount = 0 |
432 childHiddenCount = 0 |
416 for index in range(topItem.childCount()): |
433 for index in range(topItem.childCount()): |
417 itm = topItem.child(index) |
434 itm = topItem.child(index) |
418 if (self.actionButton.isChecked() and \ |
435 if (self.actionButton.isChecked() and \ |
419 not QRegExp(txt, Qt.CaseInsensitive).indexIn(itm.text(0)) > -1) or \ |
436 not QRegExp(txt, Qt.CaseInsensitive).indexIn(itm.text(0)) > |
|
437 -1) or \ |
420 (self.shortcutButton.isChecked() and \ |
438 (self.shortcutButton.isChecked() and \ |
421 not txt.lower() in itm.text(1).lower() and \ |
439 not txt.lower() in itm.text(1).lower() and \ |
422 not txt.lower() in itm.text(2).lower()): |
440 not txt.lower() in itm.text(2).lower()): |
423 itm.setHidden(True) |
441 itm.setHidden(True) |
424 childHiddenCount += 1 |
442 childHiddenCount += 1 |