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