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>
This commit is contained in:
parent
2dc6ad8adf
commit
af8a6cdd87
@ -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);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -5436,6 +5455,25 @@ bool QGraphicsScene::focusNextPrevChild(bool next)
|
||||
\sa setSelectionArea(), selectedItems(), QGraphicsItem::setSelected()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\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
|
||||
|
||||
|
@ -292,6 +292,7 @@ Q_SIGNALS:
|
||||
void changed(const QList<QRectF> ®ion);
|
||||
void sceneRectChanged(const QRectF &rect);
|
||||
void selectionChanged();
|
||||
void focusItemChanged(QGraphicsItem *newFocus, QGraphicsItem *oldFocus, Qt::FocusReason reason);
|
||||
|
||||
private:
|
||||
Q_DECLARE_PRIVATE(QGraphicsScene)
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user