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
WidgetEditorTool(FormWindow * formWindow)51 WidgetEditorTool::WidgetEditorTool(FormWindow *formWindow)
52 : QDesignerFormWindowToolInterface(formWindow),
53 m_formWindow(formWindow),
54 m_action(new QAction(tr("Edit Widgets"), this)),
55 m_specialDockDrag(false)
56 {
57 }
58
action() const59 QAction *WidgetEditorTool::action() const
60 {
61 return m_action;
62 }
63
64 WidgetEditorTool::~WidgetEditorTool() = default;
65
core() const66 QDesignerFormEditorInterface *WidgetEditorTool::core() const
67 {
68 return m_formWindow->core();
69 }
70
formWindow() const71 QDesignerFormWindowInterface *WidgetEditorTool::formWindow() const
72 {
73 return m_formWindow;
74 }
75
mainWindowSeparatorEvent(QWidget * widget,QEvent * event)76 bool WidgetEditorTool::mainWindowSeparatorEvent(QWidget *widget, QEvent *event)
77 {
78 QMainWindow *mw = qobject_cast<QMainWindow*>(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(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
handleEvent(QWidget * widget,QWidget * managedWidget,QEvent * event)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(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, static_cast<QKeyEvent*>(event));
134
135 case QEvent::KeyRelease:
136 return !passive && handleKeyReleaseEvent(widget, managedWidget, static_cast<QKeyEvent*>(event));
137
138 case QEvent::MouseMove:
139 return !passive && handleMouseMoveEvent(widget, managedWidget, static_cast<QMouseEvent*>(event));
140
141 case QEvent::MouseButtonPress:
142 return !passive && handleMousePressEvent(widget, managedWidget, static_cast<QMouseEvent*>(event));
143
144 case QEvent::MouseButtonRelease:
145 return !passive && handleMouseReleaseEvent(widget, managedWidget, static_cast<QMouseEvent*>(event));
146
147 case QEvent::MouseButtonDblClick:
148 return !passive && handleMouseButtonDblClickEvent(widget, managedWidget, static_cast<QMouseEvent*>(event));
149
150 case QEvent::ContextMenu:
151 return !passive && handleContextMenu(widget, managedWidget, static_cast<QContextMenuEvent*>(event));
152
153 case QEvent::DragEnter:
154 return handleDragEnterMoveEvent(widget, managedWidget, static_cast<QDragEnterEvent *>(event), true);
155 case QEvent::DragMove:
156 return handleDragEnterMoveEvent(widget, managedWidget, static_cast<QDragEnterEvent *>(event), false);
157 case QEvent::DragLeave:
158 return handleDragLeaveEvent(widget, managedWidget, static_cast<QDragLeaveEvent *>(event));
159 case QEvent::Drop:
160 return handleDropEvent(widget, managedWidget, static_cast<QDropEvent *>(event));
161 default:
162 break;
163
164 } // end switch
165
166 return false;
167 }
168
169 // ### remove me
170
handleContextMenu(QWidget * widget,QWidget * managedWidget,QContextMenuEvent * e)171 bool WidgetEditorTool::handleContextMenu(QWidget *widget, QWidget *managedWidget, QContextMenuEvent *e)
172 {
173 return m_formWindow->handleContextMenu(widget, managedWidget, e);
174 }
175
handleMouseButtonDblClickEvent(QWidget * widget,QWidget * managedWidget,QMouseEvent * e)176 bool WidgetEditorTool::handleMouseButtonDblClickEvent(QWidget *widget, QWidget *managedWidget, QMouseEvent *e)
177 {
178 return m_formWindow->handleMouseButtonDblClickEvent(widget, managedWidget, e);
179 }
180
handleMousePressEvent(QWidget * widget,QWidget * managedWidget,QMouseEvent * e)181 bool WidgetEditorTool::handleMousePressEvent(QWidget *widget, QWidget *managedWidget, QMouseEvent *e)
182 {
183 return m_formWindow->handleMousePressEvent(widget, managedWidget, e);
184 }
185
handleMouseMoveEvent(QWidget * widget,QWidget * managedWidget,QMouseEvent * e)186 bool WidgetEditorTool::handleMouseMoveEvent(QWidget *widget, QWidget *managedWidget, QMouseEvent *e)
187 {
188 return m_formWindow->handleMouseMoveEvent(widget, managedWidget, e);
189 }
190
handleMouseReleaseEvent(QWidget * widget,QWidget * managedWidget,QMouseEvent * e)191 bool WidgetEditorTool::handleMouseReleaseEvent(QWidget *widget, QWidget *managedWidget, QMouseEvent *e)
192 {
193 return m_formWindow->handleMouseReleaseEvent(widget, managedWidget, e);
194 }
195
handleKeyPressEvent(QWidget * widget,QWidget * managedWidget,QKeyEvent * e)196 bool WidgetEditorTool::handleKeyPressEvent(QWidget *widget, QWidget *managedWidget, QKeyEvent *e)
197 {
198 return m_formWindow->handleKeyPressEvent(widget, managedWidget, e);
199 }
200
handleKeyReleaseEvent(QWidget * widget,QWidget * managedWidget,QKeyEvent * e)201 bool WidgetEditorTool::handleKeyReleaseEvent(QWidget *widget, QWidget *managedWidget, QKeyEvent *e)
202 {
203 return m_formWindow->handleKeyReleaseEvent(widget, managedWidget, e);
204 }
205
handlePaintEvent(QWidget * widget,QWidget * managedWidget,QPaintEvent * e)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
detectDockDrag(const QDesignerMimeData * mimeData)215 void WidgetEditorTool::detectDockDrag(const QDesignerMimeData *mimeData)
216 {
217 m_specialDockDrag = false;
218 if (!mimeData)
219 return;
220
221 QMainWindow *mw = qobject_cast<QMainWindow*>(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("_q_dockDrag").toBool())
229 m_specialDockDrag = true;
230
231 }
232 }
233
handleDragEnterMoveEvent(QWidget * widget,QWidget *,QDragMoveEvent * e,bool isEnter)234 bool WidgetEditorTool::handleDragEnterMoveEvent(QWidget *widget, QWidget * /*managedWidget*/, QDragMoveEvent *e, bool isEnter)
235 {
236 const QDesignerMimeData *mimeData = qobject_cast<const QDesignerMimeData *>(e->mimeData());
237 if (!mimeData)
238 return false;
239
240 if (!m_formWindow->hasFeature(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*>(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, wum);
261 if (m_lastDropTarget && dropTarget != m_lastDropTarget)
262 m_formWindow->highlightWidget(m_lastDropTarget, m_lastDropTarget->mapFromGlobal(globalPos), FormWindow::Restore);
263 m_lastDropTarget = dropTarget;
264 }
265
266 if (m_lastDropTarget)
267 m_formWindow->highlightWidget(m_lastDropTarget, m_lastDropTarget->mapFromGlobal(globalPos), FormWindow::Highlight);
268
269 if (isEnter || m_lastDropTarget)
270 mimeData->acceptEvent(e);
271 else
272 e->ignore();
273 return true;
274 }
275
handleDropEvent(QWidget * widget,QWidget *,QDropEvent * e)276 bool WidgetEditorTool::handleDropEvent(QWidget *widget, QWidget *, QDropEvent *e)
277 {
278 const QDesignerMimeData *mimeData = qobject_cast<const QDesignerMimeData *>(e->mimeData());
279 if (!mimeData)
280 return false;
281
282 if (!m_lastDropTarget ||
283 !m_formWindow->hasFeature(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(mimeData->items().at(0), globalPos)) {
292 e->ignore();
293 return true;
294 }
295 } else if (!m_formWindow->dropWidgets(mimeData->items(), m_lastDropTarget, globalPos)) {
296 e->ignore();
297 return true;
298 }
299 mimeData->acceptEvent(e);
300 return true;
301 }
302
restoreDropHighlighting()303 bool WidgetEditorTool::restoreDropHighlighting()
304 {
305 if (!m_lastDropTarget)
306 return false;
307
308 m_formWindow->highlightWidget(m_lastDropTarget, m_lastDropTarget->mapFromGlobal(QCursor::pos()), FormWindow::Restore);
309 m_lastDropTarget = nullptr;
310 return true;
311 }
312
handleDragLeaveEvent(QWidget *,QWidget *,QDragLeaveEvent * event)313 bool WidgetEditorTool::handleDragLeaveEvent(QWidget *, QWidget *, QDragLeaveEvent *event)
314 {
315 if (restoreDropHighlighting()) {
316 event->accept();
317 return true;
318 }
319 return false;
320 }
321
editor() const322 QWidget *WidgetEditorTool::editor() const
323 {
324 Q_ASSERT(formWindow() != nullptr);
325 return formWindow()->mainContainer();
326 }
327
activated()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
deactivated()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