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
47QT_BEGIN_NAMESPACE
48
49using namespace qdesigner_internal;
50
51WidgetEditorTool::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
59QAction *WidgetEditorTool::action() const
60{
61 return m_action;
62}
63
64WidgetEditorTool::~WidgetEditorTool() = default;
65
66QDesignerFormEditorInterface *WidgetEditorTool::core() const
67{
68 return m_formWindow->core();
69}
70
71QDesignerFormWindowInterface *WidgetEditorTool::formWindow() const
72{
73 return m_formWindow;
74}
75
76bool 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
110bool 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
171bool WidgetEditorTool::handleContextMenu(QWidget *widget, QWidget *managedWidget, QContextMenuEvent *e)
172{
173 return m_formWindow->handleContextMenu(widget, managedWidget, e);
174}
175
176bool WidgetEditorTool::handleMouseButtonDblClickEvent(QWidget *widget, QWidget *managedWidget, QMouseEvent *e)
177{
178 return m_formWindow->handleMouseButtonDblClickEvent(widget, managedWidget, e);
179}
180
181bool WidgetEditorTool::handleMousePressEvent(QWidget *widget, QWidget *managedWidget, QMouseEvent *e)
182{
183 return m_formWindow->handleMousePressEvent(widget, managedWidget, e);
184}
185
186bool WidgetEditorTool::handleMouseMoveEvent(QWidget *widget, QWidget *managedWidget, QMouseEvent *e)
187{
188 return m_formWindow->handleMouseMoveEvent(widget, managedWidget, e);
189}
190
191bool WidgetEditorTool::handleMouseReleaseEvent(QWidget *widget, QWidget *managedWidget, QMouseEvent *e)
192{
193 return m_formWindow->handleMouseReleaseEvent(widget, managedWidget, e);
194}
195
196bool WidgetEditorTool::handleKeyPressEvent(QWidget *widget, QWidget *managedWidget, QKeyEvent *e)
197{
198 return m_formWindow->handleKeyPressEvent(widget, managedWidget, e);
199}
200
201bool WidgetEditorTool::handleKeyReleaseEvent(QWidget *widget, QWidget *managedWidget, QKeyEvent *e)
202{
203 return m_formWindow->handleKeyReleaseEvent(widget, managedWidget, e);
204}
205
206bool 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
215void 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
234bool 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
276bool 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
303bool 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
313bool WidgetEditorTool::handleDragLeaveEvent(QWidget *, QWidget *, QDragLeaveEvent *event)
314{
315 if (restoreDropHighlighting()) {
316 event->accept();
317 return true;
318 }
319 return false;
320}
321
322QWidget *WidgetEditorTool::editor() const
323{
324 Q_ASSERT(formWindow() != nullptr);
325 return formWindow()->mainContainer();
326}
327
328void 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
341void 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
352QT_END_NAMESPACE
353

source code of qttools/src/designer/src/components/formeditor/tool_widgeteditor.cpp