E5Gui/E5SideBar.py

changeset 55
b5c84934de9c
child 96
9624a110667d
equal deleted inserted replaced
54:31463df17fd5 55:b5c84934de9c
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2008 - 2010 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a sidebar class.
8 """
9
10 from PyQt4.QtCore import SIGNAL, SLOT, QEvent, QSize, Qt, QByteArray, \
11 QDataStream, QIODevice
12 from PyQt4.QtGui import QTabBar, QWidget, QStackedWidget, QBoxLayout, QToolButton
13
14 from E5Gui.E5Application import e5App
15
16 import UI.PixmapCache
17
18 class E5SideBar(QWidget):
19 """
20 Class implementing a sidebar with a widget area, that is hidden or shown, if the
21 current tab is clicked again.
22 """
23 Version = 1
24
25 North = 0
26 East = 1
27 South = 2
28 West = 3
29
30 def __init__(self, orientation = None, parent = None):
31 """
32 Constructor
33
34 @param orientation orientation of the sidebar widget (North, East, South, West)
35 @param parent parent widget (QWidget)
36 """
37 QWidget.__init__(self, parent)
38
39 self.__tabBar = QTabBar()
40 self.__tabBar.setDrawBase(True)
41 self.__tabBar.setShape(QTabBar.RoundedNorth)
42 self.__stackedWidget = QStackedWidget(self)
43 self.__stackedWidget.setContentsMargins(0, 0, 0, 0)
44 self.__autoHideButton = QToolButton()
45 self.__autoHideButton.setCheckable(True)
46 self.__autoHideButton.setIcon(UI.PixmapCache.getIcon("autoHideOff.png"))
47 self.__autoHideButton.setChecked(True)
48 self.__autoHideButton.setToolTip(
49 self.trUtf8("Deselect to activate automatic collapsing"))
50 self.barLayout = QBoxLayout(QBoxLayout.LeftToRight)
51 self.barLayout.setMargin(0)
52 self.layout = QBoxLayout(QBoxLayout.TopToBottom)
53 self.layout.setMargin(0)
54 self.layout.setSpacing(0)
55 self.barLayout.addWidget(self.__autoHideButton)
56 self.barLayout.addWidget(self.__tabBar)
57 self.layout.addLayout(self.barLayout)
58 self.layout.addWidget(self.__stackedWidget)
59 self.setLayout(self.layout)
60
61 self.__minimized = False
62 self.__minSize = 0
63 self.__maxSize = 0
64 self.__bigSize = QSize()
65
66 self.splitter = None
67 self.splitterSizes = []
68
69 self.__hasFocus = False # flag storing if this widget or any child has the focus
70 self.__autoHide = False
71
72 self.__tabBar.installEventFilter(self)
73
74 self.__orientation = E5SideBar.North
75 if orientation is None:
76 orientation = E5SideBar.North
77 self.setOrientation(orientation)
78
79 self.connect(self.__tabBar, SIGNAL("currentChanged(int)"),
80 self.__stackedWidget, SLOT("setCurrentIndex(int)"))
81 self.connect(e5App(), SIGNAL("focusChanged(QWidget*, QWidget*)"),
82 self.__appFocusChanged)
83 self.connect(self.__autoHideButton, SIGNAL("toggled(bool)"),
84 self.__autoHideToggled)
85
86 def setSplitter(self, splitter):
87 """
88 Public method to set the splitter managing the sidebar.
89
90 @param splitter reference to the splitter (QSplitter)
91 """
92 self.splitter = splitter
93
94 def shrink(self):
95 """
96 Public method to shrink the sidebar.
97 """
98 self.__minimized = True
99 self.__bigSize = self.size()
100 if self.__orientation in [E5SideBar.North, E5SideBar.South]:
101 self.__minSize = self.minimumHeight()
102 self.__maxSize = self.maximumHeight()
103 else:
104 self.__minSize = self.minimumWidth()
105 self.__maxSize = self.maximumWidth()
106 self.splitterSizes = self.splitter.sizes()
107
108 self.__stackedWidget.hide()
109
110 if self.__orientation in [E5SideBar.North, E5SideBar.South]:
111 self.setFixedHeight(self.__tabBar.minimumSizeHint().height())
112 else:
113 self.setFixedWidth(self.__tabBar.minimumSizeHint().width())
114
115 def expand(self):
116 """
117 Public method to expand the sidebar.
118 """
119 self.__minimized = False
120 self.__stackedWidget.show()
121 self.resize(self.__bigSize)
122 if self.__orientation in [E5SideBar.North, E5SideBar.South]:
123 self.setMinimumHeight(self.__minSize)
124 self.setMaximumHeight(self.__maxSize)
125 else:
126 self.setMinimumWidth(self.__minSize)
127 self.setMaximumWidth(self.__maxSize)
128 self.splitter.setSizes(self.splitterSizes)
129
130 def isMinimized(self):
131 """
132 Public method to check the minimized state.
133
134 @return flag indicating the minimized state (boolean)
135 """
136 return self.__minimized
137
138 def isAutoHiding(self):
139 """
140 Public method to check, if the auto hide function is active.
141
142 @return flag indicating the state of auto hiding (boolean)
143 """
144 return self.__autoHide
145
146 def eventFilter(self, obj, evt):
147 """
148 Protected method to handle some events for the tabbar.
149
150 @param obj reference to the object (QObject)
151 @param evt reference to the event object (QEvent)
152 @return flag indicating, if the event was handled (boolean)
153 """
154 if obj == self.__tabBar:
155 if evt.type() == QEvent.MouseButtonPress:
156 pos = evt.pos()
157 index = -1
158 for i in range(self.__tabBar.count()):
159 if self.__tabBar.tabRect(i).contains(pos):
160 index = i
161 break
162
163 if i == self.__tabBar.currentIndex():
164 if self.isMinimized():
165 self.expand()
166 else:
167 self.shrink()
168 return True
169 elif self.isMinimized():
170 self.expand()
171 elif evt.type() == QEvent.Wheel and not self.__stackedWidget.isHidden():
172 if evt.delta() > 0:
173 self.prevTab()
174 else:
175 self.nextTab()
176 return True
177
178 return QWidget.eventFilter(self, obj, evt)
179
180 def addTab(self, widget, iconOrLabel, label = None):
181 """
182 Public method to add a tab to the sidebar.
183
184 @param widget reference to the widget to add (QWidget)
185 @param iconOrLabel reference to the icon or the labeltext of the tab
186 (QIcon, string)
187 @param label the labeltext of the tab (string) (only to be
188 used, if the second parameter is a QIcon)
189 """
190 if label:
191 self.__tabBar.addTab(iconOrLabel, label)
192 else:
193 self.__tabBar.addTab(iconOrLabel)
194 self.__stackedWidget.addWidget(widget)
195
196 def insertTab(self, index, widget, iconOrLabel, label = None):
197 """
198 Public method to insert a tab into the sidebar.
199
200 @param index the index to insert the tab at (integer)
201 @param widget reference to the widget to insert (QWidget)
202 @param iconOrLabel reference to the icon or the labeltext of the tab
203 (QIcon, string)
204 @param label the labeltext of the tab (string) (only to be
205 used, if the second parameter is a QIcon)
206 """
207 if label:
208 self.__tabBar.insertTab(index, iconOrLabel, label)
209 else:
210 self.__tabBar.insertTab(index, iconOrLabel)
211 self.__stackedWidget.insertWidget(index, widget)
212
213 def removeTab(self, index):
214 """
215 Public method to remove a tab.
216
217 @param index the index of the tab to remove (integer)
218 """
219 self.__stackedWidget.removeWidget(self.__stackedWidget.widget(index))
220 self.__tabBar.removeTab(index)
221
222 def clear(self):
223 """
224 Public method to remove all tabs.
225 """
226 while self.count() > 0:
227 self.removeTab(0)
228
229 def prevTab(self):
230 """
231 Public slot used to show the previous tab.
232 """
233 ind = self.currentIndex() - 1
234 if ind == -1:
235 ind = self.count() - 1
236
237 self.setCurrentIndex(ind)
238 self.currentWidget().setFocus()
239
240 def nextTab(self):
241 """
242 Public slot used to show the next tab.
243 """
244 ind = self.currentIndex() + 1
245 if ind == self.count():
246 ind = 0
247
248 self.setCurrentIndex(ind)
249 self.currentWidget().setFocus()
250
251 def count(self):
252 """
253 Public method to get the number of tabs.
254
255 @return number of tabs in the sidebar (integer)
256 """
257 return self.__tabBar.count()
258
259 def currentIndex(self):
260 """
261 Public method to get the index of the current tab.
262
263 @return index of the current tab (integer)
264 """
265 return self.__stackedWidget.currentIndex()
266
267 def setCurrentIndex(self, index):
268 """
269 Public slot to set the current index.
270
271 @param index the index to set as the current index (integer)
272 """
273 self.__tabBar.setCurrentIndex(index)
274 self.__stackedWidget.setCurrentIndex(index)
275 if self.isMinimized():
276 self.expand()
277
278 def currentWidget(self):
279 """
280 Public method to get a reference to the current widget.
281
282 @return reference to the current widget (QWidget)
283 """
284 return self.__stackedWidget.currentWidget()
285
286 def setCurrentWidget(self, widget):
287 """
288 Public slot to set the current widget.
289
290 @param widget reference to the widget to become the current widget (QWidget)
291 """
292 self.__stackedWidget.setCurrentWidget(widget)
293 self.__tabBar.setCurrentIndex(self.__stackedWidget.currentIndex())
294 if self.isMinimized():
295 self.expand()
296
297 def indexOf(self, widget):
298 """
299 Public method to get the index of the given widget.
300
301 @param widget reference to the widget to get the index of (QWidget)
302 @return index of the given widget (integer)
303 """
304 return self.__stackedWidget.indexOf(widget)
305
306 def isTabEnabled(self, index):
307 """
308 Public method to check, if a tab is enabled.
309
310 @param index index of the tab to check (integer)
311 @return flag indicating the enabled state (boolean)
312 """
313 return self.__tabBar.isTabEnabled(index)
314
315 def setTabEnabled(self, index, enabled):
316 """
317 Public method to set the enabled state of a tab.
318
319 @param index index of the tab to set (integer)
320 @param enabled enabled state to set (boolean)
321 """
322 self.__tabBar.setTabEnabled(index, enabled)
323
324 def orientation(self):
325 """
326 Public method to get the orientation of the sidebar.
327
328 @return orientation of the sidebar (North, East, South, West)
329 """
330 return self.__orientation
331
332 def setOrientation(self, orient):
333 """
334 Public method to set the orientation of the sidebar.
335 @param orient orientation of the sidebar (North, East, South, West)
336 """
337 if orient == E5SideBar.North:
338 self.__tabBar.setShape(QTabBar.RoundedNorth)
339 self.barLayout.setDirection(QBoxLayout.LeftToRight)
340 self.layout.setDirection(QBoxLayout.TopToBottom)
341 self.layout.setAlignment(self.barLayout, Qt.AlignLeft)
342 elif orient == E5SideBar.East:
343 self.__tabBar.setShape(QTabBar.RoundedEast)
344 self.barLayout.setDirection(QBoxLayout.TopToBottom)
345 self.layout.setDirection(QBoxLayout.RightToLeft)
346 self.layout.setAlignment(self.barLayout, Qt.AlignTop)
347 elif orient == E5SideBar.South:
348 self.__tabBar.setShape(QTabBar.RoundedSouth)
349 self.barLayout.setDirection(QBoxLayout.LeftToRight)
350 self.layout.setDirection(QBoxLayout.BottomToTop)
351 self.layout.setAlignment(self.barLayout, Qt.AlignLeft)
352 elif orient == E5SideBar.West:
353 self.__tabBar.setShape(QTabBar.RoundedWest)
354 self.barLayout.setDirection(QBoxLayout.TopToBottom)
355 self.layout.setDirection(QBoxLayout.LeftToRight)
356 self.layout.setAlignment(self.barLayout, Qt.AlignTop)
357 self.__orientation = orient
358
359 def tabIcon(self, index):
360 """
361 Public method to get the icon of a tab.
362
363 @param index index of the tab (integer)
364 @return icon of the tab (QIcon)
365 """
366 return self.__tabBar.tabIcon(index)
367
368 def setTabIcon(self, index, icon):
369 """
370 Public method to set the icon of a tab.
371
372 @param index index of the tab (integer)
373 @param icon icon to be set (QIcon)
374 """
375 self.__tabBar.setTabIcon(index, icon)
376
377 def tabText(self, index):
378 """
379 Public method to get the text of a tab.
380
381 @param index index of the tab (integer)
382 @return text of the tab (string)
383 """
384 return self.__tabBar.tabText(index)
385
386 def setTabText(self, index, text):
387 """
388 Public method to set the text of a tab.
389
390 @param index index of the tab (integer)
391 @param text text to set (string)
392 """
393 self.__tabBar.setTabText(index, text)
394
395 def tabToolTip(self, index):
396 """
397 Public method to get the tooltip text of a tab.
398
399 @param index index of the tab (integer)
400 @return tooltip text of the tab (string)
401 """
402 return self.__tabBar.tabToolTip(index)
403
404 def setTabToolTip(self, index, tip):
405 """
406 Public method to set the tooltip text of a tab.
407
408 @param index index of the tab (integer)
409 @param tooltip text text to set (string)
410 """
411 self.__tabBar.setTabToolTip(index, tip)
412
413 def tabWhatsThis(self, index):
414 """
415 Public method to get the WhatsThis text of a tab.
416
417 @param index index of the tab (integer)
418 @return WhatsThis text of the tab (string)
419 """
420 return self.__tabBar.tabWhatsThis(index)
421
422 def setTabWhatsThis(self, index, text):
423 """
424 Public method to set the WhatsThis text of a tab.
425
426 @param index index of the tab (integer)
427 @param WhatsThis text text to set (string)
428 """
429 self.__tabBar.setTabWhatsThis(index, text)
430
431 def widget(self, index):
432 """
433 Public method to get a reference to the widget associated with a tab.
434
435 @param index index of the tab (integer)
436 @return reference to the widget (QWidget)
437 """
438 return self.__stackedWidget.widget(index)
439
440 def saveState(self):
441 """
442 Public method to save the state of the sidebar.
443
444 @return saved state as a byte array (QByteArray)
445 """
446 if len(self.splitterSizes) == 0:
447 self.splitterSizes = self.splitter.sizes()
448 self.__bigSize = self.size()
449 if self.__orientation in [E5SideBar.North, E5SideBar.South]:
450 self.__minSize = self.minimumHeight()
451 self.__maxSize = self.maximumHeight()
452 else:
453 self.__minSize = self.minimumWidth()
454 self.__maxSize = self.maximumWidth()
455
456 data = QByteArray()
457 stream = QDataStream(data, QIODevice.WriteOnly)
458
459 stream.writeUInt16(self.Version)
460 stream.writeBool(self.__minimized)
461 stream << self.__bigSize
462 stream.writeUInt16(self.__minSize)
463 stream.writeUInt16(self.__maxSize)
464 stream.writeUInt16(len(self.splitterSizes))
465 for size in self.splitterSizes:
466 stream.writeUInt16(size)
467 stream.writeBool(self.__autoHide)
468
469 return data
470
471 def restoreState(self, state):
472 """
473 Public method to restore the state of the sidebar.
474
475 @param state byte array containing the saved state (QByteArray)
476 @return flag indicating success (boolean)
477 """
478 if state.isEmpty():
479 return False
480
481 data = QByteArray(state)
482 stream = QDataStream(data, QIODevice.ReadOnly)
483 version = stream.readUInt16()
484 minimized = stream.readBool()
485
486 if minimized:
487 self.shrink()
488
489 stream >> self.__bigSize
490 self.__minSize = stream.readUInt16()
491 self.__maxSize = stream.readUInt16()
492 count = stream.readUInt16()
493 self.splitterSizes = []
494 for i in range(count):
495 self.splitterSizes.append(stream.readUInt16())
496
497 self.__autoHide = stream.readBool()
498 self.__autoHideButton.setChecked(not self.__autoHide)
499
500 if not minimized:
501 self.expand()
502
503 return True
504
505 #######################################################################
506 ## methods below implement the autohide functionality
507 #######################################################################
508
509 def __autoHideToggled(self, checked):
510 """
511 Private slot to handle the toggling of the autohide button.
512
513 @param checked flag indicating the checked state of the button (boolean)
514 """
515 self.__autoHide = not checked
516 if self.__autoHide:
517 self.__autoHideButton.setIcon(UI.PixmapCache.getIcon("autoHideOn"))
518 else:
519 self.__autoHideButton.setIcon(UI.PixmapCache.getIcon("autoHideOff"))
520
521 def __appFocusChanged(self, old, now):
522 """
523 Private slot to handle a change of the focus.
524
525 @param old reference to the widget, that lost focus (QWidget or None)
526 @param now reference to the widget having the focus (QWidget or None)
527 """
528 self.__hasFocus = self.isAncestorOf(now)
529 if self.__autoHide and not self.__hasFocus and not self.isMinimized():
530 self.shrink()
531 elif self.__autoHide and self.__hasFocus and self.isMinimized():
532 self.expand()
533
534 def enterEvent(self, event):
535 """
536 Protected method to handle the mouse entering this widget.
537
538 @param event reference to the event (QEvent)
539 """
540 if self.__autoHide and self.isMinimized():
541 self.expand()
542
543 def leaveEvent(self, event):
544 """
545 Protected method to handle the mouse leaving this widget.
546
547 @param event reference to the event (QEvent)
548 """
549 if self.__autoHide and not self.__hasFocus and not self.isMinimized():
550 self.shrink()

eric ide

mercurial