diff options
Diffstat (limited to 'src/declarative')
29 files changed, 1304 insertions, 283 deletions
diff --git a/src/declarative/graphicsitems/qdeclarativeflickable.cpp b/src/declarative/graphicsitems/qdeclarativeflickable.cpp index c0b664f..84b0ccf 100644 --- a/src/declarative/graphicsitems/qdeclarativeflickable.cpp +++ b/src/declarative/graphicsitems/qdeclarativeflickable.cpp @@ -372,11 +372,12 @@ void QDeclarativeFlickablePrivate::updateBeginningEnd() \inlineimage flickable.gif \endfloat - The following example shows a large + The following example shows a small view onto a large image in which the + user can drag or flick the image in order to view different parts of it. - \clearfloat \snippet doc/src/snippets/declarative/flickable.qml document + \clearfloat \section1 Limitations \note Due to an implementation detail, items placed inside a Flickable cannot anchor to it by @@ -1051,10 +1052,63 @@ void QDeclarativeFlickablePrivate::data_append(QDeclarativeListProperty<QObject> o->setParent(prop->object); } +static inline int children_count_helper(QGraphicsObject *object) +{ + QGraphicsItemPrivate *d = QGraphicsItemPrivate::get(object); + return d->children.count(); +} + +static inline QObject *children_at_helper(QGraphicsObject *object, int index) +{ + QGraphicsItemPrivate *d = QGraphicsItemPrivate::get(object); + if (index >= 0 && index < d->children.count()) + return d->children.at(index)->toGraphicsObject(); + else + return 0; +} + +static inline void children_clear_helper(QGraphicsObject *object) +{ + QGraphicsItemPrivate *d = QGraphicsItemPrivate::get(object); + int childCount = d->children.count(); + for (int index = 0 ;index < childCount; index++) + QGraphicsItemPrivate::get(d->children.at(0))->setParentItemHelper(0, /*newParentVariant=*/0, /*thisPointerVariant=*/0); +} + +int QDeclarativeFlickablePrivate::data_count(QDeclarativeListProperty<QObject> *prop) +{ + return QDeclarativeItemPrivate::resources_count(prop) + + children_count_helper(static_cast<QDeclarativeFlickablePrivate*>(prop->data)->contentItem); +} + +QObject *QDeclarativeFlickablePrivate::data_at(QDeclarativeListProperty<QObject> *prop, int i) +{ + int resourcesCount = QDeclarativeItemPrivate::resources_count(prop); + if (i < resourcesCount) + return QDeclarativeItemPrivate::resources_at(prop, i); + const int j = i - resourcesCount; + QGraphicsObject *contentObject = static_cast<QDeclarativeFlickablePrivate*>(prop->data)->contentItem; + if (j < children_count_helper(contentObject)) + return children_at_helper(contentObject, j); + return 0; +} + +void QDeclarativeFlickablePrivate::data_clear(QDeclarativeListProperty<QObject> *prop) +{ + QDeclarativeItemPrivate::resources_clear(prop); + QGraphicsObject *contentObject = + static_cast<QDeclarativeFlickablePrivate*>(prop->data)->contentItem; + children_clear_helper(contentObject); +} + QDeclarativeListProperty<QObject> QDeclarativeFlickable::flickableData() { Q_D(QDeclarativeFlickable); - return QDeclarativeListProperty<QObject>(this, (void *)d, QDeclarativeFlickablePrivate::data_append); + return QDeclarativeListProperty<QObject>(this, (void *)d, QDeclarativeFlickablePrivate::data_append, + QDeclarativeFlickablePrivate::data_count, + QDeclarativeFlickablePrivate::data_at, + QDeclarativeFlickablePrivate::data_clear + ); } QDeclarativeListProperty<QGraphicsObject> QDeclarativeFlickable::flickableChildren() diff --git a/src/declarative/graphicsitems/qdeclarativeflickable_p_p.h b/src/declarative/graphicsitems/qdeclarativeflickable_p_p.h index 2da034c..beee741 100644 --- a/src/declarative/graphicsitems/qdeclarativeflickable_p_p.h +++ b/src/declarative/graphicsitems/qdeclarativeflickable_p_p.h @@ -173,6 +173,9 @@ public: // flickableData property static void data_append(QDeclarativeListProperty<QObject> *, QObject *); + static int data_count(QDeclarativeListProperty<QObject> *); + static QObject *data_at(QDeclarativeListProperty<QObject> *, int); + static void data_clear(QDeclarativeListProperty<QObject> *); }; class QDeclarativeFlickableVisibleArea : public QObject diff --git a/src/declarative/graphicsitems/qdeclarativegridview.cpp b/src/declarative/graphicsitems/qdeclarativegridview.cpp index 6a99733..8d08c99 100644 --- a/src/declarative/graphicsitems/qdeclarativegridview.cpp +++ b/src/declarative/graphicsitems/qdeclarativegridview.cpp @@ -1070,27 +1070,41 @@ void QDeclarativeGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal m GridView are laid out horizontally or vertically. Grid views are inherently flickable as GridView inherits from \l Flickable. - For example, if there is a simple list model defined in a file \c ContactModel.qml like this: + \section1 Example Usage + + The following example shows the definition of a simple list model defined + in a file called \c ContactModel.qml: \snippet doc/src/snippets/declarative/gridview/ContactModel.qml 0 - Another component can display this model data in a GridView, like this: + \beginfloatright + \inlineimage gridview-simple.png + \endfloat + + This model can be referenced as \c ContactModel in other QML files. See \l{QML Modules} + for more information about creating reusable components like this. + + Another component can display this model data in a GridView, as in the following + example, which creates a \c ContactModel component for its model, and a \l Column element + (containing \l Image and \l Text elements) for its delegate. + \clearfloat \snippet doc/src/snippets/declarative/gridview/gridview.qml import \codeline \snippet doc/src/snippets/declarative/gridview/gridview.qml classdocs simple - \image gridview-simple.png - Here, the GridView creates a \c ContactModel component for its model, and a \l Column element - (containing \l Image and \ Text elements) for its delegate. The view will create a new delegate - for each item in the model. Notice the delegate is able to access the model's \c name and - \c portrait data directly. + \beginfloatright + \inlineimage gridview-highlight.png + \endfloat + + The view will create a new delegate for each item in the model. Note that the delegate + is able to access the model's \c name and \c portrait data directly. An improved grid view is shown below. The delegate is visually improved and is moved into a separate \c contactDelegate component. - + + \clearfloat \snippet doc/src/snippets/declarative/gridview/gridview.qml classdocs advanced - \image gridview-highlight.png The currently selected item is highlighted with a blue \l Rectangle using the \l highlight property, and \c focus is set to \c true to enable keyboard navigation for the grid view. @@ -1099,10 +1113,10 @@ void QDeclarativeGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal m Delegates are instantiated as needed and may be destroyed at any time. State should \e never be stored in a delegate. - \note Views do not enable \e clip automatically. If the view - is not clipped by another item or the screen, it will be necessary - to set \e {clip: true} in order to have the out of view items clipped - nicely. + \note Views do not set the \l{Item::}{clip} property automatically. + If the view is not clipped by another item or the screen, it will be necessary + to set this property to true in order to clip the items that are partially or + fully outside the view. \sa {declarative/modelviews/gridview}{GridView example} */ diff --git a/src/declarative/graphicsitems/qdeclarativeitem.cpp b/src/declarative/graphicsitems/qdeclarativeitem.cpp index bd2d52c..e9da4f7 100644 --- a/src/declarative/graphicsitems/qdeclarativeitem.cpp +++ b/src/declarative/graphicsitems/qdeclarativeitem.cpp @@ -44,6 +44,7 @@ #include "private/qdeclarativeevents_p_p.h" #include <private/qdeclarativeengine_p.h> +#include <private/qgraphicsitem_p.h> #include <qdeclarativeengine.h> #include <qdeclarativeopenmetaobject_p.h> @@ -1619,6 +1620,51 @@ void QDeclarativeItemPrivate::data_append(QDeclarativeListProperty<QObject> *pro } } +static inline int children_count_helper(QDeclarativeListProperty<QObject> *prop) +{ + QGraphicsItemPrivate *d = QGraphicsItemPrivate::get(static_cast<QGraphicsObject *>(prop->object)); + return d->children.count(); +} + +static inline QObject *children_at_helper(QDeclarativeListProperty<QObject> *prop, int index) +{ + QGraphicsItemPrivate *d = QGraphicsItemPrivate::get(static_cast<QGraphicsObject *>(prop->object)); + if (index >= 0 && index < d->children.count()) + return d->children.at(index)->toGraphicsObject(); + else + return 0; +} + +static inline void children_clear_helper(QDeclarativeListProperty<QObject> *prop) +{ + QGraphicsItemPrivate *d = QGraphicsItemPrivate::get(static_cast<QGraphicsObject *>(prop->object)); + int childCount = d->children.count(); + for (int index = 0 ;index < childCount; index++) + QGraphicsItemPrivate::get(d->children.at(0))->setParentItemHelper(0, /*newParentVariant=*/0, /*thisPointerVariant=*/0); +} + +int QDeclarativeItemPrivate::data_count(QDeclarativeListProperty<QObject> *prop) +{ + return resources_count(prop) + children_count_helper(prop); +} + +QObject *QDeclarativeItemPrivate::data_at(QDeclarativeListProperty<QObject> *prop, int i) +{ + int resourcesCount = resources_count(prop); + if (i < resourcesCount) + return resources_at(prop, i); + const int j = i - resourcesCount; + if (j < children_count_helper(prop)) + return children_at_helper(prop, j); + return 0; +} + +void QDeclarativeItemPrivate::data_clear(QDeclarativeListProperty<QObject> *prop) +{ + resources_clear(prop); + children_clear_helper(prop); +} + QObject *QDeclarativeItemPrivate::resources_at(QDeclarativeListProperty<QObject> *prop, int index) { const QObjectList children = prop->object->children(); @@ -1638,6 +1684,13 @@ int QDeclarativeItemPrivate::resources_count(QDeclarativeListProperty<QObject> * return prop->object->children().count(); } +void QDeclarativeItemPrivate::resources_clear(QDeclarativeListProperty<QObject> *prop) +{ + const QObjectList children = prop->object->children(); + for (int index = 0; index < children.count(); index++) + children.at(index)->setParent(0); +} + int QDeclarativeItemPrivate::transform_count(QDeclarativeListProperty<QGraphicsTransform> *list) { QGraphicsObject *object = qobject_cast<QGraphicsObject *>(list->object); @@ -1724,7 +1777,11 @@ void QDeclarativeItemPrivate::parentProperty(QObject *o, void *rv, QDeclarativeN QDeclarativeListProperty<QObject> QDeclarativeItemPrivate::data() { - return QDeclarativeListProperty<QObject>(q_func(), 0, QDeclarativeItemPrivate::data_append); + return QDeclarativeListProperty<QObject>(q_func(), 0, QDeclarativeItemPrivate::data_append, + QDeclarativeItemPrivate::data_count, + QDeclarativeItemPrivate::data_at, + QDeclarativeItemPrivate::data_clear + ); } /*! @@ -2413,7 +2470,9 @@ QDeclarativeListProperty<QObject> QDeclarativeItemPrivate::resources() { return QDeclarativeListProperty<QObject>(q_func(), 0, QDeclarativeItemPrivate::resources_append, QDeclarativeItemPrivate::resources_count, - QDeclarativeItemPrivate::resources_at); + QDeclarativeItemPrivate::resources_at, + QDeclarativeItemPrivate::resources_clear + ); } /*! diff --git a/src/declarative/graphicsitems/qdeclarativeitem_p.h b/src/declarative/graphicsitems/qdeclarativeitem_p.h index fffb4f7..f85fa27 100644 --- a/src/declarative/graphicsitems/qdeclarativeitem_p.h +++ b/src/declarative/graphicsitems/qdeclarativeitem_p.h @@ -176,11 +176,15 @@ public: // data property static void data_append(QDeclarativeListProperty<QObject> *, QObject *); + static int data_count(QDeclarativeListProperty<QObject> *); + static QObject *data_at(QDeclarativeListProperty<QObject> *, int); + static void data_clear(QDeclarativeListProperty<QObject> *); // resources property static QObject *resources_at(QDeclarativeListProperty<QObject> *, int); static void resources_append(QDeclarativeListProperty<QObject> *, QObject *); static int resources_count(QDeclarativeListProperty<QObject> *); + static void resources_clear(QDeclarativeListProperty<QObject> *); // transform property static int transform_count(QDeclarativeListProperty<QGraphicsTransform> *list); diff --git a/src/declarative/graphicsitems/qdeclarativelistview.cpp b/src/declarative/graphicsitems/qdeclarativelistview.cpp index ae504aa..c1e6aaa 100644 --- a/src/declarative/graphicsitems/qdeclarativelistview.cpp +++ b/src/declarative/graphicsitems/qdeclarativelistview.cpp @@ -1394,11 +1394,14 @@ void QDeclarativeListViewPrivate::flick(AxisData &data, qreal minExtent, qreal m QAbstractListModel. A ListView has a \l model, which defines the data to be displayed, and - a \l delegate, which defines how the data should be displayed. Items in a - ListView are laid out horizontally or vertically. List views are inherently flickable - as ListView inherits from \l Flickable. + a \l delegate, which defines how the data should be displayed. Items in a + ListView are laid out horizontally or vertically. List views are inherently + flickable because ListView inherits from \l Flickable. - For example, if there is a simple list model defined in a file \c ContactModel.qml like this: + \section1 Example Usage + + The following example shows the definition of a simple list model defined + in a file called \c ContactModel.qml: \snippet doc/src/snippets/declarative/listview/ContactModel.qml 0 @@ -1416,7 +1419,7 @@ void QDeclarativeListViewPrivate::flick(AxisData &data, qreal minExtent, qreal m An improved list view is shown below. The delegate is visually improved and is moved into a separate \c contactDelegate component. - + \snippet doc/src/snippets/declarative/listview/listview.qml classdocs advanced \image listview-highlight.png diff --git a/src/declarative/graphicsitems/qdeclarativeloader.cpp b/src/declarative/graphicsitems/qdeclarativeloader.cpp index 5d71625..1066c2b 100644 --- a/src/declarative/graphicsitems/qdeclarativeloader.cpp +++ b/src/declarative/graphicsitems/qdeclarativeloader.cpp @@ -212,8 +212,8 @@ QDeclarativeLoader::~QDeclarativeLoader() \qmlproperty url Loader::source This property holds the URL of the QML component to instantiate. - Note the QML component must be an \l Item-based component. Loader cannot - load non-visual components. + Note the QML component must be an \l{Item}-based component. The loader + cannot load non-visual components. To unload the currently loaded item, set this property to an empty string, or set \l sourceComponent to \c undefined. @@ -275,8 +275,8 @@ void QDeclarativeLoader::setSource(const QUrl &url) } \endqml - To unload the currently loaded item, set this property to an empty string, - or set \l sourceComponent to \c undefined. + To unload the currently loaded item, set this property to an empty string + or \c undefined. \sa source, progress */ diff --git a/src/declarative/graphicsitems/qdeclarativemousearea.cpp b/src/declarative/graphicsitems/qdeclarativemousearea.cpp index 4685e65..a0208ef 100644 --- a/src/declarative/graphicsitems/qdeclarativemousearea.cpp +++ b/src/declarative/graphicsitems/qdeclarativemousearea.cpp @@ -185,27 +185,57 @@ QDeclarativeMouseAreaPrivate::~QDeclarativeMouseAreaPrivate() \brief The MouseArea item enables simple mouse handling. \inherits Item - A MouseArea is typically used in conjunction with a visible item, - where the MouseArea effectively 'proxies' mouse handling for that - item. For example, we can put a MouseArea in a \l Rectangle that changes + A MouseArea is an invisible item that is typically used in conjunction with + a visible item in order to provide mouse handling for that item. + By effectively acting as a proxy, the logic for mouse handling can be + contained within a MouseArea item. + + For basic key handling, see the \l{Keys}{Keys attached property}. + + The \l enabled property is used to enable and disable mouse handling for + the proxied item. When disabled, the mouse area becomes transparent to + mouse events. + + The \l pressed read-only property indicates whether or not the user is + holding down a mouse button over the mouse area. This property is often + used in bindings between properties in a user interface. The containsMouse + read-only property indicates the presence of the mouse cursor over the + mouse area but, by default, only when a mouse button is held down; see below + for further details. + + Information about the mouse position and button clicks are provided via + signals for which event handler properties are defined. The most commonly + used involved handling mouse presses and clicks: onClicked, onDoubleClicked, + onPressed, onReleased and onPressAndHold. + + By default, MouseArea items only report mouse clicks and not changes to the + position of the mouse cursor. Setting the hoverEnabled property ensures that + handlers defined for onPositionChanged, onEntered and onExited are used and + that the containsMouse property is updated even when no mouse buttons are + pressed. + + \section1 Example Usage + + \beginfloatright + \inlineimage qml-mousearea-snippet.png + \endfloat + + The following example uses a MouseArea in a \l Rectangle that changes the \l Rectangle color to red when clicked: - \snippet doc/src/snippets/declarative/mousearea.qml import + \snippet doc/src/snippets/declarative/mousearea/mousearea.qml import \codeline - \snippet doc/src/snippets/declarative/mousearea.qml intro + \snippet doc/src/snippets/declarative/mousearea/mousearea.qml intro - Many MouseArea signals pass a \l {MouseEvent}{mouse} parameter that contains + \clearfloat + Many MouseArea signals pass a \l{MouseEvent}{mouse} parameter that contains additional information about the mouse event, such as the position, button, and any key modifiers. Here is an extension of the previous example that produces a different color when the area is right clicked: - \snippet doc/src/snippets/declarative/mousearea.qml intro-extended - - For basic key handling, see the \l {Keys}{Keys attached property}. - - MouseArea is an invisible item: it is never painted. + \snippet doc/src/snippets/declarative/mousearea/mousearea.qml intro-extended \sa MouseEvent, {declarative/touchinteraction/mousearea}{MouseArea example} */ @@ -312,11 +342,14 @@ QDeclarativeMouseAreaPrivate::~QDeclarativeMouseAreaPrivate() \qmlsignal MouseArea::onCanceled() This handler is called when mouse events have been canceled, either because an event was not accepted, or - because another element stole the mouse event handling. This signal is for advanced use: it is useful when - there is more than one MouseArea that is handling input, or when there is a MouseArea inside a \l Flickable. In the latter - case, if you execute some logic on the pressed signal and then start dragging, the \l Flickable will steal the mouse handling - from the MouseArea. In these cases, to reset the logic when the MouseArea has lost the mouse handling to the - \l Flickable, \c onCanceled should be used in addition to onReleased. + because another element stole the mouse event handling. + + This signal is for advanced use: it is useful when there is more than one MouseArea + that is handling input, or when there is a MouseArea inside a \l Flickable. In the latter + case, if you execute some logic on the pressed signal and then start dragging, the + \l Flickable will steal the mouse handling from the MouseArea. In these cases, to reset + the logic when the MouseArea has lost the mouse handling to the \l Flickable, + \c onCanceled should be used in addition to onReleased. */ QDeclarativeMouseArea::QDeclarativeMouseArea(QDeclarativeItem *parent) @@ -333,11 +366,13 @@ QDeclarativeMouseArea::~QDeclarativeMouseArea() /*! \qmlproperty real MouseArea::mouseX \qmlproperty real MouseArea::mouseY - These properties hold the coordinates of the mouse. + These properties hold the coordinates of the mouse cursor. If the hoverEnabled property is false then these properties will only be valid while a button is pressed, and will remain valid as long as the button is held - even if the mouse is moved outside the area. + down even if the mouse is moved outside the area. + + By default, this property is false. If hoverEnabled is true then these properties will be valid when: \list @@ -362,6 +397,8 @@ qreal QDeclarativeMouseArea::mouseY() const /*! \qmlproperty bool MouseArea::enabled This property holds whether the item accepts mouse events. + + By default, this property is true. */ bool QDeclarativeMouseArea::isEnabled() const { @@ -389,7 +426,8 @@ void QDeclarativeMouseArea::setEnabled(bool a) \endlist The code below displays "right" when the right mouse buttons is pressed: - \snippet doc/src/snippets/declarative/mousearea.qml mousebuttons + + \snippet doc/src/snippets/declarative/mousearea/mousearea.qml mousebuttons \sa acceptedButtons */ @@ -707,7 +745,8 @@ QVariant QDeclarativeMouseArea::itemChange(GraphicsItemChange change, pressed. Hover enables handling of all mouse events even when no mouse button is pressed. - This property affects the containsMouse property and the onEntered, onExited and onPositionChanged signals. + This property affects the containsMouse property and the onEntered, onExited and + onPositionChanged signals. */ bool QDeclarativeMouseArea::hoverEnabled() const { @@ -850,7 +889,7 @@ QDeclarativeDrag *QDeclarativeMouseArea::drag() The following example displays a \l Rectangle that can be dragged along the X-axis. The opacity of the rectangle is reduced when it is dragged to the right. - \snippet doc/src/snippets/declarative/mousearea.qml drag + \snippet doc/src/snippets/declarative/mousearea/mousearea.qml drag \note Items cannot be dragged if they are anchored for the requested \c drag.axis. For example, if \c anchors.left or \c anchors.right was set @@ -861,7 +900,7 @@ QDeclarativeDrag *QDeclarativeMouseArea::drag() If \c drag.filterChildren is set to true, a drag can override descendant MouseAreas. This enables a parent MouseArea to handle drags, for example, while descendants handle clicks: - \snippet doc/src/snippets/declarative/mouseareadragfilter.qml dragfilter + \snippet doc/src/snippets/declarative/mousearea/mouseareadragfilter.qml dragfilter */ diff --git a/src/declarative/graphicsitems/qdeclarativepathview.cpp b/src/declarative/graphicsitems/qdeclarativepathview.cpp index de3f9fa..dad547f 100644 --- a/src/declarative/graphicsitems/qdeclarativepathview.cpp +++ b/src/declarative/graphicsitems/qdeclarativepathview.cpp @@ -404,14 +404,14 @@ QDeclarativePathView::~QDeclarativePathView() be instantiated, but not considered to be currently on the path. Usually, these items would be set invisible, for example: - \code + \qml Component { Rectangle { visible: PathView.onPath ... } } - \endcode + \endqml It is attached to each instance of the delegate. */ diff --git a/src/declarative/graphicsitems/qdeclarativerectangle.cpp b/src/declarative/graphicsitems/qdeclarativerectangle.cpp index d027924..9831d5f 100644 --- a/src/declarative/graphicsitems/qdeclarativerectangle.cpp +++ b/src/declarative/graphicsitems/qdeclarativerectangle.cpp @@ -85,8 +85,8 @@ void QDeclarativePen::setWidth(int w) /*! \qmlclass GradientStop QDeclarativeGradientStop \ingroup qml-basic-visual-elements - \since 4.7 - \brief The GradientStop item defines the color at a position in a Gradient + \since 4.7 + \brief The GradientStop item defines the color at a position in a Gradient. \sa Gradient */ @@ -95,7 +95,12 @@ void QDeclarativePen::setWidth(int w) \qmlproperty real GradientStop::position \qmlproperty color GradientStop::color - Sets a \e color at a \e position in a gradient. + The position and color properties describe the color used at a given + position in a gradient, as represented by a gradient stop. + + The default position is 0.0; the default color is black. + + \sa Gradient */ void QDeclarativeGradientStop::updateGradient() @@ -107,20 +112,50 @@ void QDeclarativeGradientStop::updateGradient() /*! \qmlclass Gradient QDeclarativeGradient \ingroup qml-basic-visual-elements - \since 4.7 + \since 4.7 \brief The Gradient item defines a gradient fill. - A gradient is defined by two or more colors, which will be blended seemlessly. The - colors are specified at their position in the range 0.0 - 1.0 via - the GradientStop item. For example, the following code paints a - rectangle with a gradient starting with red, blending to yellow at 1/3 of the - size of the rectangle, and ending with Green: + A gradient is defined by two or more colors, which will be blended seamlessly. - \snippet doc/src/snippets/declarative/gradient.qml code + The colors are specified as a set of GradientStop child items, each of + which defines a position on the gradient from 0.0 to 1.0 and a color. + The position of each GradientStop is defined by setting its + \l{GradientStop::}{position} property; its color is defined using its + \l{GradientStop::}{color} property. + + A gradient without any gradient stops is rendered as a solid white fill. Note that this item is not a visual representation of a gradient. To display a - gradient use a visual item (like rectangle) which supports having a gradient set - on it for display. + gradient, use a visual element (like \l Rectangle) which supports the use + of gradients. + + \section1 Example Usage + + \beginfloatright + \inlineimage qml-gradient.png + \endfloat + + The following example declares a \l Rectangle item with a gradient starting + with red, blending to yellow at one third of the height of the rectangle, + and ending with green: + + \snippet doc/src/snippets/declarative/gradient.qml code + + \clearfloat + \section1 Performance and Limitations + + Calculating gradients can be computationally expensive compared to the use + of solid color fills or images. Consider using gradients for static items + in a user interface. + + In Qt 4.7, only vertical, linear gradients can be applied to items. If you + need to apply different orientations of gradients, a combination of rotation + and clipping will need to be applied to the relevant items. This can + introduce additional performance requirements for your application. + + The use of animations involving gradient stops may not give the desired + result. An alternative way to animate gradients is to use pre-generated + images or SVG drawings containing gradients. \sa GradientStop */ @@ -128,6 +163,10 @@ void QDeclarativeGradientStop::updateGradient() /*! \qmlproperty list<GradientStop> Gradient::stops This property holds the gradient stops describing the gradient. + + By default, this property contains an empty list. + + To set the gradient stops, define them as children of the Gradient element. */ const QGradient *QDeclarativeGradient::gradient() const @@ -155,27 +194,46 @@ void QDeclarativeGradient::doUpdate() /*! \qmlclass Rectangle QDeclarativeRectangle \ingroup qml-basic-visual-elements - \since 4.7 - \brief The Rectangle item allows you to add rectangles to a scene. + \since 4.7 + \brief The Rectangle item provides a filled rectangle with an optional border. \inherits Item - A Rectangle is painted using a solid fill (color) and an optional border. - You can also create rounded rectangles using the \l radius property. + Rectangle items are used to fill areas with solid color or gradients, and are + often used to hold other items. - \qml - import Qt 4.7 - - Rectangle { - width: 100 - height: 100 - color: "red" - border.color: "black" - border.width: 5 - radius: 10 - } - \endqml + \section1 Appearance + + Each Rectangle item is painted using either a solid fill color, specified using + the \l color property, or a gradient, defined using a Gradient element and set + using the \l gradient property. If both a color and a gradient are specified, + the gradient is used. + + You can add an optional border to a rectangle with its own color and thickness + by settting the \l border.color and \l border.width properties. + + You can also create rounded rectangles using the \l radius property. Since this + introduces curved edges to the corners of a rectangle, it may be appropriate to + set the \l smooth property to improve its appearance. - \image declarative-rect.png + \section1 Example Usage + + \beginfloatright + \inlineimage declarative-rect.png + \endfloat + + The following example shows the effects of some of the common properties on a + Rectangle item, which in this case is used to create a square: + + \snippet doc/src/snippets/declarative/rectangle/rectangle.qml document + + \clearfloat + \section1 Performance + + Using the \l smooth property improves the appearance of a rounded rectangle at + the cost of rendering performance. You should consider unsetting this property + for rectangles in motion, and only set it when they are stationary. + + \sa Image */ int QDeclarativeRectanglePrivate::doUpdateSlotIdx = -1; @@ -207,13 +265,14 @@ void QDeclarativeRectangle::doUpdate() rectangle's boundaries, and the spare pixel is rendered to the right and below the rectangle (as documented for QRect rendering). This can cause unintended effects if \c border.width is 1 and the rectangle is \l{Item::clip}{clipped} by a parent item: - - \table - \row - \o \snippet doc/src/snippets/declarative/rect-border-width.qml 0 - \o \image rect-border-width.png - \endtable + \beginfloatright + \inlineimage rect-border-width.png + \endfloat + + \snippet doc/src/snippets/declarative/rectangle/rect-border-width.qml 0 + + \clearfloat Here, the innermost rectangle's border is clipped on the bottom and right edges by its parent. To avoid this, the border width can be set to two instead of one. */ @@ -231,34 +290,12 @@ QDeclarativePen *QDeclarativeRectangle::border() This property allows for the construction of simple vertical gradients. Other gradients may by formed by adding rotation to the rectangle. - \table - \row - \o \image declarative-rect_gradient.png - \o - \qml - Rectangle { - y: 0; width: 80; height: 80 - color: "lightsteelblue" - } - - Rectangle { - y: 100; width: 80; height: 80 - gradient: Gradient { - GradientStop { position: 0.0; color: "lightsteelblue" } - GradientStop { position: 1.0; color: "blue" } - } - } + \beginfloatleft + \inlineimage declarative-rect_gradient.png + \endfloat - Rectangle { - y: 200; width: 80; height: 80 - rotation: 90 - gradient: Gradient { - GradientStop { position: 0.0; color: "lightsteelblue" } - GradientStop { position: 1.0; color: "blue" } - } - } - \endqml - \endtable + \snippet doc/src/snippets/declarative/rectangle/rectangle-gradient.qml rectangles + \clearfloat If both a gradient and a color are specified, the gradient will be used. @@ -319,17 +356,21 @@ void QDeclarativeRectangle::setRadius(qreal radius) \qmlproperty color Rectangle::color This property holds the color used to fill the rectangle. - \qml - // green rectangle using hexidecimal notation - Rectangle { color: "#00FF00" } + The default color is white. - // steelblue rectangle using SVG color name - Rectangle { color: "steelblue" } - \endqml + \beginfloatright + \inlineimage rect-color.png + \endfloat - The default color is white. + The following example shows rectangles with colors specified + using hexadecimal and named color notation: + \snippet doc/src/snippets/declarative/rectangle/rectangle-colors.qml rectangles + + \clearfloat If both a gradient and a color are specified, the gradient will be used. + + \sa gradient */ QColor QDeclarativeRectangle::color() const { diff --git a/src/declarative/graphicsitems/qdeclarativevisualitemmodel.cpp b/src/declarative/graphicsitems/qdeclarativevisualitemmodel.cpp index a46ee73..a70886e 100644 --- a/src/declarative/graphicsitems/qdeclarativevisualitemmodel.cpp +++ b/src/declarative/graphicsitems/qdeclarativevisualitemmodel.cpp @@ -287,16 +287,12 @@ public: m_roles = m_listModelInterface->roles(); for (int ii = 0; ii < m_roles.count(); ++ii) m_roleNames.insert(m_listModelInterface->toString(m_roles.at(ii)).toUtf8(), m_roles.at(ii)); - if (m_roles.count() == 1) - m_roleNames.insert("modelData", m_roles.at(0)); } else if (m_abstractItemModel) { for (QHash<int,QByteArray>::const_iterator it = m_abstractItemModel->roleNames().begin(); it != m_abstractItemModel->roleNames().end(); ++it) { m_roles.append(it.key()); m_roleNames.insert(*it, it.key()); } - if (m_roles.count() == 1) - m_roleNames.insert("modelData", m_roles.at(0)); if (m_roles.count()) m_roleNames.insert("hasModelChildren", -1); } else if (m_listAccessor) { @@ -314,7 +310,8 @@ public: } } - QHash<int,int> roleToPropId; + QHash<int,int> m_roleToPropId; + int m_modelDataPropId; void createMetaData() { if (!m_metaDataCreated) { ensureRoles(); @@ -322,9 +319,12 @@ public: QHash<QByteArray, int>::const_iterator it = m_roleNames.begin(); while (it != m_roleNames.end()) { int propId = m_delegateDataType->createProperty(it.key()) - m_delegateDataType->propertyOffset(); - roleToPropId.insert(*it, propId); + m_roleToPropId.insert(*it, propId); ++it; } + // Add modelData property + if (m_roles.count() == 1) + m_modelDataPropId = m_delegateDataType->createProperty("modelData") - m_delegateDataType->propertyOffset(); m_metaDataCreated = true; } } @@ -430,6 +430,11 @@ public: void setIndex(int index); int propForRole(int) const; + int modelDataPropertyId() const { + QDeclarativeVisualDataModelPrivate *model = QDeclarativeVisualDataModelPrivate::get(m_model); + return model->m_modelDataPropId; + } + void setValue(int, const QVariant &); bool hasValue(int id) const { return m_meta->hasValue(id); @@ -450,8 +455,8 @@ private: int QDeclarativeVisualDataModelData::propForRole(int id) const { QDeclarativeVisualDataModelPrivate *model = QDeclarativeVisualDataModelPrivate::get(m_model); - QHash<int,int>::const_iterator it = model->roleToPropId.find(id); - if (it != model->roleToPropId.end()) + QHash<int,int>::const_iterator it = model->m_roleToPropId.find(id); + if (it != model->m_roleToPropId.end()) return *it; return -1; @@ -518,14 +523,16 @@ QVariant QDeclarativeVisualDataModelDataMetaObject::initialValue(int propId) } } else if (model->m_abstractItemModel) { model->ensureRoles(); + QModelIndex index = model->m_abstractItemModel->index(data->m_index, 0, model->m_root); if (propName == "hasModelChildren") { - QModelIndex index = model->m_abstractItemModel->index(data->m_index, 0, model->m_root); return model->m_abstractItemModel->hasChildren(index); } else { QHash<QByteArray,int>::const_iterator it = model->m_roleNames.find(propName); if (it != model->m_roleNames.end()) { - QModelIndex index = model->m_abstractItemModel->index(data->m_index, 0, model->m_root); return model->m_abstractItemModel->data(index, *it); + } else if (model->m_roles.count() == 1 && propName == "modelData") { + //for compatibility with other lists, assign modelData if there is only a single role + return model->m_abstractItemModel->data(index, model->m_roles.first()); } } } @@ -1195,6 +1202,19 @@ void QDeclarativeVisualDataModel::_q_itemsChanged(int index, int count, qmlInfo(this) << "Changing role not present in item: " << roleName; } } + if (roles.count() == 1) { + // Handle the modelData role we add if there is just one role. + int propId = data->modelDataPropertyId(); + if (data->hasValue(propId)) { + int role = roles.at(0); + if (d->m_listModelInterface) { + data->setValue(propId, d->m_listModelInterface->data(idx, QList<int>() << role).value(role)); + } else if (d->m_abstractItemModel) { + QModelIndex index = d->m_abstractItemModel->index(idx, 0, d->m_root); + data->setValue(propId, d->m_abstractItemModel->data(index, role)); + } + } + } } } } diff --git a/src/declarative/qml/qdeclarativebinding.cpp b/src/declarative/qml/qdeclarativebinding.cpp index e096305..cb6ad8c 100644 --- a/src/declarative/qml/qdeclarativebinding.cpp +++ b/src/declarative/qml/qdeclarativebinding.cpp @@ -48,6 +48,7 @@ #include "private/qdeclarativecontext_p.h" #include "private/qdeclarativedata_p.h" #include "private/qdeclarativestringconverters_p.h" +#include "private/qdeclarativestate_p_p.h" #include <QVariant> #include <QtCore/qdebug.h> @@ -373,6 +374,18 @@ void QDeclarativeAbstractBinding::removeFromObject() } } +static void bindingDummyDeleter(QDeclarativeAbstractBinding *) +{ +} + +QDeclarativeAbstractBinding::Pointer QDeclarativeAbstractBinding::weakPointer() +{ + if (m_selfPointer.isNull()) + m_selfPointer = QSharedPointer<QDeclarativeAbstractBinding>(this, bindingDummyDeleter); + + return m_selfPointer.toWeakRef(); +} + void QDeclarativeAbstractBinding::clear() { if (m_mePtr) { diff --git a/src/declarative/qml/qdeclarativebinding_p.h b/src/declarative/qml/qdeclarativebinding_p.h index 598f09f..941a1b3 100644 --- a/src/declarative/qml/qdeclarativebinding_p.h +++ b/src/declarative/qml/qdeclarativebinding_p.h @@ -67,6 +67,8 @@ QT_BEGIN_NAMESPACE class Q_DECLARATIVE_EXPORT QDeclarativeAbstractBinding { public: + typedef QWeakPointer<QDeclarativeAbstractBinding> Pointer; + QDeclarativeAbstractBinding(); virtual void destroy(); @@ -86,21 +88,26 @@ public: void addToObject(QObject *); void removeFromObject(); + static Pointer getPointer(QDeclarativeAbstractBinding *p) { return p ? p->weakPointer() : Pointer(); } + protected: virtual ~QDeclarativeAbstractBinding(); void clear(); private: + Pointer weakPointer(); friend class QDeclarativeData; friend class QDeclarativeValueTypeProxyBinding; friend class QDeclarativePropertyPrivate; friend class QDeclarativeVME; + friend class QtSharedPointer::ExternalRefCount<QDeclarativeAbstractBinding>; QObject *m_object; QDeclarativeAbstractBinding **m_mePtr; QDeclarativeAbstractBinding **m_prevBinding; QDeclarativeAbstractBinding *m_nextBinding; + QSharedPointer<QDeclarativeAbstractBinding> m_selfPointer; }; class QDeclarativeValueTypeProxyBinding : public QDeclarativeAbstractBinding diff --git a/src/declarative/qml/qdeclarativecomponent_p.h b/src/declarative/qml/qdeclarativecomponent_p.h index 1b1454b..a551cc8 100644 --- a/src/declarative/qml/qdeclarativecomponent_p.h +++ b/src/declarative/qml/qdeclarativecomponent_p.h @@ -74,7 +74,7 @@ class QDeclarativeEngine; class QDeclarativeCompiledData; class QDeclarativeComponentAttached; -class QDeclarativeComponentPrivate : public QObjectPrivate, public QDeclarativeTypeData::TypeDataCallback +class Q_AUTOTEST_EXPORT QDeclarativeComponentPrivate : public QObjectPrivate, public QDeclarativeTypeData::TypeDataCallback { Q_DECLARE_PUBLIC(QDeclarativeComponent) diff --git a/src/declarative/qml/qdeclarativecustomparser_p.h b/src/declarative/qml/qdeclarativecustomparser_p.h index 509e30a..c3f9dd2 100644 --- a/src/declarative/qml/qdeclarativecustomparser_p.h +++ b/src/declarative/qml/qdeclarativecustomparser_p.h @@ -117,7 +117,7 @@ public: NoFlag = 0x00000000, AcceptsAttachedProperties = 0x00000001 }; - Q_DECLARE_FLAGS(Flags, Flag); + Q_DECLARE_FLAGS(Flags, Flag) QDeclarativeCustomParser() : compiler(0), object(0), m_flags(NoFlag) {} QDeclarativeCustomParser(Flags f) : compiler(0), object(0), m_flags(f) {} diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp index 9de5a77..80db230 100644 --- a/src/declarative/qml/qdeclarativeengine.cpp +++ b/src/declarative/qml/qdeclarativeengine.cpp @@ -906,7 +906,7 @@ QDeclarativeEngine::ObjectOwnership QDeclarativeEngine::objectOwnership(QObject return ddata->indestructible?CppOwnership:JavaScriptOwnership; } -void qmlExecuteDeferred(QObject *object) +Q_AUTOTEST_EXPORT void qmlExecuteDeferred(QObject *object) { QDeclarativeData *data = QDeclarativeData::get(object); diff --git a/src/declarative/qml/qdeclarativevaluetype.cpp b/src/declarative/qml/qdeclarativevaluetype.cpp index 98e9a58..fda62ee 100644 --- a/src/declarative/qml/qdeclarativevaluetype.cpp +++ b/src/declarative/qml/qdeclarativevaluetype.cpp @@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE -Q_DECL_IMPORT extern int qt_defaultDpi(); +Q_GUI_EXPORT int qt_defaultDpi(); template<typename T> int qmlRegisterValueTypeEnums(const char *qmlName) diff --git a/src/declarative/util/qdeclarativeanimation_p.h b/src/declarative/util/qdeclarativeanimation_p.h index d15d1f6..cdd5041 100644 --- a/src/declarative/util/qdeclarativeanimation_p.h +++ b/src/declarative/util/qdeclarativeanimation_p.h @@ -165,7 +165,7 @@ protected: }; class QDeclarativeScriptActionPrivate; -class QDeclarativeScriptAction : public QDeclarativeAbstractAnimation +class Q_DECLARATIVE_EXPORT QDeclarativeScriptAction : public QDeclarativeAbstractAnimation { Q_OBJECT Q_DECLARE_PRIVATE(QDeclarativeScriptAction) diff --git a/src/declarative/util/qdeclarativefontloader.cpp b/src/declarative/util/qdeclarativefontloader.cpp index 1755855..91588b7 100644 --- a/src/declarative/util/qdeclarativefontloader.cpp +++ b/src/declarative/util/qdeclarativefontloader.cpp @@ -58,23 +58,91 @@ QT_BEGIN_NAMESPACE +#define FONTLOADER_MAXIMUM_REDIRECT_RECURSION 16 + +class QDeclarativeFontObject : public QObject +{ +Q_OBJECT + +public: + QDeclarativeFontObject(int _id); + + void download(const QUrl &url, QNetworkAccessManager *manager); + +Q_SIGNALS: + void fontDownloaded(const QString&, QDeclarativeFontLoader::Status); + +private Q_SLOTS: + void replyFinished(); + +public: + int id; + +private: + QNetworkReply *reply; + int redirectCount; + + Q_DISABLE_COPY(QDeclarativeFontObject) +}; + +QDeclarativeFontObject::QDeclarativeFontObject(int _id = -1) + : QObject(0), id(_id), reply(0), redirectCount(0) {} + + +void QDeclarativeFontObject::download(const QUrl &url, QNetworkAccessManager *manager) +{ + QNetworkRequest req(url); + req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true); + reply = manager->get(req); + QObject::connect(reply, SIGNAL(finished()), this, SLOT(replyFinished())); +} + +void QDeclarativeFontObject::replyFinished() +{ + if (reply) { + redirectCount++; + if (redirectCount < FONTLOADER_MAXIMUM_REDIRECT_RECURSION) { + QVariant redirect = reply->attribute(QNetworkRequest::RedirectionTargetAttribute); + if (redirect.isValid()) { + QUrl url = reply->url().resolved(redirect.toUrl()); + QNetworkAccessManager *manager = reply->manager(); + reply->deleteLater(); + reply = 0; + download(url, manager); + return; + } + } + redirectCount = 0; + + if (!reply->error()) { + id = QFontDatabase::addApplicationFontFromData(reply->readAll()); + if (id != -1) + emit fontDownloaded(QFontDatabase::applicationFontFamilies(id).at(0), QDeclarativeFontLoader::Ready); + else + emit fontDownloaded(QString(), QDeclarativeFontLoader::Error); + } else { + emit fontDownloaded(QString(), QDeclarativeFontLoader::Error); + } + reply->deleteLater(); + reply = 0; + } +} + + class QDeclarativeFontLoaderPrivate : public QObjectPrivate { Q_DECLARE_PUBLIC(QDeclarativeFontLoader) public: - QDeclarativeFontLoaderPrivate() : reply(0), status(QDeclarativeFontLoader::Null), redirectCount(0) {} - - void addFontToDatabase(const QByteArray &); + QDeclarativeFontLoaderPrivate() : status(QDeclarativeFontLoader::Null) {} QUrl url; QString name; - QNetworkReply *reply; QDeclarativeFontLoader::Status status; - int redirectCount; + static QHash<QUrl, QDeclarativeFontObject*> fonts; }; - +QHash<QUrl, QDeclarativeFontObject*> QDeclarativeFontLoaderPrivate::fonts; /*! \qmlclass FontLoader QDeclarativeFontLoader @@ -127,30 +195,65 @@ void QDeclarativeFontLoader::setSource(const QUrl &url) if (url == d->url) return; d->url = qmlContext(this)->resolvedUrl(url); - - d->status = Loading; - emit statusChanged(); emit sourceChanged(); + #ifndef QT_NO_LOCALFILE_OPTIMIZED_QML - QString lf = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(d->url); - if (!lf.isEmpty()) { - int id = QFontDatabase::addApplicationFont(lf); - if (id != -1) { - d->name = QFontDatabase::applicationFontFamilies(id).at(0); + QString localFile = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(d->url); + if (!localFile.isEmpty()) { + if (!d->fonts.contains(d->url)) { + int id = QFontDatabase::addApplicationFont(localFile); + if (id != -1) { + updateFontInfo(QFontDatabase::applicationFontFamilies(id).at(0), Ready); + QDeclarativeFontObject *fo = new QDeclarativeFontObject(id); + d->fonts[d->url] = fo; + } else { + updateFontInfo(QString(), Error); + } + } else { + QDeclarativeFontObject *fo = d->fonts[d->url]; + d->name = QFontDatabase::applicationFontFamilies(fo->id).at(0); emit nameChanged(); d->status = QDeclarativeFontLoader::Ready; - } else { - d->status = QDeclarativeFontLoader::Error; - qmlInfo(this) << "Cannot load font: \"" << url.toString() << "\""; + emit statusChanged(); } - emit statusChanged(); } else #endif { - QNetworkRequest req(d->url); - req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true); - d->reply = qmlEngine(this)->networkAccessManager()->get(req); - QObject::connect(d->reply, SIGNAL(finished()), this, SLOT(replyFinished())); + if (!d->fonts.contains(d->url)) { + QDeclarativeFontObject *fo = new QDeclarativeFontObject; + d->fonts[d->url] = fo; + fo->download(d->url, qmlEngine(this)->networkAccessManager()); + d->status = Loading; + emit statusChanged(); + QObject::connect(fo, SIGNAL(fontDownloaded(QString, QDeclarativeFontLoader::Status)), + this, SLOT(updateFontInfo(QString, QDeclarativeFontLoader::Status))); + } else { + QDeclarativeFontObject *fo = d->fonts[d->url]; + if (fo->id == -1) { + d->status = Loading; + emit statusChanged(); + QObject::connect(fo, SIGNAL(fontDownloaded(QString, QDeclarativeFontLoader::Status)), + this, SLOT(updateFontInfo(QString, QDeclarativeFontLoader::Status))); + } + else + updateFontInfo(QFontDatabase::applicationFontFamilies(fo->id).at(0), Ready); + } + } +} + +void QDeclarativeFontLoader::updateFontInfo(const QString& name, QDeclarativeFontLoader::Status status) +{ + Q_D(QDeclarativeFontLoader); + + if (name != d->name) { + d->name = name; + emit nameChanged(); + } + if (status != d->status) { + if (status == Error) + qmlInfo(this) << "Cannot load font: \"" << d->url.toString() << "\""; + d->status = status; + emit statusChanged(); } } @@ -177,7 +280,7 @@ QString QDeclarativeFontLoader::name() const void QDeclarativeFontLoader::setName(const QString &name) { Q_D(QDeclarativeFontLoader); - if (d->name == name ) + if (d->name == name) return; d->name = name; emit nameChanged(); @@ -223,52 +326,6 @@ QDeclarativeFontLoader::Status QDeclarativeFontLoader::status() const return d->status; } -#define FONTLOADER_MAXIMUM_REDIRECT_RECURSION 16 - -void QDeclarativeFontLoader::replyFinished() -{ - Q_D(QDeclarativeFontLoader); - if (d->reply) { - d->redirectCount++; - if (d->redirectCount < FONTLOADER_MAXIMUM_REDIRECT_RECURSION) { - QVariant redirect = d->reply->attribute(QNetworkRequest::RedirectionTargetAttribute); - if (redirect.isValid()) { - QUrl url = d->reply->url().resolved(redirect.toUrl()); - d->reply->deleteLater(); - d->reply = 0; - setSource(url); - return; - } - } - d->redirectCount=0; - - if (!d->reply->error()) { - QByteArray ba = d->reply->readAll(); - d->addFontToDatabase(ba); - } else { - d->status = Error; - qmlInfo(this) << "Cannot load font: \"" << d->reply->url().toString() << "\""; - emit statusChanged(); - } - d->reply->deleteLater(); - d->reply = 0; - } -} - -void QDeclarativeFontLoaderPrivate::addFontToDatabase(const QByteArray &ba) -{ - Q_Q(QDeclarativeFontLoader); - - int id = QFontDatabase::addApplicationFontFromData(ba); - if (id != -1) { - name = QFontDatabase::applicationFontFamilies(id).at(0); - emit q->nameChanged(); - status = QDeclarativeFontLoader::Ready; - } else { - status = QDeclarativeFontLoader::Error; - qmlInfo(q) << "Cannot load font: \"" << url.toString() << "\""; - } - emit q->statusChanged(); -} - QT_END_NAMESPACE + +#include <qdeclarativefontloader.moc> diff --git a/src/declarative/util/qdeclarativefontloader_p.h b/src/declarative/util/qdeclarativefontloader_p.h index 0344d99..bebd5a0 100644 --- a/src/declarative/util/qdeclarativefontloader_p.h +++ b/src/declarative/util/qdeclarativefontloader_p.h @@ -79,7 +79,7 @@ public: Status status() const; private Q_SLOTS: - void replyFinished(); + void updateFontInfo(const QString&, QDeclarativeFontLoader::Status); Q_SIGNALS: void sourceChanged(); diff --git a/src/declarative/util/qdeclarativelistmodel.cpp b/src/declarative/util/qdeclarativelistmodel.cpp index f290ab2..cf2eada 100644 --- a/src/declarative/util/qdeclarativelistmodel.cpp +++ b/src/declarative/util/qdeclarativelistmodel.cpp @@ -69,49 +69,67 @@ QDeclarativeListModelParser::ListInstruction *QDeclarativeListModelParser::ListM \since 4.7 \brief The ListModel element defines a free-form list data source. - The ListModel is a simple hierarchy of elements containing data roles. The contents can - be defined dynamically, or explicitly in QML: + The ListModel is a simple container of ListElement definitions, each containing data roles. + The contents can be defined dynamically, or explicitly in QML. - For example: + The number of elements in the model can be obtained from its \l count property. + A number of familiar methods are also provided to manipulate the contents of the + model, including append(), insert(), move(), remove() and set(). These methods + accept dictionaries as their arguments; these are translated to ListElement objects + by the model. - \snippet doc/src/snippets/declarative/listmodel.qml 0 + Elements can be manipulated via the model using the setProperty() method, which + allows the roles of the specified element to be set and changed. + + \section1 Example Usage + + The following example shows a ListModel containing three elements, with the roles + "name" and "cost". - Roles (properties) must begin with a lower-case letter. The above example defines a - ListModel containing three elements, with the roles "name" and "cost". + \beginfloatright + \inlineimage listmodel.png + \endfloat + + \snippet doc/src/snippets/declarative/listmodel.qml 0 - Values must be simple constants - either strings (quoted and optionally within a call to QT_TR_NOOP), - bools (true, false), numbers, or enum values (like Text.AlignHCenter). + \clearfloat + Roles (properties) in each element must begin with a lower-case letter and + should be common to all elements in a model. The ListElement documentation + provides more guidelines for how elements should be defined. - The defined model can be used in views such as ListView: + Since the example model contains an \c id property, it can be referenced + by views, such as the ListView in this example: \snippet doc/src/snippets/declarative/listmodel-simple.qml 0 \dots 8 \snippet doc/src/snippets/declarative/listmodel-simple.qml 1 - \image listmodel.png - It is possible for roles to contain list data. In the example below we create a list of fruit attributes: + It is possible for roles to contain list data. In the following example we + create a list of fruit attributes: \snippet doc/src/snippets/declarative/listmodel-nested.qml model - The delegate below displays all the fruit attributes: + The delegate displays all the fruit attributes: - \snippet doc/src/snippets/declarative/listmodel-nested.qml delegate - \image listmodel-nested.png + \beginfloatright + \inlineimage listmodel-nested.png + \endfloat + \snippet doc/src/snippets/declarative/listmodel-nested.qml delegate - \section2 Modifying list models + \clearfloat + \section1 Modifying List Models The content of a ListModel may be created and modified using the clear(), append(), set() and setProperty() methods. For example: - - \snippet doc/src/snippets/declarative/listmodel-modify.qml delegate - Note that when creating content dynamically the set of available properties cannot be changed - once set. Whatever properties are first added to the model are the - only permitted properties in the model. + \snippet doc/src/snippets/declarative/listmodel-modify.qml delegate + Note that when creating content dynamically the set of available properties + cannot be changed once set. Whatever properties are first added to the model + are the only permitted properties in the model. - \section2 Using threaded list models with WorkerScript + \section1 Using Threaded List Models with WorkerScript ListModel can be used together with WorkerScript access a list model from multiple threads. This is useful if list modifications are @@ -127,16 +145,16 @@ QDeclarativeListModelParser::ListInstruction *QDeclarativeListModelParser::ListM \snippet examples/declarative/threading/threadedlistmodel/dataloader.js 0 -working-with-data - worker script by calling \l WorkerScript::sendMessage(). When this message - is received, \l {WorkerScript::onMessage}{WorkerScript.onMessage()} is invoked in - \tt dataloader.js, which appends the current time to the list model. + The timer in the main example sends messages to the worker script by calling + \l WorkerScript::sendMessage(). When this message is received, + \l{WorkerScript::onMessage}{WorkerScript.onMessage()} is invoked in \c dataloader.js, + which appends the current time to the list model. - Note the call to sync() from the \l {WorkerScript::onMessage}{WorkerScript.onMessage()} handler. - You must call sync() or else the changes made to the list from the external + Note the call to sync() from the \l{WorkerScript::onMessage}{WorkerScript.onMessage()} + handler. You must call sync() or else the changes made to the list from the external thread will not be reflected in the list model in the main thread. - \section3 Limitations + \section1 Limitations If a list model is to be accessed from a WorkerScript, it \bold cannot contain list data. So, the following model cannot be used from a WorkerScript @@ -771,6 +789,39 @@ bool QDeclarativeListModelParser::definesEmptyList(const QString &s) \since 4.7 \brief The ListElement element defines a data item in a ListModel. + List elements are defined inside ListModel definitions, and represent items in a + list that will be displayed using ListView or \l Repeater items. + + List elements are defined like other QML elements except that they contain + a collection of \e role definitions instead of properties. Using the same + syntax as property definitions, roles both define how the data is accessed + and include the data itself. + + The names used for roles must begin with a lower-case letter and should be + common to all elements in a given model. Values must be simple constants; either + strings (quoted and optionally within a call to QT_TR_NOOP), boolean values + (true, false), numbers, or enumeration values (such as AlignText.AlignHCenter). + + \section1 Referencing Roles + + The role names are used by delegates to obtain data from list elements. + Each role name is accessible in the delegate's scope, and refers to the + corresponding role in the current element. Where a role name would be + ambiguous to use, it can be accessed via the \l{ListView::}{model} + property (e.g., \c{model.cost} instead of \c{cost}). + + \section1 Example Usage + + The following model defines a series of list elements, each of which + contain "name" and "cost" roles and their associated values. + + \snippet doc/src/snippets/declarative/qml-data-models/listelements.qml model + + The delegate obtains the name and cost for each element by simply referring + to \c name and \c cost: + + \snippet doc/src/snippets/declarative/qml-data-models/listelements.qml view + \sa ListModel */ diff --git a/src/declarative/util/qdeclarativepixmapcache_p.h b/src/declarative/util/qdeclarativepixmapcache_p.h index b4d88bd..2e83cc4 100644 --- a/src/declarative/util/qdeclarativepixmapcache_p.h +++ b/src/declarative/util/qdeclarativepixmapcache_p.h @@ -98,7 +98,7 @@ public: bool connectDownloadProgress(QObject *, int); private: - Q_DISABLE_COPY(QDeclarativePixmap); + Q_DISABLE_COPY(QDeclarativePixmap) QDeclarativePixmapData *d; }; diff --git a/src/declarative/util/qdeclarativepropertychanges.cpp b/src/declarative/util/qdeclarativepropertychanges.cpp index e897458..8d01b80 100644 --- a/src/declarative/util/qdeclarativepropertychanges.cpp +++ b/src/declarative/util/qdeclarativepropertychanges.cpp @@ -52,6 +52,7 @@ #include <qdeclarativeguard_p.h> #include <qdeclarativeproperty_p.h> #include <qdeclarativecontext_p.h> +#include <qdeclarativestate_p_p.h> #include <QtCore/qdebug.h> @@ -200,14 +201,14 @@ public: }; -class QDeclarativePropertyChangesPrivate : public QObjectPrivate +class QDeclarativePropertyChangesPrivate : public QDeclarativeStateOperationPrivate { Q_DECLARE_PUBLIC(QDeclarativePropertyChanges) public: - QDeclarativePropertyChangesPrivate() : object(0), decoded(true), restore(true), + QDeclarativePropertyChangesPrivate() : decoded(true), restore(true), isExplicit(false) {} - QObject *object; + QDeclarativeGuard<QObject> object; QByteArray data; bool decoded : 1; @@ -497,4 +498,272 @@ void QDeclarativePropertyChanges::setIsExplicit(bool e) d->isExplicit = e; } +bool QDeclarativePropertyChanges::containsValue(const QByteArray &name) const +{ + Q_D(const QDeclarativePropertyChanges); + typedef QPair<QByteArray, QVariant> PropertyEntry; + + QListIterator<PropertyEntry> propertyIterator(d->properties); + while (propertyIterator.hasNext()) { + const PropertyEntry &entry = propertyIterator.next(); + if (entry.first == name) { + return true; + } + } + + return false; +} + +bool QDeclarativePropertyChanges::containsExpression(const QByteArray &name) const +{ + Q_D(const QDeclarativePropertyChanges); + typedef QPair<QByteArray, QDeclarativeExpression *> ExpressionEntry; + + QListIterator<ExpressionEntry> expressionIterator(d->expressions); + while (expressionIterator.hasNext()) { + const ExpressionEntry &entry = expressionIterator.next(); + if (entry.first == name) { + return true; + } + } + + return false; +} + +bool QDeclarativePropertyChanges::containsProperty(const QByteArray &name) const +{ + return containsValue(name) || containsExpression(name); +} + +void QDeclarativePropertyChanges::changeValue(const QByteArray &name, const QVariant &value) +{ + Q_D(QDeclarativePropertyChanges); + typedef QPair<QByteArray, QVariant> PropertyEntry; + typedef QPair<QByteArray, QDeclarativeExpression *> ExpressionEntry; + + QMutableListIterator<ExpressionEntry> expressionIterator(d->expressions); + while (expressionIterator.hasNext()) { + const ExpressionEntry &entry = expressionIterator.next(); + if (entry.first == name) { + expressionIterator.remove(); + if (state() && state()->isStateActive()) { + QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(d->property(name)); + if (oldBinding) { + QDeclarativePropertyPrivate::setBinding(d->property(name), 0); + oldBinding->destroy(); + } + d->property(name).write(value); + } + + d->properties.append(PropertyEntry(name, value)); + return; + } + } + + QMutableListIterator<PropertyEntry> propertyIterator(d->properties); + while (propertyIterator.hasNext()) { + PropertyEntry &entry = propertyIterator.next(); + if (entry.first == name) { + entry.second = value; + if (state() && state()->isStateActive()) + d->property(name).write(value); + return; + } + } + + QDeclarativeAction action; + action.restore = restoreEntryValues(); + action.property = d->property(name); + action.fromValue = action.property.read(); + action.specifiedObject = object(); + action.specifiedProperty = QString::fromUtf8(name); + action.toValue = value; + + propertyIterator.insert(PropertyEntry(name, value)); + if (state() && state()->isStateActive()) { + state()->addEntryToRevertList(action); + QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(action.property); + if (oldBinding) + oldBinding->setEnabled(false, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor); + d->property(name).write(value); + } +} + +void QDeclarativePropertyChanges::changeExpression(const QByteArray &name, const QString &expression) +{ + Q_D(QDeclarativePropertyChanges); + typedef QPair<QByteArray, QVariant> PropertyEntry; + typedef QPair<QByteArray, QDeclarativeExpression *> ExpressionEntry; + + bool hadValue = false; + + QMutableListIterator<PropertyEntry> propertyIterator(d->properties); + while (propertyIterator.hasNext()) { + PropertyEntry &entry = propertyIterator.next(); + if (entry.first == name) { + propertyIterator.remove(); + hadValue = true; + break; + } + } + + QMutableListIterator<ExpressionEntry> expressionIterator(d->expressions); + while (expressionIterator.hasNext()) { + const ExpressionEntry &entry = expressionIterator.next(); + if (entry.first == name) { + entry.second->setExpression(expression); + if (state() && state()->isStateActive()) { + QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(d->property(name)); + if (oldBinding) { + QDeclarativePropertyPrivate::setBinding(d->property(name), 0); + oldBinding->destroy(); + } + + QDeclarativeBinding *newBinding = new QDeclarativeBinding(expression, object(), qmlContext(this)); + newBinding->setTarget(d->property(name)); + QDeclarativePropertyPrivate::setBinding(d->property(name), newBinding, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor); + } + return; + } + } + + QDeclarativeExpression *newExpression = new QDeclarativeExpression(qmlContext(this), d->object, expression); + expressionIterator.insert(ExpressionEntry(name, newExpression)); + + if (state() && state()->isStateActive()) { + if (hadValue) { + QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(d->property(name)); + if (oldBinding) { + oldBinding->setEnabled(false, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor); + state()->changeBindingInRevertList(object(), name, oldBinding); + } + + QDeclarativeBinding *newBinding = new QDeclarativeBinding(expression, object(), qmlContext(this)); + newBinding->setTarget(d->property(name)); + QDeclarativePropertyPrivate::setBinding(d->property(name), newBinding, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor); + } else { + QDeclarativeAction action; + action.restore = restoreEntryValues(); + action.property = d->property(name); + action.fromValue = action.property.read(); + action.specifiedObject = object(); + action.specifiedProperty = QString::fromUtf8(name); + + + if (d->isExplicit) { + action.toValue = newExpression->evaluate(); + } else { + QDeclarativeBinding *newBinding = new QDeclarativeBinding(newExpression->expression(), object(), qmlContext(this)); + newBinding->setTarget(d->property(name)); + action.toBinding = newBinding; + action.deletableToBinding = true; + + state()->addEntryToRevertList(action); + QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(action.property); + if (oldBinding) + oldBinding->setEnabled(false, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor); + + QDeclarativePropertyPrivate::setBinding(action.property, newBinding, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor); + } + } + } + // what about the signal handler? +} + +QVariant QDeclarativePropertyChanges::property(const QByteArray &name) const +{ + Q_D(const QDeclarativePropertyChanges); + typedef QPair<QByteArray, QVariant> PropertyEntry; + typedef QPair<QByteArray, QDeclarativeExpression *> ExpressionEntry; + + QListIterator<PropertyEntry> propertyIterator(d->properties); + while (propertyIterator.hasNext()) { + const PropertyEntry &entry = propertyIterator.next(); + if (entry.first == name) { + return entry.second; + } + } + + QListIterator<ExpressionEntry> expressionIterator(d->expressions); + while (expressionIterator.hasNext()) { + const ExpressionEntry &entry = expressionIterator.next(); + if (entry.first == name) { + return QVariant(entry.second->expression()); + } + } + + return QVariant(); +} + +void QDeclarativePropertyChanges::removeProperty(const QByteArray &name) +{ + Q_D(QDeclarativePropertyChanges); + typedef QPair<QByteArray, QVariant> PropertyEntry; + typedef QPair<QByteArray, QDeclarativeExpression *> ExpressionEntry; + + QMutableListIterator<ExpressionEntry> expressionIterator(d->expressions); + while (expressionIterator.hasNext()) { + const ExpressionEntry &entry = expressionIterator.next(); + if (entry.first == name) { + expressionIterator.remove(); + state()->removeEntryFromRevertList(object(), name); + return; + } + } + + QMutableListIterator<PropertyEntry> propertyIterator(d->properties); + while (propertyIterator.hasNext()) { + const PropertyEntry &entry = propertyIterator.next(); + if (entry.first == name) { + propertyIterator.remove(); + state()->removeEntryFromRevertList(object(), name); + return; + } + } +} + +QVariant QDeclarativePropertyChanges::value(const QByteArray &name) const +{ + Q_D(const QDeclarativePropertyChanges); + typedef QPair<QByteArray, QVariant> PropertyEntry; + + QListIterator<PropertyEntry> propertyIterator(d->properties); + while (propertyIterator.hasNext()) { + const PropertyEntry &entry = propertyIterator.next(); + if (entry.first == name) { + return entry.second; + } + } + + return QVariant(); +} + +QString QDeclarativePropertyChanges::expression(const QByteArray &name) const +{ + Q_D(const QDeclarativePropertyChanges); + typedef QPair<QByteArray, QDeclarativeExpression *> ExpressionEntry; + + QListIterator<ExpressionEntry> expressionIterator(d->expressions); + while (expressionIterator.hasNext()) { + const ExpressionEntry &entry = expressionIterator.next(); + if (entry.first == name) { + return entry.second->expression(); + } + } + + return QString(); +} + +void QDeclarativePropertyChanges::detachFromState() +{ + if (state()) + state()->removeAllEntriesFromRevertList(object()); +} + +void QDeclarativePropertyChanges::attachToState() +{ + if (state()) + state()->addEntriesToRevertList(actions()); +} + QT_END_NAMESPACE diff --git a/src/declarative/util/qdeclarativepropertychanges_p.h b/src/declarative/util/qdeclarativepropertychanges_p.h index 8578086..199928f 100644 --- a/src/declarative/util/qdeclarativepropertychanges_p.h +++ b/src/declarative/util/qdeclarativepropertychanges_p.h @@ -52,7 +52,7 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) class QDeclarativePropertyChangesPrivate; -class Q_AUTOTEST_EXPORT QDeclarativePropertyChanges : public QDeclarativeStateOperation +class Q_DECLARATIVE_EXPORT QDeclarativePropertyChanges : public QDeclarativeStateOperation { Q_OBJECT Q_DECLARE_PRIVATE(QDeclarativePropertyChanges) @@ -74,6 +74,20 @@ public: void setIsExplicit(bool); virtual ActionList actions(); + + bool containsProperty(const QByteArray &name) const; + bool containsValue(const QByteArray &name) const; + bool containsExpression(const QByteArray &name) const; + void changeValue(const QByteArray &name, const QVariant &value); + void changeExpression(const QByteArray &name, const QString &expression); + void removeProperty(const QByteArray &name); + QVariant value(const QByteArray &name) const; + QString expression(const QByteArray &name) const; + + void detachFromState(); + void attachToState(); + + QVariant property(const QByteArray &name) const; }; class QDeclarativePropertyChangesParser : public QDeclarativeCustomParser diff --git a/src/declarative/util/qdeclarativestate.cpp b/src/declarative/util/qdeclarativestate.cpp index 1ed7923..0f5413e 100644 --- a/src/declarative/util/qdeclarativestate.cpp +++ b/src/declarative/util/qdeclarativestate.cpp @@ -304,7 +304,7 @@ void QDeclarativeStatePrivate::complete() for (int ii = 0; ii < reverting.count(); ++ii) { for (int jj = 0; jj < revertList.count(); ++jj) { - if (revertList.at(jj).property == reverting.at(ii)) { + if (revertList.at(jj).property() == reverting.at(ii)) { revertList.removeAt(jj); break; } @@ -370,6 +370,192 @@ void QDeclarativeAction::deleteFromBinding() } } +bool QDeclarativeState::containsPropertyInRevertList(QObject *target, const QByteArray &name) const +{ + Q_D(const QDeclarativeState); + + if (isStateActive()) { + QListIterator<QDeclarativeSimpleAction> revertListIterator(d->revertList); + + while (revertListIterator.hasNext()) { + const QDeclarativeSimpleAction &simpleAction = revertListIterator.next(); + if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty().toUtf8() == name) + return true; + } + } + + return false; +} + +bool QDeclarativeState::changeValueInRevertList(QObject *target, const QByteArray &name, const QVariant &revertValue) +{ + Q_D(QDeclarativeState); + + if (isStateActive()) { + QMutableListIterator<QDeclarativeSimpleAction> revertListIterator(d->revertList); + + while (revertListIterator.hasNext()) { + QDeclarativeSimpleAction &simpleAction = revertListIterator.next(); + if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty().toUtf8() == name) { + simpleAction.setValue(revertValue); + return true; + } + } + } + + return false; +} + +bool QDeclarativeState::changeBindingInRevertList(QObject *target, const QByteArray &name, QDeclarativeAbstractBinding *binding) +{ + Q_D(QDeclarativeState); + + if (isStateActive()) { + QMutableListIterator<QDeclarativeSimpleAction> revertListIterator(d->revertList); + + while (revertListIterator.hasNext()) { + QDeclarativeSimpleAction &simpleAction = revertListIterator.next(); + if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty().toUtf8() == name) { + if (simpleAction.binding()) + simpleAction.binding()->destroy(); + + simpleAction.setBinding(binding); + return true; + } + } + } + + return false; +} + +bool QDeclarativeState::removeEntryFromRevertList(QObject *target, const QByteArray &name) +{ + Q_D(QDeclarativeState); + + if (isStateActive()) { + QMutableListIterator<QDeclarativeSimpleAction> revertListIterator(d->revertList); + + while (revertListIterator.hasNext()) { + QDeclarativeSimpleAction &simpleAction = revertListIterator.next(); + if (simpleAction.property().object() == target && simpleAction.property().name().toUtf8() == name) { + QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(simpleAction.property()); + if (oldBinding) { + QDeclarativePropertyPrivate::setBinding(simpleAction.property(), 0); + oldBinding->destroy(); + } + + simpleAction.property().write(simpleAction.value()); + if (simpleAction.binding()) + QDeclarativePropertyPrivate::setBinding(simpleAction.property(), simpleAction.binding()); + + revertListIterator.remove(); + return true; + } + } + } + + return false; +} + +void QDeclarativeState::addEntryToRevertList(const QDeclarativeAction &action) +{ + Q_D(QDeclarativeState); + + QDeclarativeSimpleAction simpleAction(action); + + d->revertList.append(simpleAction); +} + +void QDeclarativeState::removeAllEntriesFromRevertList(QObject *target) +{ + Q_D(QDeclarativeState); + + if (isStateActive()) { + QMutableListIterator<QDeclarativeSimpleAction> revertListIterator(d->revertList); + + while (revertListIterator.hasNext()) { + QDeclarativeSimpleAction &simpleAction = revertListIterator.next(); + if (simpleAction.property().object() == target) { + QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(simpleAction.property()); + if (oldBinding) { + QDeclarativePropertyPrivate::setBinding(simpleAction.property(), 0); + oldBinding->destroy(); + } + + simpleAction.property().write(simpleAction.value()); + if (simpleAction.binding()) + QDeclarativePropertyPrivate::setBinding(simpleAction.property(), simpleAction.binding()); + + revertListIterator.remove(); + } + } + } +} + +void QDeclarativeState::addEntriesToRevertList(const QList<QDeclarativeAction> &actionList) +{ + Q_D(QDeclarativeState); + if (isStateActive()) { + QList<QDeclarativeSimpleAction> simpleActionList; + + QListIterator<QDeclarativeAction> actionListIterator(actionList); + while(actionListIterator.hasNext()) { + const QDeclarativeAction &action = actionListIterator.next(); + QDeclarativeSimpleAction simpleAction(action); + action.property.write(action.toValue); + if (action.toBinding) { + QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(simpleAction.property()); + if (oldBinding) + QDeclarativePropertyPrivate::setBinding(simpleAction.property(), 0); + QDeclarativePropertyPrivate::setBinding(simpleAction.property(), action.toBinding, QDeclarativePropertyPrivate::DontRemoveBinding); + } + + simpleActionList.append(simpleAction); + } + + d->revertList.append(simpleActionList); + } +} + +QVariant QDeclarativeState::valueInRevertList(QObject *target, const QByteArray &name) const +{ + Q_D(const QDeclarativeState); + + if (isStateActive()) { + QListIterator<QDeclarativeSimpleAction> revertListIterator(d->revertList); + + while (revertListIterator.hasNext()) { + const QDeclarativeSimpleAction &simpleAction = revertListIterator.next(); + if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty().toUtf8() == name) + return simpleAction.value(); + } + } + + return QVariant(); +} + +QDeclarativeAbstractBinding *QDeclarativeState::bindingInRevertList(QObject *target, const QByteArray &name) const +{ + Q_D(const QDeclarativeState); + + if (isStateActive()) { + QListIterator<QDeclarativeSimpleAction> revertListIterator(d->revertList); + + while (revertListIterator.hasNext()) { + const QDeclarativeSimpleAction &simpleAction = revertListIterator.next(); + if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty().toUtf8() == name) + return simpleAction.binding(); + } + } + + return 0; +} + +bool QDeclarativeState::isStateActive() const +{ + return stateGroup() && stateGroup()->state() == name(); +} + void QDeclarativeState::apply(QDeclarativeStateGroup *group, QDeclarativeTransition *trans, QDeclarativeState *revert) { Q_D(QDeclarativeState); @@ -403,13 +589,13 @@ void QDeclarativeState::apply(QDeclarativeStateGroup *group, QDeclarativeTransit continue; bool found = false; for (int jj = 0; jj < d->revertList.count(); ++jj) { - QDeclarativeActionEvent *event = d->revertList.at(jj).event; + QDeclarativeActionEvent *event = d->revertList.at(jj).event(); if (event && event->typeName() == action.event->typeName()) { if (action.event->override(event)) { found = true; - if (action.event != d->revertList.at(jj).event && action.event->needsCopy()) { - action.event->copyOriginals(d->revertList.at(jj).event); + if (action.event != d->revertList.at(jj).event() && action.event->needsCopy()) { + action.event->copyOriginals(d->revertList.at(jj).event()); QDeclarativeSimpleAction r(action); additionalReverts << r; @@ -434,9 +620,9 @@ void QDeclarativeState::apply(QDeclarativeStateGroup *group, QDeclarativeTransit action.fromBinding = QDeclarativePropertyPrivate::binding(action.property); for (int jj = 0; jj < d->revertList.count(); ++jj) { - if (d->revertList.at(jj).property == action.property) { + if (d->revertList.at(jj).property() == action.property) { found = true; - if (d->revertList.at(jj).binding != action.fromBinding) { + if (d->revertList.at(jj).binding() != action.fromBinding) { action.deleteFromBinding(); } break; @@ -445,7 +631,7 @@ void QDeclarativeState::apply(QDeclarativeStateGroup *group, QDeclarativeTransit if (!found) { if (!action.restore) { - action.deleteFromBinding(); + action.deleteFromBinding();; } else { // Only need to revert the applyList action if the previous // state doesn't have a higher priority revert already @@ -460,8 +646,8 @@ void QDeclarativeState::apply(QDeclarativeStateGroup *group, QDeclarativeTransit // into this state need to be translated into apply actions for (int ii = 0; ii < d->revertList.count(); ++ii) { bool found = false; - if (d->revertList.at(ii).event) { - QDeclarativeActionEvent *event = d->revertList.at(ii).event; + if (d->revertList.at(ii).event()) { + QDeclarativeActionEvent *event = d->revertList.at(ii).event(); if (!event->isReversable()) continue; for (int jj = 0; !found && jj < applyList.count(); ++jj) { @@ -474,31 +660,31 @@ void QDeclarativeState::apply(QDeclarativeStateGroup *group, QDeclarativeTransit } else { for (int jj = 0; !found && jj < applyList.count(); ++jj) { const QDeclarativeAction &action = applyList.at(jj); - if (action.property == d->revertList.at(ii).property) + if (action.property == d->revertList.at(ii).property()) found = true; } } if (!found) { - QVariant cur = d->revertList.at(ii).property.read(); + QVariant cur = d->revertList.at(ii).property().read(); QDeclarativeAbstractBinding *delBinding = - QDeclarativePropertyPrivate::setBinding(d->revertList.at(ii).property, 0); + QDeclarativePropertyPrivate::setBinding(d->revertList.at(ii).property(), 0); if (delBinding) delBinding->destroy(); QDeclarativeAction a; - a.property = d->revertList.at(ii).property; + a.property = d->revertList.at(ii).property(); a.fromValue = cur; - a.toValue = d->revertList.at(ii).value; - a.toBinding = d->revertList.at(ii).binding; - a.specifiedObject = d->revertList.at(ii).specifiedObject; - a.specifiedProperty = d->revertList.at(ii).specifiedProperty; - a.event = d->revertList.at(ii).event; - a.reverseEvent = d->revertList.at(ii).reverseEvent; + a.toValue = d->revertList.at(ii).value(); + a.toBinding = d->revertList.at(ii).binding(); + a.specifiedObject = d->revertList.at(ii).specifiedObject(); + a.specifiedProperty = d->revertList.at(ii).specifiedProperty(); + a.event = d->revertList.at(ii).event(); + a.reverseEvent = d->revertList.at(ii).reverseEvent(); if (a.event && a.event->isRewindable()) a.event->saveCurrentValues(); applyList << a; // Store these special reverts in the reverting list - d->reverting << d->revertList.at(ii).property; + d->reverting << d->revertList.at(ii).property(); } } // All the local reverts now become part of the ongoing revertList @@ -526,4 +712,16 @@ QDeclarativeStateOperation::ActionList QDeclarativeStateOperation::actions() return ActionList(); } +QDeclarativeState *QDeclarativeStateOperation::state() const +{ + Q_D(const QDeclarativeStateOperation); + return d->m_state; +} + +void QDeclarativeStateOperation::setState(QDeclarativeState *state) +{ + Q_D(QDeclarativeStateOperation); + d->m_state = state; +} + QT_END_NAMESPACE diff --git a/src/declarative/util/qdeclarativestate_p.h b/src/declarative/util/qdeclarativestate_p.h index 2e2ce7b..a0ab11b 100644 --- a/src/declarative/util/qdeclarativestate_p.h +++ b/src/declarative/util/qdeclarativestate_p.h @@ -111,6 +111,8 @@ public: //### rename to QDeclarativeStateChange? class QDeclarativeStateGroup; +class QDeclarativeState; +class QDeclarativeStateOperationPrivate; class Q_DECLARATIVE_EXPORT QDeclarativeStateOperation : public QObject { Q_OBJECT @@ -121,8 +123,15 @@ public: virtual ActionList actions(); + QDeclarativeState *state() const; + void setState(QDeclarativeState *state); + protected: QDeclarativeStateOperation(QObjectPrivate &dd, QObject *parent = 0); + +private: + Q_DECLARE_PRIVATE(QDeclarativeStateOperation) + Q_DISABLE_COPY(QDeclarativeStateOperation) }; typedef QDeclarativeStateOperation::ActionList QDeclarativeStateActions; @@ -169,6 +178,18 @@ public: QDeclarativeStateGroup *stateGroup() const; void setStateGroup(QDeclarativeStateGroup *); + bool containsPropertyInRevertList(QObject *target, const QByteArray &name) const; + bool changeValueInRevertList(QObject *target, const QByteArray &name, const QVariant &revertValue); + bool changeBindingInRevertList(QObject *target, const QByteArray &name, QDeclarativeAbstractBinding *binding); + bool removeEntryFromRevertList(QObject *target, const QByteArray &name); + void addEntryToRevertList(const QDeclarativeAction &action); + void removeAllEntriesFromRevertList(QObject *target); + void addEntriesToRevertList(const QList<QDeclarativeAction> &actions); + QVariant valueInRevertList(QObject *target, const QByteArray &name) const; + QDeclarativeAbstractBinding *bindingInRevertList(QObject *target, const QByteArray &name) const; + + bool isStateActive() const; + Q_SIGNALS: void completed(); diff --git a/src/declarative/util/qdeclarativestate_p_p.h b/src/declarative/util/qdeclarativestate_p_p.h index 2ef9bb0..4fd8f21 100644 --- a/src/declarative/util/qdeclarativestate_p_p.h +++ b/src/declarative/util/qdeclarativestate_p_p.h @@ -61,6 +61,8 @@ #include <private/qdeclarativeproperty_p.h> #include <private/qdeclarativeguard_p.h> +#include <private/qdeclarativebinding_p.h> + #include <private/qobject_p.h> QT_BEGIN_NAMESPACE @@ -69,30 +71,123 @@ class QDeclarativeSimpleAction { public: enum State { StartState, EndState }; - QDeclarativeSimpleAction(const QDeclarativeAction &a, State state = StartState) + QDeclarativeSimpleAction(const QDeclarativeAction &a, State state = StartState) { - property = a.property; - specifiedObject = a.specifiedObject; - specifiedProperty = a.specifiedProperty; - event = a.event; + m_property = a.property; + m_specifiedObject = a.specifiedObject; + m_specifiedProperty = a.specifiedProperty; + m_event = a.event; if (state == StartState) { - value = a.fromValue; - binding = QDeclarativePropertyPrivate::binding(property); - reverseEvent = true; + m_value = a.fromValue; + if (QDeclarativePropertyPrivate::binding(m_property)) { + m_binding = QDeclarativeAbstractBinding::getPointer(QDeclarativePropertyPrivate::binding(m_property)); + } + m_reverseEvent = true; } else { - value = a.toValue; - binding = a.toBinding; - reverseEvent = false; + m_value = a.toValue; + m_binding = QDeclarativeAbstractBinding::getPointer(a.toBinding); + m_reverseEvent = false; } } - QDeclarativeProperty property; - QVariant value; - QDeclarativeAbstractBinding *binding; - QObject *specifiedObject; - QString specifiedProperty; - QDeclarativeActionEvent *event; - bool reverseEvent; + ~QDeclarativeSimpleAction() + { + } + + QDeclarativeSimpleAction(const QDeclarativeSimpleAction &other) + : m_property(other.m_property), + m_value(other.m_value), + m_binding(QDeclarativeAbstractBinding::getPointer(other.binding())), + m_specifiedObject(other.m_specifiedObject), + m_specifiedProperty(other.m_specifiedProperty), + m_event(other.m_event), + m_reverseEvent(other.m_reverseEvent) + { + } + + QDeclarativeSimpleAction &operator =(const QDeclarativeSimpleAction &other) + { + m_property = other.m_property; + m_value = other.m_value; + m_binding = QDeclarativeAbstractBinding::getPointer(other.binding()); + m_specifiedObject = other.m_specifiedObject; + m_specifiedProperty = other.m_specifiedProperty; + m_event = other.m_event; + m_reverseEvent = other.m_reverseEvent; + + return *this; + } + + void setProperty(const QDeclarativeProperty &property) + { + m_property = property; + } + + const QDeclarativeProperty &property() const + { + return m_property; + } + + void setValue(const QVariant &value) + { + m_value = value; + } + + const QVariant &value() const + { + return m_value; + } + + void setBinding(QDeclarativeAbstractBinding *binding) + { + m_binding = QDeclarativeAbstractBinding::getPointer(binding); + } + + QDeclarativeAbstractBinding *binding() const + { + return m_binding.data(); + } + + QObject *specifiedObject() const + { + return m_specifiedObject; + } + + const QString &specifiedProperty() const + { + return m_specifiedProperty; + } + + QDeclarativeActionEvent *event() const + { + return m_event; + } + + bool reverseEvent() const + { + return m_reverseEvent; + } + +private: + QDeclarativeProperty m_property; + QVariant m_value; + QDeclarativeAbstractBinding::Pointer m_binding; + QObject *m_specifiedObject; + QString m_specifiedProperty; + QDeclarativeActionEvent *m_event; + bool m_reverseEvent; +}; + +class QDeclarativeStateOperationPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QDeclarativeStateOperation) + +public: + + QDeclarativeStateOperationPrivate() + : m_state(0) {} + + QDeclarativeState *m_state; }; class QDeclarativeStatePrivate : public QObjectPrivate @@ -122,10 +217,14 @@ public: static void operations_append(QDeclarativeListProperty<QDeclarativeStateOperation> *prop, QDeclarativeStateOperation *op) { QList<OperationGuard> *list = static_cast<QList<OperationGuard> *>(prop->data); + op->setState(qobject_cast<QDeclarativeState*>(prop->object)); list->append(OperationGuard(op, list)); } static void operations_clear(QDeclarativeListProperty<QDeclarativeStateOperation> *prop) { QList<OperationGuard> *list = static_cast<QList<OperationGuard> *>(prop->data); + QMutableListIterator<OperationGuard> listIterator(*list); + while(listIterator.hasNext()) + listIterator.next()->setState(0); list->clear(); } static int operations_count(QDeclarativeListProperty<QDeclarativeStateOperation> *prop) { diff --git a/src/declarative/util/qdeclarativestateoperations.cpp b/src/declarative/util/qdeclarativestateoperations.cpp index a78fc54..8cb813c 100644 --- a/src/declarative/util/qdeclarativestateoperations.cpp +++ b/src/declarative/util/qdeclarativestateoperations.cpp @@ -52,6 +52,7 @@ #include "private/qdeclarativecontext_p.h" #include "private/qdeclarativeproperty_p.h" #include "private/qdeclarativebinding_p.h" +#include "private/qdeclarativestate_p_p.h" #include <QtCore/qdebug.h> #include <QtGui/qgraphicsitem.h> @@ -61,7 +62,7 @@ QT_BEGIN_NAMESPACE -class QDeclarativeParentChangePrivate : public QObjectPrivate +class QDeclarativeParentChangePrivate : public QDeclarativeStateOperationPrivate { Q_DECLARE_PUBLIC(QDeclarativeParentChange) public: @@ -580,7 +581,7 @@ void QDeclarativeParentChange::rewind() d->doChange(d->rewindParent, d->rewindStackBefore); } -class QDeclarativeStateChangeScriptPrivate : public QObjectPrivate +class QDeclarativeStateChangeScriptPrivate : public QDeclarativeStateOperationPrivate { public: QDeclarativeStateChangeScriptPrivate() {} @@ -965,7 +966,7 @@ void QDeclarativeAnchorSet::resetCenterIn() } -class QDeclarativeAnchorChangesPrivate : public QObjectPrivate +class QDeclarativeAnchorChangesPrivate : public QDeclarativeStateOperationPrivate { public: QDeclarativeAnchorChangesPrivate() @@ -1030,6 +1031,11 @@ public: bool applyOrigVCenter; bool applyOrigBaseline; + QDeclarativeNullableValue<qreal> origWidth; + QDeclarativeNullableValue<qreal> origHeight; + qreal origX; + qreal origY; + QList<QDeclarativeAbstractBinding*> oldBindings; QDeclarativeProperty leftProp; @@ -1321,6 +1327,42 @@ void QDeclarativeAnchorChanges::reverse(Reason reason) QDeclarativePropertyPrivate::setBinding(d->vCenterProp, d->origVCenterBinding); if (d->origBaselineBinding) QDeclarativePropertyPrivate::setBinding(d->baselineProp, d->origBaselineBinding); + + //restore any absolute geometry changed by the state's anchors + QDeclarativeAnchors::Anchors stateVAnchors = d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::Vertical_Mask; + QDeclarativeAnchors::Anchors origVAnchors = targetPrivate->anchors()->usedAnchors() & QDeclarativeAnchors::Vertical_Mask; + QDeclarativeAnchors::Anchors stateHAnchors = d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::Horizontal_Mask; + QDeclarativeAnchors::Anchors origHAnchors = targetPrivate->anchors()->usedAnchors() & QDeclarativeAnchors::Horizontal_Mask; + + bool stateSetWidth = (stateHAnchors && + stateHAnchors != QDeclarativeAnchors::LeftAnchor && + stateHAnchors != QDeclarativeAnchors::RightAnchor && + stateHAnchors != QDeclarativeAnchors::HCenterAnchor); + bool origSetWidth = (origHAnchors && + origHAnchors != QDeclarativeAnchors::LeftAnchor && + origHAnchors != QDeclarativeAnchors::RightAnchor && + origHAnchors != QDeclarativeAnchors::HCenterAnchor); + if (d->origWidth.isValid() && stateSetWidth && !origSetWidth) + d->target->setWidth(d->origWidth.value); + + bool stateSetHeight = (stateVAnchors && + stateVAnchors != QDeclarativeAnchors::TopAnchor && + stateVAnchors != QDeclarativeAnchors::BottomAnchor && + stateVAnchors != QDeclarativeAnchors::VCenterAnchor && + stateVAnchors != QDeclarativeAnchors::BaselineAnchor); + bool origSetHeight = (origVAnchors && + origVAnchors != QDeclarativeAnchors::TopAnchor && + origVAnchors != QDeclarativeAnchors::BottomAnchor && + origVAnchors != QDeclarativeAnchors::VCenterAnchor && + origVAnchors != QDeclarativeAnchors::BaselineAnchor); + if (d->origHeight.isValid() && stateSetHeight && !origSetHeight) + d->target->setHeight(d->origHeight.value); + + if (stateHAnchors && !origHAnchors) + d->target->setX(d->origX); + + if (stateVAnchors && !origVAnchors) + d->target->setY(d->origY); } QString QDeclarativeAnchorChanges::typeName() const @@ -1383,6 +1425,14 @@ void QDeclarativeAnchorChanges::saveOriginals() d->origVCenterBinding = QDeclarativePropertyPrivate::binding(d->vCenterProp); d->origBaselineBinding = QDeclarativePropertyPrivate::binding(d->baselineProp); + QDeclarativeItemPrivate *targetPrivate = QDeclarativeItemPrivate::get(d->target); + if (targetPrivate->widthValid) + d->origWidth = d->target->width(); + if (targetPrivate->heightValid) + d->origHeight = d->target->height(); + d->origX = d->target->x(); + d->origY = d->target->y(); + d->applyOrigLeft = d->applyOrigRight = d->applyOrigHCenter = d->applyOrigTop = d->applyOrigBottom = d->applyOrigVCenter = d->applyOrigBaseline = false; @@ -1415,6 +1465,11 @@ void QDeclarativeAnchorChanges::copyOriginals(QDeclarativeActionEvent *other) d->origVCenterBinding = acp->origVCenterBinding; d->origBaselineBinding = acp->origBaselineBinding; + d->origWidth = acp->origWidth; + d->origHeight = acp->origHeight; + d->origX = acp->origX; + d->origY = acp->origY; + d->oldBindings.clear(); d->oldBindings << acp->leftBinding << acp->rightBinding << acp->hCenterBinding << acp->topBinding << acp->bottomBinding << acp->baselineBinding; diff --git a/src/declarative/util/qdeclarativetransitionmanager.cpp b/src/declarative/util/qdeclarativetransitionmanager.cpp index d82c4bb..89b0044 100644 --- a/src/declarative/util/qdeclarativetransitionmanager.cpp +++ b/src/declarative/util/qdeclarativetransitionmanager.cpp @@ -86,8 +86,8 @@ void QDeclarativeTransitionManager::complete() d->applyBindings(); for (int ii = 0; ii < d->completeList.count(); ++ii) { - const QDeclarativeProperty &prop = d->completeList.at(ii).property; - prop.write(d->completeList.at(ii).value); + const QDeclarativeProperty &prop = d->completeList.at(ii).property(); + prop.write(d->completeList.at(ii).value()); } d->completeList.clear(); |