638cbb7ff37ea9a650482f7ce93cb6ae8ca0f6b4
[profile/ivi/qtdeclarative.git] / src / quick / items / qquickview.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
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 "qquickview.h"
43 #include "qquickview_p.h"
44
45 #include "qquickcanvas_p.h"
46 #include "qquickitem_p.h"
47 #include "qquickitemchangelistener_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 QT_BEGIN_NAMESPACE
58
59 void QQuickViewPrivate::init()
60 {
61     Q_Q(QQuickView);
62
63     engine.setIncubationController(q->incubationController());
64
65     if (QDeclarativeDebugService::isDebuggingEnabled())
66         QDeclarativeInspectorService::instance()->addView(q);
67 }
68
69 QQuickViewPrivate::QQuickViewPrivate()
70     : root(0), component(0), resizeMode(QQuickView::SizeViewToRootObject), initialSize(0,0)
71 {
72 }
73
74 QQuickViewPrivate::~QQuickViewPrivate()
75 {
76     if (QDeclarativeDebugService::isDebuggingEnabled())
77         QDeclarativeInspectorService::instance()->removeView(q_func());
78
79     delete root;
80 }
81
82 void QQuickViewPrivate::execute()
83 {
84     Q_Q(QQuickView);
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 QQuickViewPrivate::itemGeometryChanged(QQuickItem *resizeItem, const QRectF &newGeometry, const QRectF &oldGeometry)
105 {
106     Q_Q(QQuickView);
107     if (resizeItem == root && resizeMode == QQuickView::SizeViewToRootObject) {
108         // wait for both width and height to be changed
109         resizetimer.start(0,q);
110     }
111     QQuickItemChangeListener::itemGeometryChanged(resizeItem, newGeometry, oldGeometry);
112 }
113
114 /*!
115     \class QQuickView
116     \since QtQuick 2.0
117     \brief The QQuickView class provides a window for displaying a Qt Quick user interface.
118
119     \inmodule QtQuick
120
121     This is a convenience subclass of QQuickCanvas which
122     will automatically load and display a QML scene when given the URL of the main source file. Alternatively,
123     you can instantiate your own objects using QDeclarativeComponent and place them in a manually setup QQuickCanvas.
124
125     Typical usage:
126
127     \code
128     QQuickView *view = new QQuickView;
129     view->setSource(QUrl::fromLocalFile("myqmlfile.qml"));
130     view->show();
131     \endcode
132
133     To receive errors related to loading and executing QML with QQuickView,
134     you can connect to the statusChanged() signal and monitor for QQuickView::Error.
135     The errors are available via QQuickView::errors().
136
137     \sa {Using QML Bindings in C++ Applications}
138 */
139
140
141 /*! \fn void QQuickView::sceneResized(QSize size)
142   This signal is emitted when the view is resized to \a size.
143 */
144
145 /*! \fn void QQuickView::statusChanged(QQuickView::Status status)
146     This signal is emitted when the component's current \a status changes.
147 */
148
149 /*! \fn void QQuickView::initialSizeChanged(QSize size)
150   \internal
151 */
152
153 /*!
154   \fn QQuickView::QQuickView(QWindow *parent)
155
156   Constructs a QQuickView with the given \a parent.
157 */
158 QQuickView::QQuickView(QWindow *parent, Qt::WindowFlags f)
159 : QQuickCanvas(*(new QQuickViewPrivate), parent)
160 {
161     setWindowFlags(f);
162     d_func()->init();
163 }
164
165 /*!
166   \fn QQuickView::QQuickView(const QUrl &source, QWidget *parent)
167
168   Constructs a QQuickView with the given QML \a source and \a parent.
169 */
170 QQuickView::QQuickView(const QUrl &source, QWindow *parent, Qt::WindowFlags f)
171 : QQuickCanvas(*(new QQuickViewPrivate), parent)
172 {
173     setWindowFlags(f);
174     d_func()->init();
175     setSource(source);
176 }
177
178 QQuickView::~QQuickView()
179 {
180 }
181
182 /*! \property QQuickView::source
183   \brief The URL of the source of the QML component.
184
185   Changing this property causes the QML component to be reloaded.
186
187     Ensure that the URL provided is full and correct, in particular, use
188     \l QUrl::fromLocalFile() when loading a file from the local filesystem.
189  */
190
191 /*!
192     Sets the source to the \a url, loads the QML component and instantiates it.
193
194     Ensure that the URL provided is full and correct, in particular, use
195     \l QUrl::fromLocalFile() when loading a file from the local filesystem.
196
197     Calling this methods multiple times with the same url will result
198     in the QML being reloaded.
199  */
200 void QQuickView::setSource(const QUrl& url)
201 {
202     Q_D(QQuickView);
203     d->source = url;
204     d->execute();
205 }
206
207 /*!
208   Returns the source URL, if set.
209
210   \sa setSource()
211  */
212 QUrl QQuickView::source() const
213 {
214     Q_D(const QQuickView);
215     return d->source;
216 }
217
218 /*!
219   Returns a pointer to the QDeclarativeEngine used for instantiating
220   QML Components.
221  */
222 QDeclarativeEngine* QQuickView::engine() const
223 {
224     Q_D(const QQuickView);
225     return const_cast<QDeclarativeEngine *>(&d->engine);
226 }
227
228 /*!
229   This function returns the root of the context hierarchy.  Each QML
230   component is instantiated in a QDeclarativeContext.  QDeclarativeContext's are
231   essential for passing data to QML components.  In QML, contexts are
232   arranged hierarchically and this hierarchy is managed by the
233   QDeclarativeEngine.
234  */
235 QDeclarativeContext* QQuickView::rootContext() const
236 {
237     Q_D(const QQuickView);
238     return d->engine.rootContext();
239 }
240
241 /*!
242     \enum QQuickView::Status
243     Specifies the loading status of the QQuickView.
244
245     \value Null This QQuickView has no source set.
246     \value Ready This QQuickView has loaded and created the QML component.
247     \value Loading This QQuickView is loading network data.
248     \value Error One or more errors has occurred. Call errors() to retrieve a list
249            of errors.
250 */
251
252 /*! \enum QQuickView::ResizeMode
253
254   This enum specifies how to resize the view.
255
256   \value SizeViewToRootObject The view resizes with the root item in the QML.
257   \value SizeRootObjectToView The view will automatically resize the root item to the size of the view.
258 */
259
260 /*!
261     \property QQuickView::status
262     The component's current \l{QQuickView::Status} {status}.
263 */
264
265 QQuickView::Status QQuickView::status() const
266 {
267     Q_D(const QQuickView);
268     if (!d->component)
269         return QQuickView::Null;
270
271     return QQuickView::Status(d->component->status());
272 }
273
274 /*!
275     Return the list of errors that occurred during the last compile or create
276     operation.  When the status is not Error, an empty list is returned.
277 */
278 QList<QDeclarativeError> QQuickView::errors() const
279 {
280     Q_D(const QQuickView);
281     if (d->component)
282         return d->component->errors();
283     return QList<QDeclarativeError>();
284 }
285
286 /*!
287     \property QQuickView::resizeMode
288     \brief whether the view should resize the canvas contents
289
290     If this property is set to SizeViewToRootObject (the default), the view
291     resizes with the root item in the QML.
292
293     If this property is set to SizeRootObjectToView, the view will
294     automatically resize the root item.
295
296     Regardless of this property, the sizeHint of the view
297     is the initial size of the root item. Note though that
298     since QML may load dynamically, that size may change.
299 */
300
301 void QQuickView::setResizeMode(ResizeMode mode)
302 {
303     Q_D(QQuickView);
304     if (d->resizeMode == mode)
305         return;
306
307     if (d->root) {
308         if (d->resizeMode == SizeViewToRootObject) {
309             QQuickItemPrivate *p = QQuickItemPrivate::get(d->root);
310             p->removeItemChangeListener(d, QQuickItemPrivate::Geometry);
311         }
312     }
313
314     d->resizeMode = mode;
315     if (d->root) {
316         d->initResize();
317     }
318 }
319
320 void QQuickViewPrivate::initResize()
321 {
322     if (root) {
323         if (resizeMode == QQuickView::SizeViewToRootObject) {
324             QQuickItemPrivate *p = QQuickItemPrivate::get(root);
325             p->addItemChangeListener(this, QQuickItemPrivate::Geometry);
326         }
327     }
328     updateSize();
329 }
330
331 void QQuickViewPrivate::updateSize()
332 {
333     Q_Q(QQuickView);
334     if (!root)
335         return;
336
337     if (resizeMode == QQuickView::SizeViewToRootObject) {
338         QSize newSize = QSize(root->width(), root->height());
339         if (newSize.isValid() && newSize != q->size()) {
340             q->resize(newSize);
341         }
342     } else if (resizeMode == QQuickView::SizeRootObjectToView) {
343         if (!qFuzzyCompare(q->width(), root->width()))
344             root->setWidth(q->width());
345         if (!qFuzzyCompare(q->height(), root->height()))
346             root->setHeight(q->height());
347     }
348 }
349
350 QSize QQuickViewPrivate::rootObjectSize() const
351 {
352     QSize rootObjectSize(0,0);
353     int widthCandidate = -1;
354     int heightCandidate = -1;
355     if (root) {
356         widthCandidate = root->width();
357         heightCandidate = root->height();
358     }
359     if (widthCandidate > 0) {
360         rootObjectSize.setWidth(widthCandidate);
361     }
362     if (heightCandidate > 0) {
363         rootObjectSize.setHeight(heightCandidate);
364     }
365     return rootObjectSize;
366 }
367
368 QQuickView::ResizeMode QQuickView::resizeMode() const
369 {
370     Q_D(const QQuickView);
371     return d->resizeMode;
372 }
373
374 /*!
375   \internal
376  */
377 void QQuickView::continueExecute()
378 {
379     Q_D(QQuickView);
380     disconnect(d->component, SIGNAL(statusChanged(QDeclarativeComponent::Status)), this, SLOT(continueExecute()));
381
382     if (d->component->isError()) {
383         QList<QDeclarativeError> errorList = d->component->errors();
384         foreach (const QDeclarativeError &error, errorList) {
385             qWarning() << error;
386         }
387         emit statusChanged(status());
388         return;
389     }
390
391     QObject *obj = d->component->create();
392
393     if (d->component->isError()) {
394         QList<QDeclarativeError> errorList = d->component->errors();
395         foreach (const QDeclarativeError &error, errorList) {
396             qWarning() << error;
397         }
398         emit statusChanged(status());
399         return;
400     }
401
402     d->setRootObject(obj);
403     emit statusChanged(status());
404 }
405
406
407 /*!
408   \internal
409 */
410 void QQuickViewPrivate::setRootObject(QObject *obj)
411 {
412     Q_Q(QQuickView);
413     if (root == obj)
414         return;
415     if (QQuickItem *sgItem = qobject_cast<QQuickItem *>(obj)) {
416         root = sgItem;
417         sgItem->setParentItem(q->QQuickCanvas::rootItem());
418     } else {
419         qWarning() << "QQuickView only supports loading of root objects that derive from QQuickItem." << endl
420                    << endl
421                    << "If your example is using QML 2, (such as qmlscene) and the .qml file you" << endl
422                    << "loaded has 'import QtQuick 1.0' or 'import Qt 4.7', this error will occur." << endl
423                    << endl
424                    << "To load files with 'import QtQuick 1.0' with QML 2, specify:" << endl
425                    << "  QMLSCENE_IMPORT_NAME=quick1" << endl
426                    << "on as an environment variable prior to launching the application." << endl
427                    << endl
428                    << "To load files with 'import Qt 4.7' with QML 2, specify:" << endl
429                    << "  QMLSCENE_IMPORT_NAME=qt" << endl
430                    << "on as an environment variable prior to launching the application." << endl;
431         delete obj;
432         root = 0;
433     }
434     if (root) {
435         initialSize = rootObjectSize();
436         if ((resizeMode == QQuickView::SizeViewToRootObject || !q->width() || !q->height())
437                 && initialSize != q->size()) {
438             q->resize(initialSize);
439         }
440         initResize();
441     }
442 }
443
444 /*!
445   \internal
446   If the \l {QTimerEvent} {timer event} \a e is this
447   view's resize timer, sceneResized() is emitted.
448  */
449 void QQuickView::timerEvent(QTimerEvent* e)
450 {
451     Q_D(QQuickView);
452     if (!e || e->timerId() == d->resizetimer.timerId()) {
453         d->updateSize();
454         d->resizetimer.stop();
455     }
456 }
457
458 /*!
459     \internal
460     Preferred size follows the root object geometry.
461 */
462 QSize QQuickView::sizeHint() const
463 {
464     Q_D(const QQuickView);
465     QSize rootObjectSize = d->rootObjectSize();
466     if (rootObjectSize.isEmpty()) {
467         return size();
468     } else {
469         return rootObjectSize;
470     }
471 }
472
473 /*!
474   Returns the initial size of the root object
475 */
476 QSize QQuickView::initialSize() const
477 {
478     Q_D(const QQuickView);
479     return d->initialSize;
480 }
481
482 /*!
483   Returns the view's root \l {QQuickItem} {item}.
484  */
485 QQuickItem *QQuickView::rootObject() const
486 {
487     Q_D(const QQuickView);
488     return d->root;
489 }
490
491 /*!
492   \internal
493   This function handles the \l {QResizeEvent} {resize event}
494   \a e.
495  */
496 void QQuickView::resizeEvent(QResizeEvent *e)
497 {
498     Q_D(QQuickView);
499     if (d->resizeMode == SizeRootObjectToView)
500         d->updateSize();
501
502     QQuickCanvas::resizeEvent(e);
503 }
504
505 void QQuickView::keyPressEvent(QKeyEvent *e)
506 {
507     QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::Key);
508
509     QQuickCanvas::keyPressEvent(e);
510 }
511
512 void QQuickView::keyReleaseEvent(QKeyEvent *e)
513 {
514     QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::Key);
515
516     QQuickCanvas::keyReleaseEvent(e);
517 }
518
519 void QQuickView::mouseMoveEvent(QMouseEvent *e)
520 {
521     QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::Mouse);
522
523     QQuickCanvas::mouseMoveEvent(e);
524 }
525
526 void QQuickView::mousePressEvent(QMouseEvent *e)
527 {
528     QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::Mouse);
529
530     QQuickCanvas::mousePressEvent(e);
531 }
532
533 void QQuickView::mouseReleaseEvent(QMouseEvent *e)
534 {
535     QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::Mouse);
536
537     QQuickCanvas::mouseReleaseEvent(e);
538 }
539
540
541 QT_END_NAMESPACE