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