From 9cd41cbd61afd2459c0c3f053aa45a02954ef77c Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Fri, 6 Nov 2009 13:13:29 +1000 Subject: Test Keys and KeyNavigation attached props. Fix Keys onPressed --- doc/src/declarative/focus.qdoc | 2 + src/declarative/graphicsitems/qmlgraphicsitem.cpp | 74 ++++++- tests/auto/declarative/declarative.pro | 1 + .../auto/declarative/qmlgraphicsitem/data/keys.qml | 15 ++ .../qmlgraphicsitem/qmlgraphicsitem.pro | 7 + .../qmlgraphicsitem/tst_qmlgraphicsitem.cpp | 237 +++++++++++++++++++++ 6 files changed, 334 insertions(+), 2 deletions(-) create mode 100644 tests/auto/declarative/qmlgraphicsitem/data/keys.qml create mode 100644 tests/auto/declarative/qmlgraphicsitem/qmlgraphicsitem.pro create mode 100644 tests/auto/declarative/qmlgraphicsitem/tst_qmlgraphicsitem.cpp diff --git a/doc/src/declarative/focus.qdoc b/doc/src/declarative/focus.qdoc index ec6a02f..6eca667 100644 --- a/doc/src/declarative/focus.qdoc +++ b/doc/src/declarative/focus.qdoc @@ -75,6 +75,8 @@ Item { \endlist +See also the \l {Keys}{Keys attached property} and {KeyNavigation}{KeyNavigation attached property}. + \section1 Querying the Active Focus Item Whether or not an \l Item has \e {active focus} can be queried through the diff --git a/src/declarative/graphicsitems/qmlgraphicsitem.cpp b/src/declarative/graphicsitems/qmlgraphicsitem.cpp index 77e6db8..a46c2be 100644 --- a/src/declarative/graphicsitems/qmlgraphicsitem.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsitem.cpp @@ -389,6 +389,76 @@ void QmlGraphicsItemKeyFilter::componentComplete() if (m_next) m_next->componentComplete(); } + +/*! + \qmlclass KeyNavigation + \brief The KeyNavigation attached property supports key navigation by arrow keys. + + It is common in key-based UIs to use arrow keys to navigate + between focussed items. The KeyNavigation property provides a + convenient way of specifying which item will gain focus + when an arrow key is pressed. The following example provides + key navigation for a 2x2 grid of items. + + \code + Grid { + columns: 2 + width: 100; height: 100 + Rectangle { + id: item1 + focus: true + width: 50; height: 50 + color: focus ? "red" : "lightgray" + KeyNavigation.right: item2 + KeyNavigation.down: item3 + } + Rectangle { + id: item2 + width: 50; height: 50 + color: focus ? "red" : "lightgray" + KeyNavigation.left: item1 + KeyNavigation.down: item4 + } + Rectangle { + id: item3 + width: 50; height: 50 + color: focus ? "red" : "lightgray" + KeyNavigation.right: item4 + KeyNavigation.up: item1 + } + Rectangle { + id: item4 + width: 50; height: 50 + color: focus ? "red" : "lightgray" + KeyNavigation.left: item3 + KeyNavigation.up: item2 + } + } + \endcode + + KeyNavigation receives key events after the item it is attached to. + If the item accepts an arrow key event, the KeyNavigation + attached property will not receive an event for that key. + + If an item has been set for a direction and the KeyNavigation + attached property receives the corresponding + key press and release events, the events will be accepted by + KeyNaviagtion and will not propagate any further. + + \sa {Keys}{Keys attached property} +*/ + +/*! + \qmlproperty Item KeyNavigation::left + \qmlproperty Item KeyNavigation::right + \qmlproperty Item KeyNavigation::up + \qmlproperty Item KeyNavigation::down + + These properties hold the item to assign focus to + when Key_Left, Key_Right, Key_Up or Key_Down are + pressed. +*/ + class QmlGraphicsKeyNavigationAttachedPrivate : public QObjectPrivate { public: @@ -606,7 +676,7 @@ void QmlGraphicsKeyNavigationAttached::keyReleased(QKeyEvent *event) See \l {Qt::Key}{Qt.Key} for the list of keyboard codes. - \sa KeyEvent + \sa KeyEvent, {KeyNavigation}{KeyNavigation attached property} */ /*! @@ -1119,7 +1189,7 @@ void QmlGraphicsKeysAttached::keyPressed(QKeyEvent *event) // If we specifically handle a key then default to accepted ke.setAccepted(true); int idx = QmlGraphicsKeysAttached::staticMetaObject.indexOfSignal(keySignal); - metaObject()->method(idx).invoke(this, Q_ARG(QmlGraphicsKeysAttached, &ke)); + metaObject()->method(idx).invoke(this, Qt::DirectConnection, Q_ARG(QmlGraphicsKeyEvent*, &ke)); } } if (!ke.isAccepted()) diff --git a/tests/auto/declarative/declarative.pro b/tests/auto/declarative/declarative.pro index 02d5a55..472fd93 100644 --- a/tests/auto/declarative/declarative.pro +++ b/tests/auto/declarative/declarative.pro @@ -20,6 +20,7 @@ SUBDIRS += \ qmldom \ # Cover qmlecmascript \ # Cover qmlfontloader \ # Cover + qmlgraphicsitem \ # Cover qmlgraphicsborderimage \ # Cover qmlgraphicsparticles \ # Cover qmlgraphicstext \ # Cover diff --git a/tests/auto/declarative/qmlgraphicsitem/data/keys.qml b/tests/auto/declarative/qmlgraphicsitem/data/keys.qml new file mode 100644 index 0000000..7c16559 --- /dev/null +++ b/tests/auto/declarative/qmlgraphicsitem/data/keys.qml @@ -0,0 +1,15 @@ +import Qt 4.6 + +Item { + focus: true + Keys.onPressed: keysTestObject.keyPress(event.key, event.text, event.modifiers) + Keys.onReleased: { keysTestObject.keyRelease(event.key, event.text, event.modifiers); event.accepted = true; } + Keys.onReturnPressed: keysTestObject.keyPress(event.key, "Return", event.modifiers) + Keys.forwardTo: [ item2 ] + + Item { + id: item2 + Keys.onPressed: keysTestObject.forwardedKey(event.key) + Keys.onReleased: keysTestObject.forwardedKey(event.key) + } +} diff --git a/tests/auto/declarative/qmlgraphicsitem/qmlgraphicsitem.pro b/tests/auto/declarative/qmlgraphicsitem/qmlgraphicsitem.pro new file mode 100644 index 0000000..ddabf9a --- /dev/null +++ b/tests/auto/declarative/qmlgraphicsitem/qmlgraphicsitem.pro @@ -0,0 +1,7 @@ +load(qttest_p4) +contains(QT_CONFIG,declarative): QT += declarative gui +macx:CONFIG -= app_bundle + +SOURCES += tst_qmlgraphicsitem.cpp + +DEFINES += SRCDIR=\\\"$$PWD\\\" diff --git a/tests/auto/declarative/qmlgraphicsitem/tst_qmlgraphicsitem.cpp b/tests/auto/declarative/qmlgraphicsitem/tst_qmlgraphicsitem.cpp new file mode 100644 index 0000000..b3b5374 --- /dev/null +++ b/tests/auto/declarative/qmlgraphicsitem/tst_qmlgraphicsitem.cpp @@ -0,0 +1,237 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include +#include +#include +#include +#include + +class tst_QmlGraphicsItem : public QObject + +{ + Q_OBJECT +public: + tst_QmlGraphicsItem(); + +private slots: + void keys(); + void keyNavigation(); + +private: + template + T *findItem(QmlGraphicsItem *parent, const QString &objectName); +}; + +class KeysTestObject : public QObject +{ + Q_OBJECT +public: + KeysTestObject() : mKey(0), mModifiers(0), mForwardedKey(0) {} + + void reset() { + mKey = 0; + mText = QString(); + mModifiers = 0; + mForwardedKey = 0; + } + +public slots: + void keyPress(int key, QString text, int modifiers) { + mKey = key; + mText = text; + mModifiers = modifiers; + } + void keyRelease(int key, QString text, int modifiers) { + mKey = key; + mText = text; + mModifiers = modifiers; + } + void forwardedKey(int key) { + mForwardedKey = key; + } + +public: + int mKey; + QString mText; + int mModifiers; + int mForwardedKey; + +private: +}; + + +tst_QmlGraphicsItem::tst_QmlGraphicsItem() +{ +} + +void tst_QmlGraphicsItem::keys() +{ + QmlView *canvas = new QmlView(0); + canvas->setFixedSize(240,320); + + canvas->setUrl(QUrl("file://" SRCDIR "/data/keys.qml")); + + KeysTestObject *testObject = new KeysTestObject; + canvas->rootContext()->setContextProperty("keysTestObject", testObject); + + canvas->execute(); + canvas->show(); + qApp->processEvents(); + + QEvent wa(QEvent::WindowActivate); + QApplication::sendEvent(canvas, &wa); + QFocusEvent fe(QEvent::FocusIn); + QApplication::sendEvent(canvas, &fe); + + QKeyEvent key(QEvent::KeyPress, Qt::Key_A, Qt::NoModifier, "A", false, 1); + QApplication::sendEvent(canvas, &key); + QCOMPARE(testObject->mKey, int(Qt::Key_A)); + QCOMPARE(testObject->mForwardedKey, int(Qt::Key_A)); + QCOMPARE(testObject->mText, QLatin1String("A")); + QVERIFY(testObject->mModifiers == Qt::NoModifier); + QVERIFY(!key.isAccepted()); + + testObject->reset(); + + key = QKeyEvent(QEvent::KeyRelease, Qt::Key_A, Qt::ShiftModifier, "A", false, 1); + QApplication::sendEvent(canvas, &key); + QCOMPARE(testObject->mKey, int(Qt::Key_A)); + QCOMPARE(testObject->mForwardedKey, int(Qt::Key_A)); + QCOMPARE(testObject->mText, QLatin1String("A")); + QVERIFY(testObject->mModifiers == Qt::ShiftModifier); + QVERIFY(key.isAccepted()); + + testObject->reset(); + + key = QKeyEvent(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier, "", false, 1); + QApplication::sendEvent(canvas, &key); + QCOMPARE(testObject->mKey, int(Qt::Key_Return)); + QCOMPARE(testObject->mForwardedKey, int(Qt::Key_Return)); + QCOMPARE(testObject->mText, QLatin1String("Return")); + QVERIFY(testObject->mModifiers == Qt::NoModifier); + QVERIFY(key.isAccepted()); + + delete canvas; + delete testObject; +} + +void tst_QmlGraphicsItem::keyNavigation() +{ + QmlView *canvas = new QmlView(0); + canvas->setFixedSize(240,320); + + canvas->setUrl(QUrl("file://" SRCDIR "/data/keynavigation.qml")); + canvas->execute(); + canvas->show(); + qApp->processEvents(); + + QEvent wa(QEvent::WindowActivate); + QApplication::sendEvent(canvas, &wa); + QFocusEvent fe(QEvent::FocusIn); + QApplication::sendEvent(canvas, &fe); + + QmlGraphicsItem *item = findItem(canvas->root(), "item1"); + QVERIFY(item); + QVERIFY(item->hasFocus()); + + // right + QKeyEvent key(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier, "", false, 1); + QApplication::sendEvent(canvas, &key); + QVERIFY(key.isAccepted()); + + item = findItem(canvas->root(), "item2"); + QVERIFY(item); + QVERIFY(item->hasFocus()); + + // down + key = QKeyEvent(QEvent::KeyPress, Qt::Key_Down, Qt::NoModifier, "", false, 1); + QApplication::sendEvent(canvas, &key); + QVERIFY(key.isAccepted()); + + item = findItem(canvas->root(), "item4"); + QVERIFY(item); + QVERIFY(item->hasFocus()); + + // left + key = QKeyEvent(QEvent::KeyPress, Qt::Key_Left, Qt::NoModifier, "", false, 1); + QApplication::sendEvent(canvas, &key); + QVERIFY(key.isAccepted()); + + item = findItem(canvas->root(), "item3"); + QVERIFY(item); + QVERIFY(item->hasFocus()); + + // up + key = QKeyEvent(QEvent::KeyPress, Qt::Key_Up, Qt::NoModifier, "", false, 1); + QApplication::sendEvent(canvas, &key); + QVERIFY(key.isAccepted()); + + item = findItem(canvas->root(), "item1"); + QVERIFY(item); + QVERIFY(item->hasFocus()); +} + +template +T *tst_QmlGraphicsItem::findItem(QmlGraphicsItem *parent, const QString &objectName) +{ + const QMetaObject &mo = T::staticMetaObject; + //qDebug() << parent->QGraphicsObject::children().count() << "children"; + for (int i = 0; i < parent->QGraphicsObject::children().count(); ++i) { + QmlGraphicsItem *item = qobject_cast(parent->QGraphicsObject::children().at(i)); + if(!item) + continue; + //qDebug() << "try" << item; + if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) + return static_cast(item); + item = findItem(item, objectName); + if (item) + return static_cast(item); + } + + return 0; +} + + + +QTEST_MAIN(tst_QmlGraphicsItem) + +#include "tst_qmlgraphicsitem.moc" -- cgit v0.12