Initial import from qtquick2.
[profile/ivi/qtdeclarative.git] / src / declarative / items / qsgview.cpp
1 // Commit: 55c4d94dfea78951f3371d3697a3cb28539b3012
2 /****************************************************************************
3 **
4 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
5 ** All rights reserved.
6 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 **
8 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 **
10 ** $QT_BEGIN_LICENSE:LGPL$
11 ** No Commercial Usage
12 ** This file contains pre-release code and may not be distributed.
13 ** You may use this file in accordance with the terms and conditions
14 ** contained in the Technology Preview License Agreement accompanying
15 ** this package.
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 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights.  These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 **
39 ** $QT_END_LICENSE$
40 **
41 ****************************************************************************/
42
43 #include "qsgview.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
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
92 void QSGViewPrivate::init()
93 {
94     q_func()->setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Preferred);
95     QDeclarativeEnginePrivate::get(&engine)->sgContext = QSGCanvasPrivate::context;
96 }
97
98 QSGViewPrivate::QSGViewPrivate()
99 : root(0), component(0), resizeMode(QSGView::SizeViewToRootObject), initialSize(0,0) 
100 {
101 }
102
103 QSGViewPrivate::~QSGViewPrivate() 
104
105     delete root; 
106 }
107
108 void QSGViewPrivate::execute()
109 {
110     Q_Q(QSGView);
111     if (root) {
112         delete root;
113         root = 0;
114     }
115     if (component) {
116         delete component;
117         component = 0;
118     }
119     if (!source.isEmpty()) {
120         component = new QDeclarativeComponent(&engine, source, q);
121         if (!component->isLoading()) {
122             q->continueExecute();
123         } else {
124             QObject::connect(component, SIGNAL(statusChanged(QDeclarativeComponent::Status)), 
125                              q, SLOT(continueExecute()));
126         }
127     }
128 }
129
130 void QSGViewPrivate::itemGeometryChanged(QSGItem *resizeItem, const QRectF &newGeometry, const QRectF &oldGeometry)
131 {
132     Q_Q(QSGView);
133     if (resizeItem == root && resizeMode == QSGView::SizeViewToRootObject) {
134         // wait for both width and height to be changed
135         resizetimer.start(0,q);
136     }
137     QSGItemChangeListener::itemGeometryChanged(resizeItem, newGeometry, oldGeometry);
138 }
139
140 QSGView::QSGView(QWidget *parent, Qt::WindowFlags f)
141 : QSGCanvas(*(new QSGViewPrivate), parent, f)
142 {
143     d_func()->init();
144 }
145
146 QSGView::QSGView(const QGLFormat &format, QWidget *parent, Qt::WindowFlags f)
147 : QSGCanvas(*(new QSGViewPrivate), format, parent, f)
148 {
149     d_func()->init();
150 }
151
152 QSGView::QSGView(const QUrl &source, QWidget *parent, Qt::WindowFlags f)
153 : QSGCanvas(*(new QSGViewPrivate), parent, f)
154 {
155     d_func()->init();
156     setSource(source);
157 }
158
159 QSGView::QSGView(const QUrl &source, const QGLFormat &format, QWidget *parent, Qt::WindowFlags f)
160 : QSGCanvas(*(new QSGViewPrivate), format, parent, f)
161 {
162     d_func()->init();
163     setSource(source);
164 }
165
166 QSGView::~QSGView()
167 {
168 }
169
170 void QSGView::setSource(const QUrl& url)
171 {
172     Q_D(QSGView);
173     d->source = url;
174     d->execute();
175 }
176
177 QUrl QSGView::source() const
178 {
179     Q_D(const QSGView);
180     return d->source;
181 }
182
183 QDeclarativeEngine* QSGView::engine() const
184 {
185     Q_D(const QSGView);
186     return const_cast<QDeclarativeEngine *>(&d->engine);
187 }
188
189 QDeclarativeContext* QSGView::rootContext() const
190 {
191     Q_D(const QSGView);
192     return d->engine.rootContext();
193 }
194
195 QSGView::Status QSGView::status() const
196 {
197     Q_D(const QSGView);
198     if (!d->component)
199         return QSGView::Null;
200
201     return QSGView::Status(d->component->status());
202 }
203
204 QList<QDeclarativeError> QSGView::errors() const
205 {
206     Q_D(const QSGView);
207     if (d->component)
208         return d->component->errors();
209     return QList<QDeclarativeError>();
210 }
211
212 void QSGView::setResizeMode(ResizeMode mode)
213 {
214     Q_D(QSGView);
215     if (d->resizeMode == mode)
216         return;
217
218     if (d->root) {
219         if (d->resizeMode == SizeViewToRootObject) {
220             QSGItemPrivate *p = QSGItemPrivate::get(d->root);
221             p->removeItemChangeListener(d, QSGItemPrivate::Geometry);
222         }
223     }
224
225     d->resizeMode = mode;
226     if (d->root) {
227         d->initResize();
228     }
229 }
230
231 void QSGViewPrivate::initResize()
232 {
233     if (root) {
234         if (resizeMode == QSGView::SizeViewToRootObject) {
235             QSGItemPrivate *p = QSGItemPrivate::get(root);
236             p->addItemChangeListener(this, QSGItemPrivate::Geometry);
237         }
238     }
239     updateSize();
240 }
241
242 void QSGViewPrivate::updateSize()
243 {
244     Q_Q(QSGView);
245     if (!root)
246         return;
247
248     if (resizeMode == QSGView::SizeViewToRootObject) {
249         QSize newSize = QSize(root->width(), root->height());
250         if (newSize.isValid() && newSize != q->size()) {
251             q->resize(newSize);
252         }
253     } else if (resizeMode == QSGView::SizeRootObjectToView) {
254         if (!qFuzzyCompare(q->width(), root->width()))
255             root->setWidth(q->width());
256         if (!qFuzzyCompare(q->height(), root->height()))
257             root->setHeight(q->height());
258     }
259
260     q->updateGeometry();
261 }
262
263 QSize QSGViewPrivate::rootObjectSize() const
264 {
265     QSize rootObjectSize(0,0);
266     int widthCandidate = -1;
267     int heightCandidate = -1;
268     if (root) {
269         widthCandidate = root->width();
270         heightCandidate = root->height();
271     }
272     if (widthCandidate > 0) {
273         rootObjectSize.setWidth(widthCandidate);
274     }
275     if (heightCandidate > 0) {
276         rootObjectSize.setHeight(heightCandidate);
277     }
278     return rootObjectSize;
279 }
280
281 QSGView::ResizeMode QSGView::resizeMode() const
282 {
283     Q_D(const QSGView);
284     return d->resizeMode;
285 }
286
287 /*!
288   \internal
289  */
290 void QSGView::continueExecute()
291 {
292     Q_D(QSGView);
293     disconnect(d->component, SIGNAL(statusChanged(QDeclarativeComponent::Status)), this, SLOT(continueExecute()));
294
295     if (d->component->isError()) {
296         QList<QDeclarativeError> errorList = d->component->errors();
297         foreach (const QDeclarativeError &error, errorList) {
298             qWarning() << error;
299         }
300         emit statusChanged(status());
301         return;
302     }
303
304     QObject *obj = d->component->create();
305
306     if(d->component->isError()) {
307         QList<QDeclarativeError> errorList = d->component->errors();
308         foreach (const QDeclarativeError &error, errorList) {
309             qWarning() << error;
310         }
311         emit statusChanged(status());
312         return;
313     }
314
315     d->setRootObject(obj);
316     emit statusChanged(status());
317 }
318
319
320 /*!
321   \internal
322 */
323 void QSGViewPrivate::setRootObject(QObject *obj)
324 {
325     Q_Q(QSGView);
326     if (root == obj)
327         return;
328     if (QSGItem *sgItem = qobject_cast<QSGItem *>(obj)) {
329         root = sgItem;
330         sgItem->setParentItem(q->QSGCanvas::rootItem());
331     } else {
332         qWarning() << "QSGView only supports loading of root objects that derive from QSGItem." << endl
333                    << endl
334                    << "If your example is using QML 2, (such as qmlscene) and the .qml file you" << endl
335                    << "loaded has 'import QtQuick 1.0' or 'import Qt 4.7', this error will occur." << endl
336                    << endl
337                    << "To load files with 'import QtQuick 1.0' with QML 2, specify:" << endl
338                    << "  QMLSCENE_IMPORT_NAME=quick1" << endl
339                    << "on as an environment variable prior to launching the application." << endl
340                    << endl
341                    << "To load files with 'import Qt 4.7' with QML 2, specify:" << endl
342                    << "  QMLSCENE_IMPORT_NAME=qt" << endl
343                    << "on as an environment variable prior to launching the application." << endl;
344         delete obj;
345         root = 0;
346     }
347
348     if (root) {
349         initialSize = rootObjectSize();
350         if (initialSize != q->size()) {
351             if (!(q->parentWidget() && q->parentWidget()->layout())) {
352                 q->resize(initialSize);
353             }
354         }
355         initResize();
356     }
357 }
358
359 /*!
360   \internal
361   If the \l {QTimerEvent} {timer event} \a e is this
362   view's resize timer, sceneResized() is emitted.
363  */
364 void QSGView::timerEvent(QTimerEvent* e)
365 {
366     Q_D(QSGView);
367     if (!e || e->timerId() == d->resizetimer.timerId()) {
368         d->updateSize();
369         d->resizetimer.stop();
370     }
371 }
372
373 /*!
374     \internal
375     Preferred size follows the root object geometry.
376 */
377 QSize QSGView::sizeHint() const
378 {
379     Q_D(const QSGView);
380     QSize rootObjectSize = d->rootObjectSize();
381     if (rootObjectSize.isEmpty()) {
382         return size();
383     } else {
384         return rootObjectSize;
385     }
386 }
387
388 QSize QSGView::initialSize() const
389 {
390     Q_D(const QSGView);
391     return d->initialSize;
392 }
393
394 QSGItem *QSGView::rootObject() const
395 {
396     Q_D(const QSGView);
397     return d->root;
398 }
399
400 /*!
401   \internal
402   This function handles the \l {QResizeEvent} {resize event}
403   \a e.
404  */
405 void QSGView::resizeEvent(QResizeEvent *e)
406 {
407     Q_D(QSGView);
408     if (d->resizeMode == SizeRootObjectToView) 
409         d->updateSize();
410     
411     QSGCanvas::resizeEvent(e);
412 }
413
414 /*!
415     \internal
416 */
417 void QSGView::paintEvent(QPaintEvent *event)
418 {
419     Q_D(QSGView);
420     int time = 0;
421     if (frameRateDebug()) 
422         time = d->frameTimer.restart();
423
424     QSGCanvas::paintEvent(event);
425
426     if (frameRateDebug())
427         qDebug() << "paintEvent:" << d->frameTimer.elapsed() << "time since last frame:" << time;
428 }
429
430 void QSGView::keyPressEvent(QKeyEvent *e)
431 {
432     QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::Key);
433
434     QSGCanvas::keyPressEvent(e);
435 }
436
437 void QSGView::keyReleaseEvent(QKeyEvent *e)
438 {
439     QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::Key);
440
441     QSGCanvas::keyReleaseEvent(e);
442 }
443
444 void QSGView::mouseMoveEvent(QMouseEvent *e)
445 {
446     QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::Mouse);
447
448     QSGCanvas::mouseMoveEvent(e);
449 }
450
451 void QSGView::mousePressEvent(QMouseEvent *e)
452 {
453     QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::Mouse);
454
455     QSGCanvas::mousePressEvent(e);
456 }
457
458 void QSGView::mouseReleaseEvent(QMouseEvent *e)
459 {
460     QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::Mouse);
461
462     QSGCanvas::mouseReleaseEvent(e);
463 }
464
465
466 QT_END_NAMESPACE