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 "qquickwindow_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 QQuickWindow 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 QQuickWindow.
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 {qtqml-cppintegration-exposecppattributes.html}{Exposing Attributes of C++ Types 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.
170 The default value of \a parent is 0.
173 QQuickView::QQuickView(QWindow *parent)
174 : QQuickWindow(*(new QQuickViewPrivate), parent)
180 Constructs a QQuickView with the given QML \a source and \a parent.
181 The default value of \a parent is 0.
184 QQuickView::QQuickView(const QUrl &source, QWindow *parent)
185 : QQuickWindow(*(new QQuickViewPrivate), parent)
192 Constructs a QQuickView with the given QML \a engine and \a parent.
194 Note: In this case, the QQuickView does not own the given \a engine object;
195 it is the caller's responsibility to destroy the engine. If the \a engine is deleted
196 before the view \a status() will return \a QQuickView::Error.
198 \sa Status, status(), errors()
200 QQuickView::QQuickView(QQmlEngine* engine, QWindow *parent)
201 : QQuickWindow(*(new QQuickViewPrivate), parent)
204 d_func()->init(engine);
208 Destroys the QQuickView.
210 QQuickView::~QQuickView()
212 // Ensure that the component is destroyed before the engine; the engine may
213 // be a child of the QQuickViewPrivate, and will be destroyed by its dtor
220 \property QQuickView::source
221 \brief The URL of the source of the QML component.
223 Ensure that the URL provided is full and correct, in particular, use
224 \l QUrl::fromLocalFile() when loading a file from the local filesystem.
226 Note that setting a source URL will result in the QML component being
227 instantiated, even if the URL is unchanged from the current value.
231 Sets the source to the \a url, loads the QML component and instantiates it.
233 Ensure that the URL provided is full and correct, in particular, use
234 \l QUrl::fromLocalFile() when loading a file from the local filesystem.
236 Calling this method multiple times with the same url will result
237 in the QML component being reinstantiated.
239 void QQuickView::setSource(const QUrl& url)
247 Returns the source URL, if set.
251 QUrl QQuickView::source() const
253 Q_D(const QQuickView);
258 Returns a pointer to the QQmlEngine used for instantiating
261 QQmlEngine* QQuickView::engine() const
263 Q_D(const QQuickView);
264 return d->engine ? const_cast<QQmlEngine *>(d->engine.data()) : 0;
268 This function returns the root of the context hierarchy. Each QML
269 component is instantiated in a QQmlContext. QQmlContext's are
270 essential for passing data to QML components. In QML, contexts are
271 arranged hierarchically and this hierarchy is managed by the
274 QQmlContext* QQuickView::rootContext() const
276 Q_D(const QQuickView);
277 return d->engine ? d->engine.data()->rootContext() : 0;
281 \enum QQuickView::Status
282 Specifies the loading status of the QQuickView.
284 \value Null This QQuickView has no source set.
285 \value Ready This QQuickView has loaded and created the QML component.
286 \value Loading This QQuickView is loading network data.
287 \value Error One or more errors has occurred. Call errors() to retrieve a list
291 /*! \enum QQuickView::ResizeMode
293 This enum specifies how to resize the view.
295 \value SizeViewToRootObject The view resizes with the root item in the QML.
296 \value SizeRootObjectToView The view will automatically resize the root item to the size of the view.
300 \property QQuickView::status
301 The component's current \l{QQuickView::Status} {status}.
304 QQuickView::Status QQuickView::status() const
306 Q_D(const QQuickView);
308 return QQuickView::Error;
311 return QQuickView::Null;
313 return QQuickView::Status(d->component->status());
317 Return the list of errors that occurred during the last compile or create
318 operation. When the status is not Error, an empty list is returned.
320 QList<QQmlError> QQuickView::errors() const
322 Q_D(const QQuickView);
323 QList<QQmlError> errs;
326 errs = d->component->errors();
330 error.setDescription(QLatin1String("QQuickView: invalid qml engine."));
338 \property QQuickView::resizeMode
339 \brief whether the view should resize the window contents
341 If this property is set to SizeViewToRootObject (the default), the view
342 resizes to the size of the root item in the QML.
344 If this property is set to SizeRootObjectToView, the view will
345 automatically resize the root item to the size of the view.
347 Regardless of this property, the sizeHint of the view
348 is the initial size of the root item. Note though that
349 since QML may load dynamically, that size may change.
354 void QQuickView::setResizeMode(ResizeMode mode)
357 if (d->resizeMode == mode)
361 if (d->resizeMode == SizeViewToRootObject) {
362 QQuickItemPrivate *p = QQuickItemPrivate::get(d->root);
363 p->removeItemChangeListener(d, QQuickItemPrivate::Geometry);
367 d->resizeMode = mode;
373 void QQuickViewPrivate::initResize()
376 if (resizeMode == QQuickView::SizeViewToRootObject) {
377 QQuickItemPrivate *p = QQuickItemPrivate::get(root);
378 p->addItemChangeListener(this, QQuickItemPrivate::Geometry);
384 void QQuickViewPrivate::updateSize()
390 if (resizeMode == QQuickView::SizeViewToRootObject) {
391 QSize newSize = QSize(root->width(), root->height());
392 if (newSize.isValid() && newSize != q->size()) {
395 } else if (resizeMode == QQuickView::SizeRootObjectToView) {
396 if (!qFuzzyCompare(q->width(), root->width()))
397 root->setWidth(q->width());
398 if (!qFuzzyCompare(q->height(), root->height()))
399 root->setHeight(q->height());
403 QSize QQuickViewPrivate::rootObjectSize() const
405 QSize rootObjectSize(0,0);
406 int widthCandidate = -1;
407 int heightCandidate = -1;
409 widthCandidate = root->width();
410 heightCandidate = root->height();
412 if (widthCandidate > 0) {
413 rootObjectSize.setWidth(widthCandidate);
415 if (heightCandidate > 0) {
416 rootObjectSize.setHeight(heightCandidate);
418 return rootObjectSize;
421 QQuickView::ResizeMode QQuickView::resizeMode() const
423 Q_D(const QQuickView);
424 return d->resizeMode;
430 void QQuickView::continueExecute()
433 disconnect(d->component, SIGNAL(statusChanged(QQmlComponent::Status)), this, SLOT(continueExecute()));
435 if (d->component->isError()) {
436 QList<QQmlError> errorList = d->component->errors();
437 foreach (const QQmlError &error, errorList) {
438 QMessageLogger(error.url().toString().toLatin1().constData(), error.line(), 0).warning()
441 emit statusChanged(status());
445 QObject *obj = d->component->create();
447 if (d->component->isError()) {
448 QList<QQmlError> errorList = d->component->errors();
449 foreach (const QQmlError &error, errorList) {
450 QMessageLogger(error.url().toString().toLatin1().constData(), error.line(), 0).warning()
453 emit statusChanged(status());
457 d->setRootObject(obj);
458 emit statusChanged(status());
465 void QQuickViewPrivate::setRootObject(QObject *obj)
470 if (QQuickItem *sgItem = qobject_cast<QQuickItem *>(obj)) {
472 sgItem->setParentItem(q->QQuickWindow::rootItem());
474 qWarning() << "QQuickView only supports loading of root objects that derive from QQuickItem." << endl
476 << "If your example is using QML 2, (such as qmlscene) and the .qml file you" << endl
477 << "loaded has 'import QtQuick 1.0' or 'import Qt 4.7', this error will occur." << endl
479 << "To load files with 'import QtQuick 1.0' or 'import Qt 4.7', use the" << endl
480 << "QQuickView class in the qtquick1 module." << endl;
485 initialSize = rootObjectSize();
486 if ((resizeMode == QQuickView::SizeViewToRootObject || q->width() <= 1 || q->height() <= 1) &&
487 initialSize != q->size()) {
488 q->resize(initialSize);
496 If the \l {QTimerEvent} {timer event} \a e is this
497 view's resize timer, sceneResized() is emitted.
499 void QQuickView::timerEvent(QTimerEvent* e)
502 if (!e || e->timerId() == d->resizetimer.timerId()) {
504 d->resizetimer.stop();
510 Preferred size follows the root object geometry.
512 QSize QQuickView::sizeHint() const
514 Q_D(const QQuickView);
515 QSize rootObjectSize = d->rootObjectSize();
516 if (rootObjectSize.isEmpty()) {
519 return rootObjectSize;
524 Returns the initial size of the root object.
526 If \l resizeMode is QQuickItem::SizeRootObjectToView the root object will be
527 resized to the size of the view. initialSize contains the size of the
528 root object before it was resized.
530 QSize QQuickView::initialSize() const
532 Q_D(const QQuickView);
533 return d->initialSize;
537 Returns the view's root \l {QQuickItem} {item}.
539 QQuickItem *QQuickView::rootObject() const
541 Q_D(const QQuickView);
547 This function handles the \l {QResizeEvent} {resize event}
550 void QQuickView::resizeEvent(QResizeEvent *e)
553 if (d->resizeMode == SizeRootObjectToView)
556 QQuickWindow::resizeEvent(e);
560 void QQuickView::keyPressEvent(QKeyEvent *e)
562 QQmlProfilerService::addEvent(QQmlProfilerService::Key);
564 QQuickWindow::keyPressEvent(e);
568 void QQuickView::keyReleaseEvent(QKeyEvent *e)
570 QQmlProfilerService::addEvent(QQmlProfilerService::Key);
572 QQuickWindow::keyReleaseEvent(e);
576 void QQuickView::mouseMoveEvent(QMouseEvent *e)
578 QQmlProfilerService::addEvent(QQmlProfilerService::Mouse);
580 QQuickWindow::mouseMoveEvent(e);
584 void QQuickView::mousePressEvent(QMouseEvent *e)
586 QQmlProfilerService::addEvent(QQmlProfilerService::Mouse);
588 QQuickWindow::mousePressEvent(e);
592 void QQuickView::mouseReleaseEvent(QMouseEvent *e)
594 QQmlProfilerService::addEvent(QQmlProfilerService::Mouse);
596 QQuickWindow::mouseReleaseEvent(e);