7ffafeb6b919dd65c53a4a2cea3b6d4bdb8fb9a1
[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
52 #include <QtQml/qqmlengine.h>
53 #include <private/qqmlengine_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 (QQmlDebugService::isDebuggingEnabled())
66         QQmlInspectorService::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 (QQmlDebugService::isDebuggingEnabled())
77         QQmlInspectorService::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 QQmlComponent(&engine, source, q);
95         if (!component->isLoading()) {
96             q->continueExecute();
97         } else {
98             QObject::connect(component, SIGNAL(statusChanged(QQmlComponent::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 QQmlComponent 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 QQmlEngine used for instantiating
220   QML Components.
221  */
222 QQmlEngine* QQuickView::engine() const
223 {
224     Q_D(const QQuickView);
225     return const_cast<QQmlEngine *>(&d->engine);
226 }
227
228 /*!
229   This function returns the root of the context hierarchy.  Each QML
230   component is instantiated in a QQmlContext.  QQmlContext'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   QQmlEngine.
234  */
235 QQmlContext* 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<QQmlError> QQuickView::errors() const
279 {
280     Q_D(const QQuickView);
281     if (d->component)
282         return d->component->errors();
283     return QList<QQmlError>();
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(QQmlComponent::Status)), this, SLOT(continueExecute()));
381
382     if (d->component->isError()) {
383         QList<QQmlError> errorList = d->component->errors();
384         foreach (const QQmlError &error, errorList) {
385             QMessageLogger(error.url().toString().toLatin1().constData(), error.line(), 0).warning()
386                     << error;
387         }
388         emit statusChanged(status());
389         return;
390     }
391
392     QObject *obj = d->component->create();
393
394     if (d->component->isError()) {
395         QList<QQmlError> errorList = d->component->errors();
396         foreach (const QQmlError &error, errorList) {
397             QMessageLogger(error.url().toString().toLatin1().constData(), error.line(), 0).warning()
398                     << error;
399         }
400         emit statusChanged(status());
401         return;
402     }
403
404     d->setRootObject(obj);
405     emit statusChanged(status());
406 }
407
408
409 /*!
410   \internal
411 */
412 void QQuickViewPrivate::setRootObject(QObject *obj)
413 {
414     Q_Q(QQuickView);
415     if (root == obj)
416         return;
417     if (QQuickItem *sgItem = qobject_cast<QQuickItem *>(obj)) {
418         root = sgItem;
419         sgItem->setParentItem(q->QQuickCanvas::rootItem());
420     } else {
421         qWarning() << "QQuickView only supports loading of root objects that derive from QQuickItem." << endl
422                    << endl
423                    << "If your example is using QML 2, (such as qmlscene) and the .qml file you" << endl
424                    << "loaded has 'import QtQuick 1.0' or 'import Qt 4.7', this error will occur." << endl
425                    << endl
426                    << "To load files with 'import QtQuick 1.0' or 'import Qt 4.7', use the" << endl
427                    << "QQuickView class in the qtquick1 module." << endl;
428         delete obj;
429         root = 0;
430     }
431     if (root) {
432         initialSize = rootObjectSize();
433         if ((resizeMode == QQuickView::SizeViewToRootObject || !q->width() || !q->height())
434                 && initialSize != q->size()) {
435             q->resize(initialSize);
436         }
437         initResize();
438     }
439 }
440
441 /*!
442   \internal
443   If the \l {QTimerEvent} {timer event} \a e is this
444   view's resize timer, sceneResized() is emitted.
445  */
446 void QQuickView::timerEvent(QTimerEvent* e)
447 {
448     Q_D(QQuickView);
449     if (!e || e->timerId() == d->resizetimer.timerId()) {
450         d->updateSize();
451         d->resizetimer.stop();
452     }
453 }
454
455 /*!
456     \internal
457     Preferred size follows the root object geometry.
458 */
459 QSize QQuickView::sizeHint() const
460 {
461     Q_D(const QQuickView);
462     QSize rootObjectSize = d->rootObjectSize();
463     if (rootObjectSize.isEmpty()) {
464         return size();
465     } else {
466         return rootObjectSize;
467     }
468 }
469
470 /*!
471   Returns the initial size of the root object
472 */
473 QSize QQuickView::initialSize() const
474 {
475     Q_D(const QQuickView);
476     return d->initialSize;
477 }
478
479 /*!
480   Returns the view's root \l {QQuickItem} {item}.
481  */
482 QQuickItem *QQuickView::rootObject() const
483 {
484     Q_D(const QQuickView);
485     return d->root;
486 }
487
488 /*!
489   \internal
490   This function handles the \l {QResizeEvent} {resize event}
491   \a e.
492  */
493 void QQuickView::resizeEvent(QResizeEvent *e)
494 {
495     Q_D(QQuickView);
496     if (d->resizeMode == SizeRootObjectToView)
497         d->updateSize();
498
499     QQuickCanvas::resizeEvent(e);
500 }
501
502 /*! \reimp */
503 void QQuickView::keyPressEvent(QKeyEvent *e)
504 {
505     QQmlProfilerService::addEvent(QQmlProfilerService::Key);
506
507     QQuickCanvas::keyPressEvent(e);
508 }
509
510 /*! \reimp */
511 void QQuickView::keyReleaseEvent(QKeyEvent *e)
512 {
513     QQmlProfilerService::addEvent(QQmlProfilerService::Key);
514
515     QQuickCanvas::keyReleaseEvent(e);
516 }
517
518 /*! \reimp */
519 void QQuickView::mouseMoveEvent(QMouseEvent *e)
520 {
521     QQmlProfilerService::addEvent(QQmlProfilerService::Mouse);
522
523     QQuickCanvas::mouseMoveEvent(e);
524 }
525
526 /*! \reimp */
527 void QQuickView::mousePressEvent(QMouseEvent *e)
528 {
529     QQmlProfilerService::addEvent(QQmlProfilerService::Mouse);
530
531     QQuickCanvas::mousePressEvent(e);
532 }
533
534 /*! \reimp */
535 void QQuickView::mouseReleaseEvent(QMouseEvent *e)
536 {
537     QQmlProfilerService::addEvent(QQmlProfilerService::Mouse);
538
539     QQuickCanvas::mouseReleaseEvent(e);
540 }
541
542
543 QT_END_NAMESPACE