1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the Qt Designer of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | |
29 | #include "tool_widgeteditor.h" |
30 | #include "formwindow.h" |
31 | |
32 | // sdk |
33 | #include <QtDesigner/abstractformeditor.h> |
34 | #include <QtDesigner/abstractwidgetfactory.h> |
35 | #include <QtDesigner/abstractwidgetbox.h> |
36 | |
37 | #include <layoutinfo_p.h> |
38 | #include <qdesigner_dnditem_p.h> |
39 | #include <qdesigner_resource.h> |
40 | |
41 | #include <QtGui/qevent.h> |
42 | #include <QtWidgets/qaction.h> |
43 | #include <QtWidgets/qmainwindow.h> |
44 | #include <QtGui/qcursor.h> |
45 | #include <QtCore/qdebug.h> |
46 | |
47 | QT_BEGIN_NAMESPACE |
48 | |
49 | using namespace qdesigner_internal; |
50 | |
51 | WidgetEditorTool::WidgetEditorTool(FormWindow *formWindow) |
52 | : QDesignerFormWindowToolInterface(formWindow), |
53 | m_formWindow(formWindow), |
54 | m_action(new QAction(tr(s: "Edit Widgets" ), this)), |
55 | m_specialDockDrag(false) |
56 | { |
57 | } |
58 | |
59 | QAction *WidgetEditorTool::action() const |
60 | { |
61 | return m_action; |
62 | } |
63 | |
64 | WidgetEditorTool::~WidgetEditorTool() = default; |
65 | |
66 | QDesignerFormEditorInterface *WidgetEditorTool::core() const |
67 | { |
68 | return m_formWindow->core(); |
69 | } |
70 | |
71 | QDesignerFormWindowInterface *WidgetEditorTool::formWindow() const |
72 | { |
73 | return m_formWindow; |
74 | } |
75 | |
76 | bool WidgetEditorTool::mainWindowSeparatorEvent(QWidget *widget, QEvent *event) |
77 | { |
78 | QMainWindow *mw = qobject_cast<QMainWindow*>(object: widget); |
79 | if (mw == nullptr) |
80 | return false; |
81 | |
82 | if (event->type() != QEvent::MouseButtonPress |
83 | && event->type() != QEvent::MouseMove |
84 | && event->type() != QEvent::MouseButtonRelease) |
85 | return false; |
86 | |
87 | QMouseEvent *e = static_cast<QMouseEvent*>(event); |
88 | |
89 | if (event->type() == QEvent::MouseButtonPress) { |
90 | if (mw->isSeparator(pos: e->pos())) { |
91 | m_separator_drag_mw = mw; |
92 | return true; |
93 | } |
94 | return false; |
95 | } |
96 | |
97 | if (event->type() == QEvent::MouseMove) |
98 | return m_separator_drag_mw == mw; |
99 | |
100 | if (event->type() == QEvent::MouseButtonRelease) { |
101 | if (m_separator_drag_mw != mw) |
102 | return false; |
103 | m_separator_drag_mw = nullptr; |
104 | return true; |
105 | } |
106 | |
107 | return false; |
108 | } |
109 | |
110 | bool WidgetEditorTool::handleEvent(QWidget *widget, QWidget *managedWidget, QEvent *event) |
111 | { |
112 | const bool passive = core()->widgetFactory()->isPassiveInteractor(widget) != 0 |
113 | || mainWindowSeparatorEvent(widget, event); // separators in QMainWindow |
114 | // are no longer widgets |
115 | switch (event->type()) { |
116 | case QEvent::Resize: |
117 | case QEvent::Move: |
118 | m_formWindow->updateSelection(w: widget); |
119 | break; |
120 | |
121 | case QEvent::FocusOut: |
122 | case QEvent::FocusIn: // Popup cancelled over a form widget: Reset its focus frame |
123 | return !(passive || widget == m_formWindow || widget == m_formWindow->mainContainer()); |
124 | |
125 | case QEvent::Wheel: // Prevent spinboxes and combos from reacting |
126 | if (widget == m_formWindow->formContainer() || widget == m_formWindow |
127 | || widget == m_formWindow->mainContainer()) { // Allow scrolling the form with wheel. |
128 | return false; |
129 | } |
130 | return !passive; |
131 | |
132 | case QEvent::KeyPress: |
133 | return !passive && handleKeyPressEvent(widget, managedWidget, e: static_cast<QKeyEvent*>(event)); |
134 | |
135 | case QEvent::KeyRelease: |
136 | return !passive && handleKeyReleaseEvent(widget, managedWidget, e: static_cast<QKeyEvent*>(event)); |
137 | |
138 | case QEvent::MouseMove: |
139 | return !passive && handleMouseMoveEvent(widget, managedWidget, e: static_cast<QMouseEvent*>(event)); |
140 | |
141 | case QEvent::MouseButtonPress: |
142 | return !passive && handleMousePressEvent(widget, managedWidget, e: static_cast<QMouseEvent*>(event)); |
143 | |
144 | case QEvent::MouseButtonRelease: |
145 | return !passive && handleMouseReleaseEvent(widget, managedWidget, e: static_cast<QMouseEvent*>(event)); |
146 | |
147 | case QEvent::MouseButtonDblClick: |
148 | return !passive && handleMouseButtonDblClickEvent(widget, managedWidget, e: static_cast<QMouseEvent*>(event)); |
149 | |
150 | case QEvent::ContextMenu: |
151 | return !passive && handleContextMenu(widget, managedWidget, e: static_cast<QContextMenuEvent*>(event)); |
152 | |
153 | case QEvent::DragEnter: |
154 | return handleDragEnterMoveEvent(widget, managedWidget, e: static_cast<QDragEnterEvent *>(event), isEnter: true); |
155 | case QEvent::DragMove: |
156 | return handleDragEnterMoveEvent(widget, managedWidget, e: static_cast<QDragEnterEvent *>(event), isEnter: false); |
157 | case QEvent::DragLeave: |
158 | return handleDragLeaveEvent(widget, managedWidget, e: static_cast<QDragLeaveEvent *>(event)); |
159 | case QEvent::Drop: |
160 | return handleDropEvent(widget, managedWidget, e: static_cast<QDropEvent *>(event)); |
161 | default: |
162 | break; |
163 | |
164 | } // end switch |
165 | |
166 | return false; |
167 | } |
168 | |
169 | // ### remove me |
170 | |
171 | bool WidgetEditorTool::handleContextMenu(QWidget *widget, QWidget *managedWidget, QContextMenuEvent *e) |
172 | { |
173 | return m_formWindow->handleContextMenu(widget, managedWidget, e); |
174 | } |
175 | |
176 | bool WidgetEditorTool::handleMouseButtonDblClickEvent(QWidget *widget, QWidget *managedWidget, QMouseEvent *e) |
177 | { |
178 | return m_formWindow->handleMouseButtonDblClickEvent(widget, managedWidget, e); |
179 | } |
180 | |
181 | bool WidgetEditorTool::handleMousePressEvent(QWidget *widget, QWidget *managedWidget, QMouseEvent *e) |
182 | { |
183 | return m_formWindow->handleMousePressEvent(widget, managedWidget, e); |
184 | } |
185 | |
186 | bool WidgetEditorTool::handleMouseMoveEvent(QWidget *widget, QWidget *managedWidget, QMouseEvent *e) |
187 | { |
188 | return m_formWindow->handleMouseMoveEvent(widget, managedWidget, e); |
189 | } |
190 | |
191 | bool WidgetEditorTool::handleMouseReleaseEvent(QWidget *widget, QWidget *managedWidget, QMouseEvent *e) |
192 | { |
193 | return m_formWindow->handleMouseReleaseEvent(widget, managedWidget, e); |
194 | } |
195 | |
196 | bool WidgetEditorTool::handleKeyPressEvent(QWidget *widget, QWidget *managedWidget, QKeyEvent *e) |
197 | { |
198 | return m_formWindow->handleKeyPressEvent(widget, managedWidget, e); |
199 | } |
200 | |
201 | bool WidgetEditorTool::handleKeyReleaseEvent(QWidget *widget, QWidget *managedWidget, QKeyEvent *e) |
202 | { |
203 | return m_formWindow->handleKeyReleaseEvent(widget, managedWidget, e); |
204 | } |
205 | |
206 | bool WidgetEditorTool::handlePaintEvent(QWidget *widget, QWidget *managedWidget, QPaintEvent *e) |
207 | { |
208 | Q_UNUSED(widget); |
209 | Q_UNUSED(managedWidget); |
210 | Q_UNUSED(e); |
211 | |
212 | return false; |
213 | } |
214 | |
215 | void WidgetEditorTool::detectDockDrag(const QDesignerMimeData *mimeData) |
216 | { |
217 | m_specialDockDrag = false; |
218 | if (!mimeData) |
219 | return; |
220 | |
221 | QMainWindow *mw = qobject_cast<QMainWindow*>(object: m_formWindow->mainContainer()); |
222 | if (!mw) |
223 | return; |
224 | |
225 | const auto item_list = mimeData->items(); |
226 | |
227 | for (QDesignerDnDItemInterface *item : item_list) { |
228 | if (item->decoration() && item->decoration()->property(name: "_q_dockDrag" ).toBool()) |
229 | m_specialDockDrag = true; |
230 | |
231 | } |
232 | } |
233 | |
234 | bool WidgetEditorTool::handleDragEnterMoveEvent(QWidget *widget, QWidget * /*managedWidget*/, QDragMoveEvent *e, bool isEnter) |
235 | { |
236 | const QDesignerMimeData *mimeData = qobject_cast<const QDesignerMimeData *>(object: e->mimeData()); |
237 | if (!mimeData) |
238 | return false; |
239 | |
240 | if (!m_formWindow->hasFeature(f: QDesignerFormWindowInterface::EditFeature)) { |
241 | e->ignore(); |
242 | return true; |
243 | } |
244 | |
245 | if (isEnter) |
246 | detectDockDrag(mimeData); |
247 | |
248 | |
249 | QPoint globalPos = QPoint(0, 0); |
250 | if (m_specialDockDrag) { |
251 | m_lastDropTarget = nullptr; |
252 | QMainWindow *mw = qobject_cast<QMainWindow*>(object: m_formWindow->mainContainer()); |
253 | if (mw) |
254 | m_lastDropTarget = mw->centralWidget(); |
255 | } else { |
256 | // If custom widgets have acceptDrops=true, the event occurs for them |
257 | const QPoint formPos = widget != m_formWindow ? widget->mapTo(m_formWindow, e->pos()) : e->pos(); |
258 | globalPos = m_formWindow->mapToGlobal(formPos); |
259 | const FormWindowBase::WidgetUnderMouseMode wum = mimeData->items().size() == 1 ? FormWindowBase::FindSingleSelectionDropTarget : FormWindowBase::FindMultiSelectionDropTarget; |
260 | QWidget *dropTarget = m_formWindow->widgetUnderMouse(formPos, m: wum); |
261 | if (m_lastDropTarget && dropTarget != m_lastDropTarget) |
262 | m_formWindow->highlightWidget(w: m_lastDropTarget, pos: m_lastDropTarget->mapFromGlobal(globalPos), mode: FormWindow::Restore); |
263 | m_lastDropTarget = dropTarget; |
264 | } |
265 | |
266 | if (m_lastDropTarget) |
267 | m_formWindow->highlightWidget(w: m_lastDropTarget, pos: m_lastDropTarget->mapFromGlobal(globalPos), mode: FormWindow::Highlight); |
268 | |
269 | if (isEnter || m_lastDropTarget) |
270 | mimeData->acceptEvent(e); |
271 | else |
272 | e->ignore(); |
273 | return true; |
274 | } |
275 | |
276 | bool WidgetEditorTool::handleDropEvent(QWidget *widget, QWidget *, QDropEvent *e) |
277 | { |
278 | const QDesignerMimeData *mimeData = qobject_cast<const QDesignerMimeData *>(object: e->mimeData()); |
279 | if (!mimeData) |
280 | return false; |
281 | |
282 | if (!m_lastDropTarget || |
283 | !m_formWindow->hasFeature(f: QDesignerFormWindowInterface::EditFeature)) { |
284 | e->ignore(); |
285 | return true; |
286 | } |
287 | // FormWindow determines the position from the decoration. |
288 | const QPoint globalPos = widget->mapToGlobal(e->pos()); |
289 | mimeData->moveDecoration(globalPos); |
290 | if (m_specialDockDrag) { |
291 | if (!m_formWindow->dropDockWidget(item: mimeData->items().at(i: 0), global_mouse_pos: globalPos)) { |
292 | e->ignore(); |
293 | return true; |
294 | } |
295 | } else if (!m_formWindow->dropWidgets(item_list: mimeData->items(), target: m_lastDropTarget, global_mouse_pos: globalPos)) { |
296 | e->ignore(); |
297 | return true; |
298 | } |
299 | mimeData->acceptEvent(e); |
300 | return true; |
301 | } |
302 | |
303 | bool WidgetEditorTool::restoreDropHighlighting() |
304 | { |
305 | if (!m_lastDropTarget) |
306 | return false; |
307 | |
308 | m_formWindow->highlightWidget(w: m_lastDropTarget, pos: m_lastDropTarget->mapFromGlobal(QCursor::pos()), mode: FormWindow::Restore); |
309 | m_lastDropTarget = nullptr; |
310 | return true; |
311 | } |
312 | |
313 | bool WidgetEditorTool::handleDragLeaveEvent(QWidget *, QWidget *, QDragLeaveEvent *event) |
314 | { |
315 | if (restoreDropHighlighting()) { |
316 | event->accept(); |
317 | return true; |
318 | } |
319 | return false; |
320 | } |
321 | |
322 | QWidget *WidgetEditorTool::editor() const |
323 | { |
324 | Q_ASSERT(formWindow() != nullptr); |
325 | return formWindow()->mainContainer(); |
326 | } |
327 | |
328 | void WidgetEditorTool::activated() |
329 | { |
330 | if (core()->widgetBox()) |
331 | core()->widgetBox()->setEnabled(true); |
332 | |
333 | if (m_formWindow == nullptr) |
334 | return; |
335 | |
336 | const QWidgetList &sel = m_formWindow->selectedWidgets(); |
337 | for (QWidget *w : sel) |
338 | m_formWindow->raiseSelection(w); |
339 | } |
340 | |
341 | void WidgetEditorTool::deactivated() |
342 | { |
343 | if (core()->widgetBox()) |
344 | core()->widgetBox()->setEnabled(false); |
345 | |
346 | if (m_formWindow == nullptr) |
347 | return; |
348 | |
349 | m_formWindow->clearSelection(); |
350 | } |
351 | |
352 | QT_END_NAMESPACE |
353 | |