1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qquickdesignersupportitems_p.h"
5#include "qquickdesignersupportproperties_p.h"
6
7#include <private/qabstractanimation_p.h>
8#include <private/qobject_p.h>
9#include <private/qquickbehavior_p.h>
10#include <private/qquicktext_p.h>
11#include <private/qquicktextinput_p.h>
12#include <private/qquicktextedit_p.h>
13#include <private/qquicktransition_p.h>
14#include <private/qquickloader_p.h>
15
16#include <private/qquickanimation_p.h>
17#include <private/qqmlmetatype_p.h>
18#include <private/qqmltimer_p.h>
19
20QT_BEGIN_NAMESPACE
21
22static void (*fixResourcePathsForObjectCallBack)(QObject*) = nullptr;
23
24static void stopAnimation(QObject *object)
25{
26 if (object == nullptr)
27 return;
28
29 QQuickTransition *transition = qobject_cast<QQuickTransition*>(object);
30 QQuickAbstractAnimation *animation = qobject_cast<QQuickAbstractAnimation*>(object);
31 QQmlTimer *timer = qobject_cast<QQmlTimer*>(object);
32 if (transition) {
33 transition->setFromState(QString());
34 transition->setToState(QString());
35 } else if (animation) {
36// QQuickScriptAction *scriptAimation = qobject_cast<QQuickScriptAction*>(animation);
37// if (scriptAimation) FIXME
38// scriptAimation->setScript(QQmlScriptString());
39 animation->complete();
40 animation->setDisableUserControl();
41 } else if (timer) {
42 timer->blockSignals(b: true);
43 }
44}
45
46static void makeLoaderSynchronous(QObject *object)
47{
48 if (QQuickLoader *loader = qobject_cast<QQuickLoader*>(object))
49 loader->setAsynchronous(false);
50}
51
52static void allSubObjects(QObject *object, QObjectList &objectList)
53{
54 // don't add null pointer and stop if the object is already in the list
55 if (!object || objectList.contains(t: object))
56 return;
57
58 objectList.append(t: object);
59
60 const QMetaObject *mo = object->metaObject();
61
62 QByteArrayList deferredPropertyNames;
63 const int namesIndex = mo->indexOfClassInfo(name: "DeferredPropertyNames");
64 if (namesIndex != -1) {
65 QMetaClassInfo classInfo = mo->classInfo(index: namesIndex);
66 deferredPropertyNames = QByteArray(classInfo.value()).split(sep: ',');
67 }
68
69 for (int index = QObject::staticMetaObject.propertyOffset();
70 index < object->metaObject()->propertyCount();
71 index++) {
72
73 QMetaProperty metaProperty = object->metaObject()->property(index);
74
75 if (deferredPropertyNames.contains(t: metaProperty.name()))
76 continue;
77
78 // search recursive in property objects
79 if (metaProperty.isReadable()
80 && metaProperty.isWritable()
81 && metaProperty.metaType().flags().testFlag(flag: QMetaType::PointerToQObject)) {
82 if (qstrcmp(str1: metaProperty.name(), str2: "parent")) {
83 QObject *propertyObject = QQmlMetaType::toQObject(metaProperty.read(obj: object));
84 allSubObjects(object: propertyObject, objectList);
85 }
86
87 }
88
89 // search recursive in property object lists
90 if (metaProperty.isReadable()
91 && QQmlMetaType::isList(type: metaProperty.metaType())) {
92 QQmlListReference list(object, metaProperty.name());
93 if (list.canCount() && list.canAt()) {
94 for (qsizetype i = 0; i < list.count(); i++) {
95 QObject *propertyObject = list.at(i);
96 allSubObjects(object: propertyObject, objectList);
97
98 }
99 }
100 }
101 }
102
103 // search recursive in object children list
104 for (QObject *childObject : object->children()) {
105 allSubObjects(object: childObject, objectList);
106 }
107
108 // search recursive in quick item childItems list
109 QQuickItem *quickItem = qobject_cast<QQuickItem*>(o: object);
110 if (quickItem) {
111 const auto childItems = quickItem->childItems();
112 for (QQuickItem *childItem : childItems)
113 allSubObjects(object: childItem, objectList);
114 }
115}
116
117void QQuickDesignerSupportItems::tweakObjects(QObject *object)
118{
119 QObjectList objectList;
120 allSubObjects(object, objectList);
121 for (QObject* childObject : std::as_const(t&: objectList)) {
122 stopAnimation(object: childObject);
123 makeLoaderSynchronous(object: childObject);
124 if (fixResourcePathsForObjectCallBack)
125 fixResourcePathsForObjectCallBack(childObject);
126 }
127}
128
129static QObject *createDummyWindow(QQmlEngine *engine)
130{
131 QQmlComponent component(engine, QUrl(QStringLiteral("qrc:/qtquickplugin/mockfiles/Window.qml")));
132 return component.create();
133}
134
135static bool isWindowMetaObject(const QMetaObject *metaObject)
136{
137 if (metaObject) {
138 if (metaObject->className() == QByteArrayLiteral("QWindow"))
139 return true;
140
141 return isWindowMetaObject(metaObject: metaObject->superClass());
142 }
143
144 return false;
145}
146
147static bool isWindow(QObject *object) {
148 if (object)
149 return isWindowMetaObject(metaObject: object->metaObject());
150
151 return false;
152}
153
154static bool isCrashingType(const QQmlType &type)
155{
156 QString name = type.qmlTypeName();
157
158 if (name == QLatin1String("QtMultimedia/MediaPlayer"))
159 return true;
160
161 if (name == QLatin1String("QtMultimedia/Audio"))
162 return true;
163
164 if (name == QLatin1String("QtQuick.Controls/MenuItem"))
165 return true;
166
167 if (name == QLatin1String("QtQuick.Controls/Menu"))
168 return true;
169
170 if (name == QLatin1String("QtQuick/Timer"))
171 return true;
172
173 return false;
174}
175
176QObject *QQuickDesignerSupportItems::createPrimitive(const QString &typeName, QTypeRevision version, QQmlContext *context)
177{
178 ComponentCompleteDisabler disableComponentComplete;
179
180 Q_UNUSED(disableComponentComplete);
181
182 QObject *object = nullptr;
183 QQmlType type = QQmlMetaType::qmlType(qualifiedName: typeName, version);
184
185 if (isCrashingType(type)) {
186 object = new QObject;
187 } else if (type.isValid()) {
188 if ( type.isComposite()) {
189 object = createComponent(componentUrl: type.sourceUrl(), context);
190 } else
191 {
192 if (type.typeName() == "QQmlComponent") {
193 object = new QQmlComponent(context->engine(), nullptr);
194 } else {
195 object = type.create();
196 }
197 }
198
199 if (isWindow(object)) {
200 delete object;
201 object = createDummyWindow(engine: context->engine());
202 }
203
204 }
205
206 if (!object) {
207 qWarning() << "QuickDesigner: Cannot create an object of type"
208 << QString::fromLatin1(ba: "%1 %2,%3").arg(a: typeName)
209 .arg(a: version.majorVersion()).arg(a: version.minorVersion())
210 << "- type isn't known to declarative meta type system";
211 }
212
213 tweakObjects(object);
214
215 if (object && QQmlEngine::contextForObject(object) == nullptr)
216 QQmlEngine::setContextForObject(object, context);
217
218 QQmlEngine::setObjectOwnership(object, QQmlEngine::CppOwnership);
219
220 return object;
221}
222
223QObject *QQuickDesignerSupportItems::createComponent(const QUrl &componentUrl, QQmlContext *context)
224{
225 ComponentCompleteDisabler disableComponentComplete;
226 Q_UNUSED(disableComponentComplete);
227
228 QQmlComponent component(context->engine(), componentUrl);
229
230 QObject *object = component.beginCreate(context);
231 tweakObjects(object);
232 component.completeCreate();
233 QQmlEngine::setObjectOwnership(object, QQmlEngine::CppOwnership);
234
235 if (component.isError()) {
236 qWarning() << "Error in:" << Q_FUNC_INFO << componentUrl;
237 const auto errors = component.errors();
238 for (const QQmlError &error : errors)
239 qWarning() << error;
240 }
241 return object;
242}
243
244bool QQuickDesignerSupportItems::objectWasDeleted(QObject *object)
245{
246 return QObjectPrivate::get(o: object)->wasDeleted;
247}
248
249void QQuickDesignerSupportItems::disableNativeTextRendering(QQuickItem *item)
250{
251 QQuickText *text = qobject_cast<QQuickText*>(object: item);
252 if (text)
253 text->setRenderType(QQuickText::QtRendering);
254
255 QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(object: item);
256 if (textInput)
257 textInput->setRenderType(QQuickTextInput::QtRendering);
258
259 QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit*>(object: item);
260 if (textEdit)
261 textEdit->setRenderType(QQuickTextEdit::QtRendering);
262}
263
264void QQuickDesignerSupportItems::disableTextCursor(QQuickItem *item)
265{
266 const auto childItems = item->childItems();
267 for (QQuickItem *childItem : childItems)
268 disableTextCursor(item: childItem);
269
270 QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(object: item);
271 if (textInput)
272 textInput->setCursorVisible(false);
273
274 QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit*>(object: item);
275 if (textEdit)
276 textEdit->setCursorVisible(false);
277}
278
279void QQuickDesignerSupportItems::disableTransition(QObject *object)
280{
281 QQuickTransition *transition = qobject_cast<QQuickTransition*>(object);
282 Q_ASSERT(transition);
283 const QString invalidState = QLatin1String("invalidState");
284 transition->setToState(invalidState);
285 transition->setFromState(invalidState);
286}
287
288void QQuickDesignerSupportItems::disableBehaivour(QObject *object)
289{
290 QQuickBehavior* behavior = qobject_cast<QQuickBehavior*>(object);
291 Q_ASSERT(behavior);
292 behavior->setEnabled(false);
293}
294
295void QQuickDesignerSupportItems::stopUnifiedTimer()
296{
297 QUnifiedTimer::instance()->setSlowdownFactor(0.00001);
298 QUnifiedTimer::instance()->setSlowModeEnabled(true);
299}
300
301void QQuickDesignerSupportItems::registerFixResourcePathsForObjectCallBack(void (*callback)(QObject *))
302{
303 fixResourcePathsForObjectCallBack = callback;
304}
305
306QT_END_NAMESPACE
307
308
309

source code of qtdeclarative/src/quick/designer/qquickdesignersupportitems.cpp