summaryrefslogtreecommitdiffstats
path: root/src/gui/graphicsview/qgraphicsscene.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/graphicsview/qgraphicsscene.cpp')
-rw-r--r--src/gui/graphicsview/qgraphicsscene.cpp164
1 files changed, 156 insertions, 8 deletions
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp
index 4b74b67..0acef0b 100644
--- a/src/gui/graphicsview/qgraphicsscene.cpp
+++ b/src/gui/graphicsview/qgraphicsscene.cpp
@@ -565,6 +565,9 @@ void QGraphicsScenePrivate::removeItemHelper(QGraphicsItem *item)
q->removeItem(item->d_ptr->children.at(i));
}
+ if (item->isPanel() && item->isVisible() && item->panelModality() != QGraphicsItem::NonModal)
+ leaveModal(item);
+
// Reset the mouse grabber and focus item data.
if (mouseGrabberItems.contains(item))
ungrabMouse(item, /* item is dying */ item->d_ptr->inDestructor);
@@ -1111,6 +1114,9 @@ void QGraphicsScenePrivate::sendMouseEvent(QGraphicsSceneMouseEvent *mouseEvent)
}
QGraphicsItem *item = mouseGrabberItems.last();
+ if (item->isBlockedByModalPanel())
+ return;
+
for (int i = 0x1; i <= 0x10; i <<= 1) {
Qt::MouseButton button = Qt::MouseButton(i);
mouseEvent->setButtonDownPos(button, mouseGrabberButtonDownPos.value(button, item->d_ptr->genericMapFromScene(mouseEvent->scenePos(), mouseEvent->widget())));
@@ -1134,6 +1140,8 @@ void QGraphicsScenePrivate::mousePressEventHandler(QGraphicsSceneMouseEvent *mou
// Deliver to any existing mouse grabber.
if (!mouseGrabberItems.isEmpty()) {
+ if (mouseGrabberItems.last()->isBlockedByModalPanel())
+ return;
// The event is ignored by default, but we disregard the event's
// accepted state after delivery; the mouse is grabbed, after all.
sendMouseEvent(mouseEvent);
@@ -1151,12 +1159,22 @@ void QGraphicsScenePrivate::mousePressEventHandler(QGraphicsSceneMouseEvent *mou
// Update window activation.
QGraphicsItem *topItem = cachedItemsUnderMouse.value(0);
QGraphicsWidget *newActiveWindow = topItem ? topItem->window() : 0;
+ if (newActiveWindow && newActiveWindow->isBlockedByModalPanel(&topItem)) {
+ // pass activation to the blocking modal window
+ newActiveWindow = topItem ? topItem->window() : 0;
+ }
+
if (newActiveWindow != q->activeWindow())
q->setActiveWindow(newActiveWindow);
// Set focus on the topmost enabled item that can take focus.
bool setFocus = false;
foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
+ if (item->isBlockedByModalPanel()) {
+ // Make sure we don't clear focus.
+ setFocus = true;
+ break;
+ }
if (item->isEnabled() && ((item->flags() & QGraphicsItem::ItemIsFocusable) && item->d_ptr->mouseSetsFocus)) {
if (!item->isWidget() || ((QGraphicsWidget *)item)->focusPolicy() & Qt::ClickFocus) {
setFocus = true;
@@ -1165,12 +1183,27 @@ void QGraphicsScenePrivate::mousePressEventHandler(QGraphicsSceneMouseEvent *mou
break;
}
}
+ if (item->isPanel())
+ break;
+ }
+
+ // Check for scene modality.
+ bool sceneModality = false;
+ for (int i = 0; i < modalPanels.size(); ++i) {
+ if (modalPanels.at(i)->panelModality() == QGraphicsItem::SceneModal) {
+ sceneModality = true;
+ break;
+ }
}
// If nobody could take focus, clear it.
- if (!stickyFocus && !setFocus)
+ if (!stickyFocus && !setFocus && !sceneModality)
q->setFocusItem(0, Qt::MouseFocusReason);
+ // Any item will do.
+ if (sceneModality && cachedItemsUnderMouse.isEmpty())
+ cachedItemsUnderMouse << modalPanels.first();
+
// Find a mouse grabber by sending mouse press events to all mouse grabber
// candidates one at a time, until the event is accepted. It's accepted by
// default, so the receiver has to explicitly ignore it for it to pass
@@ -1181,6 +1214,10 @@ void QGraphicsScenePrivate::mousePressEventHandler(QGraphicsSceneMouseEvent *mou
continue;
}
+ // Check if this item is blocked by a modal panel and deliver the mouse event to the
+ // blocking panel instead of this item if blocked.
+ (void) item->isBlockedByModalPanel(&item);
+
grabMouse(item, /* implicit = */ true);
mouseEvent->accept();
@@ -2403,6 +2440,8 @@ void QGraphicsScene::addItem(QGraphicsItem *item)
d->selectedItems << item;
if (item->isWidget() && item->isVisible() && static_cast<QGraphicsWidget *>(item)->windowType() == Qt::Popup)
d->addPopup(static_cast<QGraphicsWidget *>(item));
+ if (item->isPanel() && item->isVisible() && item->panelModality() != QGraphicsItem::NonModal)
+ d->enterModal(item);
// Update creation order focus chain. Make sure to leave the widget's
// internal tab order intact.
@@ -3205,8 +3244,12 @@ bool QGraphicsScene::event(QEvent *event)
}
return false;
case QEvent::GraphicsSceneMouseMove:
- mouseMoveEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
+ {
+ QGraphicsSceneMouseEvent *mouseEvent = static_cast<QGraphicsSceneMouseEvent *>(event);
+ d->lastSceneMousePos = mouseEvent->scenePos();
+ mouseMoveEvent(mouseEvent);
break;
+ }
case QEvent::GraphicsSceneMousePress:
mousePressEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
break;
@@ -3228,8 +3271,12 @@ bool QGraphicsScene::event(QEvent *event)
case QEvent::GraphicsSceneHoverEnter:
case QEvent::GraphicsSceneHoverLeave:
case QEvent::GraphicsSceneHoverMove:
- d->dispatchHoverEvent(static_cast<QGraphicsSceneHoverEvent *>(event));
+ {
+ QGraphicsSceneHoverEvent *hoverEvent = static_cast<QGraphicsSceneHoverEvent *>(event);
+ d->lastSceneMousePos = hoverEvent->scenePos();
+ d->dispatchHoverEvent(hoverEvent);
break;
+ }
case QEvent::Leave:
d->leaveScene();
break;
@@ -3599,8 +3646,10 @@ void QGraphicsScene::helpEvent(QGraphicsSceneHelpEvent *helpEvent)
bool QGraphicsScenePrivate::itemAcceptsHoverEvents_helper(const QGraphicsItem *item) const
{
- return item->acceptHoverEvents()
- || (item->isWidget() && static_cast<const QGraphicsWidget *>(item)->d_func()->hasDecoration());
+ return (!item->isBlockedByModalPanel() &&
+ (item->acceptHoverEvents()
+ || (item->isWidget()
+ && static_cast<const QGraphicsWidget *>(item)->d_func()->hasDecoration())));
}
/*!
@@ -3674,7 +3723,9 @@ bool QGraphicsScenePrivate::dispatchHoverEvent(QGraphicsSceneHoverEvent *hoverEv
}
// Generate a move event for the item itself
- if (item && !hoverItems.isEmpty() && item == hoverItems.last()) {
+ if (item
+ && !hoverItems.isEmpty()
+ && item == hoverItems.last()) {
sendHoverEvent(QEvent::GraphicsSceneHoverMove, item, hoverEvent);
return true;
}
@@ -3708,8 +3759,7 @@ void QGraphicsScenePrivate::leaveScene()
while (!hoverItems.isEmpty()) {
QGraphicsItem *lastItem = hoverItems.takeLast();
- if (lastItem->acceptHoverEvents()
- || (lastItem->isWidget() && static_cast<QGraphicsWidget*>(lastItem)->d_func()->hasDecoration()))
+ if (itemAcceptsHoverEvents_helper(lastItem))
sendHoverEvent(QEvent::GraphicsSceneHoverLeave, lastItem, &hoverEvent);
}
}
@@ -3736,6 +3786,8 @@ void QGraphicsScene::keyPressEvent(QKeyEvent *keyEvent)
keyEvent->accept();
// Send it; QGraphicsItem::keyPressEvent ignores it. If the event
// is filtered out, stop propagating it.
+ if (p->isBlockedByModalPanel())
+ break;
if (!d->sendEvent(p, keyEvent))
break;
} while (!keyEvent->isAccepted() && !p->isPanel() && (p = p->parentItem()));
@@ -3766,6 +3818,8 @@ void QGraphicsScene::keyReleaseEvent(QKeyEvent *keyEvent)
keyEvent->accept();
// Send it; QGraphicsItem::keyPressEvent ignores it. If the event
// is filtered out, stop propagating it.
+ if (p->isBlockedByModalPanel())
+ break;
if (!d->sendEvent(p, keyEvent))
break;
} while (!keyEvent->isAccepted() && !p->isPanel() && (p = p->parentItem()));
@@ -5420,6 +5474,8 @@ void QGraphicsScenePrivate::touchEventHandler(QTouchEvent *sceneTouchEvent)
for (; it != end; ++it) {
QGraphicsItem *item = it.key();
+ (void) item->isBlockedByModalPanel(&item);
+
// determine event type from the state mask
QEvent::Type eventType;
switch (it.value().first) {
@@ -5493,6 +5549,8 @@ bool QGraphicsScenePrivate::sendTouchBeginEvent(QGraphicsItem *origin, QTouchEve
break;
}
}
+ if (item->isPanel())
+ break;
}
// If nobody could take focus, clear it.
@@ -5518,6 +5576,8 @@ bool QGraphicsScenePrivate::sendTouchBeginEvent(QGraphicsItem *origin, QTouchEve
}
break;
}
+ if (item->isPanel())
+ break;
}
touchEvent->setAccepted(eventAccepted);
@@ -5536,6 +5596,94 @@ void QGraphicsScenePrivate::updateInputMethodSensitivityInViews()
views.at(i)->d_func()->updateInputMethodSensitivity();
}
+void QGraphicsScenePrivate::enterModal(QGraphicsItem *panel, QGraphicsItem::PanelModality previousModality)
+{
+ Q_Q(QGraphicsScene);
+ Q_ASSERT(panel && panel->isPanel());
+
+ QGraphicsItem::PanelModality panelModality = panel->d_ptr->panelModality;
+ if (previousModality != QGraphicsItem::NonModal) {
+ // the panel is changing from one modality type to another... temporarily set it back so
+ // that blockedPanels is populated correctly
+ panel->d_ptr->panelModality = previousModality;
+ }
+
+ QSet<QGraphicsItem *> blockedPanels;
+ QList<QGraphicsItem *> items = q->items(); // ### store panels separately
+ for (int i = 0; i < items.count(); ++i) {
+ QGraphicsItem *item = items.at(i);
+ if (item->isPanel() && item->isBlockedByModalPanel())
+ blockedPanels.insert(item);
+ }
+ // blockedPanels contains all currently blocked panels
+
+ if (previousModality != QGraphicsItem::NonModal) {
+ // reset the modality to the proper value, since we changed it above
+ panel->d_ptr->panelModality = panelModality;
+ // remove this panel so that it will be reinserted at the front of the stack
+ modalPanels.removeAll(panel);
+ }
+
+ modalPanels.prepend(panel);
+
+ if (!hoverItems.isEmpty()) {
+ // send GraphicsSceneHoverLeave events to newly blocked hoverItems
+ QGraphicsSceneHoverEvent hoverEvent;
+ hoverEvent.setScenePos(lastSceneMousePos);
+ dispatchHoverEvent(&hoverEvent);
+ }
+
+ if (!mouseGrabberItems.isEmpty() && lastMouseGrabberItemHasImplicitMouseGrab) {
+ QGraphicsItem *item = mouseGrabberItems.last();
+ if (item->isBlockedByModalPanel())
+ ungrabMouse(item, /*itemIsDying =*/ false);
+ }
+
+ QEvent windowBlockedEvent(QEvent::WindowBlocked);
+ QEvent windowUnblockedEvent(QEvent::WindowUnblocked);
+ for (int i = 0; i < items.count(); ++i) {
+ QGraphicsItem *item = items.at(i);
+ if (item->isPanel()) {
+ if (!blockedPanels.contains(item) && item->isBlockedByModalPanel()) {
+ // send QEvent::WindowBlocked to newly blocked panels
+ sendEvent(item, &windowBlockedEvent);
+ } else if (blockedPanels.contains(item) && !item->isBlockedByModalPanel()) {
+ // send QEvent::WindowUnblocked to unblocked panels when downgrading
+ // a panel from SceneModal to PanelModal
+ sendEvent(item, &windowUnblockedEvent);
+ }
+ }
+ }
+}
+
+void QGraphicsScenePrivate::leaveModal(QGraphicsItem *panel)
+{
+ Q_Q(QGraphicsScene);
+ Q_ASSERT(panel && panel->isPanel());
+
+ QSet<QGraphicsItem *> blockedPanels;
+ QList<QGraphicsItem *> items = q->items(); // ### same as above
+ for (int i = 0; i < items.count(); ++i) {
+ QGraphicsItem *item = items.at(i);
+ if (item->isPanel() && item->isBlockedByModalPanel())
+ blockedPanels.insert(item);
+ }
+
+ modalPanels.removeAll(panel);
+
+ QEvent e(QEvent::WindowUnblocked);
+ for (int i = 0; i < items.count(); ++i) {
+ QGraphicsItem *item = items.at(i);
+ if (item->isPanel() && blockedPanels.contains(item) && !item->isBlockedByModalPanel())
+ sendEvent(item, &e);
+ }
+
+ // send GraphicsSceneHoverEnter events to newly unblocked items
+ QGraphicsSceneHoverEvent hoverEvent;
+ hoverEvent.setScenePos(lastSceneMousePos);
+ dispatchHoverEvent(&hoverEvent);
+}
+
QT_END_NAMESPACE
#include "moc_qgraphicsscene.cpp"