E4Gui/E4ModelToolBar.py

changeset 0
de9c2efb9d02
child 7
c679fb30c8f3
equal deleted inserted replaced
-1:000000000000 0:de9c2efb9d02
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2009 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 E4ModelMenu import E4ModelMenu
14
15 class E4ModelToolBar(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 = QVariant(idx)
117
118 title = idx.data(Qt.DisplayRole).toString()
119 icon = idx.data(Qt.DecorationRole).toPyObject()
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 v = action.data()
149 if not v.isValid():
150 return QModelIndex()
151
152 idx = v.toPyObject()
153 if not isinstance(idx, QModelIndex):
154 return QModelIndex()
155
156 return idx
157
158 def _createMenu(self):
159 """
160 Protected method to create the menu for a tool bar action.
161
162 @return menu for a tool bar action (E4ModelMenu)
163 """
164 return E4ModelMenu(self)
165
166 def eventFilter(self, obj, evt):
167 """
168 Public method to handle event for other objects.
169
170 @param obj reference to the object (QObject)
171 @param evt reference to the event (QEvent)
172 @return flag indicating that the event should be filtered out (boolean)
173 """
174 if evt.type() == QEvent.MouseButtonRelease:
175 self._mouseButton = evt.button()
176 self._keyboardModifiers = evt.modifiers()
177 act = obj.defaultAction()
178 idx = self.index(act)
179 if idx.isValid():
180 self.emit(SIGNAL("activated(const QModelIndex&)"), idx)
181 elif evt.type() == QEvent.MouseButtonPress:
182 if evt.buttons() & Qt.LeftButton:
183 self.__dragStartPosition = self.mapFromGlobal(evt.globalPos())
184
185 return False
186
187 def dragEnterEvent(self, evt):
188 """
189 Protected method to handle drag enter events.
190
191 @param evt reference to the event (QDragEnterEvent)
192 """
193 if self.__model is not None:
194 mimeTypes = self.__model.mimeTypes()
195 for mimeType in mimeTypes:
196 if evt.mimeData().hasFormat(mimeType):
197 evt.acceptProposedAction()
198
199 QToolBar.dragEnterEvent(self, evt)
200
201 def dropEvent(self, evt):
202 """
203 Protected method to handle drop events.
204
205 @param evt reference to the event (QDropEvent)
206 """
207 if self.__model is not None:
208 act = self.actionAt(evt.pos())
209 parentIndex = self.__root
210 if act is None:
211 row = self.__model.rowCount(self.__root)
212 else:
213 idx = self.index(act)
214 assert idx.isValid()
215 row = idx.row()
216 if self.__model.hasChildren(idx):
217 parentIndex = idx
218 row = self.__model.rowCount(idx)
219
220 self.__dropRow = row
221 self.__dropIndex = parentIndex
222 evt.acceptProposedAction()
223 self.__model.dropMimeData(evt.mimeData(), evt.dropAction(),
224 row, 0, parentIndex)
225
226 QToolBar.dropEvent(self, evt)
227
228 def mouseMoveEvent(self, evt):
229 """
230 Protected method to handle mouse move events.
231
232 @param evt reference to the event (QMouseEvent)
233 """
234 if self.__model is None:
235 QToolBar.mouseMoveEvent(self, evt)
236 return
237
238 if not (evt.buttons() & Qt.LeftButton):
239 QToolBar.mouseMoveEvent(self, evt)
240 return
241
242 manhattanLength = (evt.pos() - self.__dragStartPosition).manhattanLength()
243 if manhattanLength <= QApplication.startDragDistance():
244 QToolBar.mouseMoveEvent(self, evt)
245 return
246
247 act = self.actionAt(self.__dragStartPosition)
248 if act is None:
249 QToolBar.mouseMoveEvent(self, evt)
250 return
251
252 idx = self.index(act)
253 assert idx.isValid()
254
255 drag = QDrag(self)
256 drag.setMimeData(self.__model.mimeData([idx]))
257 actionRect = self.actionGeometry(act)
258 drag.setPixmap(QPixmap.grabWidget(self, actionRect))
259
260 if drag.exec_() == Qt.MoveAction:
261 row = idx.row()
262 if self.__dropIndex == idx.parent() and self.__dropRow <= row:
263 row += 1
264 self.__model.removeRow(row, self.__root)
265
266 def hideEvent(self, evt):
267 """
268 Protected method to handle hide events.
269
270 @param evt reference to the hide event (QHideEvent)
271 """
272 self.clear()
273 QToolBar.hideEvent(self, evt)
274
275 def showEvent(self, evt):
276 """
277 Protected method to handle show events.
278
279 @param evt reference to the hide event (QHideEvent)
280 """
281 if len(self.actions()) == 0:
282 self._build()
283 QToolBar.showEvent(self, evt)
284
285 def resetFlags(self):
286 """
287 Public method to reset the saved internal state.
288 """
289 self._mouseButton = Qt.NoButton
290 self._keyboardModifiers = Qt.KeyboardModifiers(Qt.NoModifier)

eric ide

mercurial