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 
61 QT_BEGIN_NAMESPACE
62 
QQuickDesignerSupport()63 QQuickDesignerSupport::QQuickDesignerSupport()
64 {
65 }
66 
~QQuickDesignerSupport()67 QQuickDesignerSupport::~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 
refFromEffectItem(QQuickItem * referencedItem,bool hide)79 void 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 
derefFromEffectItem(QQuickItem * referencedItem,bool unhide)115 void 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 
renderImageForItem(QQuickItem * referencedItem,const QRectF & boundingRect,const QSize & imageSize)124 QImage 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 
isDirty(QQuickItem * referencedItem,DirtyType dirtyType)151 bool QQuickDesignerSupport::isDirty(QQuickItem *referencedItem, DirtyType dirtyType)
152 {
153     if (referencedItem == nullptr)
154         return false;
155 
156     return QQuickItemPrivate::get(referencedItem)->dirtyAttributes & dirtyType;
157 }
158 
addDirty(QQuickItem * referencedItem,QQuickDesignerSupport::DirtyType dirtyType)159 void QQuickDesignerSupport::addDirty(QQuickItem *referencedItem, QQuickDesignerSupport::DirtyType dirtyType)
160 {
161     if (referencedItem == nullptr)
162         return;
163 
164     QQuickItemPrivate::get(referencedItem)->dirtyAttributes |= dirtyType;
165 }
166 
resetDirty(QQuickItem * referencedItem)167 void 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 
windowTransform(QQuickItem * referencedItem)176 QTransform QQuickDesignerSupport::windowTransform(QQuickItem *referencedItem)
177 {
178     if (referencedItem == nullptr)
179         return QTransform();
180 
181     return QQuickItemPrivate::get(referencedItem)->itemToWindowTransform();
182 }
183 
parentTransform(QQuickItem * referencedItem)184 QTransform 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 
propertyNameForAnchorLine(const QQuickAnchors::Anchor & anchorLine)196 QString 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 
isValidAnchorName(const QString & name)211 bool 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 
isAnchoredTo(QQuickItem * fromItem,QQuickItem * toItem)226 bool 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 
areChildrenAnchoredTo(QQuickItem * fromItem,QQuickItem * toItem)241 bool 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 
anchors(QQuickItem * item)257 QQuickAnchors *anchors(QQuickItem *item)
258 {
259     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
260     return itemPrivate->anchors();
261 }
262 
anchorLineFlagForName(const QString & name)263 QQuickAnchors::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 
hasAnchor(QQuickItem * item,const QString & name)291 bool 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 
anchorFillTargetItem(QQuickItem * item)326 QQuickItem *QQuickDesignerSupport::anchorFillTargetItem(QQuickItem *item)
327 {
328     return anchors(item)->fill();
329 }
330 
anchorCenterInTargetItem(QQuickItem * item)331 QQuickItem *QQuickDesignerSupport::anchorCenterInTargetItem(QQuickItem *item)
332 {
333     return anchors(item)->centerIn();
334 }
335 
336 
337 
anchorLineTarget(QQuickItem * item,const QString & name,QQmlContext * context)338 QPair<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 
resetAnchor(QQuickItem * item,const QString & name)363 void 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 
emitComponentCompleteSignalForAttachedProperty(QObject * object)386 void 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 
statesForItem(QQuickItem * item)404 QList<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 
isComponentComplete(QQuickItem * item)416 bool QQuickDesignerSupport::isComponentComplete(QQuickItem *item)
417 {
418     return QQuickItemPrivate::get(item)->componentComplete;
419 }
420 
borderWidth(QQuickItem * item)421 int 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 
refreshExpressions(QQmlContext * context)430 void QQuickDesignerSupport::refreshExpressions(QQmlContext *context)
431 {
432     QQmlContextPrivate::get(context)->data->refreshExpressions();
433 }
434 
setRootItem(QQuickView * view,QQuickItem * item)435 void QQuickDesignerSupport::setRootItem(QQuickView *view, QQuickItem *item)
436 {
437     QQuickViewPrivate::get(view)->setRootObject(item);
438 }
439 
isValidWidth(QQuickItem * item)440 bool QQuickDesignerSupport::isValidWidth(QQuickItem *item)
441 {
442     return QQuickItemPrivate::get(item)->heightValid;
443 }
444 
isValidHeight(QQuickItem * item)445 bool QQuickDesignerSupport::isValidHeight(QQuickItem *item)
446 {
447     return QQuickItemPrivate::get(item)->widthValid;
448 }
449 
updateDirtyNode(QQuickItem * item)450 void QQuickDesignerSupport::updateDirtyNode(QQuickItem *item)
451 {
452     if (item->window())
453         QQuickWindowPrivate::get(item->window())->updateDirtyNode(item);
454 }
455 
activateDesignerWindowManager()456 void QQuickDesignerSupport::activateDesignerWindowManager()
457 {
458     QSGRenderLoop::setInstance(new QQuickDesignerWindowManager);
459 }
460 
activateDesignerMode()461 void QQuickDesignerSupport::activateDesignerMode()
462 {
463     QQmlEnginePrivate::activateDesignerMode();
464 }
465 
disableComponentComplete()466 void QQuickDesignerSupport::disableComponentComplete()
467 {
468     QQmlVME::disableComponentComplete();
469 }
470 
enableComponentComplete()471 void QQuickDesignerSupport::enableComponentComplete()
472 {
473     QQmlVME::enableComponentComplete();
474 }
475 
createOpenGLContext(QQuickWindow * window)476 void QQuickDesignerSupport::createOpenGLContext(QQuickWindow *window)
477 {
478     QQuickDesignerWindowManager::createOpenGLContext(window);
479 }
480 
polishItems(QQuickWindow * window)481 void QQuickDesignerSupport::polishItems(QQuickWindow *window)
482 {
483     QQuickWindowPrivate::get(window)->polishItems();
484 }
485 
ComponentCompleteDisabler()486 ComponentCompleteDisabler::ComponentCompleteDisabler()
487 {
488     QQuickDesignerSupport::disableComponentComplete();
489 }
490 
~ComponentCompleteDisabler()491 ComponentCompleteDisabler::~ComponentCompleteDisabler()
492 {
493     QQuickDesignerSupport::enableComponentComplete();
494 }
495 
496 
497 QT_END_NAMESPACE
498