Merge branch 'refactor'
[profile/ivi/qtdeclarative.git] / src / declarative / items / qsgview.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qsgview.h"
43 #include "qsgview_p.h"
44
45 #include "qsgcanvas_p.h"
46 #include "qsgitem_p.h"
47 #include "qsgitemchangelistener_p.h"
48
49 #include <private/qdeclarativedebugtrace_p.h>
50 #include <private/qdeclarativeinspectorservice_p.h>
51
52 #include <QtDeclarative/qdeclarativeengine.h>
53 #include <private/qdeclarativeengine_p.h>
54 #include <QtCore/qbasictimer.h>
55
56
57 // XXX todo - This whole class should probably be merged with QDeclarativeView for
58 // maximum seamlessness
59 QT_BEGIN_NAMESPACE
60
61 DEFINE_BOOL_CONFIG_OPTION(frameRateDebug, QML_SHOW_FRAMERATE)
62
63 void QSGViewPrivate::init()
64 {
65     QDeclarativeEnginePrivate::get(&engine)->sgContext = QSGCanvasPrivate::context;
66
67     QDeclarativeInspectorService::instance()->addView(q_func());
68 }
69
70 QSGViewPrivate::QSGViewPrivate()
71     : root(0), component(0), resizeMode(QSGView::SizeViewToRootObject), initialSize(0,0), resized(false)
72 {
73 }
74
75 QSGViewPrivate::~QSGViewPrivate()
76 {
77     QDeclarativeInspectorService::instance()->removeView(q_func());
78
79     delete root;
80 }
81
82 void QSGViewPrivate::execute()
83 {
84     Q_Q(QSGView);
85     if (root) {
86         delete root;
87         root = 0;
88     }
89     if (component) {
90         delete component;
91         component = 0;
92     }
93     if (!source.isEmpty()) {
94         component = new QDeclarativeComponent(&engine, source, q);
95         if (!component->isLoading()) {
96             q->continueExecute();
97         } else {
98             QObject::connect(component, SIGNAL(statusChanged(QDeclarativeComponent::Status)),
99                              q, SLOT(continueExecute()));
100         }
101     }
102 }
103
104 void QSGViewPrivate::itemGeometryChanged(QSGItem *resizeItem, const QRectF &newGeometry, const QRectF &oldGeometry)
105 {
106     Q_Q(QSGView);
107     if (resizeItem == root && resizeMode == QSGView::SizeViewToRootObject) {
108         // wait for both width and height to be changed
109         resizetimer.start(0,q);
110     }
111     QSGItemChangeListener::itemGeometryChanged(resizeItem, newGeometry, oldGeometry);
112 }
113
114 QSGView::QSGView(QWindow *parent, Qt::WindowFlags f)
115 : QSGCanvas(*(new QSGViewPrivate), parent)
116 {
117     setWindowFlags(f);
118     d_func()->init();
119 }
120
121 QSGView::QSGView(const QUrl &source, QWindow *parent, Qt::WindowFlags f)
122 : QSGCanvas(*(new QSGViewPrivate), parent)
123 {
124     setWindowFlags(f);
125     d_func()->init();
126     setSource(source);
127 }
128
129 QSGView::~QSGView()
130 {
131 }
132
133 void QSGView::setSource(const QUrl& url)
134 {
135     Q_D(QSGView);
136     d->source = url;
137     d->execute();
138 }
139
140 QUrl QSGView::source() const
141 {
142     Q_D(const QSGView);
143     return d->source;
144 }
145
146 QDeclarativeEngine* QSGView::engine() const
147 {
148     Q_D(const QSGView);
149     return const_cast<QDeclarativeEngine *>(&d->engine);
150 }
151
152 QDeclarativeContext* QSGView::rootContext() const
153 {
154     Q_D(const QSGView);
155     return d->engine.rootContext();
156 }
157
158 QSGView::Status QSGView::status() const
159 {
160     Q_D(const QSGView);
161     if (!d->component)
162         return QSGView::Null;
163
164     return QSGView::Status(d->component->status());
165 }
166
167 QList<QDeclarativeError> QSGView::errors() const
168 {
169     Q_D(const QSGView);
170     if (d->component)
171         return d->component->errors();
172     return QList<QDeclarativeError>();
173 }
174
175 void QSGView::setResizeMode(ResizeMode mode)
176 {
177     Q_D(QSGView);
178     if (d->resizeMode == mode)
179         return;
180
181     if (d->root) {
182         if (d->resizeMode == SizeViewToRootObject) {
183             QSGItemPrivate *p = QSGItemPrivate::get(d->root);
184             p->removeItemChangeListener(d, QSGItemPrivate::Geometry);
185         }
186     }
187
188     d->resizeMode = mode;
189     if (d->root) {
190         d->initResize();
191     }
192 }
193
194 void QSGViewPrivate::initResize()
195 {
196     if (root) {
197         if (resizeMode == QSGView::SizeViewToRootObject) {
198             QSGItemPrivate *p = QSGItemPrivate::get(root);
199             p->addItemChangeListener(this, QSGItemPrivate::Geometry);
200         }
201     }
202     updateSize();
203 }
204
205 void QSGViewPrivate::updateSize()
206 {
207     Q_Q(QSGView);
208     if (!root)
209         return;
210
211     if (resizeMode == QSGView::SizeViewToRootObject) {
212         QSize newSize = QSize(root->width(), root->height());
213         if (newSize.isValid() && newSize != q->size()) {
214             q->resize(newSize);
215         }
216     } else if (resizeMode == QSGView::SizeRootObjectToView) {
217         if (!qFuzzyCompare(q->width(), root->width()))
218             root->setWidth(q->width());
219         if (!qFuzzyCompare(q->height(), root->height()))
220             root->setHeight(q->height());
221     }
222 }
223
224 QSize QSGViewPrivate::rootObjectSize() const
225 {
226     QSize rootObjectSize(0,0);
227     int widthCandidate = -1;
228     int heightCandidate = -1;
229     if (root) {
230         widthCandidate = root->width();
231         heightCandidate = root->height();
232     }
233     if (widthCandidate > 0) {
234         rootObjectSize.setWidth(widthCandidate);
235     }
236     if (heightCandidate > 0) {
237         rootObjectSize.setHeight(heightCandidate);
238     }
239     return rootObjectSize;
240 }
241
242 QSGView::ResizeMode QSGView::resizeMode() const
243 {
244     Q_D(const QSGView);
245     return d->resizeMode;
246 }
247
248 /*!
249   \internal
250  */
251 void QSGView::continueExecute()
252 {
253     Q_D(QSGView);
254     disconnect(d->component, SIGNAL(statusChanged(QDeclarativeComponent::Status)), this, SLOT(continueExecute()));
255
256     if (d->component->isError()) {
257         QList<QDeclarativeError> errorList = d->component->errors();
258         foreach (const QDeclarativeError &error, errorList) {
259             qWarning() << error;
260         }
261         emit statusChanged(status());
262         return;
263     }
264
265     QObject *obj = d->component->create();
266
267     if(d->component->isError()) {
268         QList<QDeclarativeError> errorList = d->component->errors();
269         foreach (const QDeclarativeError &error, errorList) {
270             qWarning() << error;
271         }
272         emit statusChanged(status());
273         return;
274     }
275
276     d->setRootObject(obj);
277     emit statusChanged(status());
278 }
279
280
281 /*!
282   \internal
283 */
284 void QSGViewPrivate::setRootObject(QObject *obj)
285 {
286     Q_Q(QSGView);
287     if (root == obj)
288         return;
289     if (QSGItem *sgItem = qobject_cast<QSGItem *>(obj)) {
290         root = sgItem;
291         sgItem->setParentItem(q->QSGCanvas::rootItem());
292     } else {
293         qWarning() << "QSGView only supports loading of root objects that derive from QSGItem." << endl
294                    << endl
295                    << "If your example is using QML 2, (such as qmlscene) and the .qml file you" << endl
296                    << "loaded has 'import QtQuick 1.0' or 'import Qt 4.7', this error will occur." << endl
297                    << endl
298                    << "To load files with 'import QtQuick 1.0' with QML 2, specify:" << endl
299                    << "  QMLSCENE_IMPORT_NAME=quick1" << endl
300                    << "on as an environment variable prior to launching the application." << endl
301                    << endl
302                    << "To load files with 'import Qt 4.7' with QML 2, specify:" << endl
303                    << "  QMLSCENE_IMPORT_NAME=qt" << endl
304                    << "on as an environment variable prior to launching the application." << endl;
305         delete obj;
306         root = 0;
307     }
308     if (root) {
309         initialSize = rootObjectSize();
310         if ((resizeMode == QSGView::SizeViewToRootObject || !resized) // ### refactor:  || !q->testAttribute(Qt::WA_Resized)
311              && initialSize != q->size()) {
312
313             q->resize(initialSize);
314             resized = true;
315         }
316         initResize();
317     }
318 }
319
320 /*!
321   \internal
322   If the \l {QTimerEvent} {timer event} \a e is this
323   view's resize timer, sceneResized() is emitted.
324  */
325 void QSGView::timerEvent(QTimerEvent* e)
326 {
327     Q_D(QSGView);
328     if (!e || e->timerId() == d->resizetimer.timerId()) {
329         d->updateSize();
330         d->resizetimer.stop();
331     }
332 }
333
334 /*!
335     \internal
336     Preferred size follows the root object geometry.
337 */
338 QSize QSGView::sizeHint() const
339 {
340     Q_D(const QSGView);
341     QSize rootObjectSize = d->rootObjectSize();
342     if (rootObjectSize.isEmpty()) {
343         return size();
344     } else {
345         return rootObjectSize;
346     }
347 }
348
349 QSize QSGView::initialSize() const
350 {
351     Q_D(const QSGView);
352     return d->initialSize;
353 }
354
355 QSGItem *QSGView::rootObject() const
356 {
357     Q_D(const QSGView);
358     return d->root;
359 }
360
361 /*!
362   \internal
363   This function handles the \l {QResizeEvent} {resize event}
364   \a e.
365  */
366 void QSGView::resizeEvent(QResizeEvent *e)
367 {
368     Q_D(QSGView);
369     if (d->resizeMode == SizeRootObjectToView)
370         d->updateSize();
371
372     QSGCanvas::resizeEvent(e);
373 }
374
375 void QSGView::keyPressEvent(QKeyEvent *e)
376 {
377     QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::Key);
378
379     QSGCanvas::keyPressEvent(e);
380 }
381
382 void QSGView::keyReleaseEvent(QKeyEvent *e)
383 {
384     QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::Key);
385
386     QSGCanvas::keyReleaseEvent(e);
387 }
388
389 void QSGView::mouseMoveEvent(QMouseEvent *e)
390 {
391     QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::Mouse);
392
393     QSGCanvas::mouseMoveEvent(e);
394 }
395
396 void QSGView::mousePressEvent(QMouseEvent *e)
397 {
398     QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::Mouse);
399
400     QSGCanvas::mousePressEvent(e);
401 }
402
403 void QSGView::mouseReleaseEvent(QMouseEvent *e)
404 {
405     QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::Mouse);
406
407     QSGCanvas::mouseReleaseEvent(e);
408 }
409
410
411 QT_END_NAMESPACE