summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Aardal Hanssen <andreas@hanssen.name>2012-11-29 22:33:43 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2012-12-17 19:37:16 +0100
commitaf8a6cdd87c27b4ed18d5e6238757ba8885f630d (patch)
tree4acd0898cd2a69fed9f37256ee1c8fea5f03abd7
parent2dc6ad8adf7f98d55aca5def8ee3f9c12934fb7b (diff)
Add new signal: QGraphicsScene::focusItemChanged().
This signal is emitted by QGraphicsScene whenever focus changes in the scene (i.e., when an item gains or loses input focus, or when focus passes from one item to another). You can connect to this signal if you need to keep track of when other items gain input focus. It is particularily useful for implementing virtual keyboards, input methods, and cursor items. Task-number: QTBUG-10570 Change-Id: I9cbbd9a2d15d6f568e1597c2c33ec049eb70f793 Reviewed-by: Jan Arve Sæther <jan-arve.saether@digia.com> Reviewed-by: Yoann Lopes <yoann.lopes@digia.com>
-rw-r--r--src/widgets/graphicsview/qgraphicsscene.cpp50
-rw-r--r--src/widgets/graphicsview/qgraphicsscene.h1
-rw-r--r--src/widgets/graphicsview/qgraphicsscene_p.h3
-rw-r--r--tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp115
4 files changed, 162 insertions, 7 deletions
diff --git a/src/widgets/graphicsview/qgraphicsscene.cpp b/src/widgets/graphicsview/qgraphicsscene.cpp
index 139fad0163..e14a98f332 100644
--- a/src/widgets/graphicsview/qgraphicsscene.cpp
+++ b/src/widgets/graphicsview/qgraphicsscene.cpp
@@ -742,12 +742,14 @@ void QGraphicsScenePrivate::setActivePanelHelper(QGraphicsItem *item, bool durin
if (panel == activePanel || (!q->isActive() && !duringActivationEvent))
return;
+ QGraphicsItem *oldFocusItem = focusItem;
+
// Deactivate the last active panel.
if (activePanel) {
if (QGraphicsItem *fi = activePanel->focusItem()) {
// Remove focus from the current focus item.
if (fi == q->focusItem())
- q->setFocusItem(0, Qt::ActiveWindowFocusReason);
+ setFocusItemHelper(0, Qt::ActiveWindowFocusReason, /* emitFocusChanged = */ false);
}
QEvent event(QEvent::WindowDeactivate);
@@ -775,14 +777,14 @@ void QGraphicsScenePrivate::setActivePanelHelper(QGraphicsItem *item, bool durin
// focusable, or on the first focusable item in the panel's
// focus chain as a last resort.
if (QGraphicsItem *focusItem = panel->focusItem()) {
- focusItem->setFocus(Qt::ActiveWindowFocusReason);
+ setFocusItemHelper(focusItem, Qt::ActiveWindowFocusReason, /* emitFocusChanged = */ false);
} else if (panel->flags() & QGraphicsItem::ItemIsFocusable) {
- panel->setFocus(Qt::ActiveWindowFocusReason);
+ setFocusItemHelper(panel, Qt::ActiveWindowFocusReason, /* emitFocusChanged = */ false);
} else if (panel->isWidget()) {
QGraphicsWidget *fw = static_cast<QGraphicsWidget *>(panel)->d_func()->focusNext;
do {
if (fw->focusPolicy() & Qt::TabFocus) {
- fw->setFocus(Qt::ActiveWindowFocusReason);
+ setFocusItemHelper(fw, Qt::ActiveWindowFocusReason, /* emitFocusChanged = */ false);
break;
}
fw = fw->d_func()->focusNext;
@@ -796,13 +798,23 @@ void QGraphicsScenePrivate::setActivePanelHelper(QGraphicsItem *item, bool durin
q->sendEvent(item, &event);
}
}
+
+ emit q->focusItemChanged(focusItem, oldFocusItem, Qt::ActiveWindowFocusReason);
}
/*!
\internal
+
+ \a emitFocusChanged needs to be false when focus passes from one
+ item to another through setActivePanel(); i.e. when activation
+ passes from one panel to another, to avoid getting two focusChanged()
+ emissions; one focusChanged(0, lastFocus), then one
+ focusChanged(newFocus, 0). Instead setActivePanel() emits the signal
+ once itself: focusChanged(newFocus, oldFocus).
*/
void QGraphicsScenePrivate::setFocusItemHelper(QGraphicsItem *item,
- Qt::FocusReason focusReason)
+ Qt::FocusReason focusReason,
+ bool emitFocusChanged)
{
Q_Q(QGraphicsScene);
if (item == focusItem)
@@ -818,10 +830,14 @@ void QGraphicsScenePrivate::setFocusItemHelper(QGraphicsItem *item,
// Set focus on the scene if an item requests focus.
if (item) {
q->setFocus(focusReason);
- if (item == focusItem)
+ if (item == focusItem) {
+ if (emitFocusChanged)
+ emit q->focusItemChanged(focusItem, (QGraphicsItem *)0, focusReason);
return;
+ }
}
+ QGraphicsItem *oldFocusItem = focusItem;
if (focusItem) {
lastFocusItem = focusItem;
@@ -862,6 +878,9 @@ void QGraphicsScenePrivate::setFocusItemHelper(QGraphicsItem *item,
QFocusEvent event(QEvent::FocusIn, focusReason);
sendEvent(item, &event);
}
+
+ if (emitFocusChanged)
+ emit q->focusItemChanged(focusItem, oldFocusItem, focusReason);
}
/*!
@@ -5437,6 +5456,25 @@ bool QGraphicsScene::focusNextPrevChild(bool next)
*/
/*!
+ \fn QGraphicsScene::focusChanged(QGraphicsItem *newFocusItem, QGraphicsItem *oldFocusItem, Qt::FocusReason reason)
+
+ This signal is emitted by QGraphicsScene whenever focus changes in the
+ scene (i.e., when an item gains or loses input focus, or when focus
+ passes from one item to another). You can connect to this signal if you
+ need to keep track of when other items gain input focus. It is
+ particularily useful for implementing virtual keyboards, input methods,
+ and cursor items.
+
+ \a oldFocusItem is a pointer to the item that previously had focus, or
+ 0 if no item had focus before the signal was emitted. \a newFocusItem
+ is a pointer to the item that gained input focus, or 0 if focus was lost.
+ \a reason is the reason for the focus change (e.g., if the scene was
+ deactivated while an input field had focus, \a oldFocusItem would point
+ to the input field item, \a newFocusItem would be 0, and \a reason would be
+ Qt::ActiveWindowFocusReason.
+*/
+
+/*!
\since 4.4
Returns the scene's style, or the same as QApplication::style() if the
diff --git a/src/widgets/graphicsview/qgraphicsscene.h b/src/widgets/graphicsview/qgraphicsscene.h
index 27337d3a2a..3f00b74f53 100644
--- a/src/widgets/graphicsview/qgraphicsscene.h
+++ b/src/widgets/graphicsview/qgraphicsscene.h
@@ -292,6 +292,7 @@ Q_SIGNALS:
void changed(const QList<QRectF> &region);
void sceneRectChanged(const QRectF &rect);
void selectionChanged();
+ void focusItemChanged(QGraphicsItem *newFocus, QGraphicsItem *oldFocus, Qt::FocusReason reason);
private:
Q_DECLARE_PRIVATE(QGraphicsScene)
diff --git a/src/widgets/graphicsview/qgraphicsscene_p.h b/src/widgets/graphicsview/qgraphicsscene_p.h
index 6799a835ac..bcb95c694a 100644
--- a/src/widgets/graphicsview/qgraphicsscene_p.h
+++ b/src/widgets/graphicsview/qgraphicsscene_p.h
@@ -157,7 +157,8 @@ public:
int activationRefCount;
int childExplicitActivation;
void setActivePanelHelper(QGraphicsItem *item, bool duringActivationEvent);
- void setFocusItemHelper(QGraphicsItem *item, Qt::FocusReason focusReason);
+ void setFocusItemHelper(QGraphicsItem *item, Qt::FocusReason focusReason,
+ bool emitFocusChanged = true);
QList<QGraphicsWidget *> popupWidgets;
void addPopup(QGraphicsWidget *widget);
diff --git a/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp b/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp
index 69e687d633..3c253bf9cc 100644
--- a/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp
+++ b/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp
@@ -63,6 +63,7 @@
#define Q_CHECK_PAINTEVENTS
#endif
+Q_DECLARE_METATYPE(Qt::FocusReason)
Q_DECLARE_METATYPE(QList<int>)
Q_DECLARE_METATYPE(QList<QRectF>)
Q_DECLARE_METATYPE(QMatrix)
@@ -270,6 +271,7 @@ private slots:
void siblingIndexAlwaysValid();
void removeFullyTransparentItem();
void zeroScale();
+ void focusItemChangedSignal();
// task specific tests below me
void task139710_bspTreeCrash();
@@ -4565,6 +4567,119 @@ void tst_QGraphicsScene::zeroScale()
QTRY_COMPARE(cl.changes.count(), 2);
}
+void tst_QGraphicsScene::focusItemChangedSignal()
+{
+ qRegisterMetaType<QGraphicsItem *>("QGraphicsItem *");
+ qRegisterMetaType<Qt::FocusReason>("Qt::FocusReason");
+
+ QGraphicsScene scene;
+ QSignalSpy spy(&scene, SIGNAL(focusItemChanged(QGraphicsItem *, QGraphicsItem *, Qt::FocusReason)));
+ QVERIFY(spy.isValid());
+ QCOMPARE(spy.count(), 0);
+ scene.setFocus();
+ QCOMPARE(spy.count(), 0);
+ QEvent activateEvent(QEvent::WindowActivate);
+ qApp->sendEvent(&scene, &activateEvent);
+ QCOMPARE(spy.count(), 0);
+
+ QGraphicsRectItem *topLevelItem1 = new QGraphicsRectItem;
+ topLevelItem1->setFlag(QGraphicsItem::ItemIsFocusable);
+ scene.addItem(topLevelItem1);
+ QCOMPARE(spy.count(), 0);
+ QVERIFY(!topLevelItem1->hasFocus());
+
+ QGraphicsRectItem *topLevelItem2 = new QGraphicsRectItem;
+ topLevelItem2->setFlag(QGraphicsItem::ItemIsFocusable);
+ topLevelItem2->setFocus();
+ QVERIFY(!topLevelItem2->hasFocus());
+ scene.addItem(topLevelItem2);
+ QCOMPARE(spy.count(), 1);
+ QList<QVariant> arguments = spy.takeFirst();
+ QCOMPARE(arguments.size(), 3);
+ QCOMPARE(qVariantValue<QGraphicsItem *>(arguments.at(0)), (QGraphicsItem *)topLevelItem2);
+ QCOMPARE(qVariantValue<QGraphicsItem *>(arguments.at(1)), (QGraphicsItem *)0);
+ QCOMPARE(qVariantValue<Qt::FocusReason>(arguments.at(2)), Qt::OtherFocusReason);
+ QVERIFY(topLevelItem2->hasFocus());
+
+ scene.clearFocus();
+ QCOMPARE(spy.count(), 1);
+ arguments = spy.takeFirst();
+ QCOMPARE(arguments.size(), 3);
+ QCOMPARE(qVariantValue<QGraphicsItem *>(arguments.at(0)), (QGraphicsItem *)0);
+ QCOMPARE(qVariantValue<QGraphicsItem *>(arguments.at(1)), (QGraphicsItem *)topLevelItem2);
+ QCOMPARE(qVariantValue<Qt::FocusReason>(arguments.at(2)), Qt::OtherFocusReason);
+
+ scene.setFocus(Qt::MenuBarFocusReason);
+ QCOMPARE(spy.count(), 1);
+ arguments = spy.takeFirst();
+ QCOMPARE(arguments.size(), 3);
+ QCOMPARE(qVariantValue<QGraphicsItem *>(arguments.at(0)), (QGraphicsItem *)topLevelItem2);
+ QCOMPARE(qVariantValue<QGraphicsItem *>(arguments.at(1)), (QGraphicsItem *)0);
+ QCOMPARE(qVariantValue<Qt::FocusReason>(arguments.at(2)), Qt::MenuBarFocusReason);
+
+ for (int i = 0; i < 3; ++i) {
+ topLevelItem1->setFocus(Qt::TabFocusReason);
+ arguments = spy.takeFirst();
+ QCOMPARE(arguments.size(), 3);
+ QCOMPARE(qVariantValue<QGraphicsItem *>(arguments.at(0)), (QGraphicsItem *)topLevelItem1);
+ QCOMPARE(qVariantValue<QGraphicsItem *>(arguments.at(1)), (QGraphicsItem *)topLevelItem2);
+ QCOMPARE(qVariantValue<Qt::FocusReason>(arguments.at(2)), Qt::TabFocusReason);
+
+ topLevelItem2->setFocus(Qt::TabFocusReason);
+ arguments = spy.takeFirst();
+ QCOMPARE(arguments.size(), 3);
+ QCOMPARE(qVariantValue<QGraphicsItem *>(arguments.at(0)), (QGraphicsItem *)topLevelItem2);
+ QCOMPARE(qVariantValue<QGraphicsItem *>(arguments.at(1)), (QGraphicsItem *)topLevelItem1);
+ QCOMPARE(qVariantValue<Qt::FocusReason>(arguments.at(2)), Qt::TabFocusReason);
+ }
+
+ // The following two are unexpected, but fixing this (i.e., losing and gaining focus
+ // when the scene activation changes) breaks quite a few tests so leave this fix
+ // for some future release. See QTBUG-28346.
+ QEvent deactivateEvent(QEvent::WindowDeactivate);
+ qApp->sendEvent(&scene, &deactivateEvent);
+ QEXPECT_FAIL("", "QTBUG-28346", Continue);
+ QCOMPARE(spy.count(), 1);
+ qApp->sendEvent(&scene, &activateEvent);
+ QEXPECT_FAIL("", "QTBUG-28346", Continue);
+ QCOMPARE(spy.count(), 1);
+
+ QGraphicsRectItem *panel1 = new QGraphicsRectItem;
+ panel1->setFlags(QGraphicsItem::ItemIsPanel | QGraphicsItem::ItemIsFocusable);
+ panel1->setFocus();
+ scene.addItem(panel1);
+ QCOMPARE(spy.count(), 1);
+ arguments = spy.takeFirst();
+ QCOMPARE(arguments.size(), 3);
+ QCOMPARE(qVariantValue<QGraphicsItem *>(arguments.at(0)), (QGraphicsItem *)panel1);
+ QCOMPARE(qVariantValue<QGraphicsItem *>(arguments.at(1)), (QGraphicsItem *)topLevelItem2);
+ QCOMPARE(qVariantValue<Qt::FocusReason>(arguments.at(2)), Qt::ActiveWindowFocusReason);
+
+ QGraphicsRectItem *panel2 = new QGraphicsRectItem;
+ panel2->setFlags(QGraphicsItem::ItemIsPanel | QGraphicsItem::ItemIsFocusable);
+ scene.addItem(panel2);
+ QCOMPARE(spy.count(), 0);
+
+ for (int i = 0; i < 3; ++i) {
+ scene.setActivePanel(panel2);
+ QCOMPARE(spy.count(), 1);
+ arguments = spy.takeFirst();
+ QCOMPARE(arguments.size(), 3);
+ QCOMPARE(qVariantValue<QGraphicsItem *>(arguments.at(0)), (QGraphicsItem *)panel2);
+ QCOMPARE(qVariantValue<QGraphicsItem *>(arguments.at(1)), (QGraphicsItem *)panel1);
+ QCOMPARE(qVariantValue<Qt::FocusReason>(arguments.at(2)), Qt::ActiveWindowFocusReason);
+
+ scene.setActivePanel(panel1);
+ QCOMPARE(spy.count(), 1);
+ arguments = spy.takeFirst();
+ QCOMPARE(arguments.size(), 3);
+ QCOMPARE(qVariantValue<QGraphicsItem *>(arguments.at(0)), (QGraphicsItem *)panel1);
+ QCOMPARE(qVariantValue<QGraphicsItem *>(arguments.at(1)), (QGraphicsItem *)panel2);
+ QCOMPARE(qVariantValue<Qt::FocusReason>(arguments.at(2)), Qt::ActiveWindowFocusReason);
+ }
+
+}
+
void tst_QGraphicsScene::taskQTBUG_15977_renderWithDeviceCoordinateCache()
{
QGraphicsScene scene;