Fix various QtQuick.* submodule docs
[profile/ivi/qtdeclarative.git] / src / quick / items / qquickview.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
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/qqmlprofilerservice_p.h>
50 #include <private/qqmlinspectorservice_p.h>
51 #include <private/qqmlmemoryprofiler_p.h>
52
53 #include <QtQml/qqmlengine.h>
54 #include <private/qqmlengine_p.h>
55 #include <QtCore/qbasictimer.h>
56
57 QT_BEGIN_NAMESPACE
58
59 void QQuickViewPrivate::init(QQmlEngine* e)
60 {
61     Q_Q(QQuickView);
62
63     engine = e;
64
65     if (engine.isNull())
66         engine = new QQmlEngine(q);
67
68     if (!engine.data()->incubationController())
69         engine.data()->setIncubationController(q->incubationController());
70
71     if (QQmlDebugService::isDebuggingEnabled())
72         QQmlInspectorService::instance()->addView(q);
73 }
74
75 QQuickViewPrivate::QQuickViewPrivate()
76     : root(0), component(0), resizeMode(QQuickView::SizeViewToRootObject), initialSize(0,0)
77 {
78 }
79
80 QQuickViewPrivate::~QQuickViewPrivate()
81 {
82     if (QQmlDebugService::isDebuggingEnabled())
83         QQmlInspectorService::instance()->removeView(q_func());
84 }
85
86 void QQuickViewPrivate::execute()
87 {
88     Q_Q(QQuickView);
89     if (!engine) {
90         qWarning() << "QQuickView: invalid qml engine.";
91         return;
92     }
93
94     if (root) {
95         delete root;
96         root = 0;
97     }
98     if (component) {
99         delete component;
100         component = 0;
101     }
102     if (!source.isEmpty()) {
103         QML_MEMORY_SCOPE_URL(engine.data()->baseUrl().resolved(source));
104         component = new QQmlComponent(engine.data(), source, q);
105         if (!component->isLoading()) {
106             q->continueExecute();
107         } else {
108             QObject::connect(component, SIGNAL(statusChanged(QQmlComponent::Status)),
109                              q, SLOT(continueExecute()));
110         }
111     }
112 }
113
114 void QQuickViewPrivate::itemGeometryChanged(QQuickItem *resizeItem, const QRectF &newGeometry, const QRectF &oldGeometry)
115 {
116     Q_Q(QQuickView);
117     if (resizeItem == root && resizeMode == QQuickView::SizeViewToRootObject) {
118         // wait for both width and height to be changed
119         resizetimer.start(0,q);
120     }
121     QQuickItemChangeListener::itemGeometryChanged(resizeItem, newGeometry, oldGeometry);
122 }
123
124 /*!
125     \class QQuickView
126     \since QtQuick 2.0
127     \brief The QQuickView class provides a window for displaying a Qt Quick user interface.
128
129     \inmodule QtQuick
130
131     This is a convenience subclass of QQuickCanvas which
132     will automatically load and display a QML scene when given the URL of the main source file. Alternatively,
133     you can instantiate your own objects using QQmlComponent and place them in a manually setup QQuickCanvas.
134
135     Typical usage:
136
137     \code
138     QQuickView *view = new QQuickView;
139     view->setSource(QUrl::fromLocalFile("myqmlfile.qml"));
140     view->show();
141     \endcode
142
143     To receive errors related to loading and executing QML with QQuickView,
144     you can connect to the statusChanged() signal and monitor for QQuickView::Error.
145     The errors are available via QQuickView::errors().
146
147     QQuickView also manages sizing of the view and root object.  By default, the \l resizeMode
148     is SizeViewToRootObject, which will load the component and resize it to the
149     size of the view.  Alternatively the resizeMode may be set to SizeRootObjectToView which
150     will resize the view to the size of the root object.
151
152     \sa {Exposing C++ Data to QML}
153 */
154
155
156 /*! \fn void QQuickView::sceneResized(QSize size)
157   This signal is emitted when the view is resized to \a size.
158 */
159
160 /*! \fn void QQuickView::statusChanged(QQuickView::Status status)
161     This signal is emitted when the component's current \a status changes.
162 */
163
164 /*! \fn void QQuickView::initialSizeChanged(QSize size)
165   \internal
166 */
167
168 /*!
169   Constructs a QQuickView with the given \a parent and window flags \a f.
170   The default value of \a parent is 0, default window flags \a f is Qt::Window.
171
172   \sa Qt::WindowFlags
173 */
174 QQuickView::QQuickView(QWindow *parent, Qt::WindowFlags f)
175 : QQuickCanvas(*(new QQuickViewPrivate), parent)
176 {
177     setWindowFlags(f);
178     d_func()->init();
179 }
180
181 /*!
182   Constructs a QQuickView with the given QML \a source, \a parent and a window flags \a f.
183   The default value of \a parent is 0, default window flags \a f is Qt::Window.
184
185   \sa Qt::WindowFlags
186 */
187 QQuickView::QQuickView(const QUrl &source, QWindow *parent, Qt::WindowFlags f)
188 : QQuickCanvas(*(new QQuickViewPrivate), parent)
189 {
190     setWindowFlags(f);
191     d_func()->init();
192     setSource(source);
193 }
194
195 /*!
196   Constructs a QQuickView with the given QML \a engine, \a parent and a window flags \a f.
197   The default value of \a parent is 0, default window flags \a f is Qt::Window.
198
199   Note: In this case, the QQuickView does not own the given \a engine object;
200   it is the caller's responsibility to destroy the engine. If the \a engine is deleted
201   before the view \a status() will return \a QQuickView::Error.
202
203   \sa Status, status(), errors(), Qt::WindowFlags
204 */
205 QQuickView::QQuickView(QQmlEngine* engine, QWindow *parent, Qt::WindowFlags f)
206     : QQuickCanvas(*(new QQuickViewPrivate), parent)
207 {
208     Q_ASSERT(engine);
209     setWindowFlags(f);
210     d_func()->init(engine);
211 }
212
213 /*!
214   Destroys the QQuickView.
215 */
216 QQuickView::~QQuickView()
217 {
218     // Ensure that the component is destroyed before the engine; the engine may
219     // be a child of the QQuickViewPrivate, and will be destroyed by its dtor
220     Q_D(QQuickView);
221     delete d->root;
222     d->root = 0;
223 }
224
225 /*!
226   \property QQuickView::source
227   \brief The URL of the source of the QML component.
228
229   Ensure that the URL provided is full and correct, in particular, use
230   \l QUrl::fromLocalFile() when loading a file from the local filesystem.
231
232   Note that setting a source URL will result in the QML component being
233   instantiated, even if the URL is unchanged from the current value.
234 */
235
236 /*!
237     Sets the source to the \a url, loads the QML component and instantiates it.
238
239     Ensure that the URL provided is full and correct, in particular, use
240     \l QUrl::fromLocalFile() when loading a file from the local filesystem.
241
242     Calling this method multiple times with the same url will result
243     in the QML component being reinstantiated.
244  */
245 void QQuickView::setSource(const QUrl& url)
246 {
247     Q_D(QQuickView);
248     d->source = url;
249     d->execute();
250 }
251
252 /*!
253   Returns the source URL, if set.
254
255   \sa setSource()
256  */
257 QUrl QQuickView::source() const
258 {
259     Q_D(const QQuickView);
260     return d->source;
261 }
262
263 /*!
264   Returns a pointer to the QQmlEngine used for instantiating
265   QML Components.
266  */
267 QQmlEngine* QQuickView::engine() const
268 {
269     Q_D(const QQuickView);
270     return d->engine ? const_cast<QQmlEngine *>(d->engine.data()) : 0;
271 }
272
273 /*!
274   This function returns the root of the context hierarchy.  Each QML
275   component is instantiated in a QQmlContext.  QQmlContext's are
276   essential for passing data to QML components.  In QML, contexts are
277   arranged hierarchically and this hierarchy is managed by the
278   QQmlEngine.
279  */
280 QQmlContext* QQuickView::rootContext() const
281 {
282     Q_D(const QQuickView);
283     return d->engine ? d->engine.data()->rootContext() : 0;
284 }
285
286 /*!
287     \enum QQuickView::Status
288     Specifies the loading status of the QQuickView.
289
290     \value Null This QQuickView has no source set.
291     \value Ready This QQuickView has loaded and created the QML component.
292     \value Loading This QQuickView is loading network data.
293     \value Error One or more errors has occurred. Call errors() to retrieve a list
294            of errors.
295 */
296
297 /*! \enum QQuickView::ResizeMode
298
299   This enum specifies how to resize the view.
300
301   \value SizeViewToRootObject The view resizes with the root item in the QML.
302   \value SizeRootObjectToView The view will automatically resize the root item to the size of the view.
303 */
304
305 /*!
306     \property QQuickView::status
307     The component's current \l{QQuickView::Status} {status}.
308 */
309
310 QQuickView::Status QQuickView::status() const
311 {
312     Q_D(const QQuickView);
313     if (!d->engine)
314         return QQuickView::Error;
315
316     if (!d->component)
317         return QQuickView::Null;
318
319     return QQuickView::Status(d->component->status());
320 }
321
322 /*!
323     Return the list of errors that occurred during the last compile or create
324     operation.  When the status is not Error, an empty list is returned.
325 */
326 QList<QQmlError> QQuickView::errors() const
327 {
328     Q_D(const QQuickView);
329     QList<QQmlError> errs;
330
331     if (d->component)
332         errs = d->component->errors();
333
334     if (!d->engine) {
335         QQmlError error;
336         error.setDescription(QLatin1String("QQuickView: invalid qml engine."));
337         errs << error;
338     }
339
340     return errs;
341 }
342
343 /*!
344     \property QQuickView::resizeMode
345     \brief whether the view should resize the canvas contents
346
347     If this property is set to SizeViewToRootObject (the default), the view
348     resizes to the size of the root item in the QML.
349
350     If this property is set to SizeRootObjectToView, the view will
351     automatically resize the root item to the size of the view.
352
353     Regardless of this property, the sizeHint of the view
354     is the initial size of the root item. Note though that
355     since QML may load dynamically, that size may change.
356
357     \sa initialSize
358 */
359
360 void QQuickView::setResizeMode(ResizeMode mode)
361 {
362     Q_D(QQuickView);
363     if (d->resizeMode == mode)
364         return;
365
366     if (d->root) {
367         if (d->resizeMode == SizeViewToRootObject) {
368             QQuickItemPrivate *p = QQuickItemPrivate::get(d->root);
369             p->removeItemChangeListener(d, QQuickItemPrivate::Geometry);
370         }
371     }
372
373     d->resizeMode = mode;
374     if (d->root) {
375         d->initResize();
376     }
377 }
378
379 void QQuickViewPrivate::initResize()
380 {
381     if (root) {
382         if (resizeMode == QQuickView::SizeViewToRootObject) {
383             QQuickItemPrivate *p = QQuickItemPrivate::get(root);
384             p->addItemChangeListener(this, QQuickItemPrivate::Geometry);
385         }
386     }
387     updateSize();
388 }
389
390 void QQuickViewPrivate::updateSize()
391 {
392     Q_Q(QQuickView);
393     if (!root)
394         return;
395
396     if (resizeMode == QQuickView::SizeViewToRootObject) {
397         QSize newSize = QSize(root->width(), root->height());
398         if (newSize.isValid() && newSize != q->size()) {
399             q->resize(newSize);
400         }
401     } else if (resizeMode == QQuickView::SizeRootObjectToView) {
402         if (!qFuzzyCompare(q->width(), root->width()))
403             root->setWidth(q->width());
404         if (!qFuzzyCompare(q->height(), root->height()))
405             root->setHeight(q->height());
406     }
407 }
408
409 QSize QQuickViewPrivate::rootObjectSize() const
410 {
411     QSize rootObjectSize(0,0);
412     int widthCandidate = -1;
413     int heightCandidate = -1;
414     if (root) {
415         widthCandidate = root->width();
416         heightCandidate = root->height();
417     }
418     if (widthCandidate > 0) {
419         rootObjectSize.setWidth(widthCandidate);
420     }
421     if (heightCandidate > 0) {
422         rootObjectSize.setHeight(heightCandidate);
423     }
424     return rootObjectSize;
425 }
426
427 QQuickView::ResizeMode QQuickView::resizeMode() const
428 {
429     Q_D(const QQuickView);
430     return d->resizeMode;
431 }
432
433 /*!
434   \internal
435  */
436 void QQuickView::continueExecute()
437 {
438     Q_D(QQuickView);
439     disconnect(d->component, SIGNAL(statusChanged(QQmlComponent::Status)), this, SLOT(continueExecute()));
440
441     if (d->component->isError()) {
442         QList<QQmlError> errorList = d->component->errors();
443         foreach (const QQmlError &error, errorList) {
444             QMessageLogger(error.url().toString().toLatin1().constData(), error.line(), 0).warning()
445                     << error;
446         }
447         emit statusChanged(status());
448         return;
449     }
450
451     QObject *obj = d->component->create();
452
453     if (d->component->isError()) {
454         QList<QQmlError> errorList = d->component->errors();
455         foreach (const QQmlError &error, errorList) {
456             QMessageLogger(error.url().toString().toLatin1().constData(), error.line(), 0).warning()
457                     << error;
458         }
459         emit statusChanged(status());
460         return;
461     }
462
463     d->setRootObject(obj);
464     emit statusChanged(status());
465 }
466
467
468 /*!
469   \internal
470 */
471 void QQuickViewPrivate::setRootObject(QObject *obj)
472 {
473     Q_Q(QQuickView);
474     if (root == obj)
475         return;
476     if (QQuickItem *sgItem = qobject_cast<QQuickItem *>(obj)) {
477         root = sgItem;
478         sgItem->setParentItem(q->QQuickCanvas::rootItem());
479     } else {
480         qWarning() << "QQuickView only supports loading of root objects that derive from QQuickItem." << endl
481                    << endl
482                    << "If your example is using QML 2, (such as qmlscene) and the .qml file you" << endl
483                    << "loaded has 'import QtQuick 1.0' or 'import Qt 4.7', this error will occur." << endl
484                    << endl
485                    << "To load files with 'import QtQuick 1.0' or 'import Qt 4.7', use the" << endl
486                    << "QQuickView class in the qtquick1 module." << endl;
487         delete obj;
488         root = 0;
489     }
490     if (root) {
491         initialSize = rootObjectSize();
492         if ((resizeMode == QQuickView::SizeViewToRootObject || !q->width() || !q->height())
493                 && initialSize != q->size()) {
494             q->resize(initialSize);
495         }
496         initResize();
497     }
498 }
499
500 /*!
501   \internal
502   If the \l {QTimerEvent} {timer event} \a e is this
503   view's resize timer, sceneResized() is emitted.
504  */
505 void QQuickView::timerEvent(QTimerEvent* e)
506 {
507     Q_D(QQuickView);
508     if (!e || e->timerId() == d->resizetimer.timerId()) {
509         d->updateSize();
510         d->resizetimer.stop();
511     }
512 }
513
514 /*!
515     \internal
516     Preferred size follows the root object geometry.
517 */
518 QSize QQuickView::sizeHint() const
519 {
520     Q_D(const QQuickView);
521     QSize rootObjectSize = d->rootObjectSize();
522     if (rootObjectSize.isEmpty()) {
523         return size();
524     } else {
525         return rootObjectSize;
526     }
527 }
528
529 /*!
530   Returns the initial size of the root object.
531
532   If \l resizeMode is QQuickItem::SizeRootObjectToView the root object will be
533   resized to the size of the view.  initialSize contains the size of the
534   root object before it was resized.
535 */
536 QSize QQuickView::initialSize() const
537 {
538     Q_D(const QQuickView);
539     return d->initialSize;
540 }
541
542 /*!
543   Returns the view's root \l {QQuickItem} {item}.
544  */
545 QQuickItem *QQuickView::rootObject() const
546 {
547     Q_D(const QQuickView);
548     return d->root;
549 }
550
551 /*!
552   \internal
553   This function handles the \l {QResizeEvent} {resize event}
554   \a e.
555  */
556 void QQuickView::resizeEvent(QResizeEvent *e)
557 {
558     Q_D(QQuickView);
559     if (d->resizeMode == SizeRootObjectToView)
560         d->updateSize();
561
562     QQuickCanvas::resizeEvent(e);
563 }
564
565 /*! \reimp */
566 void QQuickView::keyPressEvent(QKeyEvent *e)
567 {
568     QQmlProfilerService::addEvent(QQmlProfilerService::Key);
569
570     QQuickCanvas::keyPressEvent(e);
571 }
572
573 /*! \reimp */
574 void QQuickView::keyReleaseEvent(QKeyEvent *e)
575 {
576     QQmlProfilerService::addEvent(QQmlProfilerService::Key);
577
578     QQuickCanvas::keyReleaseEvent(e);
579 }
580
581 /*! \reimp */
582 void QQuickView::mouseMoveEvent(QMouseEvent *e)
583 {
584     QQmlProfilerService::addEvent(QQmlProfilerService::Mouse);
585
586     QQuickCanvas::mouseMoveEvent(e);
587 }
588
589 /*! \reimp */
590 void QQuickView::mousePressEvent(QMouseEvent *e)
591 {
592     QQmlProfilerService::addEvent(QQmlProfilerService::Mouse);
593
594     QQuickCanvas::mousePressEvent(e);
595 }
596
597 /*! \reimp */
598 void QQuickView::mouseReleaseEvent(QMouseEvent *e)
599 {
600     QQmlProfilerService::addEvent(QQmlProfilerService::Mouse);
601
602     QQuickCanvas::mouseReleaseEvent(e);
603 }
604
605
606 QT_END_NAMESPACE