E5Gui/E5ModelToolBar.py

changeset 55
b5c84934de9c
child 482
4650a72c307a
child 792
a13346916170
equal deleted inserted replaced
54:31463df17fd5 55:b5c84934de9c
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2009 - 2010 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a tool bar populated from a QAbstractItemModel.
8 """
9
10 from PyQt4.QtCore import *
11 from PyQt4.QtGui import *
12
13 from .E5ModelMenu import E5ModelMenu
14
15 class E5ModelToolBar(QToolBar):
16 """
17 Class implementing a tool bar populated from a QAbstractItemModel.
18 """
19 def __init__(self, title = None, parent = None):
20 """
21 Constructor
22
23 @param title title for the tool bar (string)
24 @param parent reference to the parent widget (QWidget)
25 """
26 if title is not None:
27 QToolBar.__init__(self, title, parent)
28 else:
29 QToolBar.__init__(self, parent)
30
31 self.__model = None
32
33 self.__root = QModelIndex()
34 self.__dragStartPosition = QPoint()
35
36 if self.isVisible():
37 self._build()
38
39 self.setAcceptDrops(True)
40
41 self._mouseButton = Qt.NoButton
42 self._keyboardModifiers = Qt.KeyboardModifiers(Qt.NoModifier)
43 self.__dropRow = -1
44 self.__dropIndex = None
45
46 def setModel(self, model):
47 """
48 Public method to set the model for the tool bar.
49
50 @param model reference to the model (QAbstractItemModel)
51 """
52 if self.__model is not None:
53 self.disconnect(self.__model,
54 SIGNAL("modelReset()"),
55 self._build)
56 self.disconnect(self.__model,
57 SIGNAL("rowsInserted(const QModelIndex&, int, int)"),
58 self._build)
59 self.disconnect(self.__model,
60 SIGNAL("rowsRemoved(const QModelIndex&, int, int)"),
61 self._build)
62 self.disconnect(self.__model,
63 SIGNAL("dataChanged(const QModelIndex&, const QModelIndex&)"),
64 self._build)
65
66 self.__model = model
67
68 if self.__model is not None:
69 self.connect(self.__model,
70 SIGNAL("modelReset()"),
71 self._build)
72 self.connect(self.__model,
73 SIGNAL("rowsInserted(const QModelIndex&, int, int)"),
74 self._build)
75 self.connect(self.__model,
76 SIGNAL("rowsRemoved(const QModelIndex&, int, int)"),
77 self._build)
78 self.connect(self.__model,
79 SIGNAL("dataChanged(const QModelIndex&, const QModelIndex&)"),
80 self._build)
81
82 def model(self):
83 """
84 Public method to get a reference to the model.
85
86 @return reference to the model (QAbstractItemModel)
87 """
88 return self.__model
89
90 def setRootIndex(self, idx):
91 """
92 Public method to set the root index.
93
94 @param idx index to be set as the root index (QModelIndex)
95 """
96 self.__root = idx
97
98 def rootIndex(self):
99 """
100 Public method to get the root index.
101
102 @return root index (QModelIndex)
103 """
104 return self.__root
105
106 def _build(self):
107 """
108 Protected slot to build the tool bar.
109 """
110 assert self.__model is not None
111
112 self.clear()
113
114 for i in range(self.__model.rowCount(self.__root)):
115 idx = self.__model.index(i, 0, self.__root)
116 v = idx
117
118 title = idx.data(Qt.DisplayRole)
119 icon = idx.data(Qt.DecorationRole)
120 if icon == NotImplemented or icon is None:
121 icon = QIcon()
122 folder = self.__model.hasChildren(idx)
123
124 act = self.addAction(icon, title)
125 act.setData(v)
126
127 button = self.widgetForAction(act)
128 button.installEventFilter(self)
129
130 if folder:
131 menu = self._createMenu()
132 menu.setModel(self.__model)
133 menu.setRootIndex(idx)
134 act.setMenu(menu)
135 button.setPopupMode(QToolButton.InstantPopup)
136 button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
137
138 def index(self, action):
139 """
140 Public method to get the index of an action.
141
142 @param action reference to the action to get the index for (QAction)
143 @return index of the action (QModelIndex)
144 """
145 if action is None:
146 return QModelIndex()
147
148 idx = action.data()
149 if idx is None:
150 return QModelIndex()
151
152 if not isinstance(idx, QModelIndex):
153 return QModelIndex()
154
155 return idx
156
157 def _createMenu(self):
158 """
159 Protected method to create the menu for a tool bar action.
160
161 @return menu for a tool bar action (E5ModelMenu)
162 """
163 return E5ModelMenu(self)
164
165 def eventFilter(self, obj, evt):
166 """
167 Public method to handle event for other objects.
168
169 @param obj reference to the object (QObject)
170 @param evt reference to the event (QEvent)
171 @return flag indicating that the event should be filtered out (boolean)
172 """
173 if evt.type() == QEvent.MouseButtonRelease:
174 self._mouseButton = evt.button()
175 self._keyboardModifiers = evt.modifiers()
176 act = obj.defaultAction()
177 idx = self.index(act)
178 if idx.isValid():
179 self.emit(SIGNAL("activated(const QModelIndex&)"), idx)
180 elif evt.type() == QEvent.MouseButtonPress:
181 if evt.buttons() & Qt.LeftButton:
182 self.__dragStartPosition = self.mapFromGlobal(evt.globalPos())
183
184 return False
185
186 def dragEnterEvent(self, evt):
187 """
188 Protected method to handle drag enter events.
189
190 @param evt reference to the event (QDragEnterEvent)
191 """
192 if self.__model is not None:
193 mimeTypes = self.__model.mimeTypes()
194 for mimeType in mimeTypes:
195 if evt.mimeData().hasFormat(mimeType):
196 evt.acceptProposedAction()
197
198 QToolBar.dragEnterEvent(self, evt)
199
200 def dropEvent(self, evt):
201 """
202 Protected method to handle drop events.
203
204 @param evt reference to the event (QDropEvent)
205 """
206 if self.__model is not None:
207 act = self.actionAt(evt.pos())
208 parentIndex = self.__root
209 if act is None:
210 row = self.__model.rowCount(self.__root)
211 else:
212 idx = self.index(act)
213 assert idx.isValid()
214 row = idx.row()
215 if self.__model.hasChildren(idx):
216 parentIndex = idx
217 row = self.__model.rowCount(idx)
218
219 self.__dropRow = row
220 self.__dropIndex = parentIndex
221 evt.acceptProposedAction()
222 self.__model.dropMimeData(evt.mimeData(), evt.dropAction(),
223 row, 0, parentIndex)
224
225 QToolBar.dropEvent(self, evt)
226
227 def mouseMoveEvent(self, evt):
228 """
229 Protected method to handle mouse move events.
230
231 @param evt reference to the event (QMouseEvent)
232 """
233 if self.__model is None:
234 QToolBar.mouseMoveEvent(self, evt)
235 return
236
237 if not (evt.buttons() & Qt.LeftButton):
238 QToolBar.mouseMoveEvent(self, evt)
239 return
240
241 manhattanLength = (evt.pos() - self.__dragStartPosition).manhattanLength()
242 if manhattanLength <= QApplication.startDragDistance():
243 QToolBar.mouseMoveEvent(self, evt)
244 return
245
246 act = self.actionAt(self.__dragStartPosition)
247 if act is None:
248 QToolBar.mouseMoveEvent(self, evt)
249 return
250
251 idx = self.index(act)
252 assert idx.isValid()
253
254 drag = QDrag(self)
255 drag.setMimeData(self.__model.mimeData([idx]))
256 actionRect = self.actionGeometry(act)
257 drag.setPixmap(QPixmap.grabWidget(self, actionRect))
258
259 if drag.exec_() == Qt.MoveAction:
260 row = idx.row()
261 if self.__dropIndex == idx.parent() and self.__dropRow <= row:
262 row += 1
263 self.__model.removeRow(row, self.__root)
264
265 def hideEvent(self, evt):
266 """
267 Protected method to handle hide events.
268
269 @param evt reference to the hide event (QHideEvent)
270 """
271 self.clear()
272 QToolBar.hideEvent(self, evt)
273
274 def showEvent(self, evt):
275 """
276 Protected method to handle show events.
277
278 @param evt reference to the hide event (QHideEvent)
279 """
280 if len(self.actions()) == 0:
281 self._build()
282 QToolBar.showEvent(self, evt)
283
284 def resetFlags(self):
285 """
286 Public method to reset the saved internal state.
287 """
288 self._mouseButton = Qt.NoButton
289 self._keyboardModifiers = Qt.KeyboardModifiers(Qt.NoModifier)

eric ide

mercurial