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.cpp328
1 files changed, 215 insertions, 113 deletions
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp
index a819822..5dd71e2 100644
--- a/src/gui/graphicsview/qgraphicsscene.cpp
+++ b/src/gui/graphicsview/qgraphicsscene.cpp
@@ -9,8 +9,8 @@
** 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 either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** 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
@@ -21,20 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** 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.
**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -288,8 +288,10 @@ QGraphicsScenePrivate::QGraphicsScenePrivate()
focusItem(0),
lastFocusItem(0),
tabFocusFirst(0),
- activeWindow(0),
+ activePanel(0),
+ lastActivePanel(0),
activationRefCount(0),
+ childExplicitActivation(0),
lastMouseGrabberItem(0),
lastMouseGrabberItemHasImplicitMouseGrab(false),
dragDropItem(0),
@@ -516,10 +518,12 @@ void QGraphicsScenePrivate::removeItemHelper(QGraphicsItem *item)
focusItem = 0;
if (item == lastFocusItem)
lastFocusItem = 0;
- if (item == activeWindow) {
+ if (item == activePanel) {
// ### deactivate...
- activeWindow = 0;
+ activePanel = 0;
}
+ if (item == lastActivePanel)
+ lastActivePanel = 0;
// Disable selectionChanged() for individual items
++selectionChanging;
@@ -568,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)
{
@@ -670,8 +734,8 @@ void QGraphicsScenePrivate::removePopup(QGraphicsWidget *widget, bool itemIsDyin
if (focusItem && popupWidgets.isEmpty()) {
QFocusEvent event(QEvent::FocusIn, Qt::PopupFocusReason);
sendEvent(focusItem, &event);
- } else {
- ungrabKeyboard((QGraphicsItem *)widget, itemIsDying);
+ } else if (keyboardGrabberItems.contains(static_cast<QGraphicsItem *>(widget))) {
+ ungrabKeyboard(static_cast<QGraphicsItem *>(widget), itemIsDying);
}
if (!itemIsDying && widget->isVisible()) {
widget->hide();
@@ -1076,8 +1140,9 @@ void QGraphicsScenePrivate::mousePressEventHandler(QGraphicsSceneMouseEvent *mou
}
// Update window activation.
- QGraphicsWidget *newActiveWindow = windowForItem(cachedItemsUnderMouse.value(0));
- if (newActiveWindow != activeWindow)
+ QGraphicsItem *topItem = cachedItemsUnderMouse.value(0);
+ QGraphicsWidget *newActiveWindow = topItem ? topItem->window() : 0;
+ if (newActiveWindow != q->activeWindow())
q->setActiveWindow(newActiveWindow);
// Set focus on the topmost enabled item that can take focus.
@@ -1112,7 +1177,7 @@ void QGraphicsScenePrivate::mousePressEventHandler(QGraphicsSceneMouseEvent *mou
// check if the item we are sending to are disabled (before we send the event)
bool disabled = !item->isEnabled();
- bool isWindow = item->isWindow();
+ bool isPanel = item->isPanel();
if (mouseEvent->type() == QEvent::GraphicsSceneMouseDoubleClick
&& item != lastMouseGrabberItem && lastMouseGrabberItem) {
// If this item is different from the item that received the last
@@ -1153,8 +1218,8 @@ void QGraphicsScenePrivate::mousePressEventHandler(QGraphicsSceneMouseEvent *mou
}
ungrabMouse(item, /* itemIsDying = */ dontSendUngrabEvents);
- // Don't propagate through windows.
- if (isWindow)
+ // Don't propagate through panels.
+ if (isPanel)
break;
}
@@ -1176,18 +1241,6 @@ void QGraphicsScenePrivate::mousePressEventHandler(QGraphicsSceneMouseEvent *mou
}
}
-QGraphicsWidget *QGraphicsScenePrivate::windowForItem(const QGraphicsItem *item) const
-{
- if (!item)
- return 0;
- do {
- if (item->isWidget())
- return static_cast<const QGraphicsWidget *>(item)->window();
- item = item->parentItem();
- } while (item);
- return 0;
-}
-
/*!
\internal
@@ -2234,6 +2287,9 @@ void QGraphicsScene::destroyItemGroup(QGraphicsItemGroup *group)
moved to this scene), QGraphicsScene will send an addition notification as
the item is removed from its previous scene.
+ If the item is a panel, the scene is active, and there is no active panel
+ in the scene, then the item will be activated.
+
\sa removeItem(), addEllipse(), addLine(), addPath(), addPixmap(),
addRect(), addText(), addWidget()
*/
@@ -2356,9 +2412,29 @@ void QGraphicsScene::addItem(QGraphicsItem *item)
// Deliver post-change notification
item->itemChange(QGraphicsItem::ItemSceneHasChanged, newSceneVariant);
- // Auto-activate the first inactive window if the scene is active.
- if (d->activationRefCount > 0 && !d->activeWindow && item->isWindow())
- setActiveWindow(static_cast<QGraphicsWidget *>(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.
@@ -3130,40 +3206,43 @@ bool QGraphicsScene::event(QEvent *event)
case QEvent::InputMethod:
inputMethodEvent(static_cast<QInputMethodEvent *>(event));
break;
- case QEvent::WindowActivate: {
+ case QEvent::WindowActivate:
if (!d->activationRefCount++) {
- // Notify all non-window widgets.
- foreach (QGraphicsItem *item, items()) {
- if (item->isWidget() && item->isVisible() && !item->isWindow() && !item->parentWidget()) {
- QEvent event(QEvent::WindowActivate);
- QApplication::sendEvent(static_cast<QGraphicsWidget *>(item), &event);
+ if (d->lastActivePanel) {
+ // Activate the last panel.
+ d->setActivePanelHelper(d->lastActivePanel, true);
+ } else if (d->tabFocusFirst && d->tabFocusFirst->isPanel()) {
+ // Activate the panel of the first item in the tab focus
+ // chain.
+ d->setActivePanelHelper(d->tabFocusFirst, true);
+ } else {
+ // Activate all toplevel items.
+ QEvent event(QEvent::WindowActivate);
+ foreach (QGraphicsItem *item, items()) {
+ if (item->isVisible() && !item->isPanel() && !item->parentItem())
+ sendEvent(item, &event);
}
}
-
- // Restore window activation.
- QGraphicsItem *nextFocusItem = d->focusItem ? d->focusItem : d->lastFocusItem;
- if (nextFocusItem && nextFocusItem->window())
- setActiveWindow(static_cast<QGraphicsWidget *>(nextFocusItem));
- else if (d->tabFocusFirst && d->tabFocusFirst->isWindow())
- setActiveWindow(d->tabFocusFirst);
}
break;
- }
- case QEvent::WindowDeactivate: {
+ case QEvent::WindowDeactivate:
if (!--d->activationRefCount) {
- // Remove window activation.
- setActiveWindow(0);
-
- // Notify all non-window widgets.
- foreach (QGraphicsItem *item, items()) {
- if (item->isWidget() && item->isVisible() && !item->isWindow() && !item->parentWidget()) {
- QEvent event(QEvent::WindowDeactivate);
- QApplication::sendEvent(static_cast<QGraphicsWidget *>(item), &event);
+ if (d->activePanel) {
+ // Deactivate the active panel (but keep it so we can
+ // reactivate it later).
+ QGraphicsItem *lastActivePanel = d->activePanel;
+ d->setActivePanelHelper(0, true);
+ d->lastActivePanel = lastActivePanel;
+ } else {
+ // Activate all toplevel items.
+ QEvent event(QEvent::WindowDeactivate);
+ foreach (QGraphicsItem *item, items()) {
+ if (item->isVisible() && !item->isPanel() && !item->parentItem())
+ sendEvent(item, &event);
}
}
}
break;
- }
case QEvent::ApplicationFontChange: {
// Resolve the existing scene font.
d->resolveFont();
@@ -3526,8 +3605,8 @@ bool QGraphicsScenePrivate::dispatchHoverEvent(QGraphicsSceneHoverEvent *hoverEv
QGraphicsItem *commonAncestorItem = (item && !hoverItems.isEmpty()) ? item->commonAncestorItem(hoverItems.last()) : 0;
while (commonAncestorItem && !itemAcceptsHoverEvents_helper(commonAncestorItem))
commonAncestorItem = commonAncestorItem->parentItem();
- if (commonAncestorItem && commonAncestorItem->window() != item->window()) {
- // The common ancestor isn't in the same window as the two hovered
+ if (commonAncestorItem && commonAncestorItem->panel() != item->panel()) {
+ // The common ancestor isn't in the same panel as the two hovered
// items.
commonAncestorItem = 0;
}
@@ -3548,8 +3627,8 @@ bool QGraphicsScenePrivate::dispatchHoverEvent(QGraphicsSceneHoverEvent *hoverEv
QGraphicsItem *parent = item;
while (parent && parent != commonAncestorItem) {
parents.prepend(parent);
- if (parent->isWindow()) {
- // Stop at the window - we don't deliver beyond this point.
+ if (parent->isPanel()) {
+ // Stop at the panel - we don't deliver beyond this point.
break;
}
parent = parent->parentItem();
@@ -3626,7 +3705,7 @@ void QGraphicsScene::keyPressEvent(QKeyEvent *keyEvent)
// is filtered out, stop propagating it.
if (!d->sendEvent(p, keyEvent))
break;
- } while (!keyEvent->isAccepted() && !p->isWindow() && (p = p->parentItem()));
+ } while (!keyEvent->isAccepted() && !p->isPanel() && (p = p->parentItem()));
} else {
keyEvent->ignore();
}
@@ -3656,7 +3735,7 @@ void QGraphicsScene::keyReleaseEvent(QKeyEvent *keyEvent)
// is filtered out, stop propagating it.
if (!d->sendEvent(p, keyEvent))
break;
- } while (!keyEvent->isAccepted() && !p->isWindow() && (p = p->parentItem()));
+ } while (!keyEvent->isAccepted() && !p->isPanel() && (p = p->parentItem()));
} else {
keyEvent->ignore();
}
@@ -3818,9 +3897,9 @@ void QGraphicsScene::wheelEvent(QGraphicsSceneWheelEvent *wheelEvent)
wheelEvent->setPos(item->d_ptr->genericMapFromScene(wheelEvent->scenePos(),
wheelEvent->widget()));
wheelEvent->accept();
- bool isWindow = item->isWindow();
+ bool isPanel = item->isPanel();
d->sendEvent(item, wheelEvent);
- if (isWindow || wheelEvent->isAccepted())
+ if (isPanel || wheelEvent->isAccepted())
break;
}
}
@@ -4537,7 +4616,8 @@ void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, b
return;
}
- bool hasNoContents = item->d_ptr->flags & QGraphicsItem::ItemHasNoContents;
+ bool hasNoContents = item->d_ptr->flags & QGraphicsItem::ItemHasNoContents
+ && !item->d_ptr->graphicsEffect;
if (!hasNoContents) {
item->d_ptr->dirty = 1;
if (fullItemUpdate)
@@ -4627,11 +4707,15 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool
return;
}
- const bool itemHasContents = !(item->d_ptr->flags & QGraphicsItem::ItemHasNoContents);
+ bool itemHasContents = !(item->d_ptr->flags & QGraphicsItem::ItemHasNoContents);
const bool itemHasChildren = !item->d_ptr->children.isEmpty();
- if (!itemHasContents && !itemHasChildren) {
- resetDirtyItem(item);
- return; // Item has neither contents nor children!(?)
+ if (!itemHasContents) {
+ if (!itemHasChildren) {
+ resetDirtyItem(item);
+ return; // Item has neither contents nor children!(?)
+ }
+ if (item->d_ptr->graphicsEffect)
+ itemHasContents = true;
}
const qreal opacity = item->d_ptr->combineOpacityFromParent(parentOpacity);
@@ -4879,7 +4963,7 @@ bool QGraphicsScene::focusNextPrevChild(bool next)
if (widget->flags() & QGraphicsItem::ItemIsFocusable
&& widget->isEnabled() && widget->isVisibleTo(0)
&& (widget->focusPolicy() & Qt::TabFocus)
- && (!item || !item->isWindow() || item->isAncestorOf(widget))
+ && (!item || !item->isPanel() || item->isAncestorOf(widget))
) {
setFocusItem(widget, next ? Qt::TabFocusReason : Qt::BacktabFocusReason);
return true;
@@ -5066,6 +5150,49 @@ void QGraphicsScene::setPalette(const QPalette &palette)
}
/*!
+ \since 4.6
+
+ Returns true if the scene is active (e.g., it's viewed by
+ at least one QGraphicsView that is active); otherwise returns false.
+
+ \sa QGraphicsItem::isActive(), QWidget::isActiveWindow()
+*/
+bool QGraphicsScene::isActive() const
+{
+ Q_D(const QGraphicsScene);
+ return d->activationRefCount > 0;
+}
+
+/*!
+ \since 4.6
+ Returns the current active panel, or 0 if no panel is currently active.
+
+ \sa QGraphicsScene::setActivePanel()
+*/
+QGraphicsItem *QGraphicsScene::activePanel() const
+{
+ Q_D(const QGraphicsScene);
+ return d->activePanel;
+}
+
+/*!
+ \since 4.6
+ Activates \a item, which must be an item in this scene. You
+ 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);
+ d->setActivePanelHelper(item, false);
+}
+
+/*!
\since 4.4
Returns the current active window, or 0 if there is no window is currently
@@ -5076,7 +5203,9 @@ void QGraphicsScene::setPalette(const QPalette &palette)
QGraphicsWidget *QGraphicsScene::activeWindow() const
{
Q_D(const QGraphicsScene);
- return d->activeWindow;
+ if (d->activePanel && d->activePanel->isWindow())
+ return static_cast<QGraphicsWidget *>(d->activePanel);
+ return 0;
}
/*!
@@ -5089,61 +5218,34 @@ QGraphicsWidget *QGraphicsScene::activeWindow() const
*/
void QGraphicsScene::setActiveWindow(QGraphicsWidget *widget)
{
- Q_D(QGraphicsScene);
if (widget && widget->scene() != this) {
qWarning("QGraphicsScene::setActiveWindow: widget %p must be part of this scene",
widget);
return;
}
- // Activate the widget's window.
- QGraphicsWidget *window = widget ? widget->window() : 0;
- if (window == d->activeWindow)
- return;
-
- // Deactivate the last active window.
- if (d->activeWindow) {
- if (QGraphicsWidget *fw = d->activeWindow->focusWidget()) {
- // Remove focus from the current focus item.
- if (fw == focusItem())
- setFocusItem(0, Qt::ActiveWindowFocusReason);
- }
-
- QEvent event(QEvent::WindowDeactivate);
- QApplication::sendEvent(d->activeWindow, &event);
- }
-
- // Update activate state.
- d->activeWindow = window;
- QEvent event(QEvent::ActivationChange);
- QApplication::sendEvent(this, &event);
-
- // Activate
- if (window) {
- QEvent event(QEvent::WindowActivate);
- QApplication::sendEvent(window, &event);
+ // Activate the widget's panel (all windows are panels).
+ QGraphicsItem *panel = widget ? widget->panel() : 0;
+ setActivePanel(panel);
+ // Raise
+ if (panel) {
QList<QGraphicsItem *> siblingWindows;
- QGraphicsItem *parent = window->parentItem();
+ QGraphicsItem *parent = panel->parentItem();
// Raise ### inefficient for toplevels
foreach (QGraphicsItem *sibling, parent ? parent->children() : items()) {
- if (sibling != window && sibling->isWidget()
- && static_cast<QGraphicsWidget *>(sibling)->isWindow()) {
+ if (sibling != panel && sibling->isWindow())
siblingWindows << sibling;
- }
}
// Find the highest z value.
- qreal z = window->zValue();
+ qreal z = panel->zValue();
for (int i = 0; i < siblingWindows.size(); ++i)
z = qMax(z, siblingWindows.at(i)->zValue());
// This will probably never overflow.
const qreal litt = qreal(0.001);
- window->setZValue(z + litt);
-
- if (QGraphicsWidget *focusChild = window->focusWidget())
- focusChild->setFocus(Qt::ActiveWindowFocusReason);
+ panel->setZValue(z + litt);
}
}