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 QtQuick module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
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 Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qquickdesignersupportitems_p.h"
41#include "qquickdesignersupportproperties_p.h"
42
43#include <private/qabstractanimation_p.h>
44#include <private/qobject_p.h>
45#include <private/qquickbehavior_p.h>
46#include <private/qquicktext_p.h>
47#include <private/qquicktextinput_p.h>
48#include <private/qquicktextedit_p.h>
49#include <private/qquicktransition_p.h>
50#include <private/qquickloader_p.h>
51
52#include <private/qquickanimation_p.h>
53#include <private/qqmlmetatype_p.h>
54#include <private/qqmltimer_p.h>
55
56QT_BEGIN_NAMESPACE
57
58static void (*fixResourcePathsForObjectCallBack)(QObject*) = nullptr;
59
60static void stopAnimation(QObject *object)
61{
62 if (object == nullptr)
63 return;
64
65 QQuickTransition *transition = qobject_cast<QQuickTransition*>(object);
66 QQuickAbstractAnimation *animation = qobject_cast<QQuickAbstractAnimation*>(object);
67 QQmlTimer *timer = qobject_cast<QQmlTimer*>(object);
68 if (transition) {
69 transition->setFromState(QString());
70 transition->setToState(QString());
71 } else if (animation) {
72// QQuickScriptAction *scriptAimation = qobject_cast<QQuickScriptAction*>(animation);
73// if (scriptAimation) FIXME
74// scriptAimation->setScript(QQmlScriptString());
75 animation->setLoops(1);
76 animation->complete();
77 animation->setDisableUserControl();
78 } else if (timer) {
79 timer->blockSignals(true);
80 }
81}
82
83static void makeLoaderSynchronous(QObject *object)
84{
85 if (QQuickLoader *loader = qobject_cast<QQuickLoader*>(object))
86 loader->setAsynchronous(false);
87}
88
89static void allSubObjects(QObject *object, QObjectList &objectList)
90{
91 // don't add null pointer and stop if the object is already in the list
92 if (!object || objectList.contains(object))
93 return;
94
95 objectList.append(object);
96
97 const QMetaObject *mo = object->metaObject();
98
99 QByteArrayList deferredPropertyNames;
100 const int namesIndex = mo->indexOfClassInfo("DeferredPropertyNames");
101 if (namesIndex != -1) {
102 QMetaClassInfo classInfo = mo->classInfo(namesIndex);
103 deferredPropertyNames = QByteArray(classInfo.value()).split(',');
104 }
105
106 for (int index = QObject::staticMetaObject.propertyOffset();
107 index < object->metaObject()->propertyCount();
108 index++) {
109
110 QMetaProperty metaProperty = object->metaObject()->property(index);
111
112 if (deferredPropertyNames.contains(metaProperty.name()))
113 continue;
114
115 // search recursive in property objects
116 if (metaProperty.isReadable()
117 && metaProperty.isWritable()
118 && QQmlMetaType::isQObject(metaProperty.userType())) {
119 if (qstrcmp(metaProperty.name(), "parent")) {
120 QObject *propertyObject = QQmlMetaType::toQObject(metaProperty.read(object));
121 allSubObjects(propertyObject, objectList);
122 }
123
124 }
125
126 // search recursive in property object lists
127 if (metaProperty.isReadable()
128 && QQmlMetaType::isList(metaProperty.userType())) {
129 QQmlListReference list(object, metaProperty.name());
130 if (list.canCount() && list.canAt()) {
131 for (int i = 0; i < list.count(); i++) {
132 QObject *propertyObject = list.at(i);
133 allSubObjects(propertyObject, objectList);
134
135 }
136 }
137 }
138 }
139
140 // search recursive in object children list
141 for (QObject *childObject : object->children()) {
142 allSubObjects(childObject, objectList);
143 }
144
145 // search recursive in quick item childItems list
146 QQuickItem *quickItem = qobject_cast<QQuickItem*>(object);
147 if (quickItem) {
148 const auto childItems = quickItem->childItems();
149 for (QQuickItem *childItem : childItems)
150 allSubObjects(childItem, objectList);
151 }
152}
153
154void QQuickDesignerSupportItems::tweakObjects(QObject *object)
155{
156 QObjectList objectList;
157 allSubObjects(object, objectList);
158 for (QObject* childObject : qAsConst(objectList)) {
159 stopAnimation(childObject);
160 makeLoaderSynchronous(childObject);
161 if (fixResourcePathsForObjectCallBack)
162 fixResourcePathsForObjectCallBack(childObject);
163 }
164}
165
166static QObject *createDummyWindow(QQmlEngine *engine)
167{
168 QQmlComponent component(engine, QUrl(QStringLiteral("qrc:/qtquickplugin/mockfiles/Window.qml")));
169 return component.create();
170}
171
172static bool isWindowMetaObject(const QMetaObject *metaObject)
173{
174 if (metaObject) {
175 if (metaObject->className() == QByteArrayLiteral("QWindow"))
176 return true;
177
178 return isWindowMetaObject(metaObject->superClass());
179 }
180
181 return false;
182}
183
184static bool isWindow(QObject *object) {
185 if (object)
186 return isWindowMetaObject(object->metaObject());
187
188 return false;
189}
190
191static bool isCrashingType(const QQmlType &type)
192{
193 QString name = type.qmlTypeName();
194
195 if (name == QLatin1String("QtMultimedia/MediaPlayer"))
196 return true;
197
198 if (name == QLatin1String("QtMultimedia/Audio"))
199 return true;
200
201 if (name == QLatin1String("QtQuick.Controls/MenuItem"))
202 return true;
203
204 if (name == QLatin1String("QtQuick.Controls/Menu"))
205 return true;
206
207 if (name == QLatin1String("QtQuick/Timer"))
208 return true;
209
210 return false;
211}
212
213QObject *QQuickDesignerSupportItems::createPrimitive(const QString &typeName, int majorNumber, int minorNumber, QQmlContext *context)
214{
215 ComponentCompleteDisabler disableComponentComplete;
216
217 Q_UNUSED(disableComponentComplete)
218
219 QObject *object = nullptr;
220 QQmlType type = QQmlMetaType::qmlType(typeName, majorNumber, minorNumber);
221
222 if (isCrashingType(type)) {
223 object = new QObject;
224 } else if (type.isValid()) {
225 if ( type.isComposite()) {
226 object = createComponent(type.sourceUrl(), context);
227 } else
228 {
229 if (type.typeName() == "QQmlComponent") {
230 object = new QQmlComponent(context->engine(), nullptr);
231 } else {
232 object = type.create();
233 }
234 }
235
236 if (isWindow(object)) {
237 delete object;
238 object = createDummyWindow(context->engine());
239 }
240
241 }
242
243 if (!object) {
244 qWarning() << "QuickDesigner: Cannot create an object of type"
245 << QString::fromLatin1("%1 %2,%3").arg(typeName).arg(majorNumber).arg(minorNumber)
246 << "- type isn't known to declarative meta type system";
247 }
248
249 tweakObjects(object);
250
251 if (object && QQmlEngine::contextForObject(object) == nullptr)
252 QQmlEngine::setContextForObject(object, context);
253
254 QQmlEngine::setObjectOwnership(object, QQmlEngine::CppOwnership);
255
256 return object;
257}
258
259QObject *QQuickDesignerSupportItems::createComponent(const QUrl &componentUrl, QQmlContext *context)
260{
261 ComponentCompleteDisabler disableComponentComplete;
262 Q_UNUSED(disableComponentComplete)
263
264 QQmlComponent component(context->engine(), componentUrl);
265
266 QObject *object = component.beginCreate(context);
267 tweakObjects(object);
268 component.completeCreate();
269 QQmlEngine::setObjectOwnership(object, QQmlEngine::CppOwnership);
270
271 if (component.isError()) {
272 qWarning() << "Error in:" << Q_FUNC_INFO << componentUrl;
273 const auto errors = component.errors();
274 for (const QQmlError &error : errors)
275 qWarning() << error;
276 }
277 return object;
278}
279
280bool QQuickDesignerSupportItems::objectWasDeleted(QObject *object)
281{
282 return QObjectPrivate::get(object)->wasDeleted;
283}
284
285void QQuickDesignerSupportItems::disableNativeTextRendering(QQuickItem *item)
286{
287 QQuickText *text = qobject_cast<QQuickText*>(item);
288 if (text)
289 text->setRenderType(QQuickText::QtRendering);
290
291 QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(item);
292 if (textInput)
293 textInput->setRenderType(QQuickTextInput::QtRendering);
294
295 QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit*>(item);
296 if (textEdit)
297 textEdit->setRenderType(QQuickTextEdit::QtRendering);
298}
299
300void QQuickDesignerSupportItems::disableTextCursor(QQuickItem *item)
301{
302 const auto childItems = item->childItems();
303 for (QQuickItem *childItem : childItems)
304 disableTextCursor(childItem);
305
306 QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(item);
307 if (textInput)
308 textInput->setCursorVisible(false);
309
310 QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit*>(item);
311 if (textEdit)
312 textEdit->setCursorVisible(false);
313}
314
315void QQuickDesignerSupportItems::disableTransition(QObject *object)
316{
317 QQuickTransition *transition = qobject_cast<QQuickTransition*>(object);
318 Q_ASSERT(transition);
319 const QString invalidState = QLatin1String("invalidState");
320 transition->setToState(invalidState);
321 transition->setFromState(invalidState);
322}
323
324void QQuickDesignerSupportItems::disableBehaivour(QObject *object)
325{
326 QQuickBehavior* behavior = qobject_cast<QQuickBehavior*>(object);
327 Q_ASSERT(behavior);
328 behavior->setEnabled(false);
329}
330
331void QQuickDesignerSupportItems::stopUnifiedTimer()
332{
333 QUnifiedTimer::instance()->setSlowdownFactor(0.00001);
334 QUnifiedTimer::instance()->setSlowModeEnabled(true);
335}
336
337void QQuickDesignerSupportItems::registerFixResourcePathsForObjectCallBack(void (*callback)(QObject *))
338{
339 fixResourcePathsForObjectCallBack = callback;
340}
341
342QT_END_NAMESPACE
343
344
345