|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2002 - 2019 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing the baseclass for the various project browsers. |
|
8 """ |
|
9 |
|
10 from __future__ import unicode_literals |
|
11 |
|
12 import os |
|
13 |
|
14 from PyQt5.QtCore import QModelIndex, pyqtSignal, Qt, QCoreApplication, \ |
|
15 QItemSelectionModel, QItemSelection, QElapsedTimer |
|
16 from PyQt5.QtGui import QCursor |
|
17 from PyQt5.QtWidgets import QTreeView, QApplication, QMenu, QDialog, \ |
|
18 QAbstractItemView |
|
19 |
|
20 from E5Gui.E5Application import e5App |
|
21 from E5Gui import E5MessageBox |
|
22 |
|
23 from UI.Browser import Browser |
|
24 from UI.BrowserModel import BrowserDirectoryItem, BrowserFileItem |
|
25 |
|
26 from .ProjectBrowserModel import ProjectBrowserSimpleDirectoryItem, \ |
|
27 ProjectBrowserDirectoryItem, ProjectBrowserFileItem |
|
28 from .ProjectBrowserSortFilterProxyModel import \ |
|
29 ProjectBrowserSortFilterProxyModel |
|
30 |
|
31 |
|
32 class ProjectBaseBrowser(Browser): |
|
33 """ |
|
34 Baseclass implementing common functionality for the various project |
|
35 browsers. |
|
36 |
|
37 @signal closeSourceWindow(str) emitted to close a source file |
|
38 """ |
|
39 closeSourceWindow = pyqtSignal(str) |
|
40 |
|
41 def __init__(self, project, type_, parent=None): |
|
42 """ |
|
43 Constructor |
|
44 |
|
45 @param project reference to the project object |
|
46 @param type_ project browser type (string) |
|
47 @param parent parent widget of this browser |
|
48 """ |
|
49 QTreeView.__init__(self, parent) |
|
50 |
|
51 self.project = project |
|
52 |
|
53 self._model = project.getModel() |
|
54 self._sortModel = ProjectBrowserSortFilterProxyModel(type_) |
|
55 self._sortModel.setSourceModel(self._model) |
|
56 self.setModel(self._sortModel) |
|
57 |
|
58 self.selectedItemsFilter = [ProjectBrowserFileItem] |
|
59 |
|
60 # contains codes for special menu entries |
|
61 # 1 = specials for Others browser |
|
62 self.specialMenuEntries = [] |
|
63 self.isTranslationsBrowser = False |
|
64 self.expandedNames = [] |
|
65 |
|
66 self.SelectFlags = QItemSelectionModel.SelectionFlags( |
|
67 QItemSelectionModel.Select | QItemSelectionModel.Rows) |
|
68 self.DeselectFlags = QItemSelectionModel.SelectionFlags( |
|
69 QItemSelectionModel.Deselect | QItemSelectionModel.Rows) |
|
70 |
|
71 self._activating = False |
|
72 |
|
73 self.setContextMenuPolicy(Qt.CustomContextMenu) |
|
74 self.customContextMenuRequested.connect(self._contextMenuRequested) |
|
75 self.activated.connect(self._openItem) |
|
76 self._model.rowsInserted.connect(self.__modelRowsInserted) |
|
77 self._connectExpandedCollapsed() |
|
78 |
|
79 self._createPopupMenus() |
|
80 |
|
81 self.currentItemName = None |
|
82 |
|
83 self._init() # perform common initialization tasks |
|
84 |
|
85 self._keyboardSearchString = "" |
|
86 self._keyboardSearchTimer = QElapsedTimer() |
|
87 self._keyboardSearchTimer.invalidate() |
|
88 |
|
89 self._initHookMethods() # perform initialization of the hooks |
|
90 self.hooksMenuEntries = {} |
|
91 |
|
92 def _connectExpandedCollapsed(self): |
|
93 """ |
|
94 Protected method to connect the expanded and collapsed signals. |
|
95 """ |
|
96 self.expanded.connect(self._resizeColumns) |
|
97 self.collapsed.connect(self._resizeColumns) |
|
98 |
|
99 def _disconnectExpandedCollapsed(self): |
|
100 """ |
|
101 Protected method to disconnect the expanded and collapsed signals. |
|
102 """ |
|
103 self.expanded.disconnect(self._resizeColumns) |
|
104 self.collapsed.disconnect(self._resizeColumns) |
|
105 |
|
106 def _createPopupMenus(self): |
|
107 """ |
|
108 Protected overloaded method to generate the popup menus. |
|
109 """ |
|
110 # create the popup menu for source files |
|
111 self.sourceMenu = QMenu(self) |
|
112 self.sourceMenu.addAction( |
|
113 QCoreApplication.translate('ProjectBaseBrowser', 'Open'), |
|
114 self._openItem) |
|
115 |
|
116 # create the popup menu for general use |
|
117 self.menu = QMenu(self) |
|
118 self.menu.addAction( |
|
119 QCoreApplication.translate('ProjectBaseBrowser', 'Open'), |
|
120 self._openItem) |
|
121 |
|
122 # create the menu for multiple selected files |
|
123 self.multiMenu = QMenu(self) |
|
124 self.multiMenu.addAction( |
|
125 QCoreApplication.translate('ProjectBaseBrowser', 'Open'), |
|
126 self._openItem) |
|
127 |
|
128 # create the background menu |
|
129 self.backMenu = None |
|
130 |
|
131 # create the directories menu |
|
132 self.dirMenu = None |
|
133 |
|
134 # create the directory for multiple selected directories |
|
135 self.dirMultiMenu = None |
|
136 |
|
137 self.menuActions = [] |
|
138 self.multiMenuActions = [] |
|
139 self.dirMenuActions = [] |
|
140 self.dirMultiMenuActions = [] |
|
141 |
|
142 self.mainMenu = None |
|
143 |
|
144 def _contextMenuRequested(self, coord): |
|
145 """ |
|
146 Protected slot to show the context menu. |
|
147 |
|
148 @param coord the position of the mouse pointer (QPoint) |
|
149 """ |
|
150 if not self.project.isOpen(): |
|
151 return |
|
152 |
|
153 cnt = self.getSelectedItemsCount() |
|
154 if cnt > 1: |
|
155 self.multiMenu.popup(self.mapToGlobal(coord)) |
|
156 else: |
|
157 index = self.indexAt(coord) |
|
158 |
|
159 if index.isValid(): |
|
160 self.menu.popup(self.mapToGlobal(coord)) |
|
161 else: |
|
162 self.backMenu and self.backMenu.popup(self.mapToGlobal(coord)) |
|
163 |
|
164 def _selectSingleItem(self, index): |
|
165 """ |
|
166 Protected method to select a single item. |
|
167 |
|
168 @param index index of item to be selected (QModelIndex) |
|
169 """ |
|
170 if index.isValid(): |
|
171 self.setCurrentIndex(index) |
|
172 flags = QItemSelectionModel.SelectionFlags( |
|
173 QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Rows) |
|
174 self.selectionModel().select(index, flags) |
|
175 |
|
176 def _setItemSelected(self, index, selected): |
|
177 """ |
|
178 Protected method to set the selection status of an item. |
|
179 |
|
180 @param index index of item to set (QModelIndex) |
|
181 @param selected flag giving the new selection status (boolean) |
|
182 """ |
|
183 if index.isValid(): |
|
184 self.selectionModel().select( |
|
185 index, selected and self.SelectFlags or self.DeselectFlags) |
|
186 |
|
187 def _setItemRangeSelected(self, startIndex, endIndex, selected): |
|
188 """ |
|
189 Protected method to set the selection status of a range of items. |
|
190 |
|
191 @param startIndex start index of range of items to set (QModelIndex) |
|
192 @param endIndex end index of range of items to set (QModelIndex) |
|
193 @param selected flag giving the new selection status (boolean) |
|
194 """ |
|
195 selection = QItemSelection(startIndex, endIndex) |
|
196 self.selectionModel().select( |
|
197 selection, selected and self.SelectFlags or self.DeselectFlags) |
|
198 |
|
199 def __modelRowsInserted(self, parent, start, end): |
|
200 """ |
|
201 Private slot called after rows have been inserted into the model. |
|
202 |
|
203 @param parent parent index of inserted rows (QModelIndex) |
|
204 @param start start row number (integer) |
|
205 @param end end row number (integer) |
|
206 """ |
|
207 self._resizeColumns(parent) |
|
208 |
|
209 def _projectClosed(self): |
|
210 """ |
|
211 Protected slot to handle the projectClosed signal. |
|
212 """ |
|
213 self.layoutDisplay() |
|
214 if self.backMenu is not None: |
|
215 self.backMenu.setEnabled(False) |
|
216 |
|
217 self._createPopupMenus() |
|
218 |
|
219 def _projectOpened(self): |
|
220 """ |
|
221 Protected slot to handle the projectOpened signal. |
|
222 """ |
|
223 self.layoutDisplay() |
|
224 self.sortByColumn(0, Qt.DescendingOrder) |
|
225 self.sortByColumn(0, Qt.AscendingOrder) |
|
226 self._initMenusAndVcs() |
|
227 |
|
228 def _initMenusAndVcs(self): |
|
229 """ |
|
230 Protected slot to initialize the menus and the Vcs interface. |
|
231 """ |
|
232 self._createPopupMenus() |
|
233 |
|
234 if self.backMenu is not None: |
|
235 self.backMenu.setEnabled(True) |
|
236 |
|
237 if self.project.vcs is not None: |
|
238 self.vcsHelper = self.project.vcs.vcsGetProjectBrowserHelper( |
|
239 self, self.project, self.isTranslationsBrowser) |
|
240 self.vcsHelper.addVCSMenus( |
|
241 self.mainMenu, self.multiMenu, self.backMenu, |
|
242 self.dirMenu, self.dirMultiMenu) |
|
243 |
|
244 def _newProject(self): |
|
245 """ |
|
246 Protected slot to handle the newProject signal. |
|
247 """ |
|
248 # default to perform same actions as opening a project |
|
249 self._projectOpened() |
|
250 |
|
251 def _removeFile(self): |
|
252 """ |
|
253 Protected method to remove a file or files from the project. |
|
254 """ |
|
255 itmList = self.getSelectedItems() |
|
256 |
|
257 for itm in itmList[:]: |
|
258 fn = itm.fileName() |
|
259 self.closeSourceWindow.emit(fn) |
|
260 self.project.removeFile(fn) |
|
261 |
|
262 def _removeDir(self): |
|
263 """ |
|
264 Protected method to remove a (single) directory from the project. |
|
265 """ |
|
266 itmList = self.getSelectedItems( |
|
267 [ProjectBrowserSimpleDirectoryItem, ProjectBrowserDirectoryItem]) |
|
268 for itm in itmList[:]: |
|
269 dn = itm.dirName() |
|
270 self.project.removeDirectory(dn) |
|
271 |
|
272 def _deleteDirectory(self): |
|
273 """ |
|
274 Protected method to delete the selected directory from the project |
|
275 data area. |
|
276 """ |
|
277 itmList = self.getSelectedItems() |
|
278 |
|
279 dirs = [] |
|
280 fullNames = [] |
|
281 for itm in itmList: |
|
282 dn = itm.dirName() |
|
283 fullNames.append(dn) |
|
284 dn = self.project.getRelativePath(dn) |
|
285 dirs.append(dn) |
|
286 |
|
287 from UI.DeleteFilesConfirmationDialog import \ |
|
288 DeleteFilesConfirmationDialog |
|
289 dlg = DeleteFilesConfirmationDialog( |
|
290 self.parent(), |
|
291 QCoreApplication.translate( |
|
292 "ProjectBaseBrowser", "Delete directories"), |
|
293 QCoreApplication.translate( |
|
294 "ProjectBaseBrowser", |
|
295 "Do you really want to delete these directories from" |
|
296 " the project?"), |
|
297 dirs) |
|
298 |
|
299 if dlg.exec_() == QDialog.Accepted: |
|
300 for dn in fullNames: |
|
301 self.project.deleteDirectory(dn) |
|
302 |
|
303 def _renameFile(self): |
|
304 """ |
|
305 Protected method to rename a file of the project. |
|
306 """ |
|
307 itm = self.model().item(self.currentIndex()) |
|
308 fn = itm.fileName() |
|
309 self.project.renameFile(fn) |
|
310 |
|
311 def _copyToClipboard(self): |
|
312 """ |
|
313 Protected method to copy the path of an entry to the clipboard. |
|
314 """ |
|
315 itm = self.model().item(self.currentIndex()) |
|
316 try: |
|
317 fn = itm.fileName() |
|
318 except AttributeError: |
|
319 try: |
|
320 fn = itm.dirName() |
|
321 except AttributeError: |
|
322 fn = "" |
|
323 |
|
324 cb = QApplication.clipboard() |
|
325 cb.setText(fn) |
|
326 |
|
327 def selectFile(self, fn): |
|
328 """ |
|
329 Public method to highlight a node given its filename. |
|
330 |
|
331 @param fn filename of file to be highlighted (string) |
|
332 """ |
|
333 newfn = os.path.abspath(fn) |
|
334 newfn = self.project.getRelativePath(newfn) |
|
335 sindex = self._model.itemIndexByName(newfn) |
|
336 if sindex.isValid(): |
|
337 index = self.model().mapFromSource(sindex) |
|
338 if index.isValid(): |
|
339 self._selectSingleItem(index) |
|
340 self.scrollTo(index, QAbstractItemView.PositionAtTop) |
|
341 |
|
342 def selectFileLine(self, fn, lineno): |
|
343 """ |
|
344 Public method to highlight a node given its filename. |
|
345 |
|
346 @param fn filename of file to be highlighted (string) |
|
347 @param lineno one based line number of the item (integer) |
|
348 """ |
|
349 newfn = os.path.abspath(fn) |
|
350 newfn = self.project.getRelativePath(newfn) |
|
351 sindex = self._model.itemIndexByNameAndLine(newfn, lineno) |
|
352 if sindex.isValid(): |
|
353 index = self.model().mapFromSource(sindex) |
|
354 if index.isValid(): |
|
355 self._selectSingleItem(index) |
|
356 self.scrollTo(index) |
|
357 |
|
358 def _expandAllDirs(self): |
|
359 """ |
|
360 Protected slot to handle the 'Expand all directories' menu action. |
|
361 """ |
|
362 self._disconnectExpandedCollapsed() |
|
363 QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) |
|
364 QApplication.processEvents() |
|
365 index = self.model().index(0, 0) |
|
366 while index.isValid(): |
|
367 itm = self.model().item(index) |
|
368 if (isinstance(itm, ProjectBrowserSimpleDirectoryItem) or |
|
369 isinstance(itm, ProjectBrowserDirectoryItem)) and \ |
|
370 not self.isExpanded(index): |
|
371 self.expand(index) |
|
372 index = self.indexBelow(index) |
|
373 self.layoutDisplay() |
|
374 self._connectExpandedCollapsed() |
|
375 QApplication.restoreOverrideCursor() |
|
376 |
|
377 def _collapseAllDirs(self): |
|
378 """ |
|
379 Protected slot to handle the 'Collapse all directories' menu action. |
|
380 """ |
|
381 self._disconnectExpandedCollapsed() |
|
382 QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) |
|
383 QApplication.processEvents() |
|
384 # step 1: find last valid index |
|
385 vindex = QModelIndex() |
|
386 index = self.model().index(0, 0) |
|
387 while index.isValid(): |
|
388 vindex = index |
|
389 index = self.indexBelow(index) |
|
390 |
|
391 # step 2: go up collapsing all directory items |
|
392 index = vindex |
|
393 while index.isValid(): |
|
394 itm = self.model().item(index) |
|
395 if (isinstance(itm, ProjectBrowserSimpleDirectoryItem) or |
|
396 isinstance(itm, ProjectBrowserDirectoryItem)) and \ |
|
397 self.isExpanded(index): |
|
398 self.collapse(index) |
|
399 index = self.indexAbove(index) |
|
400 self.layoutDisplay() |
|
401 self._connectExpandedCollapsed() |
|
402 QApplication.restoreOverrideCursor() |
|
403 |
|
404 def _showContextMenu(self, menu): |
|
405 """ |
|
406 Protected slot called before the context menu is shown. |
|
407 |
|
408 It enables/disables the VCS menu entries depending on the overall |
|
409 VCS status and the file status. |
|
410 |
|
411 @param menu reference to the menu to be shown (QMenu) |
|
412 """ |
|
413 if self.project.vcs is None: |
|
414 for act in self.menuActions: |
|
415 act.setEnabled(True) |
|
416 else: |
|
417 self.vcsHelper.showContextMenu(menu, self.menuActions) |
|
418 |
|
419 def _showContextMenuMulti(self, menu): |
|
420 """ |
|
421 Protected slot called before the context menu (multiple selections) is |
|
422 shown. |
|
423 |
|
424 It enables/disables the VCS menu entries depending on the overall |
|
425 VCS status and the files status. |
|
426 |
|
427 @param menu reference to the menu to be shown (QMenu) |
|
428 """ |
|
429 if self.project.vcs is None: |
|
430 for act in self.multiMenuActions: |
|
431 act.setEnabled(True) |
|
432 else: |
|
433 self.vcsHelper.showContextMenuMulti(menu, self.multiMenuActions) |
|
434 |
|
435 def _showContextMenuDir(self, menu): |
|
436 """ |
|
437 Protected slot called before the context menu is shown. |
|
438 |
|
439 It enables/disables the VCS menu entries depending on the overall |
|
440 VCS status and the directory status. |
|
441 |
|
442 @param menu reference to the menu to be shown (QMenu) |
|
443 """ |
|
444 if self.project.vcs is None: |
|
445 for act in self.dirMenuActions: |
|
446 act.setEnabled(True) |
|
447 else: |
|
448 self.vcsHelper.showContextMenuDir(menu, self.dirMenuActions) |
|
449 |
|
450 def _showContextMenuDirMulti(self, menu): |
|
451 """ |
|
452 Protected slot called before the context menu is shown. |
|
453 |
|
454 It enables/disables the VCS menu entries depending on the overall |
|
455 VCS status and the directory status. |
|
456 |
|
457 @param menu reference to the menu to be shown (QMenu) |
|
458 """ |
|
459 if self.project.vcs is None: |
|
460 for act in self.dirMultiMenuActions: |
|
461 act.setEnabled(True) |
|
462 else: |
|
463 self.vcsHelper.showContextMenuDirMulti( |
|
464 menu, self.dirMultiMenuActions) |
|
465 |
|
466 def _showContextMenuBack(self, menu): |
|
467 """ |
|
468 Protected slot called before the context menu is shown. |
|
469 |
|
470 @param menu reference to the menu to be shown (QMenu) |
|
471 """ |
|
472 # nothing to do for now |
|
473 return |
|
474 |
|
475 def _selectEntries(self, local=True, filterList=None): |
|
476 """ |
|
477 Protected method to select entries based on their VCS status. |
|
478 |
|
479 @param local flag indicating local (i.e. non VCS controlled) |
|
480 file/directory entries should be selected (boolean) |
|
481 @param filterList list of classes to check against |
|
482 """ |
|
483 if self.project.vcs is None: |
|
484 return |
|
485 |
|
486 if local: |
|
487 compareString = \ |
|
488 QCoreApplication.translate('ProjectBaseBrowser', "local") |
|
489 else: |
|
490 compareString = self.project.vcs.vcsName() |
|
491 |
|
492 # expand all directories in order to iterate over all entries |
|
493 self._expandAllDirs() |
|
494 |
|
495 QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) |
|
496 QApplication.processEvents() |
|
497 self.selectionModel().clear() |
|
498 QApplication.processEvents() |
|
499 |
|
500 # now iterate over all entries |
|
501 startIndex = None |
|
502 endIndex = None |
|
503 selectedEntries = 0 |
|
504 index = self.model().index(0, 0) |
|
505 while index.isValid(): |
|
506 itm = self.model().item(index) |
|
507 if self.wantedItem(itm, filterList) and \ |
|
508 compareString == itm.data(1): |
|
509 if startIndex is not None and \ |
|
510 startIndex.parent() != index.parent(): |
|
511 self._setItemRangeSelected(startIndex, endIndex, True) |
|
512 startIndex = None |
|
513 selectedEntries += 1 |
|
514 if startIndex is None: |
|
515 startIndex = index |
|
516 endIndex = index |
|
517 else: |
|
518 if startIndex is not None: |
|
519 self._setItemRangeSelected(startIndex, endIndex, True) |
|
520 startIndex = None |
|
521 index = self.indexBelow(index) |
|
522 if startIndex is not None: |
|
523 self._setItemRangeSelected(startIndex, endIndex, True) |
|
524 QApplication.restoreOverrideCursor() |
|
525 QApplication.processEvents() |
|
526 |
|
527 if selectedEntries == 0: |
|
528 E5MessageBox.information( |
|
529 self, |
|
530 QCoreApplication.translate( |
|
531 'ProjectBaseBrowser', "Select entries"), |
|
532 QCoreApplication.translate( |
|
533 'ProjectBaseBrowser', |
|
534 """There were no matching entries found.""")) |
|
535 |
|
536 def selectLocalEntries(self): |
|
537 """ |
|
538 Public slot to handle the select local files context menu entries. |
|
539 """ |
|
540 self._selectEntries(local=True, filterList=[ProjectBrowserFileItem]) |
|
541 |
|
542 def selectVCSEntries(self): |
|
543 """ |
|
544 Public slot to handle the select VCS files context menu entries. |
|
545 """ |
|
546 self._selectEntries(local=False, filterList=[ProjectBrowserFileItem]) |
|
547 |
|
548 def selectLocalDirEntries(self): |
|
549 """ |
|
550 Public slot to handle the select local directories context menu |
|
551 entries. |
|
552 """ |
|
553 self._selectEntries( |
|
554 local=True, |
|
555 filterList=[ProjectBrowserSimpleDirectoryItem, |
|
556 ProjectBrowserDirectoryItem]) |
|
557 |
|
558 def selectVCSDirEntries(self): |
|
559 """ |
|
560 Public slot to handle the select VCS directories context menu entries. |
|
561 """ |
|
562 self._selectEntries( |
|
563 local=False, |
|
564 filterList=[ProjectBrowserSimpleDirectoryItem, |
|
565 ProjectBrowserDirectoryItem]) |
|
566 |
|
567 def getExpandedItemNames(self): |
|
568 """ |
|
569 Public method to get the file/directory names of all expanded items. |
|
570 |
|
571 @return list of expanded items names (list of string) |
|
572 """ |
|
573 expandedNames = [] |
|
574 |
|
575 childIndex = self.model().index(0, 0) |
|
576 while childIndex.isValid(): |
|
577 if self.isExpanded(childIndex): |
|
578 try: |
|
579 expandedNames.append( |
|
580 self.model().item(childIndex).name()) |
|
581 except AttributeError: |
|
582 # only items defining the name() method are returned |
|
583 pass |
|
584 childIndex = self.indexBelow(childIndex) |
|
585 |
|
586 return expandedNames |
|
587 |
|
588 def expandItemsByName(self, names): |
|
589 """ |
|
590 Public method to expand items given their names. |
|
591 |
|
592 @param names list of item names to be expanded (list of string) |
|
593 """ |
|
594 model = self.model() |
|
595 for name in names: |
|
596 childIndex = model.index(0, 0) |
|
597 while childIndex.isValid(): |
|
598 try: |
|
599 if model.item(childIndex).name() == name: |
|
600 self.setExpanded(childIndex, True) |
|
601 break |
|
602 except AttributeError: |
|
603 # ignore items not supporting this method |
|
604 pass |
|
605 childIndex = self.indexBelow(childIndex) |
|
606 |
|
607 def _prepareRepopulateItem(self, name): |
|
608 """ |
|
609 Protected slot to handle the prepareRepopulateItem signal. |
|
610 |
|
611 @param name relative name of file item to be repopulated (string) |
|
612 """ |
|
613 QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) |
|
614 QApplication.processEvents() |
|
615 itm = self.currentItem() |
|
616 if itm is not None: |
|
617 self.currentItemName = itm.data(0) |
|
618 self.expandedNames = [] |
|
619 sindex = self._model.itemIndexByName(name) |
|
620 if not sindex.isValid(): |
|
621 return |
|
622 |
|
623 index = self.model().mapFromSource(sindex) |
|
624 if not index.isValid(): |
|
625 return |
|
626 |
|
627 childIndex = self.indexBelow(index) |
|
628 while childIndex.isValid(): |
|
629 if childIndex.parent() == index.parent(): |
|
630 break |
|
631 if self.isExpanded(childIndex): |
|
632 self.expandedNames.append( |
|
633 self.model().item(childIndex).data(0)) |
|
634 childIndex = self.indexBelow(childIndex) |
|
635 |
|
636 def _completeRepopulateItem(self, name): |
|
637 """ |
|
638 Protected slot to handle the completeRepopulateItem signal. |
|
639 |
|
640 @param name relative name of file item to be repopulated (string) |
|
641 """ |
|
642 sindex = self._model.itemIndexByName(name) |
|
643 if sindex.isValid(): |
|
644 index = self.model().mapFromSource(sindex) |
|
645 if index.isValid(): |
|
646 if self.isExpanded(index): |
|
647 childIndex = self.indexBelow(index) |
|
648 while childIndex.isValid(): |
|
649 if not childIndex.isValid() or \ |
|
650 childIndex.parent() == index.parent(): |
|
651 break |
|
652 itm = self.model().item(childIndex) |
|
653 if itm is not None: |
|
654 itemData = itm.data(0) |
|
655 if self.currentItemName and \ |
|
656 self.currentItemName == itemData: |
|
657 self._selectSingleItem(childIndex) |
|
658 if itemData in self.expandedNames: |
|
659 self.setExpanded(childIndex, True) |
|
660 childIndex = self.indexBelow(childIndex) |
|
661 else: |
|
662 self._selectSingleItem(index) |
|
663 self.expandedNames = [] |
|
664 self.currentItemName = None |
|
665 QApplication.restoreOverrideCursor() |
|
666 QApplication.processEvents() |
|
667 self._resort() |
|
668 |
|
669 def currentItem(self): |
|
670 """ |
|
671 Public method to get a reference to the current item. |
|
672 |
|
673 @return reference to the current item |
|
674 """ |
|
675 itm = self.model().item(self.currentIndex()) |
|
676 return itm |
|
677 |
|
678 def _keyboardSearchType(self, item): |
|
679 """ |
|
680 Protected method to check, if the item is of the correct type. |
|
681 |
|
682 @param item reference to the item |
|
683 @type BrowserItem |
|
684 @return flag indicating a correct type |
|
685 @rtype bool |
|
686 """ |
|
687 return isinstance( |
|
688 item, (BrowserDirectoryItem, BrowserFileItem, |
|
689 ProjectBrowserSimpleDirectoryItem, |
|
690 ProjectBrowserDirectoryItem, ProjectBrowserFileItem)) |
|
691 |
|
692 ########################################################################### |
|
693 ## Support for hooks below |
|
694 ########################################################################### |
|
695 |
|
696 def _initHookMethods(self): |
|
697 """ |
|
698 Protected method to initialize the hooks dictionary. |
|
699 |
|
700 This method should be overridden by subclasses. All supported |
|
701 hook methods should be initialized with a None value. The keys |
|
702 must be strings. |
|
703 """ |
|
704 self.hooks = {} |
|
705 |
|
706 def __checkHookKey(self, key): |
|
707 """ |
|
708 Private method to check a hook key. |
|
709 |
|
710 @param key key of the hook to check (string) |
|
711 @exception KeyError raised to indicate an invalid hook |
|
712 """ |
|
713 if len(self.hooks) == 0: |
|
714 raise KeyError("Hooks are not initialized.") |
|
715 |
|
716 if key not in self.hooks: |
|
717 raise KeyError(key) |
|
718 |
|
719 def addHookMethod(self, key, method): |
|
720 """ |
|
721 Public method to add a hook method to the dictionary. |
|
722 |
|
723 @param key for the hook method (string) |
|
724 @param method reference to the hook method (method object) |
|
725 """ |
|
726 self.__checkHookKey(key) |
|
727 self.hooks[key] = method |
|
728 |
|
729 def addHookMethodAndMenuEntry(self, key, method, menuEntry): |
|
730 """ |
|
731 Public method to add a hook method to the dictionary. |
|
732 |
|
733 @param key for the hook method (string) |
|
734 @param method reference to the hook method (method object) |
|
735 @param menuEntry entry to be shown in the context menu (string) |
|
736 """ |
|
737 self.addHookMethod(key, method) |
|
738 self.hooksMenuEntries[key] = menuEntry |
|
739 |
|
740 def removeHookMethod(self, key): |
|
741 """ |
|
742 Public method to remove a hook method from the dictionary. |
|
743 |
|
744 @param key for the hook method (string) |
|
745 """ |
|
746 self.__checkHookKey(key) |
|
747 self.hooks[key] = None |
|
748 if key in self.hooksMenuEntries: |
|
749 del self.hooksMenuEntries[key] |
|
750 |
|
751 ################################################################## |
|
752 ## Configure method below |
|
753 ################################################################## |
|
754 |
|
755 def _configure(self): |
|
756 """ |
|
757 Protected method to open the configuration dialog. |
|
758 """ |
|
759 e5App().getObject("UserInterface")\ |
|
760 .showPreferences("projectBrowserPage") |