diff options
Diffstat (limited to 'src/quick/items/qquickitem.cpp')
-rw-r--r-- | src/quick/items/qquickitem.cpp | 209 |
1 files changed, 171 insertions, 38 deletions
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 4ce9b15921..d0417c80f3 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -58,6 +58,7 @@ #include <QtCore/qdebug.h> #include <QtCore/qcoreevent.h> #include <QtCore/qnumeric.h> +#include <QtGui/qpa/qplatformtheme.h> #include <private/qqmlglobal_p.h> #include <private/qqmlengine_p.h> @@ -1365,7 +1366,7 @@ QQuickKeysAttached *QQuickKeysAttached::qmlAttachedProperties(QObject *obj) \brief Property used to mirror layout behavior The LayoutMirroring attached property is used to horizontally mirror \l {anchor-layout}{Item anchors}, - \l{Item Layouts}{positioner} types (such as \l Row and \l Grid) + \l{Item Positioners}{positioner} types (such as \l Row and \l Grid) and views (such as \l GridView and horizontal \l ListView). Mirroring is a visual change: left anchors become right anchors, and positioner types like \l Grid and \l Row reverse the horizontal layout of child items. @@ -1405,7 +1406,7 @@ QQuickKeysAttached *QQuickKeysAttached::qmlAttachedProperties(QObject *obj) This property holds whether the item's layout is mirrored horizontally. Setting this to true horizontally reverses \l {anchor-layout}{anchor} settings such that left anchors become right, - and right anchors become left. For \l{Item Layouts}{positioner} types + and right anchors become left. For \l{Item Positioners}{positioner} types (such as \l Row and \l Grid) and view types (such as \l {GridView}{GridView} and \l {ListView}{ListView}) this also mirrors the horizontal layout direction of the item. @@ -1573,7 +1574,7 @@ void QQuickItemPrivate::updateSubFocusItem(QQuickItem *scope, bool focus) /*! \class QQuickItem - \brief The QQuickItem class provides the most basic of all visual items in QtQuick. + \brief The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}. \inmodule QtQuick All visual items in Qt Quick inherit from QQuickItem. Although a QQuickItem @@ -2037,6 +2038,44 @@ QQuickItem::~QQuickItem() /*! \internal +*/ +bool QQuickItemPrivate::qt_tab_all_widgets() +{ + if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) + return theme->themeHint(QPlatformTheme::TabAllWidgets).toBool(); + return true; +} + +/*! + \internal +*/ +bool QQuickItemPrivate::canAcceptTabFocus(QQuickItem *item) +{ + bool result = true; + + if (!item->window()) + return false; + + if (item == item->window()->contentItem()) + return true; + +#ifndef QT_NO_ACCESSIBILITY + result = false; + if (QObject *acc = qmlAttachedPropertiesObject<QQuickAccessibleAttached>(item, false)) { + int role = acc->property("role").toInt(); + if (role == QAccessible::EditableText + || role == QAccessible::Table + || role == QAccessible::List + || role == QAccessible::SpinBox) + result = true; + } +#endif + + return result; +} + +/*! + \internal \brief QQuickItemPrivate::focusNextPrev focuses the next/prev item in the tab-focus-chain \param item The item that currently has the focus \param forward The direction @@ -2047,8 +2086,21 @@ QQuickItem::~QQuickItem() */ bool QQuickItemPrivate::focusNextPrev(QQuickItem *item, bool forward) { + QQuickItem *next = QQuickItemPrivate::nextPrevItemInTabFocusChain(item, forward); + + if (next == item) + return false; + + next->forceActiveFocus(forward ? Qt::TabFocusReason : Qt::BacktabFocusReason); + + return true; +} + +QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, bool forward) +{ Q_ASSERT(item); - Q_ASSERT(item->activeFocusOnTab()); + + bool all = QQuickItemPrivate::qt_tab_all_widgets(); QQuickItem *from = 0; if (forward) { @@ -2060,6 +2112,10 @@ bool QQuickItemPrivate::focusNextPrev(QQuickItem *item, bool forward) from = item->parentItem(); } bool skip = false; + const QQuickItem * const contentItem = item->window()->contentItem(); + const QQuickItem * const originalItem = item; + QQuickItem * startItem = item; + QQuickItem * firstFromItem = from; QQuickItem *current = item; do { skip = false; @@ -2110,16 +2166,29 @@ bool QQuickItemPrivate::focusNextPrev(QQuickItem *item, bool forward) skip = true; } } - from = last; - } while (skip || !current->activeFocusOnTab() || !current->isEnabled() || !current->isVisible()); - - if (current == item) - return false; - - current->forceActiveFocus(forward ? Qt::TabFocusReason : Qt::BacktabFocusReason); + if (current == startItem && from == firstFromItem) { + // wrapped around, avoid endless loops + if (originalItem == contentItem) { +#ifdef FOCUS_DEBUG + qDebug() << "QQuickItemPrivate::nextPrevItemInTabFocusChain: looped, return contentItem"; +#endif + return item->window()->contentItem(); + } else { +#ifdef FOCUS_DEBUG + qDebug() << "QQuickItemPrivate::nextPrevItemInTabFocusChain: looped, return " << startItem; +#endif + return startItem; + } + } + if (!firstFromItem) { //start from root + startItem = current; + firstFromItem = from; + } + } while (skip || !current->activeFocusOnTab() || !current->isEnabled() || !current->isVisible() + || !(all || QQuickItemPrivate::canAcceptTabFocus(current))); - return true; + return current; } /*! @@ -2255,7 +2324,8 @@ void QQuickItem::setParentItem(QQuickItem *parentItem) } } - d->resolveLayoutMirror(); + if (d->parentItem) + d->resolveLayoutMirror(); d->itemChange(ItemParentHasChanged, d->parentItem); @@ -2341,13 +2411,16 @@ void QQuickItem::stackAfter(const QQuickItem *sibling) QQuickItemPrivate::get(parentPrivate->childItems.at(ii))->siblingOrderChanged(); } +/*! \fn void QQuickItem::windowChanged(QQuickWindow *window) + This signal is emitted when the item's \a window changes. +*/ + /*! Returns the window in which this item is rendered. - The item does not have a window until it has been assigned into a scene. To - get notification about this, reimplement the itemChange() function and - listen for the ItemSceneChange change. The itemChange() function is called - both when the item is entered into a scene and when it is removed from a scene. + The item does not have a window until it has been assigned into a scene. The + \l windowChanged signal provides a notification both when the item is entered + into a scene and when it is removed from a scene. */ QQuickWindow *QQuickItem::window() const { @@ -2498,8 +2571,7 @@ void QQuickItemPrivate::derefWindow() if (c->cursorItem == q) c->cursorItem = 0; #endif - if ( hoverEnabled ) - c->hoverItems.removeAll(q); + c->hoverItems.removeAll(q); if (itemNodeInstance) c->cleanup(itemNodeInstance); if (!parentItem) @@ -2688,9 +2760,26 @@ void QQuickItemPrivate::data_append(QQmlListProperty<QObject> *prop, QObject *o) } else { if (o->inherits("QGraphicsItem")) qWarning("Cannot add a QtQuick 1.0 item (%s) into a QtQuick 2.0 scene!", o->metaObject()->className()); + else { + QQuickWindow *thisWindow = qmlobject_cast<QQuickWindow *>(o); + QQuickItem *item = that; + QQuickWindow *itemWindow = that->window(); + while (!itemWindow && item && item->parentItem()) { + item = item->parentItem(); + itemWindow = item->window(); + } + + if (thisWindow) { + if (itemWindow) + thisWindow->setTransientParent(itemWindow); + else + QObject::connect(item, SIGNAL(windowChanged(QQuickWindow*)), + thisWindow, SLOT(setTransientParent_helper(QQuickWindow*))); + } + o->setParent(that); + } - // XXX todo - do we really want this behavior? - o->setParent(that); + resources_append(prop, o); } } @@ -2768,30 +2857,38 @@ void QQuickItemPrivate::data_clear(QQmlListProperty<QObject> *property) QObject *QQuickItemPrivate::resources_at(QQmlListProperty<QObject> *prop, int index) { - const QObjectList children = prop->object->children(); - if (index < children.count()) - return children.at(index); - else - return 0; + QQuickItemPrivate *quickItemPrivate = QQuickItemPrivate::get(static_cast<QQuickItem *>(prop->object)); + return quickItemPrivate->extra.isAllocated() ? quickItemPrivate->extra->resourcesList.value(index) : 0; } -void QQuickItemPrivate::resources_append(QQmlListProperty<QObject> *prop, QObject *o) +void QQuickItemPrivate::resources_append(QQmlListProperty<QObject> *prop, QObject *object) { - // XXX todo - do we really want this behavior? - o->setParent(prop->object); + QQuickItem *quickItem = static_cast<QQuickItem *>(prop->object); + QQuickItemPrivate *quickItemPrivate = QQuickItemPrivate::get(quickItem); + if (!quickItemPrivate->extra.value().resourcesList.contains(object)) { + quickItemPrivate->extra.value().resourcesList.append(object); + qmlobject_connect(object, QObject, SIGNAL(destroyed(QObject*)), + quickItem, QQuickItem, SLOT(_q_resourceObjectDeleted(QObject*))); + } } int QQuickItemPrivate::resources_count(QQmlListProperty<QObject> *prop) { - return prop->object->children().count(); + QQuickItemPrivate *quickItemPrivate = QQuickItemPrivate::get(static_cast<QQuickItem *>(prop->object)); + return quickItemPrivate->extra.isAllocated() ? quickItemPrivate->extra->resourcesList.count() : 0; } void QQuickItemPrivate::resources_clear(QQmlListProperty<QObject> *prop) { - // XXX todo - do we really want this behavior? - const QObjectList children = prop->object->children(); - for (int index = 0; index < children.count(); index++) - children.at(index)->setParent(0); + QQuickItem *quickItem = static_cast<QQuickItem *>(prop->object); + QQuickItemPrivate *quickItemPrivate = QQuickItemPrivate::get(quickItem); + if (quickItemPrivate->extra.isAllocated()) {//If extra is not allocated resources is empty. + foreach (QObject *object, quickItemPrivate->extra->resourcesList) { + qmlobject_disconnect(object, QObject, SIGNAL(destroyed(QObject*)), + quickItem, QQuickItem, SLOT(_q_resourceObjectDeleted(QObject*))); + } + quickItemPrivate->extra->resourcesList.clear(); + } } QQuickItem *QQuickItemPrivate::children_at(QQmlListProperty<QQuickItem> *prop, int index) @@ -2938,6 +3035,12 @@ void QQuickItemPrivate::transform_clear(QQmlListProperty<QQuickTransform> *prop) p->dirty(QQuickItemPrivate::Transform); } +void QQuickItemPrivate::_q_resourceObjectDeleted(QObject *object) +{ + if (extra.isAllocated() && extra->resourcesList.contains(object)) + extra->resourcesList.removeAll(object); +} + /*! \qmlproperty AnchorLine QtQuick2::Item::anchors.top \qmlproperty AnchorLine QtQuick2::Item::anchors.bottom @@ -3917,6 +4020,28 @@ void QQuickItem::forceActiveFocus(Qt::FocusReason reason) } /*! + \qmlmethod QtQuick2::Item::nextItemInFocusChain(bool forward) + + \since QtQuick 2.1 + + Returns the item in the focus chain which is next to this item. + If \a forward is \c true, or not supplied, it is the next item in + the forwards direction. If \a forward is \c false, it is the next + item in the backwards direction. +*/ +/*! + Returns the item in the focus chain which is next to this item. + If \a forward is \c true, or not supplied, it is the next item in + the forwards direction. If \a forward is \c false, it is the next + item in the backwards direction. +*/ + +QQuickItem *QQuickItem::nextItemInFocusChain(bool forward) +{ + return QQuickItemPrivate::nextPrevItemInTabFocusChain(this, forward); +} + +/*! \qmlmethod QtQuick2::Item::childAt(real x, real y) Returns the first visible child item found at point (\a x, \a y) within @@ -4280,7 +4405,8 @@ void QQuickItemPrivate::deliverKeyEvent(QKeyEvent *e) return; //only care about KeyPress now - if (q->activeFocusOnTab() && e->type() == QEvent::KeyPress) { + if ((q == q->window()->contentItem() || q->activeFocusOnTab()) + && e->type() == QEvent::KeyPress) { bool res = false; if (!(e->modifiers() & (Qt::ControlModifier | Qt::AltModifier))) { //### Add MetaModifier? if (e->key() == Qt::Key_Backtab @@ -4417,11 +4543,18 @@ void QQuickItemPrivate::deliverDragEvent(QEvent *e) \a value contains extra information relating to the change, when applicable. + + If you re-implement this method in a subclass, be sure to call + \code + QQuickItem::itemChange(change, value); + \endcode + typically at the end of your implementation, to ensure the + \l windowChanged signal will be emitted. */ void QQuickItem::itemChange(ItemChange change, const ItemChangeData &value) { - Q_UNUSED(change); - Q_UNUSED(value); + if (change == ItemSceneChange) + emit windowChanged(value.window); } #ifndef QT_NO_IM @@ -5489,7 +5622,7 @@ void QQuickItem::setActiveFocusOnTab(bool activeFocusOnTab) return; if (window()) { - if ((this == window()->activeFocusItem()) && !activeFocusOnTab) { + if ((this == window()->activeFocusItem()) && this != window()->contentItem() && !activeFocusOnTab) { qWarning("QQuickItem: Cannot set activeFocusOnTab to false once item is the active focus item."); return; } |