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 "qquickdesignersupport_p.h"
41#include <private/qquickitem_p.h>
42
43#if QT_CONFIG(quick_shadereffect)
44#include <QtQuick/private/qquickshadereffectsource_p.h>
45#endif
46#include <QtQuick/private/qquickrectangle_p.h>
47#include <QtQml/private/qabstractanimationjob_p.h>
48#include <private/qqmlengine_p.h>
49#include <private/qquickview_p.h>
50#include <private/qsgrenderloop_p.h>
51#include <QtQuick/private/qquickstategroup_p.h>
52#include <QtGui/QImage>
53#include <private/qqmlvme_p.h>
54#include <private/qqmlcomponentattached_p.h>
55#include <private/qqmldata_p.h>
56#include <private/qsgadaptationlayer_p.h>
57
58#include "qquickdesignerwindowmanager_p.h"
59
60
61QT_BEGIN_NAMESPACE
62
63QQuickDesignerSupport::QQuickDesignerSupport()
64{
65}
66
67QQuickDesignerSupport::~QQuickDesignerSupport()
68{
69 typedef QHash<QQuickItem*, QSGLayer*>::iterator ItemTextureHashIt;
70
71 for (ItemTextureHashIt iterator = m_itemTextureHash.begin(), end = m_itemTextureHash.end(); iterator != end; ++iterator) {
72 QSGLayer *texture = iterator.value();
73 QQuickItem *item = iterator.key();
74 QQuickItemPrivate::get(item)->derefFromEffectItem(true);
75 delete texture;
76 }
77}
78
79void QQuickDesignerSupport::refFromEffectItem(QQuickItem *referencedItem, bool hide)
80{
81 if (referencedItem == nullptr)
82 return;
83
84 QQuickItemPrivate::get(referencedItem)->refFromEffectItem(hide);
85 QQuickWindowPrivate::get(referencedItem->window())->updateDirtyNode(referencedItem);
86
87 Q_ASSERT(QQuickItemPrivate::get(referencedItem)->rootNode());
88
89 if (!m_itemTextureHash.contains(referencedItem)) {
90 QSGRenderContext *rc = QQuickWindowPrivate::get(referencedItem->window())->context;
91 QSGLayer *texture = rc->sceneGraphContext()->createLayer(rc);
92
93 QSizeF itemSize = referencedItem->size();
94 texture->setLive(true);
95 texture->setItem(QQuickItemPrivate::get(referencedItem)->rootNode());
96 texture->setRect(QRectF(QPointF(0, 0), itemSize));
97 texture->setSize(itemSize.toSize());
98 texture->setRecursive(true);
99#if QT_CONFIG(opengl)
100#ifndef QT_OPENGL_ES
101 if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL)
102 texture->setFormat(GL_RGBA8);
103 else
104 texture->setFormat(GL_RGBA);
105#else
106 texture->setFormat(GL_RGBA);
107#endif
108#endif
109 texture->setHasMipmaps(false);
110
111 m_itemTextureHash.insert(referencedItem, texture);
112 }
113}
114
115void QQuickDesignerSupport::derefFromEffectItem(QQuickItem *referencedItem, bool unhide)
116{
117 if (referencedItem == nullptr)
118 return;
119
120 delete m_itemTextureHash.take(referencedItem);
121 QQuickItemPrivate::get(referencedItem)->derefFromEffectItem(unhide);
122}
123
124QImage QQuickDesignerSupport::renderImageForItem(QQuickItem *referencedItem, const QRectF &boundingRect, const QSize &imageSize)
125{
126 if (referencedItem == nullptr || referencedItem->parentItem() == nullptr) {
127 qDebug() << __FILE__ << __LINE__ << "Warning: Item can be rendered.";
128 return QImage();
129 }
130
131 QSGLayer *renderTexture = m_itemTextureHash.value(referencedItem);
132
133 Q_ASSERT(renderTexture);
134 if (renderTexture == nullptr)
135 return QImage();
136 renderTexture->setRect(boundingRect);
137 renderTexture->setSize(imageSize);
138 renderTexture->setItem(QQuickItemPrivate::get(referencedItem)->rootNode());
139 renderTexture->markDirtyTexture();
140 renderTexture->updateTexture();
141
142 QImage renderImage = renderTexture->toImage();
143 renderImage = renderImage.mirrored(false, true);
144
145 if (renderImage.size().isEmpty())
146 qDebug() << __FILE__ << __LINE__ << "Warning: Image is empty.";
147
148 return renderImage;
149}
150
151bool QQuickDesignerSupport::isDirty(QQuickItem *referencedItem, DirtyType dirtyType)
152{
153 if (referencedItem == nullptr)
154 return false;
155
156 return QQuickItemPrivate::get(referencedItem)->dirtyAttributes & dirtyType;
157}
158
159void QQuickDesignerSupport::addDirty(QQuickItem *referencedItem, QQuickDesignerSupport::DirtyType dirtyType)
160{
161 if (referencedItem == nullptr)
162 return;
163
164 QQuickItemPrivate::get(referencedItem)->dirtyAttributes |= dirtyType;
165}
166
167void QQuickDesignerSupport::resetDirty(QQuickItem *referencedItem)
168{
169 if (referencedItem == nullptr)
170 return;
171
172 QQuickItemPrivate::get(referencedItem)->dirtyAttributes = 0x0;
173 QQuickItemPrivate::get(referencedItem)->removeFromDirtyList();
174}
175
176QTransform QQuickDesignerSupport::windowTransform(QQuickItem *referencedItem)
177{
178 if (referencedItem == nullptr)
179 return QTransform();
180
181 return QQuickItemPrivate::get(referencedItem)->itemToWindowTransform();
182}
183
184QTransform QQuickDesignerSupport::parentTransform(QQuickItem *referencedItem)
185{
186 if (referencedItem == nullptr)
187 return QTransform();
188
189 QTransform parentTransform;
190
191 QQuickItemPrivate::get(referencedItem)->itemToParentTransform(parentTransform);
192
193 return parentTransform;
194}
195
196QString propertyNameForAnchorLine(const QQuickAnchors::Anchor &anchorLine)
197{
198 switch (anchorLine) {
199 case QQuickAnchors::LeftAnchor: return QLatin1String("left");
200 case QQuickAnchors::RightAnchor: return QLatin1String("right");
201 case QQuickAnchors::TopAnchor: return QLatin1String("top");
202 case QQuickAnchors::BottomAnchor: return QLatin1String("bottom");
203 case QQuickAnchors::HCenterAnchor: return QLatin1String("horizontalCenter");
204 case QQuickAnchors::VCenterAnchor: return QLatin1String("verticalCenter");
205 case QQuickAnchors::BaselineAnchor: return QLatin1String("baseline");
206 case QQuickAnchors::InvalidAnchor: // fallthrough:
207 default: return QString();
208 }
209}
210
211bool isValidAnchorName(const QString &name)
212{
213 static QStringList anchorNameList(QStringList() << QLatin1String("anchors.top")
214 << QLatin1String("anchors.left")
215 << QLatin1String("anchors.right")
216 << QLatin1String("anchors.bottom")
217 << QLatin1String("anchors.verticalCenter")
218 << QLatin1String("anchors.horizontalCenter")
219 << QLatin1String("anchors.fill")
220 << QLatin1String("anchors.centerIn")
221 << QLatin1String("anchors.baseline"));
222
223 return anchorNameList.contains(name);
224}
225
226bool QQuickDesignerSupport::isAnchoredTo(QQuickItem *fromItem, QQuickItem *toItem)
227{
228 QQuickItemPrivate *fromItemPrivate = QQuickItemPrivate::get(fromItem);
229 QQuickAnchors *anchors = fromItemPrivate->anchors();
230 return anchors->fill() == toItem
231 || anchors->centerIn() == toItem
232 || anchors->bottom().item == toItem
233 || anchors->top().item == toItem
234 || anchors->left().item == toItem
235 || anchors->right().item == toItem
236 || anchors->verticalCenter().item == toItem
237 || anchors->horizontalCenter().item == toItem
238 || anchors->baseline().item == toItem;
239}
240
241bool QQuickDesignerSupport::areChildrenAnchoredTo(QQuickItem *fromItem, QQuickItem *toItem)
242{
243 const auto childItems = fromItem->childItems();
244 for (QQuickItem *childItem : childItems) {
245 if (childItem) {
246 if (isAnchoredTo(childItem, toItem))
247 return true;
248
249 if (areChildrenAnchoredTo(childItem, toItem))
250 return true;
251 }
252 }
253
254 return false;
255}
256
257QQuickAnchors *anchors(QQuickItem *item)
258{
259 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
260 return itemPrivate->anchors();
261}
262
263QQuickAnchors::Anchor anchorLineFlagForName(const QString &name)
264{
265 if (name == QLatin1String("anchors.top"))
266 return QQuickAnchors::TopAnchor;
267
268 if (name == QLatin1String("anchors.left"))
269 return QQuickAnchors::LeftAnchor;
270
271 if (name == QLatin1String("anchors.bottom"))
272 return QQuickAnchors::BottomAnchor;
273
274 if (name == QLatin1String("anchors.right"))
275 return QQuickAnchors::RightAnchor;
276
277 if (name == QLatin1String("anchors.horizontalCenter"))
278 return QQuickAnchors::HCenterAnchor;
279
280 if (name == QLatin1String("anchors.verticalCenter"))
281 return QQuickAnchors::VCenterAnchor;
282
283 if (name == QLatin1String("anchors.baseline"))
284 return QQuickAnchors::BaselineAnchor;
285
286
287 Q_ASSERT_X(false, Q_FUNC_INFO, "wrong anchor name - this should never happen");
288 return QQuickAnchors::LeftAnchor;
289}
290
291bool QQuickDesignerSupport::hasAnchor(QQuickItem *item, const QString &name)
292{
293 if (!isValidAnchorName(name))
294 return false;
295
296 if (name == QLatin1String("anchors.fill"))
297 return anchors(item)->fill() != nullptr;
298
299 if (name == QLatin1String("anchors.centerIn"))
300 return anchors(item)->centerIn() != nullptr;
301
302 if (name == QLatin1String("anchors.right"))
303 return anchors(item)->right().item != nullptr;
304
305 if (name == QLatin1String("anchors.top"))
306 return anchors(item)->top().item != nullptr;
307
308 if (name == QLatin1String("anchors.left"))
309 return anchors(item)->left().item != nullptr;
310
311 if (name == QLatin1String("anchors.bottom"))
312 return anchors(item)->bottom().item != nullptr;
313
314 if (name == QLatin1String("anchors.horizontalCenter"))
315 return anchors(item)->horizontalCenter().item != nullptr;
316
317 if (name == QLatin1String("anchors.verticalCenter"))
318 return anchors(item)->verticalCenter().item != nullptr;
319
320 if (name == QLatin1String("anchors.baseline"))
321 return anchors(item)->baseline().item != nullptr;
322
323 return anchors(item)->usedAnchors().testFlag(anchorLineFlagForName(name));
324}
325
326QQuickItem *QQuickDesignerSupport::anchorFillTargetItem(QQuickItem *item)
327{
328 return anchors(item)->fill();
329}
330
331QQuickItem *QQuickDesignerSupport::anchorCenterInTargetItem(QQuickItem *item)
332{
333 return anchors(item)->centerIn();
334}
335
336
337
338QPair<QString, QObject*> QQuickDesignerSupport::anchorLineTarget(QQuickItem *item, const QString &name, QQmlContext *context)
339{
340 QObject *targetObject = nullptr;
341 QString targetName;
342
343 if (name == QLatin1String("anchors.fill")) {
344 targetObject = anchors(item)->fill();
345 } else if (name == QLatin1String("anchors.centerIn")) {
346 targetObject = anchors(item)->centerIn();
347 } else {
348 QQmlProperty metaProperty(item, name, context);
349 if (!metaProperty.isValid())
350 return QPair<QString, QObject*>();
351
352 QQuickAnchorLine anchorLine = metaProperty.read().value<QQuickAnchorLine>();
353 if (anchorLine.anchorLine != QQuickAnchors::InvalidAnchor) {
354 targetObject = anchorLine.item;
355 targetName = propertyNameForAnchorLine(anchorLine.anchorLine);
356 }
357
358 }
359
360 return QPair<QString, QObject*>(targetName, targetObject);
361}
362
363void QQuickDesignerSupport::resetAnchor(QQuickItem *item, const QString &name)
364{
365 if (name == QLatin1String("anchors.fill")) {
366 anchors(item)->resetFill();
367 } else if (name == QLatin1String("anchors.centerIn")) {
368 anchors(item)->resetCenterIn();
369 } else if (name == QLatin1String("anchors.top")) {
370 anchors(item)->resetTop();
371 } else if (name == QLatin1String("anchors.left")) {
372 anchors(item)->resetLeft();
373 } else if (name == QLatin1String("anchors.right")) {
374 anchors(item)->resetRight();
375 } else if (name == QLatin1String("anchors.bottom")) {
376 anchors(item)->resetBottom();
377 } else if (name == QLatin1String("anchors.horizontalCenter")) {
378 anchors(item)->resetHorizontalCenter();
379 } else if (name == QLatin1String("anchors.verticalCenter")) {
380 anchors(item)->resetVerticalCenter();
381 } else if (name == QLatin1String("anchors.baseline")) {
382 anchors(item)->resetBaseline();
383 }
384}
385
386void QQuickDesignerSupport::emitComponentCompleteSignalForAttachedProperty(QObject *object)
387{
388 if (!object)
389 return;
390
391 QQmlData *data = QQmlData::get(object);
392 if (data && data->context) {
393 QQmlComponentAttached *componentAttached = data->context->componentAttached;
394 while (componentAttached) {
395 if (componentAttached->parent())
396 if (componentAttached->parent() == object)
397 emit componentAttached->completed();
398
399 componentAttached = componentAttached->next;
400 }
401 }
402}
403
404QList<QObject*> QQuickDesignerSupport::statesForItem(QQuickItem *item)
405{
406 QList<QObject*> objectList;
407 const QList<QQuickState *> stateList = QQuickItemPrivate::get(item)->_states()->states();
408
409 objectList.reserve(stateList.size());
410 for (QQuickState* state : stateList)
411 objectList.append(state);
412
413 return objectList;
414}
415
416bool QQuickDesignerSupport::isComponentComplete(QQuickItem *item)
417{
418 return QQuickItemPrivate::get(item)->componentComplete;
419}
420
421int QQuickDesignerSupport::borderWidth(QQuickItem *item)
422{
423 QQuickRectangle *rectangle = qobject_cast<QQuickRectangle*>(item);
424 if (rectangle)
425 return rectangle->border()->width();
426
427 return 0;
428}
429
430void QQuickDesignerSupport::refreshExpressions(QQmlContext *context)
431{
432 QQmlContextPrivate::get(context)->data->refreshExpressions();
433}
434
435void QQuickDesignerSupport::setRootItem(QQuickView *view, QQuickItem *item)
436{
437 QQuickViewPrivate::get(view)->setRootObject(item);
438}
439
440bool QQuickDesignerSupport::isValidWidth(QQuickItem *item)
441{
442 return QQuickItemPrivate::get(item)->heightValid;
443}
444
445bool QQuickDesignerSupport::isValidHeight(QQuickItem *item)
446{
447 return QQuickItemPrivate::get(item)->widthValid;
448}
449
450void QQuickDesignerSupport::updateDirtyNode(QQuickItem *item)
451{
452 if (item->window())
453 QQuickWindowPrivate::get(item->window())->updateDirtyNode(item);
454}
455
456void QQuickDesignerSupport::activateDesignerWindowManager()
457{
458 QSGRenderLoop::setInstance(new QQuickDesignerWindowManager);
459}
460
461void QQuickDesignerSupport::activateDesignerMode()
462{
463 QQmlEnginePrivate::activateDesignerMode();
464}
465
466void QQuickDesignerSupport::disableComponentComplete()
467{
468 QQmlVME::disableComponentComplete();
469}
470
471void QQuickDesignerSupport::enableComponentComplete()
472{
473 QQmlVME::enableComponentComplete();
474}
475
476void QQuickDesignerSupport::createOpenGLContext(QQuickWindow *window)
477{
478 QQuickDesignerWindowManager::createOpenGLContext(window);
479}
480
481void QQuickDesignerSupport::polishItems(QQuickWindow *window)
482{
483 QQuickWindowPrivate::get(window)->polishItems();
484}
485
486ComponentCompleteDisabler::ComponentCompleteDisabler()
487{
488 QQuickDesignerSupport::disableComponentComplete();
489}
490
491ComponentCompleteDisabler::~ComponentCompleteDisabler()
492{
493 QQuickDesignerSupport::enableComponentComplete();
494}
495
496
497QT_END_NAMESPACE
498