|
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) |