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 | |
20 | QT_BEGIN_NAMESPACE |
21 | |
22 | static void (*fixResourcePathsForObjectCallBack)(QObject*) = nullptr; |
23 | |
24 | static 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 | |
46 | static void makeLoaderSynchronous(QObject *object) |
47 | { |
48 | if (QQuickLoader *loader = qobject_cast<QQuickLoader*>(object)) |
49 | loader->setAsynchronous(false); |
50 | } |
51 | |
52 | static 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 | |
117 | void 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 | |
129 | static QObject *createDummyWindow(QQmlEngine *engine) |
130 | { |
131 | QQmlComponent component(engine, QUrl(QStringLiteral("qrc:/qtquickplugin/mockfiles/Window.qml" ))); |
132 | return component.create(); |
133 | } |
134 | |
135 | static 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 | |
147 | static bool isWindow(QObject *object) { |
148 | if (object) |
149 | return isWindowMetaObject(metaObject: object->metaObject()); |
150 | |
151 | return false; |
152 | } |
153 | |
154 | static 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 | |
176 | QObject *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 | |
223 | QObject *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 | |
244 | bool QQuickDesignerSupportItems::objectWasDeleted(QObject *object) |
245 | { |
246 | return QObjectPrivate::get(o: object)->wasDeleted; |
247 | } |
248 | |
249 | void 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 | |
264 | void 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 | |
279 | void 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 | |
288 | void QQuickDesignerSupportItems::disableBehaivour(QObject *object) |
289 | { |
290 | QQuickBehavior* behavior = qobject_cast<QQuickBehavior*>(object); |
291 | Q_ASSERT(behavior); |
292 | behavior->setEnabled(false); |
293 | } |
294 | |
295 | void QQuickDesignerSupportItems::stopUnifiedTimer() |
296 | { |
297 | QUnifiedTimer::instance()->setSlowdownFactor(0.00001); |
298 | QUnifiedTimer::instance()->setSlowModeEnabled(true); |
299 | } |
300 | |
301 | void QQuickDesignerSupportItems::registerFixResourcePathsForObjectCallBack(void (*callback)(QObject *)) |
302 | { |
303 | fixResourcePathsForObjectCallBack = callback; |
304 | } |
305 | |
306 | QT_END_NAMESPACE |
307 | |
308 | |
309 | |