Allow Loader to load non-Item types.
Loader has a more convenient API for loading/unloading components than the dynamic object creation APIs. Remove the Item-only restriction. Change-Id: I6f9ecc8514ff1e814f7e56a3386814ba211b7e4f Reviewed-by: Andrew den Exter <andrew.den-exter@nokia.com>
This commit is contained in:
parent
fb41baa0e8
commit
e8206bf6ab
|
@ -56,7 +56,7 @@ static const QQuickItemPrivate::ChangeTypes watchedChanges
|
||||||
= QQuickItemPrivate::Geometry | QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight;
|
= QQuickItemPrivate::Geometry | QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight;
|
||||||
|
|
||||||
QQuickLoaderPrivate::QQuickLoaderPrivate()
|
QQuickLoaderPrivate::QQuickLoaderPrivate()
|
||||||
: item(0), component(0), itemContext(0), incubator(0), updatingSize(false),
|
: item(0), object(0), component(0), itemContext(0), incubator(0), updatingSize(false),
|
||||||
active(true), loadingFromSource(false), asynchronous(false)
|
active(true), loadingFromSource(false), asynchronous(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -118,13 +118,18 @@ void QQuickLoaderPrivate::clear()
|
||||||
// the Loader to load a different item.
|
// the Loader to load a different item.
|
||||||
item->setParentItem(0);
|
item->setParentItem(0);
|
||||||
item->setVisible(false);
|
item->setVisible(false);
|
||||||
item->deleteLater();
|
|
||||||
item = 0;
|
item = 0;
|
||||||
}
|
}
|
||||||
|
if (object) {
|
||||||
|
object->deleteLater();
|
||||||
|
object = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QQuickLoaderPrivate::initResize()
|
void QQuickLoaderPrivate::initResize()
|
||||||
{
|
{
|
||||||
|
if (!item)
|
||||||
|
return;
|
||||||
QQuickItemPrivate *p = QQuickItemPrivate::get(item);
|
QQuickItemPrivate *p = QQuickItemPrivate::get(item);
|
||||||
p->addItemChangeListener(this, watchedChanges);
|
p->addItemChangeListener(this, watchedChanges);
|
||||||
_q_updateSize();
|
_q_updateSize();
|
||||||
|
@ -158,10 +163,9 @@ qreal QQuickLoaderPrivate::getImplicitHeight() const
|
||||||
\ingroup qtquick-utility
|
\ingroup qtquick-utility
|
||||||
\inherits Item
|
\inherits Item
|
||||||
|
|
||||||
\brief Allows dynamical loading of an item-based subtree from a URL or Component
|
\brief Allows dynamic loading of a subtree from a URL or Component
|
||||||
|
|
||||||
Loader is used to dynamically load visual QML components. For loading non-visual
|
Loader is used to dynamically load QML components.
|
||||||
components, see \l {Dynamic Object Management in QML}.
|
|
||||||
|
|
||||||
Loader can load a
|
Loader can load a
|
||||||
QML file (using the \l source property) or a \l Component object (using
|
QML file (using the \l source property) or a \l Component object (using
|
||||||
|
@ -175,17 +179,18 @@ qreal QQuickLoaderPrivate::getImplicitHeight() const
|
||||||
|
|
||||||
\snippet qml/loader/simple.qml 0
|
\snippet qml/loader/simple.qml 0
|
||||||
|
|
||||||
The loaded item can be accessed using the \l item property.
|
The loaded object can be accessed using the \l item property.
|
||||||
|
|
||||||
If the \l source or \l sourceComponent changes, any previously instantiated
|
If the \l source or \l sourceComponent changes, any previously instantiated
|
||||||
items are destroyed. Setting \l source to an empty string or setting
|
items are destroyed. Setting \l source to an empty string or setting
|
||||||
\l sourceComponent to \c undefined destroys the currently loaded item,
|
\l sourceComponent to \c undefined destroys the currently loaded object,
|
||||||
freeing resources and leaving the Loader empty.
|
freeing resources and leaving the Loader empty.
|
||||||
|
|
||||||
\section2 Loader sizing behavior
|
\section2 Loader sizing behavior
|
||||||
|
|
||||||
Loader is like any other visual item and must be positioned and sized
|
If the source component is not an Item type, Loader does not
|
||||||
accordingly to become visible.
|
apply any special sizing rules. When used to load visual types,
|
||||||
|
Loader applies the following sizing rules:
|
||||||
|
|
||||||
\list
|
\list
|
||||||
\li If an explicit size is not specified for the Loader, the Loader
|
\li If an explicit size is not specified for the Loader, the Loader
|
||||||
|
@ -213,9 +218,9 @@ qreal QQuickLoaderPrivate::getImplicitHeight() const
|
||||||
\endtable
|
\endtable
|
||||||
|
|
||||||
|
|
||||||
\section2 Receiving signals from loaded items
|
\section2 Receiving signals from loaded objects
|
||||||
|
|
||||||
Any signals emitted from the loaded item can be received using the
|
Any signals emitted from the loaded object can be received using the
|
||||||
\l Connections element. For example, the following \c application.qml
|
\l Connections element. For example, the following \c application.qml
|
||||||
loads \c MyItem.qml, and is able to receive the \c message signal from
|
loads \c MyItem.qml, and is able to receive the \c message signal from
|
||||||
the loaded item through a \l Connections object:
|
the loaded item through a \l Connections object:
|
||||||
|
@ -260,6 +265,8 @@ qreal QQuickLoaderPrivate::getImplicitHeight() const
|
||||||
\c event.accepted to \c true so that the event is not propagated to the
|
\c event.accepted to \c true so that the event is not propagated to the
|
||||||
parent \l Rectangle.
|
parent \l Rectangle.
|
||||||
|
|
||||||
|
Since QtQuick 2.0 Loader can also load non-visual components.
|
||||||
|
|
||||||
\sa {dynamic-object-creation}{Dynamic Object Creation}
|
\sa {dynamic-object-creation}{Dynamic Object Creation}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -326,8 +333,11 @@ void QQuickLoader::setActive(bool newVal)
|
||||||
// the Loader to load a different item.
|
// the Loader to load a different item.
|
||||||
d->item->setParentItem(0);
|
d->item->setParentItem(0);
|
||||||
d->item->setVisible(false);
|
d->item->setVisible(false);
|
||||||
d->item->deleteLater();
|
|
||||||
d->item = 0;
|
d->item = 0;
|
||||||
|
}
|
||||||
|
if (d->object) {
|
||||||
|
d->object->deleteLater();
|
||||||
|
d->object = 0;
|
||||||
emit itemChanged();
|
emit itemChanged();
|
||||||
}
|
}
|
||||||
emit statusChanged();
|
emit statusChanged();
|
||||||
|
@ -341,10 +351,10 @@ void QQuickLoader::setActive(bool newVal)
|
||||||
\qmlproperty url QtQuick2::Loader::source
|
\qmlproperty url QtQuick2::Loader::source
|
||||||
This property holds the URL of the QML component to instantiate.
|
This property holds the URL of the QML component to instantiate.
|
||||||
|
|
||||||
Note the QML component must be an \l{Item}-based component. The loader
|
Since QtQuick 2.0 Loader is able to load any type of object; it
|
||||||
cannot load non-visual components.
|
is not restricted to Item types.
|
||||||
|
|
||||||
To unload the currently loaded item, set this property to an empty string,
|
To unload the currently loaded object, set this property to an empty string,
|
||||||
or set \l sourceComponent to \c undefined. Setting \c source to a
|
or set \l sourceComponent to \c undefined. Setting \c source to a
|
||||||
new URL will also cause the item created by the previous URL to be unloaded.
|
new URL will also cause the item created by the previous URL to be unloaded.
|
||||||
|
|
||||||
|
@ -413,9 +423,12 @@ void QQuickLoader::loadFromSource()
|
||||||
}
|
}
|
||||||
\endqml
|
\endqml
|
||||||
|
|
||||||
To unload the currently loaded item, set this property to an empty string
|
To unload the currently loaded object, set this property to an empty string
|
||||||
or \c undefined.
|
or \c undefined.
|
||||||
|
|
||||||
|
Since QtQuick 2.0 Loader is able to load any type of object; it
|
||||||
|
is not restricted to Item types.
|
||||||
|
|
||||||
\sa source, progress
|
\sa source, progress
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -597,9 +610,11 @@ void QQuickLoaderPrivate::setInitialState(QObject *obj)
|
||||||
item->setWidth(q->width());
|
item->setWidth(q->width());
|
||||||
if (heightValid && !QQuickItemPrivate::get(item)->heightValid)
|
if (heightValid && !QQuickItemPrivate::get(item)->heightValid)
|
||||||
item->setHeight(q->height());
|
item->setHeight(q->height());
|
||||||
QQml_setParent_noEvent(itemContext, obj);
|
|
||||||
QQml_setParent_noEvent(item, q);
|
|
||||||
item->setParentItem(q);
|
item->setParentItem(q);
|
||||||
|
}
|
||||||
|
if (obj) {
|
||||||
|
QQml_setParent_noEvent(itemContext, obj);
|
||||||
|
QQml_setParent_noEvent(obj, q);
|
||||||
itemContext = 0;
|
itemContext = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -623,18 +638,10 @@ void QQuickLoaderPrivate::incubatorStateChanged(QQmlIncubator::Status status)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (status == QQmlIncubator::Ready) {
|
if (status == QQmlIncubator::Ready) {
|
||||||
QObject *obj = incubator->object();
|
object = incubator->object();
|
||||||
item = qmlobject_cast<QQuickItem*>(obj);
|
item = qmlobject_cast<QQuickItem*>(object);
|
||||||
if (item) {
|
|
||||||
emit q->itemChanged();
|
emit q->itemChanged();
|
||||||
initResize();
|
initResize();
|
||||||
} else {
|
|
||||||
qmlInfo(q) << QQuickLoader::tr("Loader does not support loading non-visual elements.");
|
|
||||||
delete itemContext;
|
|
||||||
itemContext = 0;
|
|
||||||
delete obj;
|
|
||||||
emit q->itemChanged();
|
|
||||||
}
|
|
||||||
incubator->clear();
|
incubator->clear();
|
||||||
} else if (status == QQmlIncubator::Error) {
|
} else if (status == QQmlIncubator::Error) {
|
||||||
if (!incubator->errors().isEmpty())
|
if (!incubator->errors().isEmpty())
|
||||||
|
@ -757,7 +764,7 @@ QQuickLoader::Status QQuickLoader::status() const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (d->item)
|
if (d->object)
|
||||||
return Ready;
|
return Ready;
|
||||||
|
|
||||||
return d->source.isEmpty() ? Null : Error;
|
return d->source.isEmpty() ? Null : Error;
|
||||||
|
@ -797,7 +804,7 @@ qreal QQuickLoader::progress() const
|
||||||
{
|
{
|
||||||
Q_D(const QQuickLoader);
|
Q_D(const QQuickLoader);
|
||||||
|
|
||||||
if (d->item)
|
if (d->object)
|
||||||
return 1.0;
|
return 1.0;
|
||||||
|
|
||||||
if (d->component)
|
if (d->component)
|
||||||
|
@ -868,13 +875,15 @@ void QQuickLoaderPrivate::_q_updateSize(bool loaderGeometryChanged)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\qmlproperty Item QtQuick2::Loader::item
|
\qmlproperty object QtQuick2::Loader::item
|
||||||
This property holds the top-level item that is currently loaded.
|
This property holds the top-level object that is currently loaded.
|
||||||
|
|
||||||
|
Since QtQuick 2.0 Loader can load any object type.
|
||||||
*/
|
*/
|
||||||
QQuickItem *QQuickLoader::item() const
|
QObject *QQuickLoader::item() const
|
||||||
{
|
{
|
||||||
Q_D(const QQuickLoader);
|
Q_D(const QQuickLoader);
|
||||||
return d->item;
|
return d->object;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QQuickLoader::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
|
void QQuickLoader::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
|
||||||
|
|
|
@ -57,7 +57,7 @@ class Q_AUTOTEST_EXPORT QQuickLoader : public QQuickImplicitSizeItem
|
||||||
Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged)
|
Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged)
|
||||||
Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
|
Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
|
||||||
Q_PROPERTY(QQmlComponent *sourceComponent READ sourceComponent WRITE setSourceComponent RESET resetSourceComponent NOTIFY sourceComponentChanged)
|
Q_PROPERTY(QQmlComponent *sourceComponent READ sourceComponent WRITE setSourceComponent RESET resetSourceComponent NOTIFY sourceComponentChanged)
|
||||||
Q_PROPERTY(QQuickItem *item READ item NOTIFY itemChanged)
|
Q_PROPERTY(QObject *item READ item NOTIFY itemChanged)
|
||||||
Q_PROPERTY(Status status READ status NOTIFY statusChanged)
|
Q_PROPERTY(Status status READ status NOTIFY statusChanged)
|
||||||
Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged)
|
Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged)
|
||||||
Q_PROPERTY(bool asynchronous READ asynchronous WRITE setAsynchronous NOTIFY asynchronousChanged)
|
Q_PROPERTY(bool asynchronous READ asynchronous WRITE setAsynchronous NOTIFY asynchronousChanged)
|
||||||
|
@ -85,7 +85,7 @@ public:
|
||||||
bool asynchronous() const;
|
bool asynchronous() const;
|
||||||
void setAsynchronous(bool a);
|
void setAsynchronous(bool a);
|
||||||
|
|
||||||
QQuickItem *item() const;
|
QObject *item() const;
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void itemChanged();
|
void itemChanged();
|
||||||
|
|
|
@ -104,6 +104,7 @@ public:
|
||||||
|
|
||||||
QUrl source;
|
QUrl source;
|
||||||
QQuickItem *item;
|
QQuickItem *item;
|
||||||
|
QObject *object;
|
||||||
QQmlComponent *component;
|
QQmlComponent *component;
|
||||||
QQmlContext *itemContext;
|
QQmlContext *itemContext;
|
||||||
QQuickLoaderIncubator *incubator;
|
QQuickLoaderIncubator *incubator;
|
||||||
|
|
|
@ -783,12 +783,17 @@ void tst_QQuickLoader::deleteComponentCrash()
|
||||||
void tst_QQuickLoader::nonItem()
|
void tst_QQuickLoader::nonItem()
|
||||||
{
|
{
|
||||||
QQmlComponent component(&engine, testFileUrl("nonItem.qml"));
|
QQmlComponent component(&engine, testFileUrl("nonItem.qml"));
|
||||||
QString err = testFileUrl("nonItem.qml").toString() + ":3:1: QML Loader: Loader does not support loading non-visual elements.";
|
|
||||||
|
|
||||||
QTest::ignoreMessage(QtWarningMsg, err.toLatin1().constData());
|
|
||||||
QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create());
|
QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create());
|
||||||
QVERIFY(loader);
|
QVERIFY(loader);
|
||||||
QVERIFY(loader->item() == 0);
|
QVERIFY(loader->item());
|
||||||
|
|
||||||
|
QCOMPARE(loader, loader->item()->parent());
|
||||||
|
|
||||||
|
QPointer<QObject> item = loader->item();
|
||||||
|
loader->setActive(false);
|
||||||
|
QVERIFY(!loader->item());
|
||||||
|
QTRY_VERIFY(!item);
|
||||||
|
|
||||||
delete loader;
|
delete loader;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue