Plugins/ViewManagerPlugins/Tabview/Tabview.py

changeset 0
de9c2efb9d02
child 7
c679fb30c8f3
equal deleted inserted replaced
-1:000000000000 0:de9c2efb9d02
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2002 - 2009 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a tabbed viewmanager class.
8 """
9
10 import os
11
12 from PyQt4.QtCore import *
13 from PyQt4.QtGui import *
14
15 from E4Gui.E4Application import e4App
16
17 from ViewManager.ViewManager import ViewManager
18
19 import QScintilla.Editor
20
21 import UI.PixmapCache
22
23 from E4Gui.E4TabWidget import E4TabWidget, E4WheelTabBar
24 from E4Gui.E4Led import E4Led
25
26 import Preferences
27
28 from eric4config import getConfig
29
30 class TabBar(E4WheelTabBar):
31 """
32 Class implementing a customized tab bar supporting drag & drop.
33
34 @signal tabMoveRequested(int, int) emitted to signal a tab move request giving
35 the old and new index position
36 @signal tabRelocateRequested(long, int, int) emitted to signal a tab relocation
37 request giving the id of the old tab widget, the index in the old tab widget
38 and the new index position
39 @signal tabCopyRequested(long, int, int) emitted to signal a clone request
40 giving the id of the source tab widget, the index in the source tab widget
41 and the new index position
42 @signal tabCopyRequested(int, int) emitted to signal a clone request giving
43 the old and new index position
44 """
45 def __init__(self, parent = None):
46 """
47 Constructor
48
49 @param parent reference to the parent widget (QWidget)
50 """
51 E4WheelTabBar.__init__(self, parent)
52 self.setAcceptDrops(True)
53
54 self.__dragStartPos = QPoint()
55
56 def mousePressEvent(self, event):
57 """
58 Protected method to handle mouse press events.
59
60 @param event reference to the mouse press event (QMouseEvent)
61 """
62 if event.button() == Qt.LeftButton:
63 self.__dragStartPos = QPoint(event.pos())
64 E4WheelTabBar.mousePressEvent(self, event)
65
66 def mouseMoveEvent(self, event):
67 """
68 Protected method to handle mouse move events.
69
70 @param event reference to the mouse move event (QMouseEvent)
71 """
72 if event.buttons() == Qt.MouseButtons(Qt.LeftButton) and \
73 (event.pos() - self.__dragStartPos).manhattanLength() > \
74 QApplication.startDragDistance():
75 drag = QDrag(self)
76 mimeData = QMimeData()
77 index = self.tabAt(event.pos())
78 mimeData.setText(self.tabText(index))
79 mimeData.setData("action", "tab-reordering")
80 mimeData.setData("tabbar-id", QByteArray.number(id(self)))
81 mimeData.setData("source-index",
82 QByteArray.number(self.tabAt(self.__dragStartPos)))
83 mimeData.setData("tabwidget-id", QByteArray.number(id(self.parentWidget())))
84 drag.setMimeData(mimeData)
85 if event.modifiers() == Qt.KeyboardModifiers(Qt.ShiftModifier):
86 drag.exec_(Qt.DropActions(Qt.CopyAction))
87 elif event.modifiers() == Qt.KeyboardModifiers(Qt.NoModifier):
88 drag.exec_(Qt.DropActions(Qt.MoveAction))
89 E4WheelTabBar.mouseMoveEvent(self, event)
90
91 def dragEnterEvent(self, event):
92 """
93 Protected method to handle drag enter events.
94
95 @param event reference to the drag enter event (QDragEnterEvent)
96 """
97 mimeData = event.mimeData()
98 formats = mimeData.formats()
99 if formats.contains("action") and \
100 mimeData.data("action") == "tab-reordering" and \
101 formats.contains("tabbar-id") and \
102 formats.contains("source-index") and \
103 formats.contains("tabwidget-id"):
104 event.acceptProposedAction()
105 E4WheelTabBar.dragEnterEvent(self, event)
106
107 def dropEvent(self, event):
108 """
109 Protected method to handle drop events.
110
111 @param event reference to the drop event (QDropEvent)
112 """
113 mimeData = event.mimeData()
114 oldID = mimeData.data("tabbar-id").toLong()[0]
115 fromIndex = mimeData.data("source-index").toInt()[0]
116 toIndex = self.tabAt(event.pos())
117 if oldID != id(self):
118 parentID = mimeData.data("tabwidget-id").toLong()[0]
119 if event.proposedAction() == Qt.MoveAction:
120 self.emit(SIGNAL("tabRelocateRequested(long, int, int)"),
121 parentID, fromIndex, toIndex)
122 event.acceptProposedAction()
123 elif event.proposedAction() == Qt.CopyAction:
124 self.emit(SIGNAL("tabCopyRequested(long, int, int)"),
125 parentID, fromIndex, toIndex)
126 event.acceptProposedAction()
127 else:
128 if fromIndex != toIndex:
129 if event.proposedAction() == Qt.MoveAction:
130 self.emit(SIGNAL("tabMoveRequested(int, int)"), fromIndex, toIndex)
131 event.acceptProposedAction()
132 elif event.proposedAction() == Qt.CopyAction:
133 self.emit(SIGNAL("tabCopyRequested(int, int)"), fromIndex, toIndex)
134 event.acceptProposedAction()
135 E4WheelTabBar.dropEvent(self, event)
136
137 class TabWidget(E4TabWidget):
138 """
139 Class implementing a custimized tab widget.
140 """
141 def __init__(self, vm):
142 """
143 Constructor
144
145 @param vm view manager widget (Tabview)
146 """
147 E4TabWidget.__init__(self)
148 self.setAttribute(Qt.WA_DeleteOnClose, True)
149
150 self.__tabBar = TabBar(self)
151 self.setTabBar(self.__tabBar)
152
153 self.connect(self.__tabBar, SIGNAL("tabMoveRequested(int, int)"),
154 self.moveTab)
155 self.connect(self.__tabBar, SIGNAL("tabRelocateRequested(long, int, int)"),
156 self.relocateTab)
157 self.connect(self.__tabBar, SIGNAL("tabCopyRequested(long, int, int)"),
158 self.copyTabOther)
159 self.connect(self.__tabBar, SIGNAL("tabCopyRequested(int, int)"),
160 self.copyTab)
161
162 self.vm = vm
163 self.editors = []
164
165 self.indicator = E4Led(self)
166 self.setCornerWidget(self.indicator, Qt.TopLeftCorner)
167
168 self.rightCornerWidget = QWidget(self)
169 self.rightCornerWidgetLayout = QHBoxLayout(self.rightCornerWidget)
170 self.rightCornerWidgetLayout.setMargin(0)
171 self.rightCornerWidgetLayout.setSpacing(0)
172
173 self.__navigationMenu = QMenu(self)
174 self.connect(self.__navigationMenu, SIGNAL("aboutToShow()"),
175 self.__showNavigationMenu)
176 self.connect(self.__navigationMenu, SIGNAL("triggered(QAction*)"),
177 self.__navigationMenuTriggered)
178
179 self.navigationButton = QToolButton(self)
180 self.navigationButton.setIcon(UI.PixmapCache.getIcon("1downarrow.png"))
181 self.navigationButton.setToolTip(self.trUtf8("Show a navigation menu"))
182 self.navigationButton.setPopupMode(QToolButton.InstantPopup)
183 self.navigationButton.setMenu(self.__navigationMenu)
184 self.navigationButton.setEnabled(False)
185 self.rightCornerWidgetLayout.addWidget(self.navigationButton)
186
187 if Preferences.getUI("SingleCloseButton") or \
188 not hasattr(self, 'setTabsClosable'):
189 self.closeButton = QToolButton(self)
190 self.closeButton.setIcon(UI.PixmapCache.getIcon("close.png"))
191 self.closeButton.setToolTip(self.trUtf8("Close the current editor"))
192 self.closeButton.setEnabled(False)
193 self.connect(self.closeButton, SIGNAL("clicked(bool)"),
194 self.__closeButtonClicked)
195 self.rightCornerWidgetLayout.addWidget(self.closeButton)
196 else:
197 self.connect(self, SIGNAL("tabCloseRequested(int)"),
198 self.__closeRequested)
199 self.closeButton = None
200
201 self.setCornerWidget(self.rightCornerWidget, Qt.TopRightCorner)
202
203 self.__initMenu()
204 self.contextMenuEditor = None
205 self.contextMenuIndex = -1
206
207 self.setTabContextMenuPolicy(Qt.CustomContextMenu)
208 self.connect(self, SIGNAL('customTabContextMenuRequested(const QPoint &, int)'),
209 self.__showContextMenu)
210
211 ericPic = QPixmap(os.path.join(getConfig('ericPixDir'), 'eric_small.png'))
212 self.emptyLabel = QLabel()
213 self.emptyLabel.setPixmap(ericPic)
214 self.emptyLabel.setAlignment(Qt.AlignVCenter | Qt.AlignHCenter)
215 E4TabWidget.addTab(self, self.emptyLabel, UI.PixmapCache.getIcon("empty.png"), "")
216
217 def __initMenu(self):
218 """
219 Private method to initialize the tab context menu.
220 """
221 self.__menu = QMenu(self)
222 self.leftMenuAct = \
223 self.__menu.addAction(UI.PixmapCache.getIcon("1leftarrow.png"),
224 self.trUtf8('Move Left'), self.__contextMenuMoveLeft)
225 self.rightMenuAct = \
226 self.__menu.addAction(UI.PixmapCache.getIcon("1rightarrow.png"),
227 self.trUtf8('Move Right'), self.__contextMenuMoveRight)
228 self.firstMenuAct = \
229 self.__menu.addAction(UI.PixmapCache.getIcon("2leftarrow.png"),
230 self.trUtf8('Move First'), self.__contextMenuMoveFirst)
231 self.lastMenuAct = \
232 self.__menu.addAction(UI.PixmapCache.getIcon("2rightarrow.png"),
233 self.trUtf8('Move Last'), self.__contextMenuMoveLast)
234 self.__menu.addSeparator()
235 self.__menu.addAction(UI.PixmapCache.getIcon("close.png"),
236 self.trUtf8('Close'), self.__contextMenuClose)
237 self.closeOthersMenuAct = self.__menu.addAction(self.trUtf8("Close Others"),
238 self.__contextMenuCloseOthers)
239 self.__menu.addAction(self.trUtf8('Close All'), self.__contextMenuCloseAll)
240 self.__menu.addSeparator()
241 self.saveMenuAct = \
242 self.__menu.addAction(UI.PixmapCache.getIcon("fileSave.png"),
243 self.trUtf8('Save'), self.__contextMenuSave)
244 self.__menu.addAction(UI.PixmapCache.getIcon("fileSaveAs.png"),
245 self.trUtf8('Save As...'), self.__contextMenuSaveAs)
246 self.__menu.addAction(UI.PixmapCache.getIcon("fileSaveAll.png"),
247 self.trUtf8('Save All'), self.__contextMenuSaveAll)
248 self.projectMenuAct = \
249 self.__menu.addAction(UI.PixmapCache.getIcon("fileSaveProject.png"),
250 self.trUtf8('Save to Project'), self.__contextMenuSaveToProject)
251 self.__menu.addSeparator()
252 self.__menu.addAction(UI.PixmapCache.getIcon("print.png"),
253 self.trUtf8('Print'), self.__contextMenuPrintFile)
254
255 def __showContextMenu(self, coord, index):
256 """
257 Private slot to show the tab context menu.
258
259 @param coord the position of the mouse pointer (QPoint)
260 @param index index of the tab the menu is requested for (integer)
261 """
262 if self.editors:
263 self.contextMenuEditor = self.widget(index)
264 if self.contextMenuEditor:
265 self.saveMenuAct.setEnabled(self.contextMenuEditor.isModified())
266 self.projectMenuAct.setEnabled(e4App().getObject("Project").isOpen())
267
268 self.contextMenuIndex = index
269 self.leftMenuAct.setEnabled(index > 0)
270 self.rightMenuAct.setEnabled(index < self.count() - 1)
271 self.firstMenuAct.setEnabled(index > 0)
272 self.lastMenuAct.setEnabled(index < self.count() - 1)
273
274 self.closeOthersMenuAct.setEnabled(self.count() > 1)
275
276 coord = self.mapToGlobal(coord)
277 self.__menu.popup(coord)
278
279 def __showNavigationMenu(self):
280 """
281 Private slot to show the navigation button menu.
282 """
283 self.__navigationMenu.clear()
284 for index in range(self.count()):
285 act = self.__navigationMenu.addAction(self.tabIcon(index),
286 self.tabText(index))
287 act.setData(QVariant(index))
288
289 def __navigationMenuTriggered(self, act):
290 """
291 Private slot called to handle the navigation button menu selection.
292
293 @param act reference to the selected action (QAction)
294 """
295 index, ok = act.data().toInt()
296 if ok:
297 self.setCurrentIndex(index)
298
299 def showIndicator(self, on):
300 """
301 Public slot to set the indicator on or off.
302
303 @param on flag indicating the dtate of the indicator (boolean)
304 """
305 if on:
306 self.indicator.setColor(QColor("green"))
307 else:
308 self.indicator.setColor(QColor("red"))
309
310 def addTab(self, editor, title):
311 """
312 Overwritten method to add a new tab.
313
314 @param editor the editor object to be added (QScintilla.Editor.Editor)
315 @param title title for the new tab (string)
316 """
317 E4TabWidget.addTab(self, editor, UI.PixmapCache.getIcon("empty.png"), title)
318 if self.closeButton:
319 self.closeButton.setEnabled(True)
320 else:
321 self.setTabsClosable(True)
322 self.navigationButton.setEnabled(True)
323
324 if not editor in self.editors:
325 self.editors.append(editor)
326 self.connect(editor, SIGNAL('captionChanged'),
327 self.__captionChange)
328
329 emptyIndex = self.indexOf(self.emptyLabel)
330 if emptyIndex > -1:
331 self.removeTab(emptyIndex)
332
333 def insertWidget(self, index, editor, title):
334 """
335 Overwritten method to insert a new tab.
336
337 @param index index position for the new tab (integer)
338 @param editor the editor object to be added (QScintilla.Editor.Editor)
339 @param title title for the new tab (string)
340 @return index of the inserted tab (integer)
341 """
342 newIndex = E4TabWidget.insertTab(self, index, editor,
343 UI.PixmapCache.getIcon("empty.png"),
344 title)
345 if self.closeButton:
346 self.closeButton.setEnabled(True)
347 else:
348 self.setTabsClosable(True)
349 self.navigationButton.setEnabled(True)
350
351 if not editor in self.editors:
352 self.editors.append(editor)
353 self.connect(editor, SIGNAL('captionChanged'),
354 self.__captionChange)
355
356 emptyIndex = self.indexOf(self.emptyLabel)
357 if emptyIndex > -1:
358 self.removeTab(emptyIndex)
359
360 return newIndex
361
362 def __captionChange(self, cap, editor):
363 """
364 Private method to handle Caption change signals from the editor.
365
366 Updates the tab text and tooltip text to reflect the new caption information.
367
368 @param cap Caption for the editor
369 @param editor Editor to update the caption for
370 """
371 fn = editor.getFileName()
372 if fn:
373 if Preferences.getUI("TabViewManagerFilenameOnly"):
374 txt = os.path.basename(fn)
375 else:
376 txt = fn
377 ppath = e4App().getObject("Project").getProjectPath()
378 if ppath:
379 txt = txt.replace(ppath + os.sep, "")
380
381 maxFileNameChars = Preferences.getUI("TabViewManagerFilenameLength")
382 if len(txt) > maxFileNameChars:
383 txt = "...%s" % txt[-maxFileNameChars:]
384 if editor.isReadOnly():
385 txt = self.trUtf8("{0} (ro)").format(txt)
386
387 index = self.indexOf(editor)
388 if index > -1:
389 self.setTabText(index, txt)
390 self.setTabToolTip(index, fn)
391
392 def removeWidget(self, object):
393 """
394 Public method to remove a widget.
395
396 @param object object to be removed (QWidget)
397 """
398 index = self.indexOf(object)
399 if index > -1:
400 self.removeTab(index)
401
402 if isinstance(object, QScintilla.Editor.Editor):
403 self.disconnect(object, SIGNAL('captionChanged'),
404 self.__captionChange)
405 self.editors.remove(object)
406
407 if not self.editors:
408 E4TabWidget.addTab(self, self.emptyLabel,
409 UI.PixmapCache.getIcon("empty.png"), "")
410 self.emptyLabel.show()
411 if self.closeButton:
412 self.closeButton.setEnabled(False)
413 else:
414 self.setTabsClosable(False)
415 self.navigationButton.setEnabled(False)
416
417 def relocateTab(self, sourceId, sourceIndex, targetIndex):
418 """
419 Public method to relocate an editor from another TabWidget.
420
421 @param sourceId id of the TabWidget to get the editor from (long)
422 @param sourceIndex index of the tab in the old tab widget (integer)
423 @param targetIndex index position to place it to (integer)
424 """
425 tw = self.vm.getTabWidgetById(sourceId)
426 if tw is not None:
427 # step 1: get data of the tab of the source
428 toolTip = tw.tabToolTip(sourceIndex)
429 text = tw.tabText(sourceIndex)
430 icon = tw.tabIcon(sourceIndex)
431 whatsThis = tw.tabWhatsThis(sourceIndex)
432 editor = tw.widget(sourceIndex)
433
434 # step 2: relocate the tab
435 tw.removeWidget(editor)
436 self.insertWidget(targetIndex, editor, text)
437
438 # step 3: set the tab data again
439 self.setTabIcon(targetIndex, icon)
440 self.setTabToolTip(targetIndex, toolTip)
441 self.setTabWhatsThis(targetIndex, whatsThis)
442
443 # step 4: set current widget
444 self.setCurrentIndex(targetIndex)
445
446 def copyTabOther(self, sourceId, sourceIndex, targetIndex):
447 """
448 Public method to copy an editor from another TabWidget.
449
450 @param sourceId id of the TabWidget to get the editor from (long)
451 @param sourceIndex index of the tab in the old tab widget (integer)
452 @param targetIndex index position to place it to (integer)
453 """
454 tw = self.vm.getTabWidgetById(sourceId)
455 if tw is not None:
456 editor = tw.widget(sourceIndex)
457 newEditor = self.vm.cloneEditor(editor, editor.getFileType(),
458 editor.getFileName())
459 self.vm.insertView(newEditor, self, targetIndex,
460 editor.getFileName(), editor.getNoName())
461
462 def copyTab(self, sourceIndex, targetIndex):
463 """
464 Public method to copy an editor.
465
466 @param sourceIndex index of the tab (integer)
467 @param targetIndex index position to place it to (integer)
468 """
469 editor = self.widget(sourceIndex)
470 newEditor = self.vm.cloneEditor(editor, editor.getFileType(),
471 editor.getFileName())
472 self.vm.insertView(newEditor, self, targetIndex,
473 editor.getFileName(), editor.getNoName())
474
475 def currentWidget(self):
476 """
477 Overridden method to return a reference to the current page.
478
479 @return reference to the current page (QWidget)
480 """
481 if not self.editors:
482 return None
483 else:
484 return E4TabWidget.currentWidget(self)
485
486 def hasEditor(self, editor):
487 """
488 Public method to check for an editor.
489
490 @param editor editor object to check for
491 @return flag indicating, whether the editor to be checked belongs
492 to the list of editors managed by this tab widget.
493 """
494 return editor in self.editors
495
496 def hasEditors(self):
497 """
498 Public method to test, if any editor is managed.
499
500 @return flag indicating editors are managed
501 """
502 return len(self.editors) > 0
503
504 def __contextMenuClose(self):
505 """
506 Private method to close the selected tab.
507 """
508 if self.contextMenuEditor:
509 self.vm.closeEditorWindow(self.contextMenuEditor)
510
511 def __contextMenuCloseOthers(self):
512 """
513 Private method to close the other tabs.
514 """
515 index = self.contextMenuIndex
516 for i in range(self.count() - 1, index, -1) + range(index - 1, -1, -1):
517 editor = self.widget(i)
518 self.vm.closeEditorWindow(editor)
519
520 def __contextMenuCloseAll(self):
521 """
522 Private method to close all tabs.
523 """
524 savedEditors = self.editors[:]
525 for editor in savedEditors:
526 self.vm.closeEditorWindow(editor)
527
528 def __contextMenuSave(self):
529 """
530 Private method to save the selected tab.
531 """
532 if self.contextMenuEditor:
533 self.vm.saveEditorEd(self.contextMenuEditor)
534
535 def __contextMenuSaveAs(self):
536 """
537 Private method to save the selected tab to a new file.
538 """
539 if self.contextMenuEditor:
540 self.vm.saveAsEditorEd(self.contextMenuEditor)
541
542 def __contextMenuSaveAll(self):
543 """
544 Private method to save all tabs.
545 """
546 self.vm.saveEditorsList(self.editors)
547
548 def __contextMenuSaveToProject(self):
549 """
550 Private method to save the selected tab to the current project.
551 """
552 if self.contextMenuEditor:
553 self.vm.saveEditorToProjectEd(self.contextMenuEditor)
554
555 def __contextMenuPrintFile(self):
556 """
557 Private method to print the selected tab.
558 """
559 if self.contextMenuEditor:
560 self.vm.printEditor(self.contextMenuEditor)
561
562 def __contextMenuMoveLeft(self):
563 """
564 Private method to move a tab one position to the left.
565 """
566 self.moveTab(self.contextMenuIndex, self.contextMenuIndex - 1)
567
568 def __contextMenuMoveRight(self):
569 """
570 Private method to move a tab one position to the right.
571 """
572 self.moveTab(self.contextMenuIndex, self.contextMenuIndex + 1)
573
574 def __contextMenuMoveFirst(self):
575 """
576 Private method to move a tab to the first position.
577 """
578 self.moveTab(self.contextMenuIndex, 0)
579
580 def __contextMenuMoveLast(self):
581 """
582 Private method to move a tab to the last position.
583 """
584 self.moveTab(self.contextMenuIndex, self.count() - 1)
585
586 def __closeButtonClicked(self):
587 """
588 Private method to handle the press of the close button.
589 """
590 self.vm.closeEditorWindow(self.currentWidget())
591
592 def __closeRequested(self, index):
593 """
594 Private method to handle the press of the individual tab close button.
595
596 @param index index of the tab (integer)
597 """
598 if index >= 0:
599 self.vm.closeEditorWindow(self.widget(index))
600
601 def mouseDoubleClickEvent(self, event):
602 """
603 Protected method handling double click events.
604
605 @param event reference to the event object (QMouseEvent)
606 """
607 self.vm.newEditor()
608
609 class Tabview(QSplitter, ViewManager):
610 """
611 Class implementing a tabbed viewmanager class embedded in a splitter.
612
613 @signal changeCaption(string) emitted if a change of the caption is necessary
614 @signal editorChanged(string) emitted when the current editor has changed
615 """
616 def __init__(self, parent):
617 """
618 Constructor
619
620 @param parent parent widget (QWidget)
621 @param ui reference to the main user interface
622 @param dbs reference to the debug server object
623 """
624 self.tabWidgets = []
625
626 QSplitter.__init__(self, parent)
627 ViewManager.__init__(self)
628 tw = TabWidget(self)
629 self.addWidget(tw)
630 self.tabWidgets.append(tw)
631 self.currentTabWidget = tw
632 self.currentTabWidget.showIndicator(True)
633 self.connect(tw, SIGNAL('currentChanged(int)'),
634 self.__currentChanged)
635 tw.installEventFilter(self)
636 tw.tabBar().installEventFilter(self)
637 self.setOrientation(Qt.Vertical)
638 self.__inRemoveView = False
639
640 self.maxFileNameChars = Preferences.getUI("TabViewManagerFilenameLength")
641 self.filenameOnly = Preferences.getUI("TabViewManagerFilenameOnly")
642
643 def canCascade(self):
644 """
645 Public method to signal if cascading of managed windows is available.
646
647 @return flag indicating cascading of windows is available
648 """
649 return False
650
651 def canTile(self):
652 """
653 Public method to signal if tiling of managed windows is available.
654
655 @return flag indicating tiling of windows is available
656 """
657 return False
658
659 def canSplit(self):
660 """
661 public method to signal if splitting of the view is available.
662
663 @return flag indicating splitting of the view is available.
664 """
665 return True
666
667 def tile(self):
668 """
669 Public method to tile the managed windows.
670 """
671 pass
672
673 def cascade(self):
674 """
675 Public method to cascade the managed windows.
676 """
677 pass
678
679 def _removeAllViews(self):
680 """
681 Protected method to remove all views (i.e. windows)
682 """
683 for win in self.editors:
684 self._removeView(win)
685
686 def _removeView(self, win):
687 """
688 Protected method to remove a view (i.e. window)
689
690 @param win editor window to be removed
691 """
692 self.__inRemoveView = True
693 for tw in self.tabWidgets:
694 if tw.hasEditor(win):
695 tw.removeWidget(win)
696 break
697 win.closeIt()
698 self.__inRemoveView = False
699
700 # if this was the last editor in this view, switch to the next, that
701 # still has open editors
702 for i in range(self.tabWidgets.index(tw), -1, -1) + \
703 range(self.tabWidgets.index(tw) + 1, len(self.tabWidgets)):
704 if self.tabWidgets[i].hasEditors():
705 self.currentTabWidget.showIndicator(False)
706 self.currentTabWidget = self.tabWidgets[i]
707 self.currentTabWidget.showIndicator(True)
708 self.activeWindow().setFocus()
709 break
710
711 aw = self.activeWindow()
712 fn = aw and aw.getFileName() or None
713 if fn:
714 self.emit(SIGNAL('changeCaption'), fn)
715 self.emit(SIGNAL('editorChanged'), fn)
716 else:
717 self.emit(SIGNAL('changeCaption'), "")
718
719 def _addView(self, win, fn = None, noName = ""):
720 """
721 Protected method to add a view (i.e. window)
722
723 @param win editor window to be added
724 @param fn filename of this editor (string)
725 @param noName name to be used for an unnamed editor (string)
726 """
727 if fn is None:
728 if not noName:
729 self.untitledCount += 1
730 noName = self.trUtf8("Untitled {0}").format(self.untitledCount)
731 self.currentTabWidget.addTab(win, noName)
732 win.setNoName(noName)
733 else:
734 if self.filenameOnly:
735 txt = os.path.basename(fn)
736 else:
737 txt = fn
738 ppath = e4App().getObject("Project").getProjectPath()
739 if ppath:
740 txt = txt.replace(ppath + os.sep, "")
741 if len(txt) > self.maxFileNameChars:
742 txt = "...%s" % txt[-self.maxFileNameChars:]
743 if not QFileInfo(fn).isWritable():
744 txt = self.trUtf8("{0} (ro)").format(txt)
745 self.currentTabWidget.addTab(win, txt)
746 index = self.currentTabWidget.indexOf(win)
747 self.currentTabWidget.setTabToolTip(index, fn)
748 self.currentTabWidget.setCurrentWidget(win)
749 win.show()
750 win.setFocus()
751 if fn:
752 self.emit(SIGNAL('changeCaption'), fn)
753 self.emit(SIGNAL('editorChanged'), fn)
754 else:
755 self.emit(SIGNAL('changeCaption'), "")
756
757 def insertView(self, win, tabWidget, index, fn = None, noName = ""):
758 """
759 Protected method to add a view (i.e. window)
760
761 @param win editor window to be added
762 @param tabWidget reference to the tab widget to insert the editor into (TabWidget)
763 @param index index position to insert at (integer)
764 @param fn filename of this editor (string)
765 @param noName name to be used for an unnamed editor (string)
766 """
767 if fn is None:
768 if not noName:
769 self.untitledCount += 1
770 noName = self.trUtf8("Untitled {0}").format(self.untitledCount)
771 tabWidget.insertWidget(index, win, noName)
772 win.setNoName(noName)
773 else:
774 if self.filenameOnly:
775 txt = os.path.basename(fn)
776 else:
777 txt = fn
778 ppath = e4App().getObject("Project").getProjectPath()
779 if ppath:
780 txt = txt.replace(ppath + os.sep, "")
781 if len(txt) > self.maxFileNameChars:
782 txt = "...%s" % txt[-self.maxFileNameChars:]
783 if not QFileInfo(fn).isWritable():
784 txt = self.trUtf8("{0} (ro)").format(txt)
785 nindex = tabWidget.insertWidget(index, win, txt)
786 tabWidget.setTabToolTip(nindex, fn)
787 tabWidget.setCurrentWidget(win)
788 win.show()
789 win.setFocus()
790 if fn:
791 self.emit(SIGNAL('changeCaption'), fn)
792 self.emit(SIGNAL('editorChanged'), fn)
793 else:
794 self.emit(SIGNAL('changeCaption'), "")
795
796 self._modificationStatusChanged(win.isModified(), win)
797 self._checkActions(win)
798
799 def _showView(self, win, fn = None):
800 """
801 Protected method to show a view (i.e. window)
802
803 @param win editor window to be shown
804 @param fn filename of this editor (string)
805 """
806 win.show()
807 for tw in self.tabWidgets:
808 if tw.hasEditor(win):
809 tw.setCurrentWidget(win)
810 self.currentTabWidget.showIndicator(False)
811 self.currentTabWidget = tw
812 self.currentTabWidget.showIndicator(True)
813 break
814 win.setFocus()
815
816 def activeWindow(self):
817 """
818 Public method to return the active (i.e. current) window.
819
820 @return reference to the active editor
821 """
822 return self.currentTabWidget.currentWidget()
823
824 def showWindowMenu(self, windowMenu):
825 """
826 Public method to set up the viewmanager part of the Window menu.
827
828 @param windowMenu reference to the window menu
829 """
830 pass
831
832 def _initWindowActions(self):
833 """
834 Protected method to define the user interface actions for window handling.
835 """
836 pass
837
838 def setEditorName(self, editor, newName):
839 """
840 Public method to change the displayed name of the editor.
841
842 @param editor editor window to be changed
843 @param newName new name to be shown (string)
844 """
845 if self.filenameOnly:
846 tabName = os.path.basename(newName)
847 else:
848 tabName = newName
849 ppath = e4App().getObject("Project").getProjectPath()
850 if ppath:
851 tabName = tabName.replace(ppath + os.sep, "")
852 if len(tabName) > self.maxFileNameChars:
853 tabName = "...%s" % tabName[-self.maxFileNameChars:]
854 index = self.currentTabWidget.indexOf(editor)
855 self.currentTabWidget.setTabText(index, tabName)
856 self.currentTabWidget.setTabToolTip(index, newName)
857 self.emit(SIGNAL('changeCaption'), newName)
858
859 def _modificationStatusChanged(self, m, editor):
860 """
861 Protected slot to handle the modificationStatusChanged signal.
862
863 @param m flag indicating the modification status (boolean)
864 @param editor editor window changed
865 """
866 for tw in self.tabWidgets:
867 if tw.hasEditor(editor):
868 break
869 index = tw.indexOf(editor)
870 if m:
871 tw.setTabIcon(index, UI.PixmapCache.getIcon("fileModified.png"))
872 elif editor.hasSyntaxErrors():
873 tw.setTabIcon(index, UI.PixmapCache.getIcon("syntaxError.png"))
874 else:
875 tw.setTabIcon(index, UI.PixmapCache.getIcon("empty.png"))
876 self._checkActions(editor)
877
878 def _syntaxErrorToggled(self, editor):
879 """
880 Protected slot to handle the syntaxerrorToggled signal.
881
882 @param editor editor that sent the signal
883 """
884 for tw in self.tabWidgets:
885 if tw.hasEditor(editor):
886 break
887 index = tw.indexOf(editor)
888 if editor.hasSyntaxErrors():
889 tw.setTabIcon(index, UI.PixmapCache.getIcon("syntaxError.png"))
890 else:
891 tw.setTabIcon(index, UI.PixmapCache.getIcon("empty.png"))
892
893 ViewManager._syntaxErrorToggled(self, editor)
894
895 def addSplit(self):
896 """
897 Public method used to split the current view.
898 """
899 tw = TabWidget(self)
900 tw.show()
901 self.addWidget(tw)
902 self.tabWidgets.append(tw)
903 self.currentTabWidget.showIndicator(False)
904 self.currentTabWidget = self.tabWidgets[-1]
905 self.currentTabWidget.showIndicator(True)
906 self.connect(tw, SIGNAL('currentChanged(int)'),
907 self.__currentChanged)
908 tw.installEventFilter(self)
909 tw.tabBar().installEventFilter(self)
910 if self.orientation() == Qt.Horizontal:
911 size = self.width()
912 else:
913 size = self.height()
914 self.setSizes([int(size/len(self.tabWidgets))] * len(self.tabWidgets))
915 self.splitRemoveAct.setEnabled(True)
916 self.nextSplitAct.setEnabled(True)
917 self.prevSplitAct.setEnabled(True)
918
919 def removeSplit(self):
920 """
921 Public method used to remove the current split view.
922
923 @return flag indicating successfull removal
924 """
925 if len(self.tabWidgets) > 1:
926 tw = self.currentTabWidget
927 res = True
928 savedEditors = tw.editors[:]
929 for editor in savedEditors:
930 res &= self.closeEditor(editor)
931 if res:
932 try:
933 i = self.tabWidgets.index(tw)
934 except ValueError:
935 return True
936 if i == len(self.tabWidgets) - 1:
937 i -= 1
938 self.tabWidgets.remove(tw)
939 tw.close()
940 self.currentTabWidget = self.tabWidgets[i]
941 self.currentTabWidget.showIndicator(True)
942 if len(self.tabWidgets) == 1:
943 self.splitRemoveAct.setEnabled(False)
944 self.nextSplitAct.setEnabled(False)
945 self.prevSplitAct.setEnabled(False)
946 return True
947
948 return False
949
950 def setSplitOrientation(self, orientation):
951 """
952 Public method used to set the orientation of the split view.
953
954 @param orientation orientation of the split
955 (Qt.Horizontal or Qt.Vertical)
956 """
957 self.setOrientation(orientation)
958
959 def nextSplit(self):
960 """
961 Public slot used to move to the next split.
962 """
963 aw = self.activeWindow()
964 _hasFocus = aw and aw.hasFocus()
965 ind = self.tabWidgets.index(self.currentTabWidget) + 1
966 if ind == len(self.tabWidgets):
967 ind = 0
968
969 self.currentTabWidget.showIndicator(False)
970 self.currentTabWidget = self.tabWidgets[ind]
971 self.currentTabWidget.showIndicator(True)
972 if _hasFocus:
973 aw = self.activeWindow()
974 if aw:
975 aw.setFocus()
976
977 def prevSplit(self):
978 """
979 Public slot used to move to the previous split.
980 """
981 aw = self.activeWindow()
982 _hasFocus = aw and aw.hasFocus()
983 ind = self.tabWidgets.index(self.currentTabWidget) - 1
984 if ind == -1:
985 ind = len(self.tabWidgets) - 1
986
987 self.currentTabWidget.showIndicator(False)
988 self.currentTabWidget = self.tabWidgets[ind]
989 self.currentTabWidget.showIndicator(True)
990 if _hasFocus:
991 aw = self.activeWindow()
992 if aw:
993 aw.setFocus()
994
995 def __currentChanged(self, index):
996 """
997 Private slot to handle the currentChanged signal.
998
999 @param index index of the current tab (integer)
1000 """
1001 if index == -1 or not self.editors:
1002 return
1003
1004 editor = self.activeWindow()
1005 if editor is None:
1006 return
1007
1008 self._checkActions(editor)
1009 editor.setFocus()
1010 fn = editor.getFileName()
1011 if fn:
1012 self.emit(SIGNAL('changeCaption'), fn)
1013 if not self.__inRemoveView:
1014 self.emit(SIGNAL('editorChanged'), fn)
1015 else:
1016 self.emit(SIGNAL('changeCaption'), "")
1017
1018 def eventFilter(self, watched, event):
1019 """
1020 Public method called to filter the event queue.
1021
1022 @param watched the QObject being watched (QObject)
1023 @param event the event that occurred (QEvent)
1024 @return always False
1025 """
1026 if event.type() == QEvent.MouseButtonPress and \
1027 not event.button() == Qt.RightButton:
1028 self.currentTabWidget.showIndicator(False)
1029 if isinstance(watched, E4TabWidget):
1030 switched = watched is not self.currentTabWidget
1031 self.currentTabWidget = watched
1032 elif isinstance(watched, QTabBar):
1033 switched = watched.parent() is not self.currentTabWidget
1034 self.currentTabWidget = watched.parent()
1035 if switched:
1036 index = self.currentTabWidget.selectTab(event.pos())
1037 switched = self.currentTabWidget.widget(index) is self.activeWindow()
1038 elif isinstance(watched, QScintilla.Editor.Editor):
1039 for tw in self.tabWidgets:
1040 if tw.hasEditor(watched):
1041 switched = tw is not self.currentTabWidget
1042 self.currentTabWidget = tw
1043 break
1044 self.currentTabWidget.showIndicator(True)
1045
1046 aw = self.activeWindow()
1047 if aw is not None:
1048 self._checkActions(aw)
1049 aw.setFocus()
1050 fn = aw.getFileName()
1051 if fn:
1052 self.emit(SIGNAL('changeCaption'), fn)
1053 if switched:
1054 self.emit(SIGNAL('editorChanged'), fn)
1055 else:
1056 self.emit(SIGNAL('changeCaption'), "")
1057
1058 return False
1059
1060 def preferencesChanged(self):
1061 """
1062 Public slot to handle the preferencesChanged signal.
1063 """
1064 ViewManager.preferencesChanged(self)
1065
1066 self.maxFileNameChars = Preferences.getUI("TabViewManagerFilenameLength")
1067 self.filenameOnly = Preferences.getUI("TabViewManagerFilenameOnly")
1068
1069 for tabWidget in self.tabWidgets:
1070 for index in range(tabWidget.count()):
1071 editor = tabWidget.widget(index)
1072 if isinstance(editor, QScintilla.Editor.Editor):
1073 fn = editor.getFileName()
1074 if fn:
1075 if self.filenameOnly:
1076 txt = os.path.basename(fn)
1077 else:
1078 txt = fn
1079 ppath = e4App().getObject("Project").getProjectPath()
1080 if ppath:
1081 txt = txt.replace(ppath + os.sep, "")
1082 if len(txt) > self.maxFileNameChars:
1083 txt = "...%s" % txt[-self.maxFileNameChars:]
1084 if not QFileInfo(fn).isWritable():
1085 txt = self.trUtf8("{0} (ro)").format(txt)
1086 tabWidget.setTabText(index, txt)
1087
1088 def getTabWidgetById(self, id_):
1089 """
1090 Public method to get a reference to a tab widget knowing it's ID.
1091
1092 @param id_ id of the tab widget (long)
1093 @return reference to the tab widget (TabWidget)
1094 """
1095 for tw in self.tabWidgets:
1096 if id(tw) == id_:
1097 return tw
1098 return None

eric ide

mercurial