1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
42 #include "qquickview.h"
43 #include "qquickview_p.h"
45 #include "qquickcanvas_p.h"
46 #include "qquickitem_p.h"
47 #include "qquickitemchangelistener_p.h"
49 #include <private/qqmlprofilerservice_p.h>
50 #include <private/qqmlinspectorservice_p.h>
51 #include <private/qqmlmemoryprofiler_p.h>
53 #include <QtQml/qqmlengine.h>
54 #include <private/qqmlengine_p.h>
55 #include <QtCore/qbasictimer.h>
59 void QQuickViewPrivate::init(QQmlEngine* e)
66 engine = new QQmlEngine(q);
68 if (!engine.data()->incubationController())
69 engine.data()->setIncubationController(q->incubationController());
71 if (QQmlDebugService::isDebuggingEnabled())
72 QQmlInspectorService::instance()->addView(q);
75 QQuickViewPrivate::QQuickViewPrivate()
76 : root(0), component(0), resizeMode(QQuickView::SizeViewToRootObject), initialSize(0,0)
80 QQuickViewPrivate::~QQuickViewPrivate()
82 if (QQmlDebugService::isDebuggingEnabled())
83 QQmlInspectorService::instance()->removeView(q_func());
86 void QQuickViewPrivate::execute()
90 qWarning() << "QQuickView: invalid qml engine.";
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();
108 QObject::connect(component, SIGNAL(statusChanged(QQmlComponent::Status)),
109 q, SLOT(continueExecute()));
114 void QQuickViewPrivate::itemGeometryChanged(QQuickItem *resizeItem, const QRectF &newGeometry, const QRectF &oldGeometry)
117 if (resizeItem == root && resizeMode == QQuickView::SizeViewToRootObject) {
118 // wait for both width and height to be changed
119 resizetimer.start(0,q);
121 QQuickItemChangeListener::itemGeometryChanged(resizeItem, newGeometry, oldGeometry);
127 \brief The QQuickView class provides a window for displaying a Qt Quick user interface.
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.
138 QQuickView *view = new QQuickView;
139 view->setSource(QUrl::fromLocalFile("myqmlfile.qml"));
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().
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.
152 \sa {Exposing C++ Data to QML}
156 /*! \fn void QQuickView::sceneResized(QSize size)
157 This signal is emitted when the view is resized to \a size.
160 /*! \fn void QQuickView::statusChanged(QQuickView::Status status)
161 This signal is emitted when the component's current \a status changes.
164 /*! \fn void QQuickView::initialSizeChanged(QSize size)
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.
174 QQuickView::QQuickView(QWindow *parent, Qt::WindowFlags f)
175 : QQuickCanvas(*(new QQuickViewPrivate), parent)
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.
187 QQuickView::QQuickView(const QUrl &source, QWindow *parent, Qt::WindowFlags f)
188 : QQuickCanvas(*(new QQuickViewPrivate), parent)
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.
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.
203 \sa Status, status(), errors(), Qt::WindowFlags
205 QQuickView::QQuickView(QQmlEngine* engine, QWindow *parent, Qt::WindowFlags f)
206 : QQuickCanvas(*(new QQuickViewPrivate), parent)
210 d_func()->init(engine);
214 Destroys the QQuickView.
216 QQuickView::~QQuickView()
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
226 \property QQuickView::source
227 \brief The URL of the source of the QML component.
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.
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.
237 Sets the source to the \a url, loads the QML component and instantiates it.
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.
242 Calling this method multiple times with the same url will result
243 in the QML component being reinstantiated.
245 void QQuickView::setSource(const QUrl& url)
253 Returns the source URL, if set.
257 QUrl QQuickView::source() const
259 Q_D(const QQuickView);
264 Returns a pointer to the QQmlEngine used for instantiating
267 QQmlEngine* QQuickView::engine() const
269 Q_D(const QQuickView);
270 return d->engine ? const_cast<QQmlEngine *>(d->engine.data()) : 0;
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
280 QQmlContext* QQuickView::rootContext() const
282 Q_D(const QQuickView);
283 return d->engine ? d->engine.data()->rootContext() : 0;
287 \enum QQuickView::Status
288 Specifies the loading status of the QQuickView.
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
297 /*! \enum QQuickView::ResizeMode
299 This enum specifies how to resize the view.
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.
306 \property QQuickView::status
307 The component's current \l{QQuickView::Status} {status}.
310 QQuickView::Status QQuickView::status() const
312 Q_D(const QQuickView);
314 return QQuickView::Error;
317 return QQuickView::Null;
319 return QQuickView::Status(d->component->status());
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.
326 QList<QQmlError> QQuickView::errors() const
328 Q_D(const QQuickView);
329 QList<QQmlError> errs;
332 errs = d->component->errors();
336 error.setDescription(QLatin1String("QQuickView: invalid qml engine."));
344 \property QQuickView::resizeMode
345 \brief whether the view should resize the canvas contents
347 If this property is set to SizeViewToRootObject (the default), the view
348 resizes to the size of the root item in the QML.
350 If this property is set to SizeRootObjectToView, the view will
351 automatically resize the root item to the size of the view.
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.
360 void QQuickView::setResizeMode(ResizeMode mode)
363 if (d->resizeMode == mode)
367 if (d->resizeMode == SizeViewToRootObject) {
368 QQuickItemPrivate *p = QQuickItemPrivate::get(d->root);
369 p->removeItemChangeListener(d, QQuickItemPrivate::Geometry);
373 d->resizeMode = mode;
379 void QQuickViewPrivate::initResize()
382 if (resizeMode == QQuickView::SizeViewToRootObject) {
383 QQuickItemPrivate *p = QQuickItemPrivate::get(root);
384 p->addItemChangeListener(this, QQuickItemPrivate::Geometry);
390 void QQuickViewPrivate::updateSize()
396 if (resizeMode == QQuickView::SizeViewToRootObject) {
397 QSize newSize = QSize(root->width(), root->height());
398 if (newSize.isValid() && newSize != q->size()) {
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());
409 QSize QQuickViewPrivate::rootObjectSize() const
411 QSize rootObjectSize(0,0);
412 int widthCandidate = -1;
413 int heightCandidate = -1;
415 widthCandidate = root->width();
416 heightCandidate = root->height();
418 if (widthCandidate > 0) {
419 rootObjectSize.setWidth(widthCandidate);
421 if (heightCandidate > 0) {
422 rootObjectSize.setHeight(heightCandidate);
424 return rootObjectSize;
427 QQuickView::ResizeMode QQuickView::resizeMode() const
429 Q_D(const QQuickView);
430 return d->resizeMode;
436 void QQuickView::continueExecute()
439 disconnect(d->component, SIGNAL(statusChanged(QQmlComponent::Status)), this, SLOT(continueExecute()));
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()
447 emit statusChanged(status());
451 QObject *obj = d->component->create();
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()
459 emit statusChanged(status());
463 d->setRootObject(obj);
464 emit statusChanged(status());
471 void QQuickViewPrivate::setRootObject(QObject *obj)
476 if (QQuickItem *sgItem = qobject_cast<QQuickItem *>(obj)) {
478 sgItem->setParentItem(q->QQuickCanvas::rootItem());
480 qWarning() << "QQuickView only supports loading of root objects that derive from QQuickItem." << 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
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;
491 initialSize = rootObjectSize();
492 if ((resizeMode == QQuickView::SizeViewToRootObject || !q->width() || !q->height())
493 && initialSize != q->size()) {
494 q->resize(initialSize);
502 If the \l {QTimerEvent} {timer event} \a e is this
503 view's resize timer, sceneResized() is emitted.
505 void QQuickView::timerEvent(QTimerEvent* e)
508 if (!e || e->timerId() == d->resizetimer.timerId()) {
510 d->resizetimer.stop();
516 Preferred size follows the root object geometry.
518 QSize QQuickView::sizeHint() const
520 Q_D(const QQuickView);
521 QSize rootObjectSize = d->rootObjectSize();
522 if (rootObjectSize.isEmpty()) {
525 return rootObjectSize;
530 Returns the initial size of the root object.
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.
536 QSize QQuickView::initialSize() const
538 Q_D(const QQuickView);
539 return d->initialSize;
543 Returns the view's root \l {QQuickItem} {item}.
545 QQuickItem *QQuickView::rootObject() const
547 Q_D(const QQuickView);
553 This function handles the \l {QResizeEvent} {resize event}
556 void QQuickView::resizeEvent(QResizeEvent *e)
559 if (d->resizeMode == SizeRootObjectToView)
562 QQuickCanvas::resizeEvent(e);
566 void QQuickView::keyPressEvent(QKeyEvent *e)
568 QQmlProfilerService::addEvent(QQmlProfilerService::Key);
570 QQuickCanvas::keyPressEvent(e);
574 void QQuickView::keyReleaseEvent(QKeyEvent *e)
576 QQmlProfilerService::addEvent(QQmlProfilerService::Key);
578 QQuickCanvas::keyReleaseEvent(e);
582 void QQuickView::mouseMoveEvent(QMouseEvent *e)
584 QQmlProfilerService::addEvent(QQmlProfilerService::Mouse);
586 QQuickCanvas::mouseMoveEvent(e);
590 void QQuickView::mousePressEvent(QMouseEvent *e)
592 QQmlProfilerService::addEvent(QQmlProfilerService::Mouse);
594 QQuickCanvas::mousePressEvent(e);
598 void QQuickView::mouseReleaseEvent(QMouseEvent *e)
600 QQmlProfilerService::addEvent(QQmlProfilerService::Mouse);
602 QQuickCanvas::mouseReleaseEvent(e);