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 "widgetbox_dnditem.h"
30
31#include <widgetfactory_p.h>
32#include <spacer_widget_p.h>
33#include <qdesigner_formbuilder_p.h>
34#include <qtresourcemodel_p.h>
35#include <formwindowbase_p.h>
36#include <qdesigner_utils_p.h>
37#include <qdesigner_dockwidget_p.h>
38#include <qsimpleresource_p.h>
39
40#include <QtDesigner/abstractformeditor.h>
41#include <QtDesigner/abstractformwindowmanager.h>
42
43#include <QtDesigner/private/ui4_p.h>
44
45#include <QtWidgets/qstyle.h>
46#include <QtWidgets/qapplication.h>
47
48QT_BEGIN_NAMESPACE
49
50namespace qdesigner_internal {
51/*******************************************************************************
52** WidgetBoxResource
53*/
54
55static inline DeviceProfile currentDeviceProfile(const QDesignerFormEditorInterface *core)
56{
57 if (QDesignerFormWindowInterface *cfw = core->formWindowManager()->activeFormWindow())
58 if (const FormWindowBase *fwb = qobject_cast<const FormWindowBase *>(object: cfw))
59 return fwb->deviceProfile();
60 return DeviceProfile();
61}
62
63class WidgetBoxResource : public QDesignerFormBuilder
64{
65public:
66 WidgetBoxResource(QDesignerFormEditorInterface *core);
67
68 // protected->public
69 QWidget *createUI(DomUI *ui, QWidget *parents) { return QDesignerFormBuilder::create(ui, parentWidget: parents); }
70
71protected:
72
73 QWidget *create(DomWidget *ui_widget, QWidget *parents) override;
74 QWidget *createWidget(const QString &widgetName, QWidget *parentWidget, const QString &name) override;
75 void createCustomWidgets(DomCustomWidgets *) override;
76};
77
78WidgetBoxResource::WidgetBoxResource(QDesignerFormEditorInterface *core) :
79 QDesignerFormBuilder(core, currentDeviceProfile(core))
80{
81}
82
83
84QWidget *WidgetBoxResource::createWidget(const QString &widgetName, QWidget *parentWidget, const QString &name)
85{
86 if (widgetName == QStringLiteral("Spacer")) {
87 Spacer *spacer = new Spacer(parentWidget);
88 spacer->setObjectName(name);
89 return spacer;
90 }
91
92 return QDesignerFormBuilder::createWidget(widgetName, parentWidget, name);
93}
94
95QWidget *WidgetBoxResource::create(DomWidget *ui_widget, QWidget *parent)
96{
97 QWidget *result = QDesignerFormBuilder::create(ui_widget, parentWidget: parent);
98 // It is possible to have a syntax error or something in custom
99 // widget XML, so, try to recover here by creating an artificial
100 // top level + widget.
101 if (!result) {
102 const QString msg = QApplication::translate(context: "qdesigner_internal::WidgetBox", key: "Warning: Widget creation failed in the widget box. This could be caused by invalid custom widget XML.");
103 qdesigner_internal::designerWarning(message: msg);
104 result = new QWidget(parent);
105 new QWidget(result);
106 }
107 result->setFocusPolicy(Qt::NoFocus);
108 result->setObjectName(ui_widget->attributeName());
109 return result;
110}
111
112void WidgetBoxResource::createCustomWidgets(DomCustomWidgets *dc)
113{
114 // Make a promotion entry in case someone has a promoted widget
115 // in the scratchpad.
116 QSimpleResource::handleDomCustomWidgets(core: core(), dom_custom_widgets: dc);
117
118}
119
120/*******************************************************************************
121** WidgetBoxResource
122*/
123
124static QSize geometryProp(const DomWidget *dw)
125{
126 const auto &prop_list = dw->elementProperty();
127 const QString geometry = QStringLiteral("geometry");
128 for (DomProperty *prop : prop_list) {
129 if (prop->attributeName() != geometry)
130 continue;
131 DomRect *dr = prop->elementRect();
132 if (dr == nullptr)
133 continue;
134 return QSize(dr->elementWidth(), dr->elementHeight());
135 }
136 return QSize();
137}
138
139static QSize domWidgetSize(const DomWidget *dw)
140{
141 QSize size = geometryProp(dw);
142 if (size.isValid())
143 return size;
144
145 const auto &elementWidgets = dw->elementWidget();
146 for (const DomWidget *child : elementWidgets) {
147 size = geometryProp(dw: child);
148 if (size.isValid())
149 return size;
150 }
151
152 const auto &elementLayouts = dw->elementLayout();
153 for (const DomLayout *dl : elementLayouts) {
154 const auto &elementItems = dl->elementItem();
155 for (DomLayoutItem *item : elementItems) {
156 const DomWidget *child = item->elementWidget();
157 if (child == nullptr)
158 continue;
159 size = geometryProp(dw: child);
160 if (size.isValid())
161 return size;
162 }
163 }
164
165 return QSize();
166}
167
168static QWidget *decorationFromDomWidget(DomUI *dom_ui, QDesignerFormEditorInterface *core)
169{
170 WidgetBoxResource builder(core);
171 // We have the builder create the articial QWidget fake top level as a tooltip
172 // because the size algorithm works better at weird DPI settings
173 // if the actual widget is created as a child of a container
174 QWidget *fakeTopLevel = builder.createUI(ui: dom_ui, parents: nullptr);
175 fakeTopLevel->setParent(parent: nullptr, f: Qt::ToolTip); // Container
176 // Actual widget
177 const DomWidget *domW = dom_ui->elementWidget()->elementWidget().constFirst();
178 QWidget *w = fakeTopLevel->findChildren<QWidget*>().constFirst();
179 Q_ASSERT(w);
180 // hack begin;
181 // We set _q_dockDrag dynamic property which will be detected in drag enter event of form window.
182 // Dock drop is handled in special way (highlight goes to central widget of main window)
183 if (qobject_cast<QDesignerDockWidget *>(object: w))
184 fakeTopLevel->setProperty(name: "_q_dockDrag", value: QVariant(true));
185 // hack end;
186 w->setAutoFillBackground(true); // Different style for embedded
187 QSize size = domWidgetSize(dw: domW);
188 const QSize minimumSize = w->minimumSizeHint();
189 if (!size.isValid())
190 size = w->sizeHint();
191 if (size.width() < minimumSize.width())
192 size.setWidth(minimumSize.width());
193 if (size.height() < minimumSize.height())
194 size.setHeight(minimumSize.height());
195 // A QWidget might have size -1,-1 if no geometry property is specified in the widget box.
196 if (size.isEmpty())
197 size = size.expandedTo(otherSize: QSize(16, 16));
198 w->setGeometry(QRect(QPoint(0, 0), size));
199 fakeTopLevel->resize(size);
200 return fakeTopLevel;
201}
202
203WidgetBoxDnDItem::WidgetBoxDnDItem(QDesignerFormEditorInterface *core,
204 DomUI *dom_ui,
205 const QPoint &global_mouse_pos) :
206 QDesignerDnDItem(CopyDrop)
207{
208 QWidget *decoration = decorationFromDomWidget(dom_ui, core);
209 decoration->move(global_mouse_pos - QPoint(5, 5));
210
211 init(ui: dom_ui, widget: nullptr, decoration, global_mouse_pos);
212}
213}
214
215QT_END_NAMESPACE
216

source code of qttools/src/designer/src/components/widgetbox/widgetbox_dnditem.cpp