blob: e87e8375a08ff498633e0629972b9f290b267a4a [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements 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.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.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qglobal.h"
#ifndef QT_NO_GRAPHICSVIEW
#include "qgraphicslayout.h"
#include "qgraphicsproxywidget.h"
#include "private/qgraphicsproxywidget_p.h"
#include "private/qwidget_p.h"
#include "private/qapplication_p.h"
#include <QtCore/qdebug.h>
#include <QtGui/qevent.h>
#include <QtGui/qgraphicsscene.h>
#include <QtGui/qgraphicssceneevent.h>
#include <QtGui/qlayout.h>
#include <QtGui/qpainter.h>
#include <QtGui/qstyleoption.h>
#include <QtGui/qgraphicsview.h>
#include <QtGui/qlistview.h>
#include <QtGui/qlineedit.h>
#include <QtGui/qtextedit.h>
QT_BEGIN_NAMESPACE
//#define GRAPHICSPROXYWIDGET_DEBUG
/*!
\class QGraphicsProxyWidget
\brief The QGraphicsProxyWidget class provides a proxy layer for embedding
a QWidget in a QGraphicsScene.
\since 4.4
\ingroup graphicsview-api
QGraphicsProxyWidget embeds QWidget-based widgets, for example, a
QPushButton, QFontComboBox, or even QFileDialog, into
QGraphicsScene. It forwards events between the two objects and
translates between QWidget's integer-based geometry and
QGraphicsWidget's qreal-based geometry. QGraphicsProxyWidget
supports all core features of QWidget, including tab focus,
keyboard input, Drag & Drop, and popups. You can also embed
complex widgets, e.g., widgets with subwidgets.
Example:
\snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsproxywidget.cpp 0
QGraphicsProxyWidget takes care of automatically embedding popup children
of embedded widgets through creating a child proxy for each popup. This
means that when an embedded QComboBox shows its popup list, a new
QGraphicsProxyWidget is created automatically, embedding the popup, and
positioning it correctly. This only works if the popup is child of the
embedded widget (for example QToolButton::setMenu() requires the QMenu instance
to be child of the QToolButton).
\section1 Embedding a Widget with QGraphicsProxyWidget
There are two ways to embed a widget using QGraphicsProxyWidget. The most
common way is to pass a widget pointer to QGraphicsScene::addWidget()
together with any relevant \l Qt::WindowFlags. This function returns a
pointer to a QGraphicsProxyWidget. You can then choose to reparent or
position either the proxy, or the embedded widget itself.
For example, in the code snippet below, we embed a group box into the proxy:
\snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsproxywidget.cpp 1
The image below is the output obtained with its contents margin and
contents rect labeled.
\image qgraphicsproxywidget-embed.png
Alternatively, you can start by creating a new QGraphicsProxyWidget item,
and then call setWidget() to embed a QWidget later. The widget() function
returns a pointer to the embedded widget. QGraphicsProxyWidget shares
ownership with QWidget, so if either of the two widgets are destroyed, the
other widget will be automatically destroyed as well.
\section1 Synchronizing Widget States
QGraphicsProxyWidget keeps its state in sync with the embedded widget. For
example, if the proxy is hidden or disabled, the embedded widget will be
hidden or disabled as well, and vice versa. When the widget is embedded by
calling addWidget(), QGraphicsProxyWidget copies the state from the widget
into the proxy, and after that, the two will stay synchronized where
possible. By default, when you embed a widget into a proxy, both the widget
and the proxy will be visible because a QGraphicsWidget is visible when
created (you do not have to call show()). If you explicitly hide the
embedded widget, the proxy will also become invisible.
Example:
\snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsproxywidget.cpp 2
QGraphicsProxyWidget maintains symmetry for the following states:
\table
\header \o QWidget state \o QGraphicsProxyWidget state \o Notes
\row \o QWidget::enabled
\o QGraphicsProxyWidget::enabled
\o
\row \o QWidget::visible
\o QGraphicsProxyWidget::visible
\o The explicit state is also symmetric.
\row \o QWidget::geometry
\o QGraphicsProxyWidget::geometry
\o Geometry is only guaranteed to be symmetric while
the embedded widget is visible.
\row \o QWidget::layoutDirection
\o QGraphicsProxyWidget::layoutDirection
\o
\row \o QWidget::style
\o QGraphicsProxyWidget::style
\o
\row \o QWidget::palette
\o QGraphicsProxyWidget::palette
\o
\row \o QWidget::font
\o QGraphicsProxyWidget::font
\o
\row \o QWidget::cursor
\o QGraphicsProxyWidget::cursor
\o The embedded widget overrides the proxy widget
cursor. The proxy cursor changes depending on
which embedded subwidget is currently under the
mouse.
\row \o QWidget::sizeHint()
\o QGraphicsProxyWidget::sizeHint()
\o All size hint functionality from the embedded
widget is forwarded by the proxy.
\row \o QWidget::getContentsMargins()
\o QGraphicsProxyWidget::getContentsMargins()
\o Updated once by setWidget().
\row \o QWidget::windowTitle
\o QGraphicsProxyWidget::windowTitle
\o Updated once by setWidget().
\endtable
\note QGraphicsScene keeps the embedded widget in a special state that
prevents it from disturbing other widgets (both embedded and not embedded)
while the widget is embedded. In this state, the widget may differ slightly
in behavior from when it is not embedded.
\warning This class is provided for convenience when bridging
QWidgets and QGraphicsItems, it should not be used for
high-performance scenarios.
\sa QGraphicsScene::addWidget(), QGraphicsWidget
*/
extern bool qt_sendSpontaneousEvent(QObject *, QEvent *);
Q_GUI_EXPORT extern bool qt_tab_all_widgets;
/*!
\internal
*/
void QGraphicsProxyWidgetPrivate::init()
{
Q_Q(QGraphicsProxyWidget);
q->setFocusPolicy(Qt::WheelFocus);
q->setAcceptDrops(true);
}
/*!
\internal
*/
void QGraphicsProxyWidgetPrivate::sendWidgetMouseEvent(QGraphicsSceneHoverEvent *event)
{
QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMouseMove);
mouseEvent.setPos(event->pos());
mouseEvent.setScreenPos(event->screenPos());
mouseEvent.setButton(Qt::NoButton);
mouseEvent.setButtons(0);
mouseEvent.setModifiers(event->modifiers());
sendWidgetMouseEvent(&mouseEvent);
event->setAccepted(mouseEvent.isAccepted());
}
/*!
\internal
*/
void QGraphicsProxyWidgetPrivate::sendWidgetMouseEvent(QGraphicsSceneMouseEvent *event)
{
if (!event || !widget || !widget->isVisible())
return;
Q_Q(QGraphicsProxyWidget);
// Find widget position and receiver.
QPointF pos = event->pos();
QPointer<QWidget> alienWidget = widget->childAt(pos.toPoint());
QPointer<QWidget> receiver = alienWidget ? alienWidget : widget;
if (QWidgetPrivate::nearestGraphicsProxyWidget(receiver) != q)
return; //another proxywidget will handle the events
// Translate QGraphicsSceneMouse events to QMouseEvents.
QEvent::Type type = QEvent::None;
switch (event->type()) {
case QEvent::GraphicsSceneMousePress:
type = QEvent::MouseButtonPress;
if (!embeddedMouseGrabber)
embeddedMouseGrabber = receiver;
else
receiver = embeddedMouseGrabber;
break;
case QEvent::GraphicsSceneMouseRelease:
type = QEvent::MouseButtonRelease;
if (embeddedMouseGrabber)
receiver = embeddedMouseGrabber;
break;
case QEvent::GraphicsSceneMouseDoubleClick:
type = QEvent::MouseButtonDblClick;
if (!embeddedMouseGrabber)
embeddedMouseGrabber = receiver;
else
receiver = embeddedMouseGrabber;
break;
case QEvent::GraphicsSceneMouseMove:
type = QEvent::MouseMove;
if (embeddedMouseGrabber)
receiver = embeddedMouseGrabber;
break;
default:
Q_ASSERT_X(false, "QGraphicsProxyWidget", "internal error");
break;
}
if (!lastWidgetUnderMouse) {
QApplicationPrivate::dispatchEnterLeave(embeddedMouseGrabber ? embeddedMouseGrabber : widget, 0);
lastWidgetUnderMouse = widget;
}
// Map event position from us to the receiver
pos = mapToReceiver(pos, receiver);
// Send mouse event.
QMouseEvent *mouseEvent = QMouseEvent::createExtendedMouseEvent(type, pos,
receiver->mapToGlobal(pos.toPoint()), event->button(),
event->buttons(), event->modifiers());
QWidget *embeddedMouseGrabberPtr = (QWidget *)embeddedMouseGrabber;
QApplicationPrivate::sendMouseEvent(receiver, mouseEvent, alienWidget, widget,
&embeddedMouseGrabberPtr, lastWidgetUnderMouse, event->spontaneous());
embeddedMouseGrabber = embeddedMouseGrabberPtr;
// Handle enter/leave events when last button is released from mouse
// grabber child widget.
if (embeddedMouseGrabber && type == QEvent::MouseButtonRelease && !event->buttons()) {
Q_Q(QGraphicsProxyWidget);
if (q->rect().contains(event->pos()) && q->acceptsHoverEvents())
lastWidgetUnderMouse = alienWidget ? alienWidget : widget;
else // released on the frame our outside the item, or doesn't accept hover events.
lastWidgetUnderMouse = 0;
QApplicationPrivate::dispatchEnterLeave(lastWidgetUnderMouse, embeddedMouseGrabber);
embeddedMouseGrabber = 0;
#ifndef QT_NO_CURSOR
// ### Restore the cursor, don't override it.
if (!lastWidgetUnderMouse)
q->unsetCursor();
#endif
}
event->setAccepted(mouseEvent->isAccepted());
delete mouseEvent;
}
void QGraphicsProxyWidgetPrivate::sendWidgetKeyEvent(QKeyEvent *event)
{
Q_Q(QGraphicsProxyWidget);
if (!event || !widget || !widget->isVisible())
return;
QPointer<QWidget> receiver = widget->focusWidget();
if (!receiver)
receiver = widget;
Q_ASSERT(receiver);
do {
bool res = QApplication::sendEvent(receiver, event);
if ((res && event->isAccepted()) || (q->isWindow() && receiver == widget))
break;
receiver = receiver->parentWidget();
} while (receiver);
}
/*!
\internal
*/
void QGraphicsProxyWidgetPrivate::removeSubFocusHelper(QWidget *widget, Qt::FocusReason reason)
{
QFocusEvent event(QEvent::FocusOut, reason);
QPointer<QWidget> widgetGuard = widget;
QApplication::sendEvent(widget, &event);
if (widgetGuard && event.isAccepted())
QApplication::sendEvent(widget->style(), &event);
}
/*!
\internal
Reimplemented from QGraphicsItemPrivate. ### Qt 5: Move impl to
reimplementation QGraphicsProxyWidget::inputMethodQuery().
*/
QVariant QGraphicsProxyWidgetPrivate::inputMethodQueryHelper(Qt::InputMethodQuery query) const
{
Q_Q(const QGraphicsProxyWidget);
if (!widget || !q->hasFocus())
return QVariant();
QWidget *focusWidget = widget->focusWidget();
if (!focusWidget)
focusWidget = widget;
QVariant v = focusWidget->inputMethodQuery(query);
QPointF focusWidgetPos = q->subWidgetRect(focusWidget).topLeft();
switch (v.type()) {
case QVariant::RectF:
v = v.toRectF().translated(focusWidgetPos);
break;
case QVariant::PointF:
v = v.toPointF() + focusWidgetPos;
break;
case QVariant::Rect:
v = v.toRect().translated(focusWidgetPos.toPoint());
break;
case QVariant::Point:
v = v.toPoint() + focusWidgetPos.toPoint();
break;
default:
break;
}
return v;
}
/*!
\internal
Some of the logic is shared with QApplicationPrivate::focusNextPrevChild_helper
*/
QWidget *QGraphicsProxyWidgetPrivate::findFocusChild(QWidget *child, bool next) const
{
if (!widget)
return 0;
// Run around the focus chain until we find a widget that can take tab focus.
if (!child) {
child = next ? (QWidget *)widget : widget->d_func()->focus_prev;
} else {
child = next ? child->d_func()->focus_next : child->d_func()->focus_prev;
if ((next && child == widget) || (!next && child == widget->d_func()->focus_prev)) {
return 0;
}
}
QWidget *oldChild = child;
uint focus_flag = qt_tab_all_widgets ? Qt::TabFocus : Qt::StrongFocus;
do {
if (child->isEnabled()
&& child->isVisibleTo(widget)
&& ((child->focusPolicy() & focus_flag) == focus_flag)
&& !(child->d_func()->extra && child->d_func()->extra->focus_proxy)) {
return child;
}
child = next ? child->d_func()->focus_next : child->d_func()->focus_prev;
} while (child != oldChild && !(next && child == widget) && !(!next && child == widget->d_func()->focus_prev));
return 0;
}
/*!
\internal
*/
void QGraphicsProxyWidgetPrivate::_q_removeWidgetSlot()
{
Q_Q(QGraphicsProxyWidget);
widget = 0;
delete q;
}
/*!
\internal
*/
void QGraphicsProxyWidgetPrivate::updateWidgetGeometryFromProxy()
{
}
/*!
\internal
*/
void QGraphicsProxyWidgetPrivate::updateProxyGeometryFromWidget()
{
Q_Q(QGraphicsProxyWidget);
if (!widget)
return;
QRectF widgetGeometry = widget->geometry();
QWidget *parentWidget = widget->parentWidget();
if (widget->isWindow()) {
QGraphicsProxyWidget *proxyParent = 0;
if (parentWidget && (proxyParent = qobject_cast<QGraphicsProxyWidget *>(q->parentWidget()))) {
// Nested window proxy (e.g., combobox popup), map widget to the
// parent widget's global coordinates, and map that to the parent
// proxy's child coordinates.
widgetGeometry.moveTo(proxyParent->subWidgetRect(parentWidget).topLeft()
+ parentWidget->mapFromGlobal(widget->pos()));
}
}
// Adjust to size hint if the widget has never been resized.
if (!widget->size().isValid())
widgetGeometry.setSize(widget->sizeHint());
// Assign new geometry.
posChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
sizeChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
q->setGeometry(widgetGeometry);
posChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
sizeChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
}
/*!
\internal
*/
void QGraphicsProxyWidgetPrivate::updateProxyInputMethodAcceptanceFromWidget()
{
Q_Q(QGraphicsProxyWidget);
if (!widget)
return;
QWidget *focusWidget = widget->focusWidget();
if (!focusWidget)
focusWidget = widget;
q->setFlag(QGraphicsItem::ItemAcceptsInputMethod,
focusWidget->testAttribute(Qt::WA_InputMethodEnabled));
}
/*!
\internal
Embeds \a subWin as a subwindow of this proxy widget. \a subWin must be a top-level
widget and a descendant of the widget managed by this proxy. A separate subproxy
will be created as a child of this proxy widget to manage \a subWin.
*/
void QGraphicsProxyWidgetPrivate::embedSubWindow(QWidget *subWin)
{
QWExtra *extra;
if (!((extra = subWin->d_func()->extra) && extra->proxyWidget)) {
QGraphicsProxyWidget *subProxy = new QGraphicsProxyWidget(q_func(), subWin->windowFlags());
subProxy->d_func()->setWidget_helper(subWin, false);
}
}
/*!
\internal
Removes ("unembeds") \a subWin and deletes the proxy holder item. This can
happen when QWidget::setParent() reparents the embedded window out of
"embedded space".
*/
void QGraphicsProxyWidgetPrivate::unembedSubWindow(QWidget *subWin)
{
foreach (QGraphicsItem *child, children) {
if (child->isWidget()) {
if (QGraphicsProxyWidget *proxy = qobject_cast<QGraphicsProxyWidget *>(static_cast<QGraphicsWidget *>(child))) {
if (proxy->widget() == subWin) {
proxy->setWidget(0);
scene->removeItem(proxy);
delete proxy;
return;
}
}
}
}
}
bool QGraphicsProxyWidgetPrivate::isProxyWidget() const
{
return true;
}
/*!
\internal
*/
QPointF QGraphicsProxyWidgetPrivate::mapToReceiver(const QPointF &pos, const QWidget *receiver) const
{
QPointF p = pos;
// Map event position from us to the receiver, preserving its
// precision (don't use QWidget::mapFrom here).
while (receiver && receiver != widget) {
p -= QPointF(receiver->pos());
receiver = receiver->parentWidget();
}
return p;
}
/*!
Constructs a new QGraphicsProxy widget. \a parent and \a wFlags are passed
to QGraphicsItem's constructor.
*/
QGraphicsProxyWidget::QGraphicsProxyWidget(QGraphicsItem *parent, Qt::WindowFlags wFlags)
: QGraphicsWidget(*new QGraphicsProxyWidgetPrivate, parent, 0, wFlags)
{
Q_D(QGraphicsProxyWidget);
d->init();
}
/*!
Destroys the proxy widget and any embedded widget.
*/
QGraphicsProxyWidget::~QGraphicsProxyWidget()
{
Q_D(QGraphicsProxyWidget);
if (d->widget) {
QObject::disconnect(d->widget, SIGNAL(destroyed()), this, SLOT(_q_removeWidgetSlot()));
delete d->widget;
}
}
/*!
Embeds \a widget into this proxy widget. The embedded widget must reside
exclusively either inside or outside of Graphics View. You cannot embed a
widget as long as it is is visible elsewhere in the UI, at the same time.
\a widget must be a top-level widget whose parent is 0.
When the widget is embedded, its state (e.g., visible, enabled, geometry,
size hints) is copied into the proxy widget. If the embedded widget is
explicitly hidden or disabled, the proxy widget will become explicitly
hidden or disabled after embedding is complete. The class documentation
has a full overview over the shared state.
QGraphicsProxyWidget's window flags determine whether the widget, after
embedding, will be given window decorations or not.
After this function returns, QGraphicsProxyWidget will keep its state
synchronized with that of \a widget whenever possible.
If a widget is already embedded by this proxy when this function is
called, that widget will first be automatically unembedded. Passing 0 for
the \a widget argument will only unembed the widget, and the ownership of
the currently embedded widget will be passed on to the caller.
Every child widget that are embedded will also be embedded and their proxy
widget destroyed.
Note that widgets with the Qt::WA_PaintOnScreen widget attribute
set and widgets that wrap an external application or controller
cannot be embedded. Examples are QGLWidget and QAxWidget.
\sa widget()
*/
void QGraphicsProxyWidget::setWidget(QWidget *widget)
{
Q_D(QGraphicsProxyWidget);
d->setWidget_helper(widget, true);
}
void QGraphicsProxyWidgetPrivate::setWidget_helper(QWidget *newWidget, bool autoShow)
{
Q_Q(QGraphicsProxyWidget);
if (newWidget == widget)
return;
if (widget) {
QObject::disconnect(widget, SIGNAL(destroyed()), q, SLOT(_q_removeWidgetSlot()));
widget->removeEventFilter(q);
widget->setAttribute(Qt::WA_DontShowOnScreen, false);
widget->d_func()->extra->proxyWidget = 0;
resolveFont(inheritedFontResolveMask);
resolvePalette(inheritedPaletteResolveMask);
widget->update();
foreach (QGraphicsItem *child, q->childItems()) {
if (child->d_ptr->isProxyWidget()) {
QGraphicsProxyWidget *childProxy = static_cast<QGraphicsProxyWidget *>(child);
QWidget * parent = childProxy->widget();
while (parent->parentWidget() != 0) {
if (parent == widget)
break;
parent = parent->parentWidget();
}
if (!childProxy->widget() || parent != widget)
continue;
childProxy->setWidget(0);
delete childProxy;
}
}
widget = 0;
#ifndef QT_NO_CURSOR
q->unsetCursor();
#endif
q->setAcceptHoverEvents(false);
if (!newWidget)
q->update();
}
if (!newWidget)
return;
if (!newWidget->isWindow()) {
QWExtra *extra = newWidget->parentWidget()->d_func()->extra;
if (!extra || !extra->proxyWidget) {
qWarning("QGraphicsProxyWidget::setWidget: cannot embed widget %p "
"which is not a toplevel widget, and is not a child of an embedded widget", newWidget);
return;
}
}
// Register this proxy within the widget's private.
// ### This is a bit backdoorish
QWExtra *extra = newWidget->d_func()->extra;
if (!extra) {
newWidget->d_func()->createExtra();
extra = newWidget->d_func()->extra;
}
QGraphicsProxyWidget **proxyWidget = &extra->proxyWidget;
if (*proxyWidget) {
if (*proxyWidget != q) {
qWarning("QGraphicsProxyWidget::setWidget: cannot embed widget %p"
"; already embedded", newWidget);
}
return;
}
*proxyWidget = q;
newWidget->setAttribute(Qt::WA_DontShowOnScreen);
newWidget->ensurePolished();
// Do not wait for this widget to close before the app closes ###
// shouldn't this widget inherit the attribute?
newWidget->setAttribute(Qt::WA_QuitOnClose, false);
q->setAcceptHoverEvents(true);
if (newWidget->testAttribute(Qt::WA_NoSystemBackground))
q->setAttribute(Qt::WA_NoSystemBackground);
if (newWidget->testAttribute(Qt::WA_OpaquePaintEvent))
q->setAttribute(Qt::WA_OpaquePaintEvent);
widget = newWidget;
// Changes only go from the widget to the proxy.
enabledChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
visibleChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
posChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
sizeChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
if ((autoShow && !newWidget->testAttribute(Qt::WA_WState_ExplicitShowHide)) || !newWidget->testAttribute(Qt::WA_WState_Hidden)) {
newWidget->show();
}
// Copy the state from the widget onto the proxy.
#ifndef QT_NO_CURSOR
if (newWidget->testAttribute(Qt::WA_SetCursor))
q->setCursor(widget->cursor());
#endif
q->setEnabled(newWidget->isEnabled());
q->setVisible(newWidget->isVisible());
q->setLayoutDirection(newWidget->layoutDirection());
if (newWidget->testAttribute(Qt::WA_SetStyle))
q->setStyle(widget->style());
resolveFont(inheritedFontResolveMask);
resolvePalette(inheritedPaletteResolveMask);
if (!newWidget->testAttribute(Qt::WA_Resized))
newWidget->adjustSize();
int left, top, right, bottom;
newWidget->getContentsMargins(&left, &top, &right, &bottom);
q->setContentsMargins(left, top, right, bottom);
q->setWindowTitle(newWidget->windowTitle());
// size policies and constraints..
q->setSizePolicy(newWidget->sizePolicy());
QSize sz = newWidget->minimumSize();
q->setMinimumSize(sz.isNull() ? QSizeF() : QSizeF(sz));
sz = newWidget->maximumSize();
q->setMaximumSize(sz.isNull() ? QSizeF() : QSizeF(sz));
updateProxyGeometryFromWidget();
updateProxyInputMethodAcceptanceFromWidget();
// Hook up the event filter to keep the state up to date.
newWidget->installEventFilter(q);
QObject::connect(newWidget, SIGNAL(destroyed()), q, SLOT(_q_removeWidgetSlot()));
// Changes no longer go only from the widget to the proxy.
enabledChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
visibleChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
posChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
sizeChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
}
/*!
Returns a pointer to the embedded widget.
\sa setWidget()
*/
QWidget *QGraphicsProxyWidget::widget() const
{
Q_D(const QGraphicsProxyWidget);
return d->widget;
}
/*!
Returns the rectangle for \a widget, which must be a descendant of
widget(), or widget() itself, in this proxy item's local coordinates.
If no widget is embedded, \a widget is 0, or \a widget is not a
descendant of the embedded widget, this function returns an empty QRectF.
\sa widget()
*/
QRectF QGraphicsProxyWidget::subWidgetRect(const QWidget *widget) const
{
Q_D(const QGraphicsProxyWidget);
if (!widget || !d->widget)
return QRectF();
if (d->widget == widget || d->widget->isAncestorOf(widget))
return QRectF(widget->mapTo(d->widget, QPoint(0, 0)), widget->size());
return QRectF();
}
/*!
\reimp
*/
void QGraphicsProxyWidget::setGeometry(const QRectF &rect)
{
Q_D(QGraphicsProxyWidget);
bool proxyResizesWidget = !d->posChangeMode && !d->sizeChangeMode;
if (proxyResizesWidget) {
d->posChangeMode = QGraphicsProxyWidgetPrivate::ProxyToWidgetMode;
d->sizeChangeMode = QGraphicsProxyWidgetPrivate::ProxyToWidgetMode;
}
QGraphicsWidget::setGeometry(rect);
if (proxyResizesWidget) {
d->posChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
d->sizeChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
}
}
/*!
\reimp
*/
QVariant QGraphicsProxyWidget::itemChange(GraphicsItemChange change,
const QVariant &value)
{
Q_D(QGraphicsProxyWidget);
switch (change) {
case ItemPositionChange:
// The item's position is either changed directly on the proxy, in
// which case the position change should propagate to the widget,
// otherwise it happens as a side effect when filtering QEvent::Move.
if (!d->posChangeMode)
d->posChangeMode = QGraphicsProxyWidgetPrivate::ProxyToWidgetMode;
break;
case ItemPositionHasChanged:
// Move the internal widget if we're in widget-to-proxy
// mode. Otherwise the widget has already moved.
if (d->widget && d->posChangeMode != QGraphicsProxyWidgetPrivate::WidgetToProxyMode)
d->widget->move(value.toPoint());
if (d->posChangeMode == QGraphicsProxyWidgetPrivate::ProxyToWidgetMode)
d->posChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
break;
case ItemVisibleChange:
if (!d->visibleChangeMode)
d->visibleChangeMode = QGraphicsProxyWidgetPrivate::ProxyToWidgetMode;
break;
case ItemVisibleHasChanged:
if (d->widget && d->visibleChangeMode != QGraphicsProxyWidgetPrivate::WidgetToProxyMode)
d->widget->setVisible(isVisible());
if (d->visibleChangeMode == QGraphicsProxyWidgetPrivate::ProxyToWidgetMode)
d->visibleChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
break;
case ItemEnabledChange:
if (!d->enabledChangeMode)
d->enabledChangeMode = QGraphicsProxyWidgetPrivate::ProxyToWidgetMode;
break;
case ItemEnabledHasChanged:
if (d->widget && d->enabledChangeMode != QGraphicsProxyWidgetPrivate::WidgetToProxyMode)
d->widget->setEnabled(isEnabled());
if (d->enabledChangeMode == QGraphicsProxyWidgetPrivate::ProxyToWidgetMode)
d->enabledChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
break;
default:
break;
}
return QGraphicsWidget::itemChange(change, value);
}
/*!
\reimp
*/
bool QGraphicsProxyWidget::event(QEvent *event)
{
Q_D(QGraphicsProxyWidget);
if (!d->widget)
return QGraphicsWidget::event(event);
switch (event->type()) {
case QEvent::StyleChange:
// Propagate style changes to the embedded widget.
if (!d->styleChangeMode) {
d->styleChangeMode = QGraphicsProxyWidgetPrivate::ProxyToWidgetMode;
d->widget->setStyle(style());
d->styleChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
}
break;
case QEvent::FontChange: {
// Propagate to widget.
QWidgetPrivate *wd = d->widget->d_func();
int mask = d->font.resolve() | d->inheritedFontResolveMask;
wd->inheritedFontResolveMask = mask;
wd->resolveFont();
break;
}
case QEvent::PaletteChange: {
// Propagate to widget.
QWidgetPrivate *wd = d->widget->d_func();
int mask = d->palette.resolve() | d->inheritedPaletteResolveMask;
wd->inheritedPaletteResolveMask = mask;
wd->resolvePalette();
break;
}
case QEvent::InputMethod: {
// Forward input method events if the focus widget enables
// input methods.
// ### Qt 4.5: this code must also go into a reimplementation
// of inputMethodEvent().
QWidget *focusWidget = d->widget->focusWidget();
if (focusWidget && focusWidget->testAttribute(Qt::WA_InputMethodEnabled))
QApplication::sendEvent(focusWidget, event);
break;
}
case QEvent::ShortcutOverride: {
QWidget *focusWidget = d->widget->focusWidget();
while (focusWidget) {
QApplication::sendEvent(focusWidget, event);
if (event->isAccepted())
return true;
focusWidget = focusWidget->parentWidget();
}
return false;
}
case QEvent::KeyPress: {
QKeyEvent *k = static_cast<QKeyEvent *>(event);
if (k->key() == Qt::Key_Tab || k->key() == Qt::Key_Backtab) {
if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier))) { //### Add MetaModifier?
QWidget *focusWidget = d->widget->focusWidget();
while (focusWidget) {
bool res = QApplication::sendEvent(focusWidget, event);
if ((res && event->isAccepted()) || (isWindow() && focusWidget == d->widget)) {
event->accept();
break;
}
focusWidget = focusWidget->parentWidget();
}
return true;
}
}
break;
}
#ifndef QT_NO_TOOLTIP
case QEvent::GraphicsSceneHelp: {
// Propagate the help event (for tooltip) to the widget under mouse
if (d->lastWidgetUnderMouse) {
QGraphicsSceneHelpEvent *he = static_cast<QGraphicsSceneHelpEvent *>(event);
QPoint pos = d->mapToReceiver(mapFromScene(he->scenePos()), d->lastWidgetUnderMouse).toPoint();
QHelpEvent e(QEvent::ToolTip, pos, he->screenPos());
QApplication::sendEvent(d->lastWidgetUnderMouse, &e);
event->setAccepted(e.isAccepted());
return e.isAccepted();
}
break;
}
case QEvent::ToolTipChange: {
// Propagate tooltip change to the widget
if (!d->tooltipChangeMode) {
d->tooltipChangeMode = QGraphicsProxyWidgetPrivate::ProxyToWidgetMode;
d->widget->setToolTip(toolTip());
d->tooltipChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
}
break;
}
#endif
default:
break;
}
return QGraphicsWidget::event(event);
}
/*!
\reimp
*/
bool QGraphicsProxyWidget::eventFilter(QObject *object, QEvent *event)
{
Q_D(QGraphicsProxyWidget);
if (object == d->widget) {
switch (event->type()) {
case QEvent::LayoutRequest:
updateGeometry();
break;
case QEvent::Resize:
// If the widget resizes itself, we resize the proxy too.
// Prevent feed-back by checking the geometry change mode.
if (!d->sizeChangeMode)
d->updateProxyGeometryFromWidget();
break;
case QEvent::Move:
// If the widget moves itself, we move the proxy too. Prevent
// feed-back by checking the geometry change mode.
if (!d->posChangeMode)
d->updateProxyGeometryFromWidget();
break;
case QEvent::Hide:
case QEvent::Show:
// If the widget toggles its visible state, the proxy will follow.
if (!d->visibleChangeMode) {
d->visibleChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
setVisible(event->type() == QEvent::Show);
d->visibleChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
}
break;
case QEvent::EnabledChange:
// If the widget toggles its enabled state, the proxy will follow.
if (!d->enabledChangeMode) {
d->enabledChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
setEnabled(d->widget->isEnabled());
d->enabledChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
}
break;
case QEvent::StyleChange:
// Propagate style changes to the proxy.
if (!d->styleChangeMode) {
d->styleChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
setStyle(d->widget->style());
d->styleChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
}
break;
#ifndef QT_NO_TOOLTIP
case QEvent::ToolTipChange:
// Propagate tooltip change to the proxy.
if (!d->tooltipChangeMode) {
d->tooltipChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
setToolTip(d->widget->toolTip());
d->tooltipChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
}
break;
#endif
default:
break;
}
}
return QGraphicsWidget::eventFilter(object, event);
}
/*!
\reimp
*/
void QGraphicsProxyWidget::showEvent(QShowEvent *event)
{
Q_UNUSED(event);
}
/*!
\reimp
*/
void QGraphicsProxyWidget::hideEvent(QHideEvent *event)
{
Q_UNUSED(event);
}
#ifndef QT_NO_CONTEXTMENU
/*!
\reimp
*/
void QGraphicsProxyWidget::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
Q_D(QGraphicsProxyWidget);
if (!event || !d->widget || !d->widget->isVisible() || !hasFocus())
return;
// Find widget position and receiver.
QPointF pos = event->pos();
QPointer<QWidget> alienWidget = d->widget->childAt(pos.toPoint());
QPointer<QWidget> receiver = alienWidget ? alienWidget : d->widget;
// Map event position from us to the receiver
pos = d->mapToReceiver(pos, receiver);
QPoint globalPos = receiver->mapToGlobal(pos.toPoint());
//If the receiver by-pass the proxy its popups
//will be top level QWidgets therefore they need
//the screen position. mapToGlobal expect the widget to
//have proper coordinates in regards of the windowing system
//but it's not true because the widget is embedded.
if (bypassGraphicsProxyWidget(receiver))
globalPos = event->screenPos();
// Send mouse event. ### Doesn't propagate the event.
QContextMenuEvent contextMenuEvent(QContextMenuEvent::Reason(event->reason()),
pos.toPoint(), globalPos, event->modifiers());
QApplication::sendEvent(receiver, &contextMenuEvent);
event->setAccepted(contextMenuEvent.isAccepted());
}
#endif // QT_NO_CONTEXTMENU
#ifndef QT_NO_DRAGANDDROP
/*!
\reimp
*/
void QGraphicsProxyWidget::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
{
#ifdef QT_NO_DRAGANDDROP
Q_UNUSED(event);
#else
Q_D(QGraphicsProxyWidget);
if (!d->widget)
return;
QDragEnterEvent proxyDragEnter(event->pos().toPoint(), event->dropAction(), event->mimeData(), event->buttons(), event->modifiers());
proxyDragEnter.setAccepted(event->isAccepted());
QApplication::sendEvent(d->widget, &proxyDragEnter);
event->setAccepted(proxyDragEnter.isAccepted());
if (proxyDragEnter.isAccepted()) // we discard answerRect
event->setDropAction(proxyDragEnter.dropAction());
#endif
}
/*!
\reimp
*/
void QGraphicsProxyWidget::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
{
Q_UNUSED(event);
#ifndef QT_NO_DRAGANDDROP
Q_D(QGraphicsProxyWidget);
if (!d->widget || !d->dragDropWidget)
return;
QDragLeaveEvent proxyDragLeave;
QApplication::sendEvent(d->dragDropWidget, &proxyDragLeave);
d->dragDropWidget = 0;
#endif
}
/*!
\reimp
*/
void QGraphicsProxyWidget::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
{
#ifdef QT_NO_DRAGANDDROP
Q_UNUSED(event);
#else
Q_D(QGraphicsProxyWidget);
if (!d->widget)
return;
QPointF p = event->pos();
event->ignore();
QPointer<QWidget> subWidget = d->widget->childAt(p.toPoint());
QPointer<QWidget> receiver = subWidget ? subWidget : d->widget;
bool eventDelivered = false;
for (; receiver; receiver = receiver->parentWidget()) {
if (!receiver->isEnabled() || !receiver->acceptDrops())
continue;
// Map event position from us to the receiver
QPoint receiverPos = d->mapToReceiver(p, receiver).toPoint();
if (receiver != d->dragDropWidget) {
// Try to enter before we leave
QDragEnterEvent dragEnter(receiverPos, event->possibleActions(), event->mimeData(), event->buttons(), event->modifiers());
dragEnter.setDropAction(event->proposedAction());
QApplication::sendEvent(receiver, &dragEnter);
event->setAccepted(dragEnter.isAccepted());
event->setDropAction(dragEnter.dropAction());
if (!event->isAccepted()) {
// propagate to the parent widget
continue;
}
d->lastDropAction = event->dropAction();
if (d->dragDropWidget) {
QDragLeaveEvent dragLeave;
QApplication::sendEvent(d->dragDropWidget, &dragLeave);
}
d->dragDropWidget = receiver;
}
QDragMoveEvent dragMove(receiverPos, event->possibleActions(), event->mimeData(), event->buttons(), event->modifiers());
event->setDropAction(d->lastDropAction);
QApplication::sendEvent(receiver, &dragMove);
event->setAccepted(dragMove.isAccepted());
event->setDropAction(dragMove.dropAction());
if (event->isAccepted())
d->lastDropAction = event->dropAction();
eventDelivered = true;
break;
}
if (!eventDelivered) {
if (d->dragDropWidget) {
// Leave the last drag drop item
QDragLeaveEvent dragLeave;
QApplication::sendEvent(d->dragDropWidget, &dragLeave);
d->dragDropWidget = 0;
}
// Propagate
event->setDropAction(Qt::IgnoreAction);
}
#endif
}
/*!
\reimp
*/
void QGraphicsProxyWidget::dropEvent(QGraphicsSceneDragDropEvent *event)
{
#ifdef QT_NO_DRAGANDDROP
Q_UNUSED(event);
#else
Q_D(QGraphicsProxyWidget);
if (d->widget && d->dragDropWidget) {
QPoint widgetPos = d->mapToReceiver(event->pos(), d->dragDropWidget).toPoint();
QDropEvent dropEvent(widgetPos, event->possibleActions(), event->mimeData(), event->buttons(), event->modifiers());
QApplication::sendEvent(d->dragDropWidget, &dropEvent);
event->setAccepted(dropEvent.isAccepted());
d->dragDropWidget = 0;
}
#endif
}
#endif
/*!
\reimp
*/
void QGraphicsProxyWidget::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
Q_UNUSED(event);
}
/*!
\reimp
*/
void QGraphicsProxyWidget::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
Q_UNUSED(event);
Q_D(QGraphicsProxyWidget);
// If hoverMove was compressed away, make sure we update properly here.
if (d->lastWidgetUnderMouse) {
QApplicationPrivate::dispatchEnterLeave(0, d->lastWidgetUnderMouse);
d->lastWidgetUnderMouse = 0;
}
}
/*!
\reimp
*/
void QGraphicsProxyWidget::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
{
Q_D(QGraphicsProxyWidget);
#ifdef GRAPHICSPROXYWIDGET_DEBUG
qDebug() << "QGraphicsProxyWidget::hoverMoveEvent";
#endif
// Ignore events on the window frame.
if (!d->widget || !rect().contains(event->pos())) {
if (d->lastWidgetUnderMouse) {
QApplicationPrivate::dispatchEnterLeave(0, d->lastWidgetUnderMouse);
d->lastWidgetUnderMouse = 0;
}
return;
}
d->embeddedMouseGrabber = 0;
d->sendWidgetMouseEvent(event);
}
/*!
\reimp
*/
void QGraphicsProxyWidget::grabMouseEvent(QEvent *event)
{
Q_UNUSED(event);
}
/*!
\reimp
*/
void QGraphicsProxyWidget::ungrabMouseEvent(QEvent *event)
{
Q_D(QGraphicsProxyWidget);
Q_UNUSED(event);
d->embeddedMouseGrabber = 0;
}
/*!
\reimp
*/
void QGraphicsProxyWidget::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
Q_D(QGraphicsProxyWidget);
#ifdef GRAPHICSPROXYWIDGET_DEBUG
qDebug() << "QGraphicsProxyWidget::mouseMoveEvent";
#endif
d->sendWidgetMouseEvent(event);
}
/*!
\reimp
*/
void QGraphicsProxyWidget::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
Q_D(QGraphicsProxyWidget);
#ifdef GRAPHICSPROXYWIDGET_DEBUG
qDebug() << "QGraphicsProxyWidget::mousePressEvent";
#endif
d->sendWidgetMouseEvent(event);
}
/*!
\reimp
*/
void QGraphicsProxyWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
Q_D(QGraphicsProxyWidget);
#ifdef GRAPHICSPROXYWIDGET_DEBUG
qDebug() << "QGraphicsProxyWidget::mouseDoubleClickEvent";
#endif
d->sendWidgetMouseEvent(event);
}
/*!
\reimp
*/
#ifndef QT_NO_WHEELEVENT
void QGraphicsProxyWidget::wheelEvent(QGraphicsSceneWheelEvent *event)
{
Q_D(QGraphicsProxyWidget);
#ifdef GRAPHICSPROXYWIDGET_DEBUG
qDebug() << "QGraphicsProxyWidget::wheelEvent";
#endif
if (!d->widget)
return;
QPointF pos = event->pos();
QPointer<QWidget> receiver = d->widget->childAt(pos.toPoint());
if (!receiver)
receiver = d->widget;
// Map event position from us to the receiver
pos = d->mapToReceiver(pos, receiver);
// Send mouse event.
QWheelEvent wheelEvent(pos.toPoint(), event->screenPos(), event->delta(),
event->buttons(), event->modifiers(), event->orientation());
QPointer<QWidget> focusWidget = d->widget->focusWidget();
extern bool qt_sendSpontaneousEvent(QObject *, QEvent *);
qt_sendSpontaneousEvent(receiver, &wheelEvent);
event->setAccepted(wheelEvent.isAccepted());
// ### Remove, this should be done by proper focusIn/focusOut events.
if (focusWidget && !focusWidget->hasFocus()) {
focusWidget->update();
focusWidget = d->widget->focusWidget();
if (focusWidget && focusWidget->hasFocus())
focusWidget->update();
}
}
#endif
/*!
\reimp
*/
void QGraphicsProxyWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
Q_D(QGraphicsProxyWidget);
#ifdef GRAPHICSPROXYWIDGET_DEBUG
qDebug() << "QGraphicsProxyWidget::mouseReleaseEvent";
#endif
d->sendWidgetMouseEvent(event);
}
/*!
\reimp
*/
void QGraphicsProxyWidget::keyPressEvent(QKeyEvent *event)
{
Q_D(QGraphicsProxyWidget);
#ifdef GRAPHICSPROXYWIDGET_DEBUG
qDebug() << "QGraphicsProxyWidget::keyPressEvent";
#endif
d->sendWidgetKeyEvent(event);
}
/*!
\reimp
*/
void QGraphicsProxyWidget::keyReleaseEvent(QKeyEvent *event)
{
Q_D(QGraphicsProxyWidget);
#ifdef GRAPHICSPROXYWIDGET_DEBUG
qDebug() << "QGraphicsProxyWidget::keyReleaseEvent";
#endif
d->sendWidgetKeyEvent(event);
}
/*!
\reimp
*/
void QGraphicsProxyWidget::focusInEvent(QFocusEvent *event)
{
#ifdef GRAPHICSPROXYWIDGET_DEBUG
qDebug() << "QGraphicsProxyWidget::focusInEvent";
#endif
Q_D(QGraphicsProxyWidget);
if (d->focusFromWidgetToProxy) {
// Prevent recursion when the proxy autogains focus through the
// embedded widget calling setFocus(). ### Could be done with event
// filter on FocusIn instead?
return;
}
d->proxyIsGivingFocus = true;
switch (event->reason()) {
case Qt::TabFocusReason: {
if (QWidget *focusChild = d->findFocusChild(0, true))
focusChild->setFocus(event->reason());
break;
}
case Qt::BacktabFocusReason:
if (QWidget *focusChild = d->findFocusChild(0, false))
focusChild->setFocus(event->reason());
break;
default:
if (d->widget && d->widget->focusWidget()) {
d->widget->focusWidget()->setFocus(event->reason());
}
break;
}
d->proxyIsGivingFocus = false;
}
/*!
\reimp
*/
void QGraphicsProxyWidget::focusOutEvent(QFocusEvent *event)
{
#ifdef GRAPHICSPROXYWIDGET_DEBUG
qDebug() << "QGraphicsProxyWidget::focusOutEvent";
#endif
Q_D(QGraphicsProxyWidget);
if (d->widget) {
// We need to explicitly remove subfocus from the embedded widget's
// focus widget.
if (QWidget *focusWidget = d->widget->focusWidget())
d->removeSubFocusHelper(focusWidget, event->reason());
}
}
/*!
\reimp
*/
bool QGraphicsProxyWidget::focusNextPrevChild(bool next)
{
Q_D(QGraphicsProxyWidget);
if (!d->widget || !d->scene)
return QGraphicsWidget::focusNextPrevChild(next);
Qt::FocusReason reason = next ? Qt::TabFocusReason : Qt::BacktabFocusReason;
QWidget *lastFocusChild = d->widget->focusWidget();
if (QWidget *newFocusChild = d->findFocusChild(lastFocusChild, next)) {
newFocusChild->setFocus(reason);
return true;
}
return QGraphicsWidget::focusNextPrevChild(next);
}
/*!
\reimp
*/
QSizeF QGraphicsProxyWidget::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
Q_D(const QGraphicsProxyWidget);
if (!d->widget)
return QGraphicsWidget::sizeHint(which, constraint);
QSizeF sh;
switch (which) {
case Qt::PreferredSize:
if (QLayout *l = d->widget->layout())
sh = l->sizeHint();
else
sh = d->widget->sizeHint();
break;
case Qt::MinimumSize:
if (QLayout *l = d->widget->layout())
sh = l->minimumSize();
else
sh = d->widget->minimumSizeHint();
break;
case Qt::MaximumSize:
if (QLayout *l = d->widget->layout())
sh = l->maximumSize();
else
sh = QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
break;
case Qt::MinimumDescent:
sh = constraint;
break;
default:
break;
}
return sh;
}
/*!
\reimp
*/
void QGraphicsProxyWidget::resizeEvent(QGraphicsSceneResizeEvent *event)
{
Q_D(QGraphicsProxyWidget);
if (d->widget) {
if (d->sizeChangeMode != QGraphicsProxyWidgetPrivate::WidgetToProxyMode)
d->widget->resize(event->newSize().toSize());
}
QGraphicsWidget::resizeEvent(event);
}
/*!
\reimp
*/
void QGraphicsProxyWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_D(QGraphicsProxyWidget);
Q_UNUSED(widget);
if (!d->widget || !d->widget->isVisible())
return;
// Filter out repaints on the window frame.
const QRect exposedWidgetRect = (option->exposedRect & rect()).toAlignedRect();
if (exposedWidgetRect.isEmpty())
return;
// Disable QPainter's default pen being cosmetic. This allows widgets and
// styles to follow Qt's existing defaults without getting ugly cosmetic
// lines when scaled.
bool restore = !(painter->renderHints() & QPainter::NonCosmeticDefaultPen);
painter->setRenderHints(QPainter::NonCosmeticDefaultPen, true);
d->widget->render(painter, exposedWidgetRect.topLeft(), exposedWidgetRect);
// Restore the render hints if necessary.
if (restore)
painter->setRenderHints(QPainter::NonCosmeticDefaultPen, false);
}
/*!
\reimp
*/
int QGraphicsProxyWidget::type() const
{
return Type;
}
/*!
\since 4.5
Creates a proxy widget for the given \a child of the widget
contained in this proxy.
This function makes it possible to acquire proxies for
non top-level widgets. For instance, you can embed a dialog,
and then transform only one of its widgets.
If the widget is already embedded, return the existing proxy widget.
\sa newProxyWidget(), QGraphicsScene::addWidget()
*/
QGraphicsProxyWidget *QGraphicsProxyWidget::createProxyForChildWidget(QWidget *child)
{
QGraphicsProxyWidget *proxy = child->graphicsProxyWidget();
if (proxy)
return proxy;
if (!child->parentWidget()) {
qWarning("QGraphicsProxyWidget::createProxyForChildWidget: top-level widget not in a QGraphicsScene");
return 0;
}
QGraphicsProxyWidget *parentProxy = createProxyForChildWidget(child->parentWidget());
if (!parentProxy)
return 0;
if (!QMetaObject::invokeMethod(parentProxy, "newProxyWidget", Qt::DirectConnection,
Q_RETURN_ARG(QGraphicsProxyWidget*, proxy), Q_ARG(const QWidget*, child)))
return 0;
proxy->setParent(parentProxy);
proxy->setWidget(child);
return proxy;
}
/*!
\fn QGraphicsProxyWidget *QGraphicsProxyWidget::newProxyWidget(const QWidget *child)
\since 4.5
Creates a proxy widget for the given \a child of the widget contained in this
proxy.
You should not call this function directly; use
QGraphicsProxyWidget::createProxyForChildWidget() instead.
This function is a fake virtual slot that you can reimplement in
your subclass in order to control how new proxy widgets are
created. The default implementation returns a proxy created with
the QGraphicsProxyWidget() constructor with this proxy widget as
the parent.
\sa createProxyForChildWidget()
*/
QGraphicsProxyWidget *QGraphicsProxyWidget::newProxyWidget(const QWidget *)
{
return new QGraphicsProxyWidget(this);
}
QT_END_NAMESPACE
#include "moc_qgraphicsproxywidget.cpp"
#endif //QT_NO_GRAPHICSVIEW