summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Aardal Hanssen <andreas.aardal.hanssen@nokia.com>2009-08-31 12:06:47 (GMT)
committerAndreas Aardal Hanssen <andreas.aardal.hanssen@nokia.com>2009-08-31 14:14:48 (GMT)
commit62ca28a96d200fe55ed5bc2d0d1df327ab44c97e (patch)
tree0b88b18056f074f7dfb851f3a7fe0aa885955561
parent940b0b9e51f234f251d332f729531d6e9c3cea84 (diff)
downloadQt-62ca28a96d200fe55ed5bc2d0d1df327ab44c97e.zip
Qt-62ca28a96d200fe55ed5bc2d0d1df327ab44c97e.tar.gz
Qt-62ca28a96d200fe55ed5bc2d0d1df327ab44c97e.tar.bz2
Fix activation behavior for panels, and add QGraphicsItem::setActive().
Allow delayed activation for more fine grained control over which panels are activated or left inactive when the scene is created. Autotests included. Reviewed-by: Brad
-rw-r--r--src/gui/graphicsview/qgraphicsitem.cpp37
-rw-r--r--src/gui/graphicsview/qgraphicsitem.h2
-rw-r--r--src/gui/graphicsview/qgraphicsitem_p.h8
-rw-r--r--src/gui/graphicsview/qgraphicsscene.cpp149
-rw-r--r--src/gui/graphicsview/qgraphicsscene_p.h2
-rw-r--r--tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp140
6 files changed, 255 insertions, 83 deletions
diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp
index 86c589d..31fd53a 100644
--- a/src/gui/graphicsview/qgraphicsitem.cpp
+++ b/src/gui/graphicsview/qgraphicsitem.cpp
@@ -2669,6 +2669,37 @@ bool QGraphicsItem::isActive() const
}
/*!
+ \since 4.6
+
+ If \a active is true, and the scene is active, this item's panel will be
+ activated. Otherwise, the panel is deactivated.
+
+ If the item is not part of an active scene, \a active will decide what
+ happens to the panel when the scene becomes active or the item is added to
+ the scene. If true, the item's panel will be activated when the item is
+ either added to the scene or the scene is activated. Otherwise, the item
+ will stay inactive independent of the scene's activated state.
+
+ \sa isPanel(), QGraphicsScene::setActivePanel(), QGraphicsScene::isActive()
+*/
+void QGraphicsItem::setActive(bool active)
+{
+ d_ptr->explicitActivate = 1;
+ d_ptr->wantsActive = active;
+ if (d_ptr->scene) {
+ if (active) {
+ // Activate this item.
+ d_ptr->scene->setActivePanel(this);
+ } else {
+ // Deactivate this item, and reactivate the last active item
+ // (if any).
+ QGraphicsItem *lastActive = d_ptr->scene->d_func()->lastActivePanel;
+ d_ptr->scene->setActivePanel(lastActive != this ? lastActive : 0);
+ }
+ }
+}
+
+/*!
Returns true if this item is active, and it or its \l{focusProxy()}{focus
proxy} has keyboard input focus; otherwise, returns false.
@@ -6099,8 +6130,10 @@ bool QGraphicsItem::sceneEvent(QEvent *event)
if (d_ptr->scene) {
for (int i = 0; i < d_ptr->children.size(); ++i) {
QGraphicsItem *child = d_ptr->children.at(i);
- if (!(child->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorHandlesChildEvents))
- d_ptr->scene->sendEvent(child, event);
+ if (child->isVisible() && !child->isPanel()) {
+ if (!(child->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorHandlesChildEvents))
+ d_ptr->scene->sendEvent(child, event);
+ }
}
}
break;
diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h
index 04fe0cb..df25e6a 100644
--- a/src/gui/graphicsview/qgraphicsitem.h
+++ b/src/gui/graphicsview/qgraphicsitem.h
@@ -235,6 +235,8 @@ public:
void setHandlesChildEvents(bool enabled);
bool isActive() const;
+ void setActive(bool active);
+
bool hasFocus() const;
void setFocus(Qt::FocusReason focusReason = Qt::OtherFocusReason);
void clearFocus();
diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h
index 2bc876c..1090620 100644
--- a/src/gui/graphicsview/qgraphicsitem_p.h
+++ b/src/gui/graphicsview/qgraphicsitem_p.h
@@ -171,6 +171,8 @@ public:
notifyBoundingRectChanged(0),
notifyInvalidated(0),
mouseSetsFocus(1),
+ explicitActivate(0),
+ wantsActive(0),
globalStackingOrder(-1),
q_ptr(0)
{
@@ -461,7 +463,7 @@ public:
quint32 needSortChildren : 1;
quint32 allChildrenDirty : 1;
- // New 32 bits
+ // Packed 32 bits
quint32 fullUpdatePending : 1;
quint32 flags : 16;
quint32 dirtyChildrenBoundingRect : 1;
@@ -480,6 +482,10 @@ public:
quint32 notifyInvalidated : 1;
quint32 mouseSetsFocus : 1;
+ // New 32 bits
+ quint32 explicitActivate : 1;
+ quint32 wantsActive : 1;
+
// Optional stacking order
int globalStackingOrder;
QGraphicsItem *q_ptr;
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp
index ac30668..2ac1dca 100644
--- a/src/gui/graphicsview/qgraphicsscene.cpp
+++ b/src/gui/graphicsview/qgraphicsscene.cpp
@@ -291,6 +291,7 @@ QGraphicsScenePrivate::QGraphicsScenePrivate()
activePanel(0),
lastActivePanel(0),
activationRefCount(0),
+ childExplicitActivation(0),
lastMouseGrabberItem(0),
lastMouseGrabberItemHasImplicitMouseGrab(false),
dragDropItem(0),
@@ -571,6 +572,66 @@ void QGraphicsScenePrivate::removeItemHelper(QGraphicsItem *item)
/*!
\internal
*/
+void QGraphicsScenePrivate::setActivePanelHelper(QGraphicsItem *item, bool duringActivationEvent)
+{
+ Q_Q(QGraphicsScene);
+ if (item && item->scene() != q) {
+ qWarning("QGraphicsScene::setActivePanel: item %p must be part of this scene",
+ item);
+ return;
+ }
+
+ // Find the item's panel.
+ QGraphicsItem *panel = item ? item->panel() : 0;
+ lastActivePanel = panel ? activePanel : 0;
+ if (panel == activePanel || (!q->isActive() && !duringActivationEvent))
+ return;
+
+ // 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);
+ }
+
+ QEvent event(QEvent::WindowDeactivate);
+ q->sendEvent(activePanel, &event);
+ } else if (panel && !duringActivationEvent) {
+ // Deactivate the scene if changing activation to a panel.
+ QEvent event(QEvent::WindowDeactivate);
+ foreach (QGraphicsItem *item, q->items()) {
+ if (item->isVisible() && !item->isPanel() && !item->parentItem())
+ q->sendEvent(item, &event);
+ }
+ }
+
+ // Update activate state.
+ activePanel = panel;
+ QEvent event(QEvent::ActivationChange);
+ QApplication::sendEvent(q, &event);
+
+ // Activate
+ if (panel) {
+ QEvent event(QEvent::WindowActivate);
+ q->sendEvent(panel, &event);
+
+ // Set focus on the panel's focus item.
+ if (QGraphicsItem *focusItem = panel->focusItem())
+ focusItem->setFocus(Qt::ActiveWindowFocusReason);
+ } else if (q->isActive()) {
+ // Activate the scene
+ QEvent event(QEvent::WindowActivate);
+ foreach (QGraphicsItem *item, q->items()) {
+ if (item->isVisible() && !item->isPanel() && !item->parentItem())
+ q->sendEvent(item, &event);
+ }
+ }
+}
+
+/*!
+ \internal
+*/
void QGraphicsScenePrivate::setFocusItemHelper(QGraphicsItem *item,
Qt::FocusReason focusReason)
{
@@ -2351,9 +2412,29 @@ void QGraphicsScene::addItem(QGraphicsItem *item)
// Deliver post-change notification
item->itemChange(QGraphicsItem::ItemSceneHasChanged, newSceneVariant);
- // Auto-activate the first inactive panel if the scene is active.
- if (isActive() && !d->activePanel && item->isPanel())
- setActivePanel(item);
+ // Update explicit activation
+ bool autoActivate = true;
+ if (!d->childExplicitActivation && item->d_ptr->explicitActivate)
+ d->childExplicitActivation = item->d_ptr->wantsActive ? 1 : 2;
+ if (d->childExplicitActivation && item->isPanel()) {
+ if (d->childExplicitActivation == 1)
+ setActivePanel(item);
+ else
+ autoActivate = false;
+ d->childExplicitActivation = 0;
+ } else if (!item->d_ptr->parent) {
+ d->childExplicitActivation = 0;
+ }
+
+ // Auto-activate this item's panel if nothing else has been activated
+ if (autoActivate) {
+ if (!d->lastActivePanel && !d->activePanel && item->isPanel()) {
+ if (isActive())
+ setActivePanel(item);
+ else
+ d->lastActivePanel = item;
+ }
+ }
// Ensure that newly added items that have subfocus set, gain
// focus automatically if there isn't a focus item already.
@@ -3129,11 +3210,11 @@ bool QGraphicsScene::event(QEvent *event)
if (!d->activationRefCount++) {
if (d->lastActivePanel) {
// Activate the last panel.
- setActivePanel(d->lastActivePanel);
+ d->setActivePanelHelper(d->lastActivePanel, true);
} else if (d->tabFocusFirst && d->tabFocusFirst->isPanel()) {
// Activate the panel of the first item in the tab focus
// chain.
- setActivePanel(d->tabFocusFirst);
+ d->setActivePanelHelper(d->tabFocusFirst, true);
} else {
// Activate all toplevel items.
QEvent event(QEvent::WindowActivate);
@@ -3150,7 +3231,7 @@ bool QGraphicsScene::event(QEvent *event)
// Deactivate the active panel (but keep it so we can
// reactivate it later).
QGraphicsItem *lastActivePanel = d->activePanel;
- setActivePanel(0);
+ d->setActivePanelHelper(0, true);
d->lastActivePanel = lastActivePanel;
} else {
// Activate all toplevel items.
@@ -5095,63 +5176,15 @@ QGraphicsItem *QGraphicsScene::activePanel() const
can also pass 0 for \a item, in which case QGraphicsScene will
deactivate any currently active panel.
+ If the scene is currently inactive, \a item remains inactive until the
+ scene becomes active (or, ir \a item is 0, no item will be activated).
+
\sa activePanel(), isActive(), QGraphicsItem::isActive()
*/
void QGraphicsScene::setActivePanel(QGraphicsItem *item)
{
Q_D(QGraphicsScene);
- if (item && item->scene() != this) {
- qWarning("QGraphicsScene::setActivePanel: item %p must be part of this scene",
- item);
- return;
- }
-
- // Find the item's panel.
- QGraphicsItem *panel = item ? item->panel() : 0;
- d->lastActivePanel = panel ? d->activePanel : 0;
- if (panel == d->activePanel)
- return;
-
- // Deactivate the last active panel.
- if (d->activePanel) {
- if (QGraphicsItem *fi = d->activePanel->focusItem()) {
- // Remove focus from the current focus item.
- if (fi == focusItem())
- setFocusItem(0, Qt::ActiveWindowFocusReason);
- }
-
- QEvent event(QEvent::WindowDeactivate);
- sendEvent(d->activePanel, &event);
- } else if (panel) {
- // Deactivate the scene if changing activation to a panel.
- QEvent event(QEvent::WindowDeactivate);
- foreach (QGraphicsItem *item, items()) {
- if (item->isVisible() && !item->isPanel() && !item->parentItem())
- sendEvent(item, &event);
- }
- }
-
- // Update activate state.
- d->activePanel = panel;
- QEvent event(QEvent::ActivationChange);
- QApplication::sendEvent(this, &event);
-
- // Activate
- if (panel) {
- QEvent event(QEvent::WindowActivate);
- sendEvent(panel, &event);
-
- // Set focus on the panel's focus item.
- if (QGraphicsItem *focusItem = panel->focusItem())
- focusItem->setFocus(Qt::ActiveWindowFocusReason);
- } else if (isActive()) {
- // Activate the scene
- QEvent event(QEvent::WindowActivate);
- foreach (QGraphicsItem *item, items()) {
- if (item->isVisible() && !item->isPanel() && !item->parentItem())
- sendEvent(item, &event);
- }
- }
+ d->setActivePanelHelper(item, false);
}
/*!
diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h
index c1b78ff..1f66eb4 100644
--- a/src/gui/graphicsview/qgraphicsscene_p.h
+++ b/src/gui/graphicsview/qgraphicsscene_p.h
@@ -132,6 +132,8 @@ public:
QGraphicsItem *activePanel;
QGraphicsItem *lastActivePanel;
int activationRefCount;
+ int childExplicitActivation;
+ void setActivePanelHelper(QGraphicsItem *item, bool duringActivationEvent);
void setFocusItemHelper(QGraphicsItem *item, Qt::FocusReason focusReason);
QList<QGraphicsWidget *> popupWidgets;
diff --git a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp
index 541b5ba..517380e 100644
--- a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp
+++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp
@@ -289,6 +289,8 @@ private slots:
void setGraphicsEffect();
void panel();
void addPanelToActiveScene();
+ void activate();
+ void setActivePanelOnInactiveScene();
// task specific tests below me
void task141694_textItemEnsureVisible();
@@ -7823,26 +7825,15 @@ void tst_QGraphicsItem::panel()
// No previous activation, so the scene is active.
QVERIFY(scene.isActive());
- QVERIFY(!scene.activePanel());
- QVERIFY(!panel1->isActive());
- QVERIFY(!panel2->isActive());
- QVERIFY(!panel3->isActive());
- QVERIFY(!panel4->isActive());
- QVERIFY(notPanel1->isActive());
- QVERIFY(notPanel2->isActive());
- QCOMPARE(spy_activate_notPanel1.count(), 1);
- QCOMPARE(spy_activate_notPanel2.count(), 1);
-
- // Switch to panel1.
- scene.setActivePanel(panel1);
+ QCOMPARE(scene.activePanel(), (QGraphicsItem *)panel1);
QVERIFY(panel1->isActive());
QVERIFY(!panel2->isActive());
QVERIFY(!panel3->isActive());
QVERIFY(!panel4->isActive());
QVERIFY(!notPanel1->isActive());
QVERIFY(!notPanel2->isActive());
- QCOMPARE(spy_deactivate_notPanel1.count(), 1);
- QCOMPARE(spy_deactivate_notPanel2.count(), 1);
+ QCOMPARE(spy_deactivate_notPanel1.count(), 0);
+ QCOMPARE(spy_deactivate_notPanel2.count(), 0);
QCOMPARE(spy_activate_panel1.count(), 1);
QCOMPARE(spy_activate_panel2.count(), 0);
QCOMPARE(spy_activate_panel3.count(), 0);
@@ -7857,8 +7848,8 @@ void tst_QGraphicsItem::panel()
QVERIFY(!panel4->isActive());
QVERIFY(notPanel1->isActive());
QVERIFY(notPanel2->isActive());
- QCOMPARE(spy_activate_notPanel1.count(), 2);
- QCOMPARE(spy_activate_notPanel2.count(), 2);
+ QCOMPARE(spy_activate_notPanel1.count(), 1);
+ QCOMPARE(spy_activate_notPanel2.count(), 1);
// Deactivate the scene
QApplication::sendEvent(&scene, &deactivate);
@@ -7869,8 +7860,8 @@ void tst_QGraphicsItem::panel()
QVERIFY(!panel4->isActive());
QVERIFY(!notPanel1->isActive());
QVERIFY(!notPanel2->isActive());
- QCOMPARE(spy_deactivate_notPanel1.count(), 2);
- QCOMPARE(spy_deactivate_notPanel2.count(), 2);
+ QCOMPARE(spy_deactivate_notPanel1.count(), 1);
+ QCOMPARE(spy_deactivate_notPanel2.count(), 1);
// Reactivate the scene
QApplication::sendEvent(&scene, &activate);
@@ -7881,14 +7872,14 @@ void tst_QGraphicsItem::panel()
QVERIFY(!panel4->isActive());
QVERIFY(notPanel1->isActive());
QVERIFY(notPanel2->isActive());
- QCOMPARE(spy_activate_notPanel1.count(), 3);
- QCOMPARE(spy_activate_notPanel2.count(), 3);
+ QCOMPARE(spy_activate_notPanel1.count(), 2);
+ QCOMPARE(spy_activate_notPanel2.count(), 2);
// Switch to panel1
scene.setActivePanel(panel1);
QVERIFY(panel1->isActive());
- QCOMPARE(spy_deactivate_notPanel1.count(), 3);
- QCOMPARE(spy_deactivate_notPanel2.count(), 3);
+ QCOMPARE(spy_deactivate_notPanel1.count(), 2);
+ QCOMPARE(spy_deactivate_notPanel2.count(), 2);
QCOMPARE(spy_activate_panel1.count(), 2);
// Deactivate the scene
@@ -7942,5 +7933,110 @@ void tst_QGraphicsItem::addPanelToActiveScene()
QCOMPARE(scene.activePanel(), (QGraphicsItem *)rect);
}
+void tst_QGraphicsItem::activate()
+{
+ QGraphicsScene scene;
+ QGraphicsRectItem *rect = scene.addRect(-10, -10, 20, 20);
+ QVERIFY(!rect->isActive());
+
+ QEvent activate(QEvent::WindowActivate);
+ QEvent deactivate(QEvent::WindowDeactivate);
+
+ QApplication::sendEvent(&scene, &activate);
+
+ // Non-panel item (active when scene is active).
+ QVERIFY(rect->isActive());
+
+ QGraphicsRectItem *rect2 = new QGraphicsRectItem;
+ rect2->setFlag(QGraphicsItem::ItemIsPanel);
+ QGraphicsRectItem *rect3 = new QGraphicsRectItem;
+ rect3->setFlag(QGraphicsItem::ItemIsPanel);
+
+ // Test normal activation.
+ QVERIFY(!rect2->isActive());
+ scene.addItem(rect2);
+ QVERIFY(rect2->isActive()); // first panel item is activated
+ scene.addItem(rect3);
+ QVERIFY(!rect3->isActive()); // second panel item is _not_ activated
+ rect3->setActive(true);
+ QVERIFY(rect3->isActive());
+ scene.removeItem(rect3);
+ QVERIFY(!rect3->isActive()); // no panel is active anymore
+ QCOMPARE(scene.activePanel(), (QGraphicsItem *)0);
+ scene.addItem(rect3);
+ QVERIFY(rect3->isActive()); // second panel item is activated
+
+ // Test pending activation.
+ scene.removeItem(rect3);
+ rect2->setActive(true);
+ QVERIFY(rect2->isActive()); // first panel item is activated
+ rect3->setActive(true);
+ QVERIFY(!rect3->isActive()); // not active (yet)
+ scene.addItem(rect3);
+ QVERIFY(rect3->isActive()); // now becomes active
+
+ // Test pending deactivation.
+ scene.removeItem(rect3);
+ rect3->setActive(false);
+ scene.addItem(rect3);
+ QVERIFY(!rect3->isActive()); // doesn't become active
+
+ // Child of panel activation.
+ rect3->setActive(true);
+ QGraphicsRectItem *rect4 = new QGraphicsRectItem;
+ rect4->setFlag(QGraphicsItem::ItemIsPanel);
+ QGraphicsRectItem *rect5 = new QGraphicsRectItem(rect4);
+ QGraphicsRectItem *rect6 = new QGraphicsRectItem(rect5);
+ scene.addItem(rect4);
+ QCOMPARE(scene.activePanel(), (QGraphicsItem *)rect3);
+ scene.removeItem(rect4);
+ rect6->setActive(true);
+ scene.addItem(rect4);
+ QVERIFY(rect4->isActive());
+ QVERIFY(rect5->isActive());
+ QVERIFY(rect6->isActive());
+ QCOMPARE(scene.activePanel(), (QGraphicsItem *)rect4);
+ scene.removeItem(rect4); // no active panel
+ rect6->setActive(false);
+ scene.addItem(rect4);
+ QVERIFY(!rect4->isActive());
+ QVERIFY(!rect5->isActive());
+ QVERIFY(!rect6->isActive());
+ QCOMPARE(scene.activePanel(), (QGraphicsItem *)0);
+
+ // Controlling auto-activation when the scene changes activation.
+ rect4->setActive(true);
+ QApplication::sendEvent(&scene, &deactivate);
+ QVERIFY(!scene.isActive());
+ QVERIFY(!rect4->isActive());
+ rect4->setActive(false);
+ QApplication::sendEvent(&scene, &activate);
+ QVERIFY(scene.isActive());
+ QVERIFY(!scene.activePanel());
+ QVERIFY(!rect4->isActive());
+}
+
+void tst_QGraphicsItem::setActivePanelOnInactiveScene()
+{
+ QGraphicsScene scene;
+ QGraphicsRectItem *item = scene.addRect(QRectF());
+ QGraphicsRectItem *panel = scene.addRect(QRectF());
+ panel->setFlag(QGraphicsItem::ItemIsPanel);
+
+ EventSpy itemActivateSpy(&scene, item, QEvent::WindowActivate);
+ EventSpy itemDeactivateSpy(&scene, item, QEvent::WindowDeactivate);
+ EventSpy panelActivateSpy(&scene, panel, QEvent::WindowActivate);
+ EventSpy panelDeactivateSpy(&scene, panel, QEvent::WindowDeactivate);
+ EventSpy sceneActivationChangeSpy(&scene, QEvent::ActivationChange);
+
+ scene.setActivePanel(panel);
+ QCOMPARE(scene.activePanel(), (QGraphicsItem *)0);
+ QCOMPARE(itemActivateSpy.count(), 0);
+ QCOMPARE(itemDeactivateSpy.count(), 0);
+ QCOMPARE(panelActivateSpy.count(), 0);
+ QCOMPARE(panelDeactivateSpy.count(), 0);
+ QCOMPARE(sceneActivationChangeSpy.count(), 0);
+}
+
QTEST_MAIN(tst_QGraphicsItem)
#include "tst_qgraphicsitem.moc"