E5Gui/E5TabWidget.py

changeset 55
b5c84934de9c
child 154
25d288e43a6c
equal deleted inserted replaced
54:31463df17fd5 55:b5c84934de9c
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2005 - 2010 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a TabWidget class substituting QTabWidget.
8 """
9
10 from PyQt4.QtGui import QTabWidget, QTabBar, QApplication, QDrag, QStyle, QLabel, QMovie
11 from PyQt4.QtCore import Qt, SIGNAL, QPoint, QMimeData, QByteArray
12
13 class E5WheelTabBar(QTabBar):
14 """
15 Class implementing a tab bar class substituting QTabBar to support wheel events.
16 """
17 def __init__(self, parent = None):
18 """
19 Constructor
20
21 @param parent reference to the parent widget (QWidget)
22 """
23 QTabBar.__init__(self, parent)
24 self._tabWidget = parent
25
26 def wheelEvent(self, event):
27 """
28 Protected slot to support wheel events.
29
30 @param reference to the wheel event (QWheelEvent)
31 """
32 try:
33 if event.delta() > 0:
34 self._tabWidget.prevTab()
35 else:
36 self._tabWidget.nextTab()
37
38 event.accept()
39 except AttributeError:
40 pass
41
42 class E5DnDTabBar(E5WheelTabBar):
43 """
44 Class implementing a tab bar class substituting QTabBar.
45
46 @signal tabMoveRequested(int, int) emitted to signal a tab move request giving
47 the old and new index position
48 """
49 def __init__(self, parent = None):
50 """
51 Constructor
52
53 @param parent reference to the parent widget (QWidget)
54 """
55 E5WheelTabBar.__init__(self, parent)
56 self.setAcceptDrops(True)
57
58 self.__dragStartPos = QPoint()
59
60 def mousePressEvent(self, event):
61 """
62 Protected method to handle mouse press events.
63
64 @param event reference to the mouse press event (QMouseEvent)
65 """
66 if event.button() == Qt.LeftButton:
67 self.__dragStartPos = QPoint(event.pos())
68 E5WheelTabBar.mousePressEvent(self, event)
69
70 def mouseMoveEvent(self, event):
71 """
72 Protected method to handle mouse move events.
73
74 @param event reference to the mouse move event (QMouseEvent)
75 """
76 if event.buttons() == Qt.MouseButtons(Qt.LeftButton) and \
77 (event.pos() - self.__dragStartPos).manhattanLength() > \
78 QApplication.startDragDistance():
79 drag = QDrag(self)
80 mimeData = QMimeData()
81 index = self.tabAt(event.pos())
82 mimeData.setText(self.tabText(index))
83 mimeData.setData("action", "tab-reordering")
84 mimeData.setData("tabbar-id", QByteArray.number(id(self)))
85 drag.setMimeData(mimeData)
86 drag.exec_()
87 E5WheelTabBar.mouseMoveEvent(self, event)
88
89 def dragEnterEvent(self, event):
90 """
91 Protected method to handle drag enter events.
92
93 @param event reference to the drag enter event (QDragEnterEvent)
94 """
95 mimeData = event.mimeData()
96 formats = mimeData.formats()
97 if "action" in formats and \
98 mimeData.data("action") == "tab-reordering" and \
99 "tabbar-id" in formats and \
100 mimeData.data("tabbar-id") == id(self):
101 event.acceptProposedAction()
102 E5WheelTabBar.dragEnterEvent(self, event)
103
104 def dropEvent(self, event):
105 """
106 Protected method to handle drop events.
107
108 @param event reference to the drop event (QDropEvent)
109 """
110 fromIndex = self.tabAt(self.__dragStartPos)
111 toIndex = self.tabAt(event.pos())
112 if fromIndex != toIndex:
113 self.emit(SIGNAL("tabMoveRequested(int, int)"), fromIndex, toIndex)
114 event.acceptProposedAction()
115 E5WheelTabBar.dropEvent(self, event)
116
117 class E5TabWidget(QTabWidget):
118 """
119 Class implementing a tab widget class substituting QTabWidget.
120
121 It provides slots to show the previous and next tab and give
122 them the input focus and it allows to have a context menu for the tabs.
123
124 @signal customTabContextMenuRequested(const QPoint & point, int index) emitted when
125 a context menu for a tab is requested
126 """
127 def __init__(self, parent = None, dnd = False):
128 """
129 Constructor
130
131 @param parent reference to the parent widget (QWidget)
132 @keyparam dnd flag indicating the support for Drag & Drop (boolean)
133 """
134 QTabWidget.__init__(self, parent)
135
136 if dnd:
137 if not hasattr(self, 'setMovable'):
138 self.__tabBar = E5DnDTabBar(self)
139 self.connect(self.__tabBar, SIGNAL("tabMoveRequested(int, int)"),
140 self.moveTab)
141 self.setTabBar(self.__tabBar)
142 else:
143 self.__tabBar = E5WheelTabBar(self)
144 self.setTabBar(self.__tabBar)
145 self.setMovable(True)
146 else:
147 self.__tabBar = E5WheelTabBar(self)
148 self.setTabBar(self.__tabBar)
149
150 self.__lastCurrentIndex = -1
151 self.__currentIndex = -1
152 self.connect(self, SIGNAL("currentChanged(int)"), self.__currentChanged)
153
154 def __currentChanged(self, index):
155 """
156 Private slot to handle the currentChanged signal.
157
158 @param index index of the current tab
159 """
160 if index == -1:
161 self.__lastCurrentIndex = -1
162 else:
163 self.__lastCurrentIndex = self.__currentIndex
164 self.__currentIndex = index
165
166 def switchTab(self):
167 """
168 Public slot used to switch between the current and the previous current tab.
169 """
170 if self.__lastCurrentIndex == -1 or self.__currentIndex == -1:
171 return
172
173 self.setCurrentIndex(self.__lastCurrentIndex)
174 self.currentWidget().setFocus()
175
176 def nextTab(self):
177 """
178 Public slot used to show the next tab.
179 """
180 ind = self.currentIndex() + 1
181 if ind == self.count():
182 ind = 0
183
184 self.setCurrentIndex(ind)
185 self.currentWidget().setFocus()
186
187 def prevTab(self):
188 """
189 Public slot used to show the previous tab.
190 """
191 ind = self.currentIndex() - 1
192 if ind == -1:
193 ind = self.count() - 1
194
195 self.setCurrentIndex(ind)
196 self.currentWidget().setFocus()
197
198 def setTabContextMenuPolicy(self, policy):
199 """
200 Public method to set the context menu policy of the tab.
201
202 @param policy context menu policy to set (Qt.ContextMenuPolicy)
203 """
204 self.tabBar().setContextMenuPolicy(policy)
205 if policy == Qt.CustomContextMenu:
206 self.connect(self.tabBar(),
207 SIGNAL("customContextMenuRequested(const QPoint &)"),
208 self.__handleTabCustomContextMenuRequested)
209 else:
210 self.disconnect(self.tabBar(),
211 SIGNAL("customContextMenuRequested(const QPoint &)"),
212 self.__handleTabCustomContextMenuRequested)
213
214 def __handleTabCustomContextMenuRequested(self, point):
215 """
216 Private slot to handle the context menu request for the tabbar.
217
218 @param point point the context menu was requested (QPoint)
219 """
220 _tabbar = self.tabBar()
221 for index in range(_tabbar.count()):
222 rect = _tabbar.tabRect(index)
223 if rect.contains(point):
224 self.emit(SIGNAL("customTabContextMenuRequested(const QPoint &, int)"),
225 _tabbar.mapToParent(point), index)
226 break
227
228 def selectTab(self, pos):
229 """
230 Public method to get the index of a tab given a position.
231
232 @param pos position determining the tab index (QPoint)
233 @return index of the tab (integer)
234 """
235 _tabbar = self.tabBar()
236 for index in range(_tabbar.count()):
237 rect = _tabbar.tabRect(index)
238 if rect.contains(pos):
239 return index
240
241 return -1
242
243 def moveTab(self, curIndex, newIndex):
244 """
245 Public method to move a tab to a new index.
246
247 @param curIndex index of tab to be moved (integer)
248 @param newIndex index the tab should be moved to (integer)
249 """
250 # step 1: save the tab data of tab to be moved
251 toolTip = self.tabToolTip(curIndex)
252 text = self.tabText(curIndex)
253 icon = self.tabIcon(curIndex)
254 whatsThis = self.tabWhatsThis(curIndex)
255 widget = self.widget(curIndex)
256 curWidget = self.currentWidget()
257
258 # step 2: move the tab
259 self.removeTab(curIndex)
260 self.insertTab(newIndex, widget, icon, text)
261
262 # step 3: set the tab data again
263 self.setTabToolTip(newIndex, toolTip)
264 self.setTabWhatsThis(newIndex, whatsThis)
265
266 # step 4: set current widget
267 self.setCurrentWidget(curWidget)
268
269 def __freeSide(self):
270 """
271 Private method to determine the free side of a tab.
272
273 @return free side (QTabBar.ButtonPosition)
274 """
275 side = self.__tabBar.style().styleHint(QStyle.SH_TabBar_CloseButtonPosition)
276 if side == QTabBar.LeftSide:
277 side = QTabBar.RightSide
278 else:
279 side = QTabBar.LeftSide
280 return side
281
282 def animationLabel(self, index, animationFile):
283 """
284 Public slot to set an animated icon.
285
286 @param index tab index (integer)
287 @param animationFile name of the file containing the animation (string)
288 @return reference to the created label (QLabel)
289 """
290 if index == -1:
291 return None
292
293 if hasattr(self.__tabBar, 'setTabButton'):
294 side = self.__freeSide()
295 animation = QLabel(self)
296 if animationFile and not animation.movie():
297 movie = QMovie(animationFile, QByteArray(), animation)
298 movie.setSpeed(50)
299 animation.setMovie(movie)
300 movie.start()
301 self.__tabBar.setTabButton(index, side, None)
302 self.__tabBar.setTabButton(index, side, animation)
303 return animation
304 else:
305 return None
306
307 def resetAnimation(self, index):
308 """
309 Public slot to reset an animated icon.
310
311 @param index tab index (integer)
312 """
313 if index == -1:
314 return None
315
316 if hasattr(self.__tabBar, 'tabButton'):
317 side = self.__freeSide()
318 animation = self.__tabBar.tabButton(index, side)
319 if animation is not None:
320 animation.movie().stop()
321 self.__tabBar.setTabButton(index, side, None)
322 del animation

eric ide

mercurial