src/gui/kernel/qlayoutitem.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gui/kernel/qlayoutitem.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,836 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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$
+** 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 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
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qlayout.h"
+
+#include "qapplication.h"
+#include "qlayoutengine_p.h"
+#include "qmenubar.h"
+#include "qtoolbar.h"
+#include "qevent.h"
+#include "qstyle.h"
+#include "qvariant.h"
+#include "qwidget_p.h"
+
+QT_BEGIN_NAMESPACE
+
+inline static QRect fromLayoutItemRect(QWidgetPrivate *priv, const QRect &rect)
+{
+    return rect.adjusted(priv->leftLayoutItemMargin, priv->topLayoutItemMargin,
+                         -priv->rightLayoutItemMargin, -priv->bottomLayoutItemMargin);
+}
+
+inline static QSize fromLayoutItemSize(QWidgetPrivate *priv, const QSize &size)
+{
+    return fromLayoutItemRect(priv, QRect(QPoint(0, 0), size)).size();
+}
+
+inline static QRect toLayoutItemRect(QWidgetPrivate *priv, const QRect &rect)
+{
+    return rect.adjusted(-priv->leftLayoutItemMargin, -priv->topLayoutItemMargin,
+                         priv->rightLayoutItemMargin, priv->bottomLayoutItemMargin);
+}
+
+inline static QSize toLayoutItemSize(QWidgetPrivate *priv, const QSize &size)
+{
+    return toLayoutItemRect(priv, QRect(QPoint(0, 0), size)).size();
+}
+
+/*!
+   Returns a QVariant storing this QSizePolicy.
+*/
+QSizePolicy::operator QVariant() const
+{
+    return QVariant(QVariant::SizePolicy, this);
+}
+
+/*!
+    \class QLayoutItem
+    \brief The QLayoutItem class provides an abstract item that a
+    QLayout manipulates.
+
+    \ingroup geomanagement
+
+    This is used by custom layouts.
+
+    Pure virtual functions are provided to return information about
+    the layout, including, sizeHint(), minimumSize(), maximumSize()
+    and expanding().
+
+    The layout's geometry can be set and retrieved with setGeometry()
+    and geometry(), and its alignment with setAlignment() and
+    alignment().
+
+    isEmpty() returns whether the layout item is empty. If the
+    concrete item is a QWidget, it can be retrieved using widget().
+    Similarly for layout() and spacerItem().
+
+    Some layouts have width and height interdependencies. These can
+    be expressed using hasHeightForWidth(), heightForWidth(), and
+    minimumHeightForWidth(). For more explanation see the \e{Qt
+    Quarterly} article
+    \l{http://qt.nokia.com/doc/qq/qq04-height-for-width.html}{Trading
+    Height for Width}.
+
+    \sa QLayout
+*/
+
+/*!
+    \class QSpacerItem
+    \ingroup geomanagement
+    \brief The QSpacerItem class provides blank space in a layout.
+
+    Normally, you don't need to use this class directly. Qt's
+    built-in layout managers provide the following functions for
+    manipulating empty space in layouts:
+
+    \table
+    \header \o Class
+            \o Functions
+    \row    \o QHBoxLayout
+            \o \l{QBoxLayout::addSpacing()}{addSpacing()},
+               \l{QBoxLayout::addStretch()}{addStretch()},
+               \l{QBoxLayout::insertSpacing()}{insertSpacing()},
+               \l{QBoxLayout::insertStretch()}{insertStretch()}
+    \row    \o QGridLayout
+            \o \l{QGridLayout::setRowMinimumHeight()}{setRowMinimumHeight()},
+               \l{QGridLayout::setRowStretch()}{setRowStretch()},
+               \l{QGridLayout::setColumnMinimumWidth()}{setColumnMinimumWidth()},
+               \l{QGridLayout::setColumnStretch()}{setColumnStretch()}
+    \endtable
+
+    \sa QLayout, QWidgetItem, QLayoutItem::spacerItem()
+*/
+
+/*!
+    \class QWidgetItem
+    \ingroup geomanagement
+    \brief The QWidgetItem class is a layout item that represents a widget.
+
+    Normally, you don't need to use this class directly. Qt's
+    built-in layout managers provide the following functions for
+    manipulating widgets in layouts:
+
+    \table
+    \header \o Class
+            \o Functions
+    \row    \o QBoxLayout
+            \o \l{QBoxLayout::addWidget()}{addWidget()},
+               \l{QBoxLayout::insertWidget()}{insertWidget()},
+               \l{QBoxLayout::setStretchFactor()}{setStretchFactor()}
+    \row    \o QGridLayout
+            \o \l{QGridLayout::addWidget()}{addWidget()}
+    \row    \o QStackedLayout
+            \o \l{QStackedLayout::addWidget()}{addWidget()},
+               \l{QStackedLayout::insertWidget()}{insertWidget()},
+               \l{QStackedLayout::currentWidget()}{currentWidget()},
+               \l{QStackedLayout::setCurrentWidget()}{setCurrentWidget()},
+               \l{QStackedLayout::widget()}{widget()}
+    \endtable
+
+    \sa QLayout, QSpacerItem, QLayoutItem::widget()
+*/
+
+/*!
+    \fn QLayoutItem::QLayoutItem(Qt::Alignment alignment)
+
+    Constructs a layout item with an \a alignment.
+    Not all subclasses support alignment.
+*/
+
+/*!
+    \fn Qt::Alignment QLayoutItem::alignment() const
+
+    Returns the alignment of this item.
+*/
+
+/*!
+    Sets the alignment of this item to \a alignment.
+
+    \bold{Note:} Item alignment is only supported by QLayoutItem subclasses
+    where it would have a visual effect. Except for QSpacerItem, which provides
+    blank space for layouts, all public Qt classes that inherit QLayoutItem
+    support item alignment.
+*/
+void QLayoutItem::setAlignment(Qt::Alignment alignment)
+{
+    align = alignment;
+}
+
+/*!
+    \fn QSize QLayoutItem::maximumSize() const
+
+    Implemented in subclasses to return the maximum size of this item.
+*/
+
+/*!
+    \fn QSize QLayoutItem::minimumSize() const
+
+    Implemented in subclasses to return the minimum size of this item.
+*/
+
+/*!
+    \fn QSize QLayoutItem::sizeHint() const
+
+    Implemented in subclasses to return the preferred size of this item.
+*/
+
+/*!
+    \fn Qt::Orientations QLayoutItem::expandingDirections() const
+
+    Returns whether this layout item can make use of more space than
+    sizeHint(). A value of Qt::Vertical or Qt::Horizontal means that
+    it wants to grow in only one dimension, whereas Qt::Vertical |
+    Qt::Horizontal means that it wants to grow in both dimensions.
+*/
+
+/*!
+    \fn void QLayoutItem::setGeometry(const QRect &r)
+
+    Implemented in subclasses to set this item's geometry to \a r.
+
+    \sa geometry()
+*/
+
+/*!
+    \fn QRect QLayoutItem::geometry() const
+
+    Returns the rectangle covered by this layout item.
+
+    \sa setGeometry()
+*/
+
+/*!
+    \fn virtual bool QLayoutItem::isEmpty() const
+
+    Implemented in subclasses to return whether this item is empty,
+    i.e. whether it contains any widgets.
+*/
+
+/*!
+    \fn QSpacerItem::QSpacerItem(int w, int h, QSizePolicy::Policy hPolicy, QSizePolicy::Policy vPolicy)
+
+    Constructs a spacer item with preferred width \a w, preferred
+    height \a h, horizontal size policy \a hPolicy and vertical size
+    policy \a vPolicy.
+
+    The default values provide a gap that is able to stretch if
+    nothing else wants the space.
+*/
+
+/*!
+    Changes this spacer item to have preferred width \a w, preferred
+    height \a h, horizontal size policy \a hPolicy and vertical size
+    policy \a vPolicy.
+
+    The default values provide a gap that is able to stretch if
+    nothing else wants the space.
+
+    Note that if changeSize() is called after the spacer item has been added
+    to a layout, it is necessary to invalidate the layout in order for the
+    spacer item's new size to take effect.
+
+    \sa QSpacerItem::invalidate()
+*/
+void QSpacerItem::changeSize(int w, int h, QSizePolicy::Policy hPolicy,
+                             QSizePolicy::Policy vPolicy)
+{
+    width = w;
+    height = h;
+    sizeP = QSizePolicy(hPolicy, vPolicy);
+}
+
+/*!
+    \fn QWidgetItem::QWidgetItem(QWidget *widget)
+
+    Creates an item containing the given \a widget.
+*/
+
+/*!
+    Destroys the QLayoutItem.
+*/
+QLayoutItem::~QLayoutItem()
+{
+}
+
+/*!
+    Invalidates any cached information in this layout item.
+*/
+void QLayoutItem::invalidate()
+{
+}
+
+/*!
+    If this item is a QLayout, it is returned as a QLayout; otherwise
+    0 is returned. This function provides type-safe casting.
+*/
+QLayout * QLayoutItem::layout()
+{
+    return 0;
+}
+
+/*!
+    If this item is a QSpacerItem, it is returned as a QSpacerItem;
+    otherwise 0 is returned. This function provides type-safe casting.
+*/
+QSpacerItem * QLayoutItem::spacerItem()
+{
+    return 0;
+}
+
+/*!
+    \reimp
+*/
+QLayout * QLayout::layout()
+{
+    return this;
+}
+
+/*!
+    Returns a pointer to this object.
+*/
+QSpacerItem * QSpacerItem::spacerItem()
+{
+    return this;
+}
+
+/*!
+    If this item is a QWidget, it is returned as a QWidget; otherwise
+    0 is returned. This function provides type-safe casting.
+*/
+QWidget * QLayoutItem::widget()
+{
+    return 0;
+}
+
+/*!
+    Returns the widget managed by this item.
+*/
+QWidget *QWidgetItem::widget()
+{
+    return wid;
+}
+
+/*!
+    Returns true if this layout's preferred height depends on its
+    width; otherwise returns false. The default implementation returns
+    false.
+
+    Reimplement this function in layout managers that support height
+    for width.
+
+    \sa heightForWidth(), QWidget::heightForWidth()
+*/
+bool QLayoutItem::hasHeightForWidth() const
+{
+    return false;
+}
+
+/*!
+    Returns the minimum height this widget needs for the given width,
+    \a w. The default implementation simply returns heightForWidth(\a
+    w).
+*/
+int QLayoutItem::minimumHeightForWidth(int w) const
+{
+    return heightForWidth(w);
+}
+
+
+/*!
+    Returns the preferred height for this layout item, given the width
+    \a w.
+
+    The default implementation returns -1, indicating that the
+    preferred height is independent of the width of the item. Using
+    the function hasHeightForWidth() will typically be much faster
+    than calling this function and testing for -1.
+
+    Reimplement this function in layout managers that support height
+    for width. A typical implementation will look like this:
+    \snippet doc/src/snippets/code/src_gui_kernel_qlayoutitem.cpp 0
+
+    Caching is strongly recommended; without it layout will take
+    exponential time.
+
+    \sa hasHeightForWidth()
+*/
+int QLayoutItem::heightForWidth(int /* w */) const
+{
+    return -1;
+}
+
+/*!
+    Returns the control type(s) for the layout item. For a
+    QWidgetItem, the control type comes from the widget's size
+    policy; for a QLayoutItem, the control types is derived from the
+    layout's contents.
+
+    \sa QSizePolicy::controlType()
+*/
+QSizePolicy::ControlTypes QLayoutItem::controlTypes() const
+{
+    // ### Qt 5: This function should probably be virtual instead
+    if (const QWidget *widget = const_cast<QLayoutItem*>(this)->widget()) {
+        return widget->sizePolicy().controlType();
+    } else if (const QLayout *layout = const_cast<QLayoutItem*>(this)->layout()) {
+        if (layout->count() == 0)
+            return QSizePolicy::DefaultType;
+        QSizePolicy::ControlTypes types;
+        for (int i = layout->count() - 1; i >= 0; --i)
+            types |= layout->itemAt(i)->controlTypes();
+        return types;
+    }
+    return QSizePolicy::DefaultType;
+}
+
+/*!
+    \reimp
+*/
+void QSpacerItem::setGeometry(const QRect &r)
+{
+    rect = r;
+}
+
+/*!
+    \reimp
+*/
+void QWidgetItem::setGeometry(const QRect &rect)
+{
+    if (isEmpty())
+        return;
+
+    QRect r = !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect)
+            ? fromLayoutItemRect(wid->d_func(), rect)
+            : rect;
+    const QSize widgetRectSurplus = r.size() - rect.size(); 
+
+    /* 
+       For historical reasons, this code is done using widget rect 
+       coordinates, not layout item rect coordinates. However, 
+       QWidgetItem's sizeHint(), maximumSize(), and heightForWidth() 
+       all work in terms of layout item rect coordinates, so we have to 
+       add or subtract widgetRectSurplus here and there. The code could 
+       be much simpler if we did everything using layout item rect 
+       coordinates and did the conversion right before the call to 
+       QWidget::setGeometry(). 
+     */ 
+
+    QSize s = r.size().boundedTo(maximumSize() + widgetRectSurplus);  
+    int x = r.x();
+    int y = r.y();
+    if (align & (Qt::AlignHorizontal_Mask | Qt::AlignVertical_Mask)) {
+        QSize pref(sizeHint());
+        QSizePolicy sp = wid->sizePolicy();
+        if (sp.horizontalPolicy() == QSizePolicy::Ignored)
+            pref.setWidth(wid->sizeHint().expandedTo(wid->minimumSize()).width());
+        if (sp.verticalPolicy() == QSizePolicy::Ignored)
+            pref.setHeight(wid->sizeHint().expandedTo(wid->minimumSize()).height());
+        pref += widgetRectSurplus;
+        if (align & Qt::AlignHorizontal_Mask)
+            s.setWidth(qMin(s.width(), pref.width()));
+        if (align & Qt::AlignVertical_Mask) {
+            if (hasHeightForWidth())
+                s.setHeight(qMin(s.height(), 
+                                 heightForWidth(s.width() - widgetRectSurplus.width()) 
+                                 + widgetRectSurplus.height()));
+            else
+                s.setHeight(qMin(s.height(), pref.height()));
+        }
+    }
+    Qt::Alignment alignHoriz = QStyle::visualAlignment(wid->layoutDirection(), align);
+    if (alignHoriz & Qt::AlignRight)
+        x = x + (r.width() - s.width());
+    else if (!(alignHoriz & Qt::AlignLeft))
+        x = x + (r.width() - s.width()) / 2;
+
+    if (align & Qt::AlignBottom)
+        y = y + (r.height() - s.height());
+    else if (!(align & Qt::AlignTop))
+        y = y + (r.height() - s.height()) / 2;
+
+    wid->setGeometry(x, y, s.width(), s.height());
+}
+
+/*!
+    \reimp
+*/
+QRect QSpacerItem::geometry() const
+{
+    return rect;
+}
+
+/*!
+    \reimp
+*/
+QRect QWidgetItem::geometry() const
+{
+    return !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect)
+           ? toLayoutItemRect(wid->d_func(), wid->geometry())
+           : wid->geometry();
+}
+
+
+/*!
+    \reimp
+*/
+bool QWidgetItem::hasHeightForWidth() const
+{
+    if (isEmpty())
+        return false;
+    if (wid->layout())
+        return wid->layout()->hasHeightForWidth();
+    return wid->sizePolicy().hasHeightForWidth();
+}
+
+/*!
+    \reimp
+*/
+int QWidgetItem::heightForWidth(int w) const
+{
+    if (isEmpty())
+        return -1;
+
+    w = !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect)
+      ? fromLayoutItemSize(wid->d_func(), QSize(w, 0)).width()
+      : w;
+
+    int hfw;
+    if (wid->layout())
+        hfw = wid->layout()->totalHeightForWidth(w);
+    else
+        hfw = wid->heightForWidth(w);
+
+    if (hfw > wid->maximumHeight())
+        hfw = wid->maximumHeight();
+    if (hfw < wid->minimumHeight())
+        hfw = wid->minimumHeight();
+
+    hfw = !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect)
+        ? toLayoutItemSize(wid->d_func(), QSize(0, hfw)).height()
+        : hfw;
+
+    if (hfw < 0)
+        hfw = 0;
+    return hfw;
+}
+
+/*!
+    \reimp
+*/
+Qt::Orientations QSpacerItem::expandingDirections() const
+{
+    return sizeP.expandingDirections();
+}
+
+/*!
+    \reimp
+*/
+Qt::Orientations QWidgetItem::expandingDirections() const
+{
+    if (isEmpty())
+        return Qt::Orientations(0);
+
+    Qt::Orientations e = wid->sizePolicy().expandingDirections();
+    /*
+      ### Qt 4.0:
+      If the layout is expanding, we make the widget expanding, even if
+      its own size policy isn't expanding. This behavior should be
+      reconsidered.
+    */
+    if (wid->layout()) {
+        if (wid->sizePolicy().horizontalPolicy() & QSizePolicy::GrowFlag
+                && (wid->layout()->expandingDirections() & Qt::Horizontal))
+            e |= Qt::Horizontal;
+        if (wid->sizePolicy().verticalPolicy() & QSizePolicy::GrowFlag
+                && (wid->layout()->expandingDirections() & Qt::Vertical))
+            e |= Qt::Vertical;
+    }
+
+    if (align & Qt::AlignHorizontal_Mask)
+        e &= ~Qt::Horizontal;
+    if (align & Qt::AlignVertical_Mask)
+        e &= ~Qt::Vertical;
+    return e;
+}
+
+/*!
+    \reimp
+*/
+QSize QSpacerItem::minimumSize() const
+{
+    return QSize(sizeP.horizontalPolicy() & QSizePolicy::ShrinkFlag ? 0 : width,
+                 sizeP.verticalPolicy() & QSizePolicy::ShrinkFlag ? 0 : height);
+}
+
+/*!
+    \reimp
+*/
+QSize QWidgetItem::minimumSize() const
+{
+    if (isEmpty())
+        return QSize(0, 0);
+    return !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect)
+           ? toLayoutItemSize(wid->d_func(), qSmartMinSize(this))
+           : qSmartMinSize(this);
+}
+
+/*!
+    \reimp
+*/
+QSize QSpacerItem::maximumSize() const
+{
+    return QSize(sizeP.horizontalPolicy() & QSizePolicy::GrowFlag ? QLAYOUTSIZE_MAX : width,
+                 sizeP.verticalPolicy() & QSizePolicy::GrowFlag ? QLAYOUTSIZE_MAX : height);
+}
+
+/*!
+    \reimp
+*/
+QSize QWidgetItem::maximumSize() const
+{
+    if (isEmpty()) {
+        return QSize(0, 0);
+    } else {
+        return !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect)
+               ? toLayoutItemSize(wid->d_func(), qSmartMaxSize(this, align))
+               : qSmartMaxSize(this, align);
+    }
+}
+
+/*!
+    \reimp
+*/
+QSize QSpacerItem::sizeHint() const
+{
+    return QSize(width, height);
+}
+
+/*!
+    \reimp
+*/
+QSize QWidgetItem::sizeHint() const
+{
+    QSize s(0, 0);
+    if (!isEmpty()) {
+        s = wid->sizeHint().expandedTo(wid->minimumSizeHint());
+        s = s.boundedTo(wid->maximumSize())
+             .expandedTo(wid->minimumSize());
+        s = !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect)
+           ? toLayoutItemSize(wid->d_func(), s)
+           : s;
+
+        if (wid->sizePolicy().horizontalPolicy() == QSizePolicy::Ignored)
+            s.setWidth(0);
+        if (wid->sizePolicy().verticalPolicy() == QSizePolicy::Ignored)
+            s.setHeight(0);
+    }
+    return s;
+}
+
+/*!
+    Returns true.
+*/
+bool QSpacerItem::isEmpty() const
+{
+    return true;
+}
+
+/*!
+    Returns true if the widget is hidden; otherwise returns false.
+
+    \sa QWidget::isHidden()
+*/
+bool QWidgetItem::isEmpty() const
+{
+    return wid->isHidden() || wid->isWindow();
+}
+
+/*!
+    \class QWidgetItemV2
+    \internal
+*/
+
+inline bool QWidgetItemV2::useSizeCache() const
+{
+    return wid->d_func()->widgetItem == this;
+}
+
+void QWidgetItemV2::updateCacheIfNecessary() const
+{
+    if (q_cachedMinimumSize.width() != Dirty)
+        return;
+
+    const QSize sizeHint(wid->sizeHint());
+    const QSize minimumSizeHint(wid->minimumSizeHint());
+    const QSize minimumSize(wid->minimumSize());
+    const QSize maximumSize(wid->maximumSize());
+    const QSizePolicy sizePolicy(wid->sizePolicy());
+    const QSize expandedSizeHint(sizeHint.expandedTo(minimumSizeHint));
+
+    const QSize smartMinSize(qSmartMinSize(sizeHint, minimumSizeHint, minimumSize, maximumSize, sizePolicy));
+    const QSize smartMaxSize(qSmartMaxSize(expandedSizeHint, minimumSize, maximumSize, sizePolicy, align));
+
+    const bool useLayoutItemRect = !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect);
+
+    q_cachedMinimumSize = useLayoutItemRect
+           ? toLayoutItemSize(wid->d_func(), smartMinSize)
+           : smartMinSize;
+
+    q_cachedSizeHint = expandedSizeHint;
+    q_cachedSizeHint = q_cachedSizeHint.boundedTo(maximumSize)
+                                       .expandedTo(minimumSize);
+    q_cachedSizeHint = useLayoutItemRect
+           ? toLayoutItemSize(wid->d_func(), q_cachedSizeHint)
+           : q_cachedSizeHint;
+
+    if (wid->sizePolicy().horizontalPolicy() == QSizePolicy::Ignored)
+        q_cachedSizeHint.setWidth(0);
+    if (wid->sizePolicy().verticalPolicy() == QSizePolicy::Ignored)
+        q_cachedSizeHint.setHeight(0);
+
+    q_cachedMaximumSize = useLayoutItemRect
+               ? toLayoutItemSize(wid->d_func(), smartMaxSize)
+               : smartMaxSize;
+}
+
+QWidgetItemV2::QWidgetItemV2(QWidget *widget)
+    : QWidgetItem(widget),
+      q_cachedMinimumSize(Dirty, Dirty),
+      q_cachedSizeHint(Dirty, Dirty),
+      q_cachedMaximumSize(Dirty, Dirty),
+      q_firstCachedHfw(0),
+      q_hfwCacheSize(0),
+      d(0)
+{
+    QWidgetPrivate *wd = wid->d_func();
+    if (!wd->widgetItem)
+        wd->widgetItem = this;
+}
+
+QWidgetItemV2::~QWidgetItemV2()
+{
+    if (wid) {
+        QWidgetPrivate *wd = wid->d_func();
+        if (wd->widgetItem == this)
+            wd->widgetItem = 0;
+    }
+}
+
+QSize QWidgetItemV2::sizeHint() const
+{
+    if (isEmpty())
+        return QSize(0, 0);
+
+    if (useSizeCache()) {
+        updateCacheIfNecessary();
+        return q_cachedSizeHint;
+    } else {
+        return QWidgetItem::sizeHint();
+    }
+}
+
+QSize QWidgetItemV2::minimumSize() const
+{
+    if (isEmpty())
+        return QSize(0, 0);
+
+    if (useSizeCache()) {
+        updateCacheIfNecessary();
+        return q_cachedMinimumSize;
+    } else {
+        return QWidgetItem::minimumSize();
+    }
+}
+
+QSize QWidgetItemV2::maximumSize() const
+{
+    if (isEmpty())
+        return QSize(0, 0);
+
+    if (useSizeCache()) {
+        updateCacheIfNecessary();
+        return q_cachedMaximumSize;
+    } else {
+        return QWidgetItem::maximumSize();
+    }
+}
+
+/*
+    The height-for-width cache is organized as a circular buffer. The entries
+
+        q_hfwCachedHfws[q_firstCachedHfw],
+        ...,
+        q_hfwCachedHfws[(q_firstCachedHfw + q_hfwCacheSize - 1) % HfwCacheMaxSize]
+
+    contain the last cached values. When the cache is full, the first entry to
+    be erased is the entry before q_hfwCachedHfws[q_firstCachedHfw]. When
+    values are looked up, we try to move q_firstCachedHfw to point to that new
+    entry (unless the cache is not full, in which case it would leave the cache
+    in a broken state), so that the most recently used entry is also the last
+    to be erased.
+*/
+
+int QWidgetItemV2::heightForWidth(int width) const
+{
+    if (isEmpty())
+        return -1;
+
+    for (int i = 0; i < q_hfwCacheSize; ++i) {
+        int offset = q_firstCachedHfw + i;
+        const QSize &size = q_cachedHfws[offset % HfwCacheMaxSize];
+        if (size.width() == width) {
+            if (q_hfwCacheSize == HfwCacheMaxSize)
+                q_firstCachedHfw = offset;
+            return size.height();
+        }
+    }
+
+    if (q_hfwCacheSize < HfwCacheMaxSize)
+        ++q_hfwCacheSize;
+    q_firstCachedHfw = (q_firstCachedHfw + HfwCacheMaxSize - 1) % HfwCacheMaxSize;
+
+    int height = QWidgetItem::heightForWidth(width);
+    q_cachedHfws[q_firstCachedHfw] = QSize(width, height);
+    return height;
+}
+
+QT_END_NAMESPACE