Merge branch 'master' into 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
44 #include "qsgcanvas_p.h"
45 #include "qsgitem_p.h"
46 #include "qsgitemchangelistener_p.h"
47
48 #include <private/qdeclarativedebugtrace_p.h>
49 #include <private/qdeclarativeinspectorservice_p.h>
50
51 #include <QtDeclarative/qdeclarativeengine.h>
52 #include <private/qdeclarativeengine_p.h>
53 #include <QtCore/qbasictimer.h>
54
55 // XXX todo - This whole class should probably be merged with QDeclarativeView for 
56 // maximum seamlessness
57 QT_BEGIN_NAMESPACE
58
59 DEFINE_BOOL_CONFIG_OPTION(frameRateDebug, QML_SHOW_FRAMERATE)
60
61 class QSGViewPrivate : public QSGCanvasPrivate, 
62                        public QSGItemChangeListener
63 {
64     Q_DECLARE_PUBLIC(QSGView)
65 public:
66     QSGViewPrivate();
67     ~QSGViewPrivate();
68
69     void execute();
70     void itemGeometryChanged(QSGItem *item, const QRectF &newGeometry, const QRectF &oldGeometry);
71     void initResize();
72     void updateSize();
73     void setRootObject(QObject *);
74
75     void init();
76
77     QSize rootObjectSize() const;
78
79     QPointer<QSGItem> root;
80
81     QUrl source;
82
83     QDeclarativeEngine engine;
84     QDeclarativeComponent *component;
85     QBasicTimer resizetimer;
86
87     QSGView::ResizeMode resizeMode;
88     QSize initialSize;
89     QElapsedTimer frameTimer;
90
91     bool resized;
92 };
93
94 void QSGViewPrivate::init()
95 {
96     QDeclarativeEnginePrivate::get(&engine)->sgContext = QSGCanvasPrivate::context;
97
98     QDeclarativeInspectorService::instance()->addView(q_func());
99 }
100
101 QSGViewPrivate::QSGViewPrivate()
102     : root(0), component(0), resizeMode(QSGView::SizeViewToRootObject), initialSize(0,0), resized(false)
103 {
104 }
105
106 QSGViewPrivate::~QSGViewPrivate() 
107
108     QDeclarativeInspectorService::instance()->removeView(q_func());
109
110     delete root;
111 }
112
113 void QSGViewPrivate::execute()
114 {
115     Q_Q(QSGView);
116     if (root) {
117         delete root;
118         root = 0;
119     }
120     if (component) {
121         delete component;
122         component = 0;
123     }
124     if (!source.isEmpty()) {
125         component = new QDeclarativeComponent(&engine, source, q);
126         if (!component->isLoading()) {
127             q->continueExecute();
128         } else {
129             QObject::connect(component, SIGNAL(statusChanged(QDeclarativeComponent::Status)), 
130                              q, SLOT(continueExecute()));
131         }
132     }
133 }
134
135 void QSGViewPrivate::itemGeometryChanged(QSGItem *resizeItem, const QRectF &newGeometry, const QRectF &oldGeometry)
136 {
137     Q_Q(QSGView);
138     if (resizeItem == root && resizeMode == QSGView::SizeViewToRootObject) {
139         // wait for both width and height to be changed
140         resizetimer.start(0,q);
141     }
142     QSGItemChangeListener::itemGeometryChanged(resizeItem, newGeometry, oldGeometry);
143 }
144
145 QSGView::QSGView(QWindow *parent, Qt::WindowFlags f)
146 : QSGCanvas(*(new QSGViewPrivate), parent)
147 {
148     setWindowFlags(f);
149     d_func()->init();
150 }
151
152 QSGView::QSGView(const QUrl &source, QWindow *parent, Qt::WindowFlags f)
153 : QSGCanvas(*(new QSGViewPrivate), parent)
154 {
155     setWindowFlags(f);
156     d_func()->init();
157     setSource(source);
158 }
159
160 QSGView::~QSGView()
161 {
162 }
163
164 void QSGView::setSource(const QUrl& url)
165 {
166     Q_D(QSGView);
167     d->source = url;
168     d->execute();
169 }
170
171 QUrl QSGView::source() const
172 {
173     Q_D(const QSGView);
174     return d->source;
175 }
176
177 QDeclarativeEngine* QSGView::engine() const
178 {
179     Q_D(const QSGView);
180     return const_cast<QDeclarativeEngine *>(&d->engine);
181 }
182
183 QDeclarativeContext* QSGView::rootContext() const
184 {
185     Q_D(const QSGView);
186     return d->engine.rootContext();
187 }
188
189 QSGView::Status QSGView::status() const
190 {
191     Q_D(const QSGView);
192     if (!d->component)
193         return QSGView::Null;
194
195     return QSGView::Status(d->component->status());
196 }
197
198 QList<QDeclarativeError> QSGView::errors() const
199 {
200     Q_D(const QSGView);
201     if (d->component)
202         return d->component->errors();
203     return QList<QDeclarativeError>();
204 }
205
206 void QSGView::setResizeMode(ResizeMode mode)
207 {
208     Q_D(QSGView);
209     if (d->resizeMode == mode)
210         return;
211
212     if (d->root) {
213         if (d->resizeMode == SizeViewToRootObject) {
214             QSGItemPrivate *p = QSGItemPrivate::get(d->root);
215             p->removeItemChangeListener(d, QSGItemPrivate::Geometry);
216         }
217     }
218
219     d->resizeMode = mode;
220     if (d->root) {
221         d->initResize();
222     }
223 }
224
225 void QSGViewPrivate::initResize()
226 {
227     if (root) {
228         if (resizeMode == QSGView::SizeViewToRootObject) {
229             QSGItemPrivate *p = QSGItemPrivate::get(root);
230             p->addItemChangeListener(this, QSGItemPrivate::Geometry);
231         }
232     }
233     updateSize();
234 }
235
236 void QSGViewPrivate::updateSize()
237 {
238     Q_Q(QSGView);
239     if (!root)
240         return;
241
242     if (resizeMode == QSGView::SizeViewToRootObject) {
243         QSize newSize = QSize(root->width(), root->height());
244         if (newSize.isValid() && newSize != q->size()) {
245             q->resize(newSize);
246         }
247     } else if (resizeMode == QSGView::SizeRootObjectToView) {
248         if (!qFuzzyCompare(q->width(), root->width()))
249             root->setWidth(q->width());
250         if (!qFuzzyCompare(q->height(), root->height()))
251             root->setHeight(q->height());
252     }
253 }
254
255 QSize QSGViewPrivate::rootObjectSize() const
256 {
257     QSize rootObjectSize(0,0);
258     int widthCandidate = -1;
259     int heightCandidate = -1;
260     if (root) {
261         widthCandidate = root->width();
262         heightCandidate = root->height();
263     }
264     if (widthCandidate > 0) {
265         rootObjectSize.setWidth(widthCandidate);
266     }
267     if (heightCandidate > 0) {
268         rootObjectSize.setHeight(heightCandidate);
269     }
270     return rootObjectSize;
271 }
272
273 QSGView::ResizeMode QSGView::resizeMode() const
274 {
275     Q_D(const QSGView);
276     return d->resizeMode;
277 }
278
279 /*!
280   \internal
281  */
282 void QSGView::continueExecute()
283 {
284     Q_D(QSGView);
285     disconnect(d->component, SIGNAL(statusChanged(QDeclarativeComponent::Status)), this, SLOT(continueExecute()));
286
287     if (d->component->isError()) {
288         QList<QDeclarativeError> errorList = d->component->errors();
289         foreach (const QDeclarativeError &error, errorList) {
290             qWarning() << error;
291         }
292         emit statusChanged(status());
293         return;
294     }
295
296     QObject *obj = d->component->create();
297
298     if(d->component->isError()) {
299         QList<QDeclarativeError> errorList = d->component->errors();
300         foreach (const QDeclarativeError &error, errorList) {
301             qWarning() << error;
302         }
303         emit statusChanged(status());
304         return;
305     }
306
307     d->setRootObject(obj);
308     emit statusChanged(status());
309 }
310
311
312 /*!
313   \internal
314 */
315 void QSGViewPrivate::setRootObject(QObject *obj)
316 {
317     Q_Q(QSGView);
318     if (root == obj)
319         return;
320     if (QSGItem *sgItem = qobject_cast<QSGItem *>(obj)) {
321         root = sgItem;
322         sgItem->setParentItem(q->QSGCanvas::rootItem());
323     } else {
324         qWarning() << "QSGView only supports loading of root objects that derive from QSGItem." << endl
325                    << endl
326                    << "If your example is using QML 2, (such as qmlscene) and the .qml file you" << endl
327                    << "loaded has 'import QtQuick 1.0' or 'import Qt 4.7', this error will occur." << endl
328                    << endl
329                    << "To load files with 'import QtQuick 1.0' with QML 2, specify:" << endl
330                    << "  QMLSCENE_IMPORT_NAME=quick1" << endl
331                    << "on as an environment variable prior to launching the application." << endl
332                    << endl
333                    << "To load files with 'import Qt 4.7' with QML 2, specify:" << endl
334                    << "  QMLSCENE_IMPORT_NAME=qt" << endl
335                    << "on as an environment variable prior to launching the application." << endl;
336         delete obj;
337         root = 0;
338     }
339     if (root) {
340         initialSize = rootObjectSize();
341         if ((resizeMode == QSGView::SizeViewToRootObject || !resized) // ### refactor:  || !q->testAttribute(Qt::WA_Resized)
342              && initialSize != q->size()) {
343
344             q->resize(initialSize);
345             resized = true;
346         }
347         initResize();
348     }
349 }
350
351 /*!
352   \internal
353   If the \l {QTimerEvent} {timer event} \a e is this
354   view's resize timer, sceneResized() is emitted.
355  */
356 void QSGView::timerEvent(QTimerEvent* e)
357 {
358     Q_D(QSGView);
359     if (!e || e->timerId() == d->resizetimer.timerId()) {
360         d->updateSize();
361         d->resizetimer.stop();
362     }
363 }
364
365 /*!
366     \internal
367     Preferred size follows the root object geometry.
368 */
369 QSize QSGView::sizeHint() const
370 {
371     Q_D(const QSGView);
372     QSize rootObjectSize = d->rootObjectSize();
373     if (rootObjectSize.isEmpty()) {
374         return size();
375     } else {
376         return rootObjectSize;
377     }
378 }
379
380 QSize QSGView::initialSize() const
381 {
382     Q_D(const QSGView);
383     return d->initialSize;
384 }
385
386 QSGItem *QSGView::rootObject() const
387 {
388     Q_D(const QSGView);
389     return d->root;
390 }
391
392 /*!
393   \internal
394   This function handles the \l {QResizeEvent} {resize event}
395   \a e.
396  */
397 void QSGView::resizeEvent(QResizeEvent *e)
398 {
399     Q_D(QSGView);
400     if (d->resizeMode == SizeRootObjectToView) 
401         d->updateSize();
402     
403     QSGCanvas::resizeEvent(e);
404 }
405
406 void QSGView::keyPressEvent(QKeyEvent *e)
407 {
408     QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::Key);
409
410     QSGCanvas::keyPressEvent(e);
411 }
412
413 void QSGView::keyReleaseEvent(QKeyEvent *e)
414 {
415     QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::Key);
416
417     QSGCanvas::keyReleaseEvent(e);
418 }
419
420 void QSGView::mouseMoveEvent(QMouseEvent *e)
421 {
422     QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::Mouse);
423
424     QSGCanvas::mouseMoveEvent(e);
425 }
426
427 void QSGView::mousePressEvent(QMouseEvent *e)
428 {
429     QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::Mouse);
430
431     QSGCanvas::mousePressEvent(e);
432 }
433
434 void QSGView::mouseReleaseEvent(QMouseEvent *e)
435 {
436     QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::Mouse);
437
438     QSGCanvas::mouseReleaseEvent(e);
439 }
440
441
442 QT_END_NAMESPACE