diff options
Diffstat (limited to 'src/gui/graphicsview/qgraphicsscene.cpp')
-rw-r--r-- | src/gui/graphicsview/qgraphicsscene.cpp | 328 |
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); } } |