src/declarative/graphicsitems/qdeclarativeitem.cpp
changeset 33 3e2da88830cd
parent 30 5dc02b23752f
child 37 758a864f9613
--- a/src/declarative/graphicsitems/qdeclarativeitem.cpp	Tue Jul 06 15:10:48 2010 +0300
+++ b/src/declarative/graphicsitems/qdeclarativeitem.cpp	Wed Aug 18 10:37:55 2010 +0300
@@ -63,12 +63,10 @@
 #include <QtGui/qgraphicstransform.h>
 #include <qlistmodelinterface_p.h>
 
+#include <float.h>
+
 QT_BEGIN_NAMESPACE
 
-#ifndef FLT_MAX
-#define FLT_MAX 1E+37
-#endif
-
 /*!
     \qmlclass Transform QGraphicsTransform
     \since 4.7
@@ -86,20 +84,22 @@
     The Transform elements let you create and control advanced transformations that can be configured
     independently using specialized properties.
 
-    You can assign any number of Transform elements to an Item. Each Transform is applied in order,
-    one at a time, to the Item it's assigned to.
+    You can assign any number of Transform elements to an \l Item. Each Transform is applied in order,
+    one at a time.
 */
 
 /*!
-    \qmlclass Translate QGraphicsTranslate
+    \qmlclass Translate QDeclarativeTranslate
     \since 4.7
     \brief The Translate object provides a way to move an Item without changing its x or y properties.
 
     The Translate object provides independent control over position in addition to the Item's x and y properties.
 
-    The following example moves the Y axis of the Rectangles while still allowing the Row element
+    The following example moves the Y axis of the \l Rectangle elements while still allowing the \l Row element
     to lay the items out as if they had not been transformed:
     \qml
+    import Qt 4.7
+
     Row {
         Rectangle {
             width: 100; height: 100
@@ -113,6 +113,8 @@
         }
     }
     \endqml
+
+    \image translate.png
 */
 
 /*!
@@ -130,9 +132,9 @@
 /*!
     \qmlclass Scale QGraphicsScale
     \since 4.7
-    \brief The Scale object provides a way to scale an Item.
-
-    The Scale object gives more control over scaling than using Item's scale property. Specifically,
+    \brief The Scale element provides a way to scale an Item.
+
+    The Scale element gives more control over scaling than using \l Item's \l{Item::scale}{scale} property. Specifically,
     it allows a different scale for the x and y axes, and allows the scale to be relative to an
     arbitrary point.
 
@@ -144,6 +146,8 @@
         transform: Scale { origin.x: 25; origin.y: 25; xScale: 3}
     }
     \endqml
+
+    \sa Rotation, Translate
 */
 
 /*!
@@ -171,7 +175,7 @@
     \since 4.7
     \brief The Rotation object provides a way to rotate an Item.
 
-    The Rotation object gives more control over rotation than using Item's rotation property.
+    The Rotation object gives more control over rotation than using \l Item's \l{Item::rotation}{rotation} property.
     Specifically, it allows (z axis) rotation to be relative to an arbitrary point.
 
     The following example rotates a Rectangle around its interior point 25, 25:
@@ -190,6 +194,8 @@
     \snippet doc/src/snippets/declarative/rotation.qml 0
 
     \image axisrotation.png
+
+    \sa {declarative/ui-components/dialcontrol}{Dial Control example}, {declarative/toys/clocks}{Clocks example}
 */
 
 /*!
@@ -225,9 +231,10 @@
     \brief The QDeclarativeContents class gives access to the height and width of an item's contents.
 
 */
-
-QDeclarativeContents::QDeclarativeContents() : m_x(0), m_y(0), m_width(0), m_height(0)
+QDeclarativeContents::QDeclarativeContents(QDeclarativeItem *item) : m_item(item), m_x(0), m_y(0), m_width(0), m_height(0)
 {
+    //### optimize
+    connect(this, SIGNAL(rectChanged(QRectF)), m_item, SIGNAL(childrenRectChanged(QRectF)));
 }
 
 QDeclarativeContents::~QDeclarativeContents()
@@ -322,12 +329,8 @@
         emit rectChanged(rectF());
 }
 
-void QDeclarativeContents::setItem(QDeclarativeItem *item)
+void QDeclarativeContents::complete()
 {
-    m_item = item;
-    //### optimize
-    connect(this, SIGNAL(rectChanged(QRectF)), m_item, SIGNAL(childrenRectChanged(QRectF)));
-
     QList<QGraphicsItem *> children = m_item->childItems();
     for (int i = 0; i < children.count(); ++i) {
         QDeclarativeItem *child = qobject_cast<QDeclarativeItem *>(children.at(i));
@@ -337,33 +340,31 @@
         //###what about changes to visibility?
     }
 
-    //### defer until componentComplete
-    calcHeight();
-    calcWidth();
+    calcGeometry();
 }
 
 void QDeclarativeContents::itemGeometryChanged(QDeclarativeItem *changed, const QRectF &newGeometry, const QRectF &oldGeometry)
 {
-    if (newGeometry.width() != oldGeometry.width())
-        calcWidth(changed);
-    if (newGeometry.height() != oldGeometry.height())
-        calcHeight(changed);
+    Q_UNUSED(changed)
+    //### we can only pass changed if the left edge has moved left, or the right edge has moved right
+    if (newGeometry.width() != oldGeometry.width() || newGeometry.x() != oldGeometry.x())
+        calcWidth(/*changed*/);
+    if (newGeometry.height() != oldGeometry.height() || newGeometry.y() != oldGeometry.y())
+        calcHeight(/*changed*/);
 }
 
 void QDeclarativeContents::itemDestroyed(QDeclarativeItem *item)
 {
     if (item)
         QDeclarativeItemPrivate::get(item)->removeItemChangeListener(this, QDeclarativeItemPrivate::Geometry | QDeclarativeItemPrivate::Destroyed);
-    calcWidth();
-    calcHeight();
+    calcGeometry();
 }
 
 void QDeclarativeContents::childRemoved(QDeclarativeItem *item)
 {
     if (item)
         QDeclarativeItemPrivate::get(item)->removeItemChangeListener(this, QDeclarativeItemPrivate::Geometry | QDeclarativeItemPrivate::Destroyed);
-    calcWidth();
-    calcHeight();
+    calcGeometry();
 }
 
 void QDeclarativeContents::childAdded(QDeclarativeItem *item)
@@ -417,7 +418,7 @@
 
 
 /*!
-    \qmlclass KeyNavigation
+    \qmlclass KeyNavigation QDeclarativeKeyNavigationAttached
     \since 4.7
     \brief The KeyNavigation attached property supports key navigation by arrow keys.
 
@@ -711,7 +712,7 @@
 }
 
 /*!
-    \qmlclass Keys
+    \qmlclass Keys QDeclarativeKeysAttached
     \since 4.7
     \brief The Keys attached property provides key handling to Items.
 
@@ -722,7 +723,7 @@
     The signal properties have a \l KeyEvent parameter, named
     \e event which contains details of the event.  If a key is
     handled \e event.accepted should be set to true to prevent the
-    event from propagating up the item heirarchy.
+    event from propagating up the item hierarchy.
 
     \code
     Item {
@@ -1385,26 +1386,6 @@
 */
 
 /*!
-    \property QDeclarativeItem::baseline
-    \internal
-*/
-
-/*!
-    \property QDeclarativeItem::focus
-    \internal
-*/
-
-/*!
-    \property QDeclarativeItem::wantsFocus
-    \internal
-*/
-
-/*!
-    \property QDeclarativeItem::transformOrigin
-    \internal
-*/
-
-/*!
     \fn void QDeclarativeItem::childrenRectChanged(const QRectF &)
     \internal
 */
@@ -1449,7 +1430,7 @@
 */
 
 /*!
-    \fn void QDeclarativeItem::wantsFocusChanged(bool)
+    \fn void QDeclarativeItem::activeFocusChanged(bool)
     \internal
 */
 
@@ -1531,6 +1512,9 @@
     \endqml
 
     The default transform origin is \c Item.Center.
+
+    To set an arbitrary transform origin point use the \l Scale or \l Rotation
+    transform elements.
 */
 
 /*!
@@ -1598,7 +1582,7 @@
     Returns true if construction of the QML component is complete; otherwise
     returns false.
 
-    It is often desireable to delay some processing until the component is
+    It is often desirable to delay some processing until the component is
     completed.
 
     \sa componentComplete()
@@ -1606,7 +1590,7 @@
 bool QDeclarativeItem::isComponentComplete() const
 {
     Q_D(const QDeclarativeItem);
-    return d->_componentComplete;
+    return d->componentComplete;
 }
 
 void QDeclarativeItemPrivate::data_append(QDeclarativeListProperty<QObject> *prop, QObject *o)
@@ -1629,7 +1613,7 @@
 
 QObject *QDeclarativeItemPrivate::resources_at(QDeclarativeListProperty<QObject> *prop, int index)
 {
-    QObjectList children = prop->object->children();
+    const QObjectList children = prop->object->children();
     if (index < children.count())
         return children.at(index);
     else
@@ -1746,8 +1730,9 @@
 {
     Q_D(QDeclarativeItem);
     if (!d->_contents) {
-        d->_contents = new QDeclarativeContents;
-        d->_contents->setItem(this);
+        d->_contents = new QDeclarativeContents(this);
+        if (d->componentComplete)
+            d->_contents->complete();
     }
     return d->_contents->rectF();
 }
@@ -1966,6 +1951,9 @@
     return v;
 }
 
+/*!
+  \internal
+ */
 void QDeclarativeItem::keyPressPreHandler(QKeyEvent *event)
 {
     Q_D(QDeclarativeItem);
@@ -1976,6 +1964,9 @@
     d->doneEventPreHandler = true;
 }
 
+/*!
+  \internal
+ */
 void QDeclarativeItem::keyReleasePreHandler(QKeyEvent *event)
 {
     Q_D(QDeclarativeItem);
@@ -1986,6 +1977,9 @@
     d->doneEventPreHandler = true;
 }
 
+/*!
+  \internal
+ */
 void QDeclarativeItem::inputMethodPreHandler(QInputMethodEvent *event)
 {
     Q_D(QDeclarativeItem);
@@ -1996,7 +1990,6 @@
     d->doneEventPreHandler = true;
 }
 
-
 /*!
     \internal
 */
@@ -2055,20 +2048,6 @@
 }
 
 /*!
-  \qmlproperty AnchorLine Item::top
-  \qmlproperty AnchorLine Item::bottom
-  \qmlproperty AnchorLine Item::left
-  \qmlproperty AnchorLine Item::right
-  \qmlproperty AnchorLine Item::horizontalCenter
-  \qmlproperty AnchorLine Item::verticalCenter
-  \qmlproperty AnchorLine Item::baseline
-
-  The anchor lines of the item.
-
-  For more information see \l {anchor-layout}{Anchor Layouts}.
-*/
-
-/*!
   \qmlproperty AnchorLine Item::anchors.top
   \qmlproperty AnchorLine Item::anchors.bottom
   \qmlproperty AnchorLine Item::anchors.left
@@ -2093,7 +2072,7 @@
   relationship with other items.
 
   Margins apply to top, bottom, left, right, and fill anchors.
-  The margins property can be used to set all of the various margins at once, to the same value.
+  The \c anchors.margins property can be used to set all of the various margins at once, to the same value.
 
   Offsets apply for horizontal center, vertical center, and baseline anchors.
 
@@ -2128,10 +2107,12 @@
   \endqml
   \endtable
 
-  anchors.fill provides a convenient way for one item to have the
+  \c anchors.fill provides a convenient way for one item to have the
   same geometry as another item, and is equivalent to connecting all
   four directional anchors.
 
+  To clear an anchor value, set it to \c undefined.
+
   \note You can only anchor an item to siblings or a parent.
 
   For more information see \l {anchor-layout}{Anchor Layouts}.
@@ -2141,7 +2122,7 @@
   \property QDeclarativeItem::baselineOffset
   \brief The position of the item's baseline in local coordinates.
 
-  The baseline of a Text item is the imaginary line on which the text
+  The baseline of a \l Text item is the imaginary line on which the text
   sits. Controls containing text usually set their baseline to the
   baseline of their text.
 
@@ -2150,19 +2131,19 @@
 qreal QDeclarativeItem::baselineOffset() const
 {
     Q_D(const QDeclarativeItem);
-    if (!d->_baselineOffset.isValid()) {
+    if (!d->baselineOffset.isValid()) {
         return 0.0;
     } else
-        return d->_baselineOffset;
+        return d->baselineOffset;
 }
 
 void QDeclarativeItem::setBaselineOffset(qreal offset)
 {
     Q_D(QDeclarativeItem);
-    if (offset == d->_baselineOffset)
+    if (offset == d->baselineOffset)
         return;
 
-    d->_baselineOffset = offset;
+    d->baselineOffset = offset;
 
     for(int ii = 0; ii < d->changeListeners.count(); ++ii) {
         const QDeclarativeItemPrivate::ChangeListener &change = d->changeListeners.at(ii);
@@ -2198,6 +2179,8 @@
   }
   \endqml
   \endtable
+
+  \sa transform, Rotation
 */
 
 /*!
@@ -2234,6 +2217,8 @@
   }
   \endqml
   \endtable
+
+  \sa transform, Scale
 */
 
 /*!
@@ -2291,7 +2276,7 @@
 bool QDeclarativeItem::keepMouseGrab() const
 {
     Q_D(const QDeclarativeItem);
-    return d->_keepMouse;
+    return d->keepMouse;
 }
 
 /*!
@@ -2315,7 +2300,7 @@
 void QDeclarativeItem::setKeepMouseGrab(bool keep)
 {
     Q_D(QDeclarativeItem);
-    d->_keepMouse = keep;
+    d->keepMouse = keep;
 }
 
 /*!
@@ -2371,12 +2356,12 @@
 }
 
 /*!
-    \qmlmethod Item::forceFocus()
-
-    Force the focus on the item.
-    This method sets the focus on the item and makes sure that all the focus scopes higher in the object hierarchy are given focus.
+    \qmlmethod Item::forceActiveFocus()
+
+    Force active focus on the item.
+    This method sets focus on the item and makes sure that all the focus scopes higher in the object hierarchy are also given focus.
 */
-void QDeclarativeItem::forceFocus()
+void QDeclarativeItem::forceActiveFocus()
 {
     setFocus(true);
     QGraphicsItem *parent = parentItem();
@@ -2387,10 +2372,45 @@
     }
 }
 
+
+/*!
+  \qmlmethod Item::childAt(real x, real y)
+
+  Returns the visible child item at point (\a x, \a y), which is in this
+  item's coordinate system, or \c null if there is no such item.
+  */
+QDeclarativeItem *QDeclarativeItem::childAt(qreal x, qreal y) const
+{
+    const QList<QGraphicsItem *> children = childItems();
+    for (int i = children.count()-1; i >= 0; --i) {
+        if (QDeclarativeItem *child = qobject_cast<QDeclarativeItem *>(children.at(i))) {
+            if (child->isVisible() && child->x() <= x
+                && child->x() + child->width() >= x
+                && child->y() <= y
+                && child->y() + child->height() >= y)
+                return child;
+        }
+    }
+    return 0;
+}
+
 void QDeclarativeItemPrivate::focusChanged(bool flag)
 {
     Q_Q(QDeclarativeItem);
-    emit q->focusChanged(flag);
+    if (!(flags & QGraphicsItem::ItemIsFocusScope) && parent)
+        emit q->activeFocusChanged(flag);   //see also QDeclarativeItemPrivate::subFocusItemChange()
+
+    bool inScope = false;
+    QGraphicsItem *p = parent;
+    while (p) {
+        if (p->flags() & QGraphicsItem::ItemIsFocusScope) {
+            inScope = true;
+            break;
+        }
+        p = p->parentItem();
+    }
+    if (!inScope)
+        emit q->focusChanged(flag);
 }
 
 /*! \internal */
@@ -2473,7 +2493,7 @@
   \qmlproperty bool Item::clip
   This property holds whether clipping is enabled.
 
-  if clipping is enabled, an item will clip its own painting, as well
+  If clipping is enabled, an item will clip its own painting, as well
   as the painting of its children, to its bounding rectangle.
 
   Non-rectangular clipping regions are not supported for performance reasons.
@@ -2513,11 +2533,6 @@
   \sa {qmlstates}{States}
 */
 
-/*!
-  \property QDeclarativeItem::state
-  \internal
-*/
-
 /*! \internal */
 QString QDeclarativeItemPrivate::state() const
 {
@@ -2540,11 +2555,6 @@
   For more information see \l Transform.
 */
 
-/*!
-  \property QDeclarativeItem::transform
-  \internal
-*/
-
 /*! \internal */
 QDeclarativeListProperty<QGraphicsTransform> QDeclarativeItem::transform()
 {
@@ -2564,7 +2574,7 @@
 void QDeclarativeItem::classBegin()
 {
     Q_D(QDeclarativeItem);
-    d->_componentComplete = false;
+    d->componentComplete = false;
     if (d->_stateGroup)
         d->_stateGroup->classBegin();
     if (d->_anchors)
@@ -2575,14 +2585,14 @@
   \internal
 
   componentComplete() is called when all items in the component
-  have been constructed.  It is often desireable to delay some
+  have been constructed.  It is often desirable to delay some
   processing until the component is complete an all bindings in the
   component have been resolved.
 */
 void QDeclarativeItem::componentComplete()
 {
     Q_D(QDeclarativeItem);
-    d->_componentComplete = true;
+    d->componentComplete = true;
     if (d->_stateGroup)
         d->_stateGroup->componentComplete();
     if (d->_anchors) {
@@ -2591,6 +2601,8 @@
     }
     if (d->keyHandler)
         d->keyHandler->componentComplete();
+    if (d->_contents)
+        d->_contents->complete();
 }
 
 QDeclarativeStateGroup *QDeclarativeItemPrivate::_states()
@@ -2598,7 +2610,7 @@
     Q_Q(QDeclarativeItem);
     if (!_stateGroup) {
         _stateGroup = new QDeclarativeStateGroup;
-        if (!_componentComplete)
+        if (!componentComplete)
             _stateGroup->classBegin();
         QObject::connect(_stateGroup, SIGNAL(stateChanged(QString)),
                          q, SIGNAL(stateChanged(QString)));
@@ -2675,14 +2687,14 @@
 
         if (event->type() == QEvent::FocusIn ||
             event->type() == QEvent::FocusOut) {
-            d->focusChanged(hasFocus());
+            d->focusChanged(hasActiveFocus());
         }
         return rv;
     }
 }
 
 /*!
-    \reimp
+    \internal
 
     Note that unlike QGraphicsItems, QDeclarativeItem::itemChange() is \e not called
     during initial widget polishing. Items wishing to optimize start-up construction
@@ -2831,6 +2843,26 @@
 }
 
 /*!
+  \property QDeclarativeItem::focus
+  \internal
+*/
+
+/*!
+  \property QDeclarativeItem::transform
+  \internal
+*/
+
+/*!
+  \property QDeclarativeItem::transformOrigin
+  \internal
+*/
+
+/*!
+  \property QDeclarativeItem::activeFocus
+  \internal
+*/
+
+/*!
     \internal
     Return the width of the item
 */
@@ -3069,31 +3101,86 @@
 }
 
 /*!
-  \qmlproperty bool Item::wantsFocus
-
-  This property indicates whether the item has has an active focus request.
-
-  \sa {qmlfocus}{Keyboard Focus}
+  \qmlproperty bool Item::activeFocus
+
+  This property indicates whether the item has active focus.
+
+  An item with active focus will receive keyboard input,
+  or is a FocusScope ancestor of the item that will receive keyboard input.
+
+  Usually, activeFocus is gained by setting focus on an item and its enclosing
+  FocusScopes. In the following example \c input will have activeFocus.
+  \qml
+  Rectangle {
+      FocusScope {
+          focus: true
+          TextInput {
+              id: input
+              focus: true
+          }
+      }
+  }
+  \endqml
+
+  \sa focus, {qmlfocus}{Keyboard Focus}
 */
 
 /*! \internal */
-bool QDeclarativeItem::wantsFocus() const
+bool QDeclarativeItem::hasActiveFocus() const
 {
-    return focusItem() != 0;
+    Q_D(const QDeclarativeItem);
+    return focusItem() == this ||
+           (d->flags & QGraphicsItem::ItemIsFocusScope && focusItem() != 0) ||
+           (!parentItem() && focusItem() != 0);
 }
 
 /*!
   \qmlproperty bool Item::focus
-  This property indicates whether the item has keyboard input focus. Set this
-  property to true to request focus.
-
-  \sa {qmlfocus}{Keyboard Focus}
+  This property indicates whether the item has focus within the enclosing focus scope. If true, this item
+  will gain active focus when the enclosing focus scope gains active focus.
+  In the following example, \c input will be given active focus when \c scope gains active focus.
+  \qml
+  Rectangle {
+      FocusScope {
+          id: scope
+          TextInput {
+              id: input
+              focus: true
+          }
+      }
+  }
+  \endqml
+
+  For the purposes of this property, the top level item in the scene
+  is assumed to act like a focus scope, and to always have active focus
+  when the scene has focus. On a practical level, that means the following
+  QML will give active focus to \c input on startup.
+
+  \qml
+  Rectangle {
+      TextInput {
+          id: input
+          focus: true
+      }
+  }
+  \endqml
+
+  \sa activeFocus, {qmlfocus}{Keyboard Focus}
 */
 
 /*! \internal */
 bool QDeclarativeItem::hasFocus() const
 {
-    return QGraphicsItem::hasFocus();
+    Q_D(const QDeclarativeItem);
+    QGraphicsItem *p = d->parent;
+    while (p) {
+        if (p->flags() & QGraphicsItem::ItemIsFocusScope) {
+            return p->focusScopeItem() == this;
+        }
+        p = p->parentItem();
+    }
+
+    return hasActiveFocus() ? true : (!QGraphicsItem::parentItem() ? true : false);
 }
 
 /*! \internal */
@@ -3131,6 +3218,7 @@
     return QGraphicsObject::event(ev);
 }
 
+#ifndef QT_NO_DEBUG_STREAM
 QDebug operator<<(QDebug debug, QDeclarativeItem *item)
 {
     if (!item) {
@@ -3144,42 +3232,58 @@
           << ", z =" << item->zValue() << ')';
     return debug;
 }
-
-int QDeclarativeItemPrivate::consistentTime = -1;
-void QDeclarativeItemPrivate::setConsistentTime(int t)
+#endif
+
+qint64 QDeclarativeItemPrivate::consistentTime = -1;
+void QDeclarativeItemPrivate::setConsistentTime(qint64 t)
 {
     consistentTime = t;
 }
 
-QTime QDeclarativeItemPrivate::currentTime()
-{
-    if (consistentTime == -1)
-        return QTime::currentTime();
-    else
-        return QTime(0, 0).addMSecs(consistentTime);
-}
-
-void QDeclarativeItemPrivate::start(QTime &t)
-{
-    t = currentTime();
-}
-
-int QDeclarativeItemPrivate::elapsed(QTime &t)
+class QElapsedTimerConsistentTimeHack
 {
-    int n = t.msecsTo(currentTime());
-    if (n < 0)                                // passed midnight
-        n += 86400 * 1000;
-    return n;
+public:
+    void start() {
+        t1 = QDeclarativeItemPrivate::consistentTime;
+        t2 = 0;
+    }
+    qint64 elapsed() {
+        return QDeclarativeItemPrivate::consistentTime - t1;
+    }
+    qint64 restart() {
+        qint64 val = QDeclarativeItemPrivate::consistentTime - t1;
+        t1 = QDeclarativeItemPrivate::consistentTime;
+        t2 = 0;
+        return val;
+    }
+
+private:
+    qint64 t1;
+    qint64 t2;
+};
+
+void QDeclarativeItemPrivate::start(QElapsedTimer &t)
+{
+    if (QDeclarativeItemPrivate::consistentTime == -1)
+        t.start();
+    else
+        ((QElapsedTimerConsistentTimeHack*)&t)->start();
 }
 
-int QDeclarativeItemPrivate::restart(QTime &t)
+qint64 QDeclarativeItemPrivate::elapsed(QElapsedTimer &t)
 {
-    QTime time = currentTime();
-    int n = t.msecsTo(time);
-    if (n < 0)                                // passed midnight
-        n += 86400*1000;
-    t = time;
-    return n;
+    if (QDeclarativeItemPrivate::consistentTime == -1)
+        return t.elapsed();
+    else
+        return ((QElapsedTimerConsistentTimeHack*)&t)->elapsed();
+}
+
+qint64 QDeclarativeItemPrivate::restart(QElapsedTimer &t)
+{
+    if (QDeclarativeItemPrivate::consistentTime == -1)
+        return t.restart();
+    else
+        return ((QElapsedTimerConsistentTimeHack*)&t)->restart();
 }
 
 QT_END_NAMESPACE