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