src/qt3support/widgets/q3scrollview.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/qt3support/widgets/q3scrollview.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,2807 @@
+/****************************************************************************
+**
+** 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 Qt3Support 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 "qwidget.h"
+#ifndef QT_NO_SCROLLVIEW
+#include "qscrollbar.h"
+#include "qpainter.h"
+#include "qpixmap.h"
+#include "qcursor.h"
+#include "q3scrollview.h"
+#include "q3ptrdict.h"
+#include "qapplication.h"
+#include "qtimer.h"
+#include "qstyle.h"
+#include "q3ptrlist.h"
+#include "qevent.h"
+#include "q3listview.h"
+#ifdef Q_WS_MAC
+# include "private/qt_mac_p.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt;
+
+static const int coord_limit = 4000;
+static const int autoscroll_margin = 16;
+static const int initialScrollTime = 30;
+static const int initialScrollAccel = 5;
+
+struct QSVChildRec {
+    QSVChildRec(QWidget* c, int xx, int yy) :
+        child(c),
+        x(xx), y(yy)
+    {
+    }
+
+    void hideOrShow(Q3ScrollView* sv, QWidget* clipped_viewport);
+    void moveTo(Q3ScrollView* sv, int xx, int yy, QWidget* clipped_viewport)
+    {
+        if (x != xx || y != yy) {
+            x = xx;
+            y = yy;
+            hideOrShow(sv,clipped_viewport);
+        }
+    }
+    QWidget* child;
+    int x, y;
+};
+
+void QSVChildRec::hideOrShow(Q3ScrollView* sv, QWidget* clipped_viewport)
+{
+    if (clipped_viewport) {
+        if (x+child->width() < sv->contentsX()+clipped_viewport->x()
+             || x > sv->contentsX()+clipped_viewport->width()
+             || y+child->height() < sv->contentsY()+clipped_viewport->y()
+             || y > sv->contentsY()+clipped_viewport->height()) {
+            child->move(clipped_viewport->width(),
+                        clipped_viewport->height());
+        } else {
+            child->move(x-sv->contentsX()-clipped_viewport->x(),
+                        y-sv->contentsY()-clipped_viewport->y());
+        }
+    } else {
+        child->move(x-sv->contentsX(), y-sv->contentsY());
+    }
+}
+
+class QAbstractScrollAreaWidget : public QWidget
+{
+    Q_OBJECT
+
+public:
+    QAbstractScrollAreaWidget(Q3ScrollView* parent=0, const char* name=0, Qt::WindowFlags f = 0)
+        : QWidget(parent, name, f)
+    {
+        setAutoFillBackground(true);
+    }
+};
+
+class QClipperWidget : public QWidget
+{
+    Q_OBJECT
+
+public:
+    QClipperWidget(QWidget * parent=0, const char * name=0, Qt::WindowFlags f=0)
+        : QWidget (parent,name,f) {}
+};
+
+QT_BEGIN_INCLUDE_NAMESPACE
+#include "q3scrollview.moc"
+QT_END_INCLUDE_NAMESPACE
+
+class Q3ScrollViewData {
+public:
+    Q3ScrollViewData(Q3ScrollView* parent, int vpwflags) :
+        hbar(new QScrollBar(Qt::Horizontal, parent, "qt_hbar")),
+        vbar(new QScrollBar(Qt::Vertical, parent, "qt_vbar")),
+        viewport(new QAbstractScrollAreaWidget(parent, "qt_viewport", QFlag(vpwflags))),
+        clipped_viewport(0),
+        flags(vpwflags),
+        vx(0), vy(0), vwidth(1), vheight(1),
+#ifndef QT_NO_DRAGANDDROP
+        autoscroll_timer(parent, "scrollview autoscroll timer"),
+        drag_autoscroll(true),
+#endif
+        scrollbar_timer(parent, "scrollview scrollbar timer"),
+        inresize(false), use_cached_size_hint(true)
+    {
+        l_marg = r_marg = t_marg = b_marg = 0;
+        viewport->polish();
+        vMode = Q3ScrollView::Auto;
+        hMode = Q3ScrollView::Auto;
+        corner = 0;
+        vbar->setSteps(20, 1/*set later*/);
+        hbar->setSteps(20, 1/*set later*/);
+        policy = Q3ScrollView::Default;
+        signal_choke = false;
+        static_bg = false;
+        fake_scroll = false;
+        hbarPressed = false;
+        vbarPressed = false;
+        hbar->setLayoutDirection(Qt::LeftToRight);
+    }
+    ~Q3ScrollViewData();
+
+    QSVChildRec* rec(QWidget* w) { return childDict.find(w); }
+    QSVChildRec* ancestorRec(QWidget* w);
+    QSVChildRec* addChildRec(QWidget* w, int x, int y)
+    {
+        QSVChildRec *r = new QSVChildRec(w,x,y);
+        children.append(r);
+        childDict.insert(w, r);
+        return r;
+    }
+    void deleteChildRec(QSVChildRec* r)
+    {
+        childDict.remove(r->child);
+        children.removeRef(r);
+        delete r;
+    }
+
+    void hideOrShowAll(Q3ScrollView* sv, bool isScroll = false);
+    void moveAllBy(int dx, int dy);
+    bool anyVisibleChildren();
+    void autoMove(Q3ScrollView* sv);
+    void autoResize(Q3ScrollView* sv);
+    void autoResizeHint(Q3ScrollView* sv);
+    void viewportResized(int w, int h);
+
+    QScrollBar*  hbar;
+    QScrollBar*  vbar;
+    bool hbarPressed;
+    bool vbarPressed;
+    QAbstractScrollAreaWidget*    viewport;
+    QClipperWidget*     clipped_viewport;
+    int         flags;
+    Q3PtrList<QSVChildRec>       children;
+    Q3PtrDict<QSVChildRec>       childDict;
+    QWidget*    corner;
+    int         vx, vy, vwidth, vheight; // for drawContents-style usage
+    int         l_marg, r_marg, t_marg, b_marg;
+    Q3ScrollView::ResizePolicy policy;
+    Q3ScrollView::ScrollBarMode  vMode;
+    Q3ScrollView::ScrollBarMode  hMode;
+#ifndef QT_NO_DRAGANDDROP
+    QPoint cpDragStart;
+    QTimer autoscroll_timer;
+    int autoscroll_time;
+    int autoscroll_accel;
+    bool drag_autoscroll;
+#endif
+    QTimer scrollbar_timer;
+
+    uint static_bg : 1;
+    uint fake_scroll : 1;
+
+    // This variable allows ensureVisible to move the contents then
+    // update both the sliders.  Otherwise, updating the sliders would
+    // cause two image scrolls, creating ugly flashing.
+    //
+    uint signal_choke : 1;
+
+    // This variables indicates in updateScrollBars() that we are
+    // in a resizeEvent() and thus don't want to flash scroll bars
+    uint inresize : 1;
+    uint use_cached_size_hint : 1;
+    QSize cachedSizeHint;
+
+    inline int contentsX() const { return -vx; }
+    inline int contentsY() const { return -vy; }
+    inline int contentsWidth() const { return vwidth; }
+};
+
+inline Q3ScrollViewData::~Q3ScrollViewData()
+{
+    children.setAutoDelete(true);
+}
+
+QSVChildRec* Q3ScrollViewData::ancestorRec(QWidget* w)
+{
+    if (clipped_viewport) {
+        while (w->parentWidget() != clipped_viewport) {
+            w = w->parentWidget();
+            if (!w) return 0;
+        }
+    } else {
+        while (w->parentWidget() != viewport) {
+            w = w->parentWidget();
+            if (!w) return 0;
+        }
+    }
+    return rec(w);
+}
+
+void Q3ScrollViewData::hideOrShowAll(Q3ScrollView* sv, bool isScroll)
+{
+    if (!clipped_viewport)
+        return;
+    if (clipped_viewport->x() <= 0
+         && clipped_viewport->y() <= 0
+         && clipped_viewport->width()+clipped_viewport->x() >=
+         viewport->width()
+         && clipped_viewport->height()+clipped_viewport->y() >=
+         viewport->height()) {
+        // clipped_viewport still covers viewport
+        if(static_bg)
+            clipped_viewport->repaint(true);
+        else if ((!isScroll && !clipped_viewport->testAttribute(Qt::WA_StaticContents)) || static_bg)
+            clipped_viewport->update();
+    } else {
+        // Re-center
+        int nx = (viewport->width() - clipped_viewport->width()) / 2;
+        int ny = (viewport->height() - clipped_viewport->height()) / 2;
+        clipped_viewport->move(nx,ny);
+        clipped_viewport->update();
+    }
+    for (QSVChildRec *r = children.first(); r; r=children.next()) {
+        r->hideOrShow(sv, clipped_viewport);
+    }
+}
+
+void Q3ScrollViewData::moveAllBy(int dx, int dy)
+{
+    if (clipped_viewport && !static_bg) {
+        clipped_viewport->move(clipped_viewport->x()+dx,
+                                clipped_viewport->y()+dy);
+    } else {
+        for (QSVChildRec *r = children.first(); r; r=children.next()) {
+            r->child->move(r->child->x()+dx,r->child->y()+dy);
+        }
+        if (static_bg)
+            viewport->repaint(true);
+    }
+}
+
+bool Q3ScrollViewData::anyVisibleChildren()
+{
+    for (QSVChildRec *r = children.first(); r; r=children.next()) {
+        if (r->child->isVisible()) return true;
+    }
+    return false;
+}
+
+void Q3ScrollViewData::autoMove(Q3ScrollView* sv)
+{
+    if (policy == Q3ScrollView::AutoOne) {
+        QSVChildRec* r = children.first();
+        if (r)
+            sv->setContentsPos(-r->child->x(),-r->child->y());
+    }
+}
+
+void Q3ScrollViewData::autoResize(Q3ScrollView* sv)
+{
+    if (policy == Q3ScrollView::AutoOne) {
+        QSVChildRec* r = children.first();
+        if (r)
+            sv->resizeContents(r->child->width(),r->child->height());
+    }
+}
+
+void Q3ScrollViewData::autoResizeHint(Q3ScrollView* sv)
+{
+    if (policy == Q3ScrollView::AutoOne) {
+        QSVChildRec* r = children.first();
+        if (r) {
+            QSize s = r->child->sizeHint();
+            if (s.isValid())
+                r->child->resize(s);
+        }
+    } else if (policy == Q3ScrollView::AutoOneFit) {
+        QSVChildRec* r = children.first();
+        if (r) {
+            QSize sh = r->child->sizeHint();
+            sh = sh.boundedTo(r->child->maximumSize());
+            sv->resizeContents(sh.width(), sh.height());
+        }
+    }
+}
+
+void Q3ScrollViewData::viewportResized(int w, int h)
+{
+    if (policy == Q3ScrollView::AutoOneFit) {
+        QSVChildRec* r = children.first();
+        if (r) {
+            QSize sh = r->child->sizeHint();
+            sh = sh.boundedTo(r->child->maximumSize());
+            r->child->resize(QMAX(w,sh.width()), QMAX(h,sh.height()));
+        }
+
+    }
+}
+
+
+/*!
+    \class Q3ScrollView
+    \brief The Q3ScrollView widget provides a scrolling area with on-demand scroll bars.
+
+    \compat
+
+    The Q3ScrollView is a large canvas - potentially larger than the
+    coordinate system normally supported by the underlying window
+    system. This is important because it is quite easy to go beyond
+    these limitations (e.g. many web pages are more than 32000 pixels
+    high). Additionally, the Q3ScrollView can have QWidgets positioned
+    on it that scroll around with the drawn content. These sub-widgets
+    can also have positions outside the normal coordinate range (but
+    they are still limited in size).
+
+    To provide content for the widget, inherit from Q3ScrollView,
+    reimplement drawContents() and use resizeContents() to set the
+    size of the viewed area. Use addChild() and moveChild() to
+    position widgets on the view.
+
+    To use Q3ScrollView effectively it is important to understand its
+    widget structure in the three styles of use: a single large child
+    widget, a large panning area with some widgets and a large panning
+    area with many widgets.
+
+    \section1 Using One Big Widget
+
+    \img qscrollview-vp2.png
+
+    The first, simplest usage of Q3ScrollView (depicted above), is
+    appropriate for scrolling areas that are never more than about
+    4000 pixels in either dimension (this is about the maximum
+    reliable size on X11 servers). In this usage, you just make one
+    large child in the Q3ScrollView. The child should be a child of the
+    viewport() of the scrollview and be added with addChild():
+    \snippet doc/src/snippets/code/src_qt3support_widgets_q3scrollview.cpp 0
+    You can go on to add arbitrary child widgets to the single child
+    in the scrollview as you would with any widget:
+    \snippet doc/src/snippets/code/src_qt3support_widgets_q3scrollview.cpp 1
+
+    Here the Q3ScrollView has four children: the viewport(), the
+    verticalScrollBar(), the horizontalScrollBar() and a small
+    cornerWidget(). The viewport() has one child: the QWidget. The
+    QWidget has the three QLabel objects as child widgets. When the view
+    is scrolled, the QWidget is moved; its children move with it as
+    child widgets normally do.
+
+    \section1 Using a Very Big View with Some Widgets
+
+    \img qscrollview-vp.png
+
+    The second usage of Q3ScrollView (depicted above) is appropriate
+    when few, if any, widgets are on a very large scrolling area that
+    is potentially larger than 4000 pixels in either dimension. In
+    this usage you call resizeContents() to set the size of the area
+    and reimplement drawContents() to paint the contents. You may also
+    add some widgets by making them children of the viewport() and
+    adding them with addChild() (this is the same as the process for
+    the single large widget in the previous example):
+    \snippet doc/src/snippets/code/src_qt3support_widgets_q3scrollview.cpp 2
+    Here, the Q3ScrollView has the same four children: the viewport(),
+    the verticalScrollBar(), the horizontalScrollBar() and a small
+    cornerWidget(). The viewport() has the three QLabel objects as
+    child widgets. When the view is scrolled, the scrollview moves the
+    child widgets individually.
+
+    \section1 Using a Very Big View with Many Widgets
+
+    \img qscrollview-cl.png
+
+    The final usage of Q3ScrollView (depicted above) is appropriate
+    when many widgets are on a very large scrolling area that is
+    potentially larger than 4000 pixels in either dimension. In this
+    usage you call resizeContents() to set the size of the area and
+    reimplement drawContents() to paint the contents. You then call
+    enableClipper(true) and add widgets, again by making them children
+    of the viewport(), and adding them with addChild():
+    \snippet doc/src/snippets/code/src_qt3support_widgets_q3scrollview.cpp 3
+
+    Here, the Q3ScrollView has four children:  the clipper() (not the
+    viewport() this time), the verticalScrollBar(), the
+    horizontalScrollBar() and a small cornerWidget(). The clipper()
+    has one child: the viewport(). The viewport() has the same three
+    labels as child widgets. When the view is scrolled the viewport()
+    is moved; its children move with it as child widgets normally do.
+
+    \target allviews
+    \section1 Details Relevant for All Views
+
+    Normally you will use the first or third method if you want any
+    child widgets in the view.
+
+    Note that the widget you see in the scrolled area is the
+    viewport() widget, not the Q3ScrollView itself. So to turn mouse
+    tracking on, for example, use viewport()->setMouseTracking(true).
+
+    To enable drag-and-drop, you would setAcceptDrops(true) on the
+    Q3ScrollView (because drag-and-drop events propagate to the
+    parent). But to work out the logical position in the view, you
+    would need to map the drop co-ordinate from being relative to the
+    Q3ScrollView to being relative to the contents; use the function
+    viewportToContents() for this.
+
+    To handle mouse events on the scrolling area, subclass scrollview
+    as you would subclass other widgets, but rather than
+    reimplementing mousePressEvent(), reimplement
+    contentsMousePressEvent() instead. The contents specific event
+    handlers provide translated events in the coordinate system of the
+    scrollview. If you reimplement mousePressEvent(), you'll get
+    called only when part of the Q3ScrollView is clicked: and the only
+    such part is the "corner" (if you don't set a cornerWidget()) and
+    the frame; everything else is covered up by the viewport, clipper
+    or scroll bars.
+
+    When you construct a Q3ScrollView, some of the window flags apply
+    to the viewport() instead of being sent to the QWidget constructor
+    for the Q3ScrollView.
+
+    \list
+
+    \i An image-manipulation widget would use \c
+    WNoAutoErase|WStaticContents because the widget draws all pixels
+    itself, and when its size increases, it only needs a paint event
+    for the new part because the old part remains unchanged.
+
+    \i A scrolling game widget in which the background scrolls as the
+    characters move might use \c WNoAutoErase (in addition to \c
+    WStaticContents) so that the window system background does not
+    flash in and out during scrolling.
+
+    \i A word processing widget might use \c WNoAutoErase and repaint
+    itself line by line to get a less-flickery resizing. If the widget
+    is in a mode in which no text justification can take place, it
+    might use \c WStaticContents too, so that it would only get a
+    repaint for the newly visible parts.
+
+    \endlist
+
+    Child widgets may be moved using addChild() or moveChild(). Use
+    childX() and childY() to get the position of a child widget.
+
+    A widget may be placed in the corner between the vertical and
+    horizontal scroll bars with setCornerWidget(). You can get access
+    to the scroll bars using horizontalScrollBar() and
+    verticalScrollBar(), and to the viewport with viewport(). The
+    scroll view can be scrolled using scrollBy(), ensureVisible(),
+    setContentsPos() or center().
+
+    The visible area is given by visibleWidth() and visibleHeight(),
+    and the contents area by contentsWidth() and contentsHeight(). The
+    contents may be repainted using one of the repaintContents() or
+    updateContents() functions.
+
+    Coordinate conversion is provided by contentsToViewport() and
+    viewportToContents().
+
+    The contentsMoving() signal is emitted just before the contents
+    are moved to a new position.
+
+    \warning Q3ScrollView currently does not erase the background when
+    resized, i.e. you must always clear the background manually in
+    scrollview subclasses. This will change in a future version of Qt
+    and we recommend specifying the \c WNoAutoErase flag explicitly.
+*/
+
+
+/*!
+    \enum Q3ScrollView::ResizePolicy
+
+    This enum type is used to control a Q3ScrollView's reaction to
+    resize events.
+
+    \value Default  the Q3ScrollView selects one of the other settings
+    automatically when it has to. In this version of Qt, Q3ScrollView
+    changes to \c Manual if you resize the contents with
+    resizeContents() and to \c AutoOne if a child is added.
+
+    \value Manual  the contents stays the size set by resizeContents().
+
+    \value AutoOne  if there is only one child widget the contents stays
+    the size of that widget. Otherwise the behavior is undefined.
+
+    \value AutoOneFit if there is only one child widget the contents stays
+    the size of that widget's sizeHint(). If the scrollview is resized
+    larger than the child's sizeHint(), the child will be resized to
+    fit. If there is more than one child, the behavior is undefined.
+
+*/
+//####  The widget will be resized to its sizeHint() when a LayoutHint event
+//#### is received
+
+/*!
+    Constructs a Q3ScrollView called \a name with parent \a parent and
+    widget flags \a f.
+
+    The widget flags \c WStaticContents, \c WNoAutoErase and \c
+    WPaintClever are propagated to the viewport() widget. The other
+    widget flags are propagated to the parent constructor as usual.
+*/
+
+Q3ScrollView::Q3ScrollView(QWidget *parent, const char *name, Qt::WindowFlags f) :
+    Q3Frame(parent, name, f & (~WStaticContents) & (~WNoAutoErase) & (~WResizeNoErase))
+{
+    WindowFlags flags = WResizeNoErase | (f&WPaintClever) | (f&WRepaintNoErase) | (f&WStaticContents);
+    d = new Q3ScrollViewData(this, flags);
+
+#ifndef QT_NO_DRAGANDDROP
+    connect(&d->autoscroll_timer, SIGNAL(timeout()),
+             this, SLOT(doDragAutoScroll()));
+#endif
+
+    connect(d->hbar, SIGNAL(valueChanged(int)),
+        this, SLOT(hslide(int)));
+    connect(d->vbar, SIGNAL(valueChanged(int)),
+        this, SLOT(vslide(int)));
+
+    connect(d->hbar, SIGNAL(sliderPressed()), this, SLOT(hbarIsPressed()));
+    connect(d->hbar, SIGNAL(sliderReleased()), this, SLOT(hbarIsReleased()));
+    connect(d->vbar, SIGNAL(sliderPressed()), this, SLOT(vbarIsPressed()));
+    connect(d->vbar, SIGNAL(sliderReleased()), this, SLOT(vbarIsReleased()));
+
+
+    d->viewport->installEventFilter(this);
+
+    connect(&d->scrollbar_timer, SIGNAL(timeout()),
+             this, SLOT(updateScrollBars()));
+
+    setFrameStyle(Q3Frame::StyledPanel | Q3Frame::Sunken);
+    setLineWidth(style()->pixelMetric(QStyle::PM_DefaultFrameWidth));
+    setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
+}
+
+
+/*!
+    Destroys the Q3ScrollView. Any children added with addChild() will
+    be deleted.
+*/
+Q3ScrollView::~Q3ScrollView()
+{
+    // Be careful not to get all those useless events...
+    if (d->clipped_viewport)
+        d->clipped_viewport->removeEventFilter(this);
+    else
+        d->viewport->removeEventFilter(this);
+
+    // order is important
+    // ~QWidget may cause a WM_ERASEBKGND on Windows
+    delete d->vbar;
+    d->vbar = 0;
+    delete d->hbar;
+    d->hbar = 0;
+    delete d->viewport;
+    d->viewport = 0;
+    delete d;
+    d = 0;
+}
+
+/*!
+    \fn void Q3ScrollView::horizontalSliderPressed()
+
+    This signal is emitted whenever the user presses the horizontal slider.
+*/
+/*!
+    \fn void Q3ScrollView::horizontalSliderReleased()
+
+    This signal is emitted whenever the user releases the horizontal slider.
+*/
+/*!
+    \fn void Q3ScrollView::verticalSliderPressed()
+
+    This signal is emitted whenever the user presses the vertical slider.
+*/
+/*!
+    \fn void Q3ScrollView::verticalSliderReleased()
+
+    This signal is emitted whenever the user releases the vertical slider.
+*/
+void Q3ScrollView::hbarIsPressed()
+{
+    d->hbarPressed = true;
+    emit(horizontalSliderPressed());
+}
+
+void Q3ScrollView::hbarIsReleased()
+{
+    d->hbarPressed = false;
+    emit(horizontalSliderReleased());
+}
+
+/*!
+    Returns true if horizontal slider is pressed by user; otherwise returns false.
+*/
+bool Q3ScrollView::isHorizontalSliderPressed()
+{
+    return d->hbarPressed;
+}
+
+void Q3ScrollView::vbarIsPressed()
+{
+    d->vbarPressed = true;
+    emit(verticalSliderPressed());
+}
+
+void Q3ScrollView::vbarIsReleased()
+{
+    d->vbarPressed = false;
+    emit(verticalSliderReleased());
+}
+
+/*!
+    Returns true if vertical slider is pressed by user; otherwise returns false.
+*/
+bool Q3ScrollView::isVerticalSliderPressed()
+{
+    return d->vbarPressed;
+}
+
+/*!
+    \internal
+*/
+void Q3ScrollView::styleChange(QStyle& old)
+{
+    QWidget::styleChange(old);
+    updateScrollBars();
+    d->cachedSizeHint = QSize();
+}
+
+/*!
+    \internal
+*/
+void Q3ScrollView::fontChange(const QFont &old)
+{
+    QWidget::fontChange(old);
+    updateScrollBars();
+    d->cachedSizeHint = QSize();
+}
+
+void Q3ScrollView::hslide(int pos)
+{
+    if (!d->signal_choke) {
+        moveContents(-pos, -d->contentsY());
+        QApplication::syncX();
+    }
+}
+
+void Q3ScrollView::vslide(int pos)
+{
+    if (!d->signal_choke) {
+        moveContents(-d->contentsX(), -pos);
+        QApplication::syncX();
+    }
+}
+
+/*!
+    Called when the horizontal scroll bar geometry changes. This is
+    provided as a protected function so that subclasses can do
+    interesting things such as providing extra buttons in some of the
+    space normally used by the scroll bars.
+
+    The default implementation simply gives all the space to \a hbar.
+    The new geometry is given by \a x, \a y, \a w and \a h.
+
+    \sa setVBarGeometry()
+*/
+void Q3ScrollView::setHBarGeometry(QScrollBar& hbar,
+    int x, int y, int w, int h)
+{
+    hbar.setGeometry(x, y, w, h);
+}
+
+/*!
+    Called when the vertical scroll bar geometry changes. This is
+    provided as a protected function so that subclasses can do
+    interesting things such as providing extra buttons in some of the
+    space normally used by the scroll bars.
+
+    The default implementation simply gives all the space to \a vbar.
+    The new geometry is given by \a x, \a y, \a w and \a h.
+
+    \sa setHBarGeometry()
+*/
+void Q3ScrollView::setVBarGeometry(QScrollBar& vbar,
+    int x, int y, int w, int h)
+{
+    vbar.setGeometry(x, y, w, h);
+}
+
+
+/*!
+    Returns the viewport size for size (\a x, \a y).
+
+    The viewport size depends on (\a x, \a y) (the size of the contents),
+    the size of this widget and the modes of the horizontal and
+    vertical scroll bars.
+
+    This function permits widgets that can trade vertical and
+    horizontal space for each other to control scroll bar appearance
+    better. For example, a word processor or web browser can control
+    the width of the right margin accurately, whether or not there
+    needs to be a vertical scroll bar.
+*/
+
+QSize Q3ScrollView::viewportSize(int x, int y) const
+{
+    int fw = frameWidth();
+    int lmarg = fw+d->l_marg;
+    int rmarg = fw+d->r_marg;
+    int tmarg = fw+d->t_marg;
+    int bmarg = fw+d->b_marg;
+
+    int w = width();
+    int h = height();
+
+    bool needh, needv;
+    bool showh, showv;
+    int hsbExt = horizontalScrollBar()->sizeHint().height();
+    int vsbExt = verticalScrollBar()->sizeHint().width();
+
+    if (d->policy != AutoOne || d->anyVisibleChildren()) {
+        // Do we definitely need the scroll bar?
+        needh = w-lmarg-rmarg < x;
+        needv = h-tmarg-bmarg < y;
+
+        // Do we intend to show the scroll bar?
+        if (d->hMode == AlwaysOn)
+            showh = true;
+        else if (d->hMode == AlwaysOff)
+            showh = false;
+        else
+            showh = needh;
+
+        if (d->vMode == AlwaysOn)
+            showv = true;
+        else if (d->vMode == AlwaysOff)
+            showv = false;
+        else
+            showv = needv;
+
+        // Given other scroll bar will be shown, NOW do we need one?
+        if (showh && h-vsbExt-tmarg-bmarg < y) {
+            if (d->vMode == Auto)
+                showv=true;
+        }
+        if (showv && w-hsbExt-lmarg-rmarg < x) {
+            if (d->hMode == Auto)
+                showh=true;
+        }
+    } else {
+        // Scroll bars not needed, only show scroll bar that are always on.
+        showh = d->hMode == AlwaysOn;
+        showv = d->vMode == AlwaysOn;
+    }
+
+    return QSize(w-lmarg-rmarg - (showv ? vsbExt : 0),
+                  h-tmarg-bmarg - (showh ? hsbExt : 0));
+}
+
+
+/*!
+    Updates scroll bars: all possibilities are considered. You should
+    never need to call this in your code.
+*/
+void Q3ScrollView::updateScrollBars()
+{
+    if(!horizontalScrollBar() && !verticalScrollBar())
+        return;
+
+    // I support this should use viewportSize()... but it needs
+    // so many of the temporary variables from viewportSize.  hm.
+    int fw = frameWidth();
+    int lmarg = fw+d->l_marg;
+    int rmarg = fw+d->r_marg;
+    int tmarg = fw+d->t_marg;
+    int bmarg = fw+d->b_marg;
+
+    int w = width();
+    int h = height();
+
+    int portw, porth;
+
+    bool needh;
+    bool needv;
+    bool showh;
+    bool showv;
+    bool showc = false;
+
+    int hsbExt = horizontalScrollBar()->sizeHint().height();
+    int vsbExt = verticalScrollBar()->sizeHint().width();
+
+    QSize oldVisibleSize(visibleWidth(), visibleHeight());
+
+    if (d->policy != AutoOne || d->anyVisibleChildren()) {
+        // Do we definitely need the scroll bar?
+        needh = w-lmarg-rmarg < d->contentsWidth();
+        if (d->inresize)
+            needh  = !horizontalScrollBar()->isHidden();
+        needv = h-tmarg-bmarg < contentsHeight();
+
+        // Do we intend to show the scroll bar?
+        if (d->hMode == AlwaysOn)
+            showh = true;
+        else if (d->hMode == AlwaysOff)
+            showh = false;
+        else
+            showh = needh;
+
+        if (d->vMode == AlwaysOn)
+            showv = true;
+        else if (d->vMode == AlwaysOff)
+            showv = false;
+        else
+            showv = needv;
+
+#ifdef Q_WS_MAC
+        bool mac_need_scroll = false;
+        if(!parentWidget()) {
+            mac_need_scroll = true;
+        } else {
+            QWidget *tlw = window();
+#ifndef QT_MAC_USE_COCOA
+            QPoint tlw_br = QPoint(tlw->width(), tlw->height()),
+                    my_br = qt_mac_posInWindow(this) + QPoint(w, h);
+            if(my_br.x() >= tlw_br.x() - 3 && my_br.y() >= tlw_br.y() - 3)
+#endif
+                mac_need_scroll = true;
+        }
+        if(mac_need_scroll) {
+#ifndef QT_MAC_USE_COCOA
+            WindowAttributes attr;
+            GetWindowAttributes((WindowPtr)handle(), &attr);
+            mac_need_scroll = (attr & kWindowResizableAttribute);
+#endif
+        }
+        if(mac_need_scroll) {
+            showc = true;
+            if(d->vMode == Auto)
+                showv = true;
+            if(d->hMode == Auto)
+                showh = true;
+        }
+#endif
+
+        // Given other scroll bar will be shown, NOW do we need one?
+        if (showh && h-vsbExt-tmarg-bmarg < contentsHeight()) {
+            needv=true;
+            if (d->vMode == Auto)
+                showv=true;
+        }
+        if (showv && !d->inresize && w-hsbExt-lmarg-rmarg < d->contentsWidth()) {
+            needh=true;
+            if (d->hMode == Auto)
+                showh=true;
+        }
+    } else {
+        // Scrollbars not needed, only show scroll bar that are always on.
+        needh = needv = false;
+        showh = d->hMode == AlwaysOn;
+        showv = d->vMode == AlwaysOn;
+    }
+
+    bool sc = d->signal_choke;
+    d->signal_choke=true;
+
+    // Hide unneeded scroll bar, calculate viewport size
+    if (showh) {
+        porth=h-hsbExt-tmarg-bmarg;
+    } else {
+        if (!needh)
+            d->hbar->setValue(0);
+        d->hbar->hide();
+        porth=h-tmarg-bmarg;
+    }
+    if (showv) {
+        portw=w-vsbExt-lmarg-rmarg;
+    } else {
+        if (!needv)
+            d->vbar->setValue(0);
+        d->vbar->hide();
+        portw=w-lmarg-rmarg;
+    }
+
+    // Configure scroll bars that we will show
+    if (needv) {
+        d->vbar->setRange(0, contentsHeight()-porth);
+        d->vbar->setSteps(Q3ScrollView::d->vbar->lineStep(), porth);
+    } else {
+        d->vbar->setRange(0, 0);
+    }
+    if (needh) {
+        d->hbar->setRange(0, QMAX(0, d->contentsWidth()-portw));
+        d->hbar->setSteps(Q3ScrollView::d->hbar->lineStep(), portw);
+    } else {
+        d->hbar->setRange(0, 0);
+    }
+
+    // Position the scroll bars, viewport and corner widget.
+    int bottom;
+    bool reverse = QApplication::reverseLayout();
+    int xoffset = (reverse && (showv || cornerWidget())) ? vsbExt : 0;
+    int xpos = reverse ? 0 : w - vsbExt;
+    bool frameContentsOnly =
+        style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents);
+
+    if(! frameContentsOnly) {
+        if (reverse)
+            xpos += fw;
+        else
+            xpos -= fw;
+    }
+    if (showh) {
+        int right = (showc || showv || cornerWidget()) ? w-vsbExt : w;
+        if (! frameContentsOnly)
+            setHBarGeometry(*d->hbar, fw + xoffset, h-hsbExt-fw,
+                             right-fw-fw, hsbExt);
+        else
+            setHBarGeometry(*d->hbar, 0 + xoffset, h-hsbExt, right,
+                             hsbExt);
+        bottom=h-hsbExt;
+    } else {
+        bottom=h;
+    }
+    if (showv) {
+        clipper()->setGeometry(lmarg + xoffset, tmarg,
+                                w-vsbExt-lmarg-rmarg,
+                                bottom-tmarg-bmarg);
+        d->viewportResized(w-vsbExt-lmarg-rmarg, bottom-tmarg-bmarg);
+        if (! frameContentsOnly)
+            changeFrameRect(QRect(0, 0, w, h));
+        else
+            changeFrameRect(QRect(xoffset, 0, w-vsbExt, bottom));
+        if (showc || cornerWidget()) {
+            if (! frameContentsOnly)
+                setVBarGeometry(*d->vbar, xpos,
+                                 fw, vsbExt,
+                                 h-hsbExt-fw-fw);
+            else
+                setVBarGeometry(*d->vbar, xpos, 0,
+                                 vsbExt,
+                                 h-hsbExt);
+        }
+        else {
+            if (! frameContentsOnly)
+                setVBarGeometry(*d->vbar, xpos,
+                                 fw, vsbExt,
+                                 bottom-fw-fw);
+            else
+                setVBarGeometry(*d->vbar, xpos, 0,
+                                 vsbExt, bottom);
+        }
+    } else {
+        if (! frameContentsOnly)
+            changeFrameRect(QRect(0, 0, w, h));
+        else
+            changeFrameRect(QRect(0, 0, w, bottom));
+        clipper()->setGeometry(lmarg, tmarg,
+                                w-lmarg-rmarg, bottom-tmarg-bmarg);
+        d->viewportResized(w-lmarg-rmarg, bottom-tmarg-bmarg);
+    }
+
+    QWidget *corner = d->corner;
+    if (d->corner) {
+        if (! frameContentsOnly)
+            corner->setGeometry(xpos,
+                                h-hsbExt-fw,
+                                vsbExt,
+                                hsbExt);
+        else
+            corner->setGeometry(xpos,
+                                h-hsbExt,
+                                vsbExt,
+                                hsbExt);
+    }
+
+    d->signal_choke=sc;
+
+    if (d->contentsX()+visibleWidth() > d->contentsWidth()) {
+        int x;
+#if 0
+        if (reverse)
+            x =QMIN(0,d->contentsWidth()-visibleWidth());
+        else
+#endif
+            x =QMAX(0,d->contentsWidth()-visibleWidth());
+        d->hbar->setValue(x);
+        // Do it even if it is recursive
+        moveContents(-x, -d->contentsY());
+    }
+    if (d->contentsY()+visibleHeight() > contentsHeight()) {
+        int y=QMAX(0,contentsHeight()-visibleHeight());
+        d->vbar->setValue(y);
+        // Do it even if it is recursive
+        moveContents(-d->contentsX(), -y);
+    }
+
+    // Finally, show the scroll bars
+    if (showh && (d->hbar->isHidden() || !d->hbar->isVisible()))
+        d->hbar->show();
+    if (showv && (d->vbar->isHidden() || !d->vbar->isVisible()))
+        d->vbar->show();
+
+    d->signal_choke=true;
+    d->vbar->setValue(d->contentsY());
+    d->hbar->setValue(d->contentsX());
+    d->signal_choke=false;
+
+    QSize newVisibleSize(visibleWidth(), visibleHeight());
+    if (d->clipped_viewport && oldVisibleSize != newVisibleSize) {
+        QResizeEvent e(newVisibleSize, oldVisibleSize);
+        viewportResizeEvent(&e);
+    }
+}
+
+
+/*!
+    \reimp
+*/
+void Q3ScrollView::setVisible(bool visible)
+{
+    if (visible && !isVisible()) {
+        QWidget::setVisible(visible);
+        updateScrollBars();
+        d->hideOrShowAll(this);
+    } else {
+        QWidget::setVisible(visible);
+    }
+}
+
+/*!
+    \internal
+ */
+void Q3ScrollView::resize(int w, int h)
+{
+    QWidget::resize(w, h);
+}
+
+/*!
+    \internal
+*/
+void Q3ScrollView::resize(const QSize& s)
+{
+    resize(s.width(), s.height());
+}
+
+/*!
+    \reimp
+*/
+void Q3ScrollView::resizeEvent(QResizeEvent* event)
+{
+    Q3Frame::resizeEvent(event);
+
+#if 0
+    if (QApplication::reverseLayout()) {
+        d->fake_scroll = true;
+        scrollBy(-event->size().width() + event->oldSize().width(), 0);
+        d->fake_scroll = false;
+    }
+#endif
+
+    bool inresize = d->inresize;
+    d->inresize = true;
+    updateScrollBars();
+    d->inresize = inresize;
+    d->scrollbar_timer.start(0, true);
+
+    d->hideOrShowAll(this);
+}
+
+
+
+/*!
+    \reimp
+*/
+void  Q3ScrollView::mousePressEvent(QMouseEvent * e)
+{
+    e->ignore();
+}
+
+/*!
+    \reimp
+*/
+void  Q3ScrollView::mouseReleaseEvent(QMouseEvent *e)
+{
+    e->ignore();
+}
+
+
+/*!
+    \reimp
+*/
+void  Q3ScrollView::mouseDoubleClickEvent(QMouseEvent *e)
+{
+    e->ignore();
+}
+
+/*!
+    \reimp
+*/
+void  Q3ScrollView::mouseMoveEvent(QMouseEvent *e)
+{
+    e->ignore();
+}
+
+/*!
+    \reimp
+*/
+#ifndef QT_NO_WHEELEVENT
+void Q3ScrollView::wheelEvent(QWheelEvent *e)
+{
+    QWheelEvent ce(viewport()->mapFromGlobal(e->globalPos()),
+                    e->globalPos(), e->delta(), e->state());
+    viewportWheelEvent(&ce);
+    if (!ce.isAccepted()) {
+        if (e->orientation() == Horizontal && horizontalScrollBar())
+            horizontalScrollBar()->event(e);
+        else  if (e->orientation() == Vertical && verticalScrollBar())
+            verticalScrollBar()->event(e);
+    } else {
+        e->accept();
+    }
+}
+#endif
+
+/*!
+    \reimp
+*/
+void Q3ScrollView::contextMenuEvent(QContextMenuEvent *e)
+{
+    if (e->reason() != QContextMenuEvent::Keyboard) {
+        e->ignore();
+        return;
+    }
+
+    QContextMenuEvent ce(e->reason(), viewport()->mapFromGlobal(e->globalPos()),
+                          e->globalPos(), e->state());
+    viewportContextMenuEvent(&ce);
+    if (ce.isAccepted())
+        e->accept();
+    else
+        e->ignore();
+}
+
+Q3ScrollView::ScrollBarMode Q3ScrollView::vScrollBarMode() const
+{
+    return d->vMode;
+}
+
+
+/*!
+    \enum Q3ScrollView::ScrollBarMode
+
+    This enum type describes the various modes of Q3ScrollView's scroll
+    bars.
+
+    \value Auto  Q3ScrollView shows a scroll bar when the content is
+    too large to fit and not otherwise. This is the default.
+
+    \value AlwaysOff  Q3ScrollView never shows a scroll bar.
+
+    \value AlwaysOn  Q3ScrollView always shows a scroll bar.
+
+    (The modes for the horizontal and vertical scroll bars are
+    independent.)
+*/
+
+
+/*!
+    \property Q3ScrollView::vScrollBarMode
+    \brief the mode for the vertical scroll bar
+
+    The default mode is Q3ScrollView::Auto.
+
+    \sa hScrollBarMode
+*/
+void  Q3ScrollView::setVScrollBarMode(ScrollBarMode mode)
+{
+    if (d->vMode != mode) {
+        d->vMode = mode;
+        updateScrollBars();
+    }
+}
+
+
+/*!
+    \property Q3ScrollView::hScrollBarMode
+    \brief the mode for the horizontal scroll bar
+
+    The default mode is Q3ScrollView::Auto.
+
+    \sa vScrollBarMode
+*/
+Q3ScrollView::ScrollBarMode Q3ScrollView::hScrollBarMode() const
+{
+    return d->hMode;
+}
+
+void Q3ScrollView::setHScrollBarMode(ScrollBarMode mode)
+{
+    if (d->hMode != mode) {
+        d->hMode = mode;
+        updateScrollBars();
+    }
+}
+
+
+/*!
+    Returns the widget in the corner between the two scroll bars.
+
+    By default, no corner widget is present.
+*/
+QWidget* Q3ScrollView::cornerWidget() const
+{
+    return d->corner;
+}
+
+/*!
+    Sets the widget in the \a corner between the two scroll bars.
+
+    You will probably also want to set at least one of the scroll bar
+    modes to \c AlwaysOn.
+
+    Passing 0 shows no widget in the corner.
+
+    Any previous \a corner widget is hidden.
+
+    You may call setCornerWidget() with the same widget at different
+    times.
+
+    All widgets set here will be deleted by the Q3ScrollView when it is
+    destroyed unless you separately reparent the widget after setting
+    some other corner widget (or 0).
+
+    Any \e newly set widget should have no current parent.
+
+    By default, no corner widget is present.
+
+    \sa setVScrollBarMode(), setHScrollBarMode()
+*/
+void Q3ScrollView::setCornerWidget(QWidget* corner)
+{
+    QWidget* oldcorner = d->corner;
+    if (oldcorner != corner) {
+        if (oldcorner) oldcorner->hide();
+        d->corner = corner;
+        if (corner) corner->setParent(this);
+        updateScrollBars();
+        if (corner) corner->show();
+    }
+}
+
+
+void Q3ScrollView::setResizePolicy(ResizePolicy r)
+{
+    d->policy = r;
+}
+
+/*!
+    \property Q3ScrollView::resizePolicy
+    \brief the resize policy
+
+    The default is \c Default.
+
+    \sa ResizePolicy
+*/
+Q3ScrollView::ResizePolicy Q3ScrollView::resizePolicy() const
+{
+    return d->policy;
+}
+
+/*!
+    \internal
+*/
+void Q3ScrollView::setEnabled(bool enable)
+{
+    Q3Frame::setEnabled(enable);
+}
+
+/*!
+    Removes the \a child widget from the scrolled area. Note that this
+    happens automatically if the \a child is deleted.
+*/
+void Q3ScrollView::removeChild(QWidget* child)
+{
+    if (!d || !child) // First check in case we are destructing
+        return;
+
+    QSVChildRec *r = d->rec(child);
+    if (r) d->deleteChildRec(r);
+}
+
+/*!
+    \internal
+*/
+void Q3ScrollView::removeChild(QObject* child)
+{
+    Q3Frame::removeChild(child);
+}
+
+/*!
+    Inserts the widget, \a child, into the scrolled area positioned at
+    (\a x, \a y). The position defaults to (0, 0). If the child is
+    already in the view, it is just moved.
+
+    You may want to call enableClipper(true) if you add a large number
+    of widgets.
+*/
+void Q3ScrollView::addChild(QWidget* child, int x, int y)
+{
+    if (!child) {
+#if defined(QT_CHECK_NULL)
+        qWarning("Q3ScrollView::addChild(): Cannot add null child");
+#endif
+        return;
+    }
+    child->polish();
+    child->setBackgroundOrigin(WidgetOrigin);
+
+    if (child->parentWidget() == viewport()) {
+        // May already be there
+        QSVChildRec *r = d->rec(child);
+        if (r) {
+            r->moveTo(this,x,y,d->clipped_viewport);
+            if (d->policy > Manual) {
+                d->autoResizeHint(this);
+                d->autoResize(this); // #### better to just deal with this one widget!
+            }
+            return;
+        }
+    }
+
+    if (d->children.isEmpty() && d->policy != Manual) {
+        if (d->policy == Default)
+            setResizePolicy(AutoOne);
+        child->installEventFilter(this);
+    } else if (d->policy == AutoOne) {
+        child->removeEventFilter(this); //#### ?????
+        setResizePolicy(Manual);
+    }
+    if (child->parentWidget() != viewport()) {
+            child->reparent(viewport(), 0, QPoint(0,0), false);
+    }
+    d->addChildRec(child,x,y)->hideOrShow(this, d->clipped_viewport);
+
+    if (d->policy > Manual) {
+        d->autoResizeHint(this);
+        d->autoResize(this); // #### better to just deal with this one widget!
+    }
+}
+
+/*!
+    Repositions the \a child widget to (\a x, \a y). This function is
+    the same as addChild().
+*/
+void Q3ScrollView::moveChild(QWidget* child, int x, int y)
+{
+    addChild(child,x,y);
+}
+
+/*!
+    Returns the X position of the given \a child widget. Use this
+    rather than QWidget::x() for widgets added to the view.
+
+    This function returns 0 if \a child has not been added to the view.
+*/
+int Q3ScrollView::childX(QWidget* child)
+{
+    QSVChildRec *r = d->rec(child);
+    return r ? r->x : 0;
+}
+
+/*!
+    Returns the Y position of the given \a child widget. Use this
+    rather than QWidget::y() for widgets added to the view.
+
+    This function returns 0 if \a child has not been added to the view.
+*/
+int Q3ScrollView::childY(QWidget* child)
+{
+    QSVChildRec *r = d->rec(child);
+    return r ? r->y : 0;
+}
+
+/*! \fn bool Q3ScrollView::childIsVisible(QWidget*)
+  \obsolete
+
+  Returns true if \a child is visible. This is equivalent
+  to child->isVisible().
+*/
+
+/*! \fn void Q3ScrollView::showChild(QWidget* child, bool y)
+  \obsolete
+
+  Sets the visibility of \a child. Equivalent to
+  QWidget::show() or QWidget::hide().
+*/
+
+/*!
+    This event filter ensures the scroll bars are updated when a
+    single contents widget is resized, shown, hidden or destroyed; it
+    passes mouse events to the Q3ScrollView. The event is in \a e and
+    the object is in \a obj.
+*/
+
+bool Q3ScrollView::eventFilter(QObject *obj, QEvent *e)
+{
+    bool disabled = !(qobject_cast<QWidget*>(obj)->isEnabled());
+    if (!d)
+        return false; // we are destructing
+    if (obj == d->viewport || obj == d->clipped_viewport) {
+        switch (e->type()) {
+            /* Forward many events to viewport...() functions */
+        case QEvent::Paint:
+            viewportPaintEvent((QPaintEvent*)e);
+            break;
+        case QEvent::Resize:
+            if (!d->clipped_viewport)
+                viewportResizeEvent((QResizeEvent *)e);
+            break;
+        case QEvent::MouseButtonPress:
+            if (disabled)
+                return false;
+            viewportMousePressEvent((QMouseEvent*)e);
+            if (((QMouseEvent*)e)->isAccepted())
+                return true;
+            break;
+        case QEvent::MouseButtonRelease:
+            if (disabled)
+                return false;
+            viewportMouseReleaseEvent((QMouseEvent*)e);
+            if (((QMouseEvent*)e)->isAccepted())
+                return true;
+            break;
+        case QEvent::MouseButtonDblClick:
+            if (disabled)
+                return false;
+            viewportMouseDoubleClickEvent((QMouseEvent*)e);
+            if (((QMouseEvent*)e)->isAccepted())
+                return true;
+            break;
+        case QEvent::MouseMove:
+            if (disabled)
+                return false;
+            viewportMouseMoveEvent((QMouseEvent*)e);
+            if (((QMouseEvent*)e)->isAccepted())
+                return true;
+            break;
+#ifndef QT_NO_DRAGANDDROP
+        case QEvent::DragEnter:
+            if (disabled)
+                return false;
+            viewportDragEnterEvent((QDragEnterEvent*)e);
+            break;
+        case QEvent::DragMove: {
+            if (disabled)
+                return false;
+            if (d->drag_autoscroll) {
+                QPoint vp = ((QDragMoveEvent*) e)->pos();
+                QRect inside_margin(autoscroll_margin, autoscroll_margin,
+                                     visibleWidth() - autoscroll_margin * 2,
+                                     visibleHeight() - autoscroll_margin * 2);
+                if (!inside_margin.contains(vp)) {
+                    startDragAutoScroll();
+                    // Keep sending move events
+                    ((QDragMoveEvent*)e)->accept(QRect(0,0,0,0));
+                }
+            }
+            viewportDragMoveEvent((QDragMoveEvent*)e);
+        } break;
+        case QEvent::DragLeave:
+            if (disabled)
+                return false;
+            stopDragAutoScroll();
+            viewportDragLeaveEvent((QDragLeaveEvent*)e);
+            break;
+        case QEvent::Drop:
+            if (disabled)
+                return false;
+            stopDragAutoScroll();
+            viewportDropEvent((QDropEvent*)e);
+            break;
+#endif // QT_NO_DRAGANDDROP
+#ifndef QT_NO_WHEELEVENT
+        case QEvent::Wheel:
+            if (disabled)
+                return false;
+            break;
+#endif
+        case QEvent::ContextMenu:
+            if (disabled)
+                return false;
+            viewportContextMenuEvent((QContextMenuEvent*)e);
+            if (((QContextMenuEvent*)e)->isAccepted())
+                return true;
+            break;
+        case QEvent::ChildRemoved:
+            removeChild((QWidget*)((QChildEvent*)e)->child());
+            break;
+        case QEvent::LayoutHint:
+            d->autoResizeHint(this);
+            break;
+        default:
+            break;
+        }
+    } else if (d && d->rec((QWidget*)obj)) {  // must be a child
+        if (e->type() == QEvent::Resize)
+            d->autoResize(this);
+        else if (e->type() == QEvent::Move)
+            d->autoMove(this);
+    }
+    return Q3Frame::eventFilter(obj, e);  // always continue with standard event processing
+}
+
+/*!
+    This event handler is called whenever the Q3ScrollView receives a
+    mousePressEvent(): the press position in \a e is translated to be a point
+    on the contents.
+*/
+void Q3ScrollView::contentsMousePressEvent(QMouseEvent* e)
+{
+    e->ignore();
+}
+
+/*!
+    This event handler is called whenever the Q3ScrollView receives a
+    mouseReleaseEvent(): the release position in \a e is translated to be a
+    point on the contents.
+*/
+void Q3ScrollView::contentsMouseReleaseEvent(QMouseEvent* e)
+{
+    e->ignore();
+}
+
+/*!
+    This event handler is called whenever the Q3ScrollView receives a
+    mouseDoubleClickEvent(): the click position in \a e is translated to be a
+    point on the contents.
+
+    The default implementation generates a normal mouse press event.
+*/
+void Q3ScrollView::contentsMouseDoubleClickEvent(QMouseEvent* e)
+{
+    contentsMousePressEvent(e);             // try mouse press event
+}
+
+/*!
+    This event handler is called whenever the Q3ScrollView receives a
+    mouseMoveEvent(): the mouse position in \a e is translated to be a point
+    on the contents.
+*/
+void Q3ScrollView::contentsMouseMoveEvent(QMouseEvent* e)
+{
+    e->ignore();
+}
+
+#ifndef QT_NO_DRAGANDDROP
+
+/*!
+    This event handler is called whenever the Q3ScrollView receives a
+    dragEnterEvent(): the drag position is translated to be a point
+    on the contents.
+
+    The default implementation does nothing. The \a event parameter is
+    ignored.
+*/
+void Q3ScrollView::contentsDragEnterEvent(QDragEnterEvent * /* event */)
+{
+}
+
+/*!
+    This event handler is called whenever the Q3ScrollView receives a
+    dragMoveEvent(): the drag position is translated to be a point on
+    the contents.
+
+    The default implementation does nothing. The \a event parameter is
+    ignored.
+*/
+void Q3ScrollView::contentsDragMoveEvent(QDragMoveEvent * /* event */)
+{
+}
+
+/*!
+    This event handler is called whenever the Q3ScrollView receives a
+    dragLeaveEvent(): the drag position is translated to be a point
+    on the contents.
+
+    The default implementation does nothing. The \a event parameter is
+    ignored.
+*/
+void Q3ScrollView::contentsDragLeaveEvent(QDragLeaveEvent * /* event */)
+{
+}
+
+/*!
+    This event handler is called whenever the Q3ScrollView receives a
+    dropEvent(): the drop position is translated to be a point on the
+    contents.
+
+    The default implementation does nothing. The \a event parameter is
+    ignored.
+*/
+
+void Q3ScrollView::contentsDropEvent(QDropEvent * /* event */)
+{
+}
+
+#endif // QT_NO_DRAGANDDROP
+
+/*!
+    This event handler is called whenever the Q3ScrollView receives a
+    wheelEvent() in \a{e}: the mouse position is translated to be a
+    point on the contents.
+*/
+#ifndef QT_NO_WHEELEVENT
+void Q3ScrollView::contentsWheelEvent(QWheelEvent * e)
+{
+    e->ignore();
+}
+#endif
+/*!
+    This event handler is called whenever the Q3ScrollView receives a
+    contextMenuEvent() in \a{e}: the mouse position is translated to
+    be a point on the contents.
+*/
+void Q3ScrollView::contentsContextMenuEvent(QContextMenuEvent *e)
+{
+    e->ignore();
+}
+
+/*!
+    This is a low-level painting routine that draws the viewport
+    contents. Reimplement this if drawContents() is too high-level
+    (for example, if you don't want to open a QPainter on the
+    viewport). The paint event is passed in \a pe.
+*/
+void Q3ScrollView::viewportPaintEvent(QPaintEvent* pe)
+{
+    QWidget* vp = viewport();
+
+    QPainter p(vp);
+    QRect r = pe->rect();
+
+    if (d->clipped_viewport) {
+        QRect rr(
+            -d->clipped_viewport->x(), -d->clipped_viewport->y(),
+            d->viewport->width(), d->viewport->height()
+           );
+        r &= rr;
+        if (r.isValid()) {
+            int ex = r.x() + d->clipped_viewport->x() + d->contentsX();
+            int ey = r.y() + d->clipped_viewport->y() + d->contentsY();
+            int ew = r.width();
+            int eh = r.height();
+            drawContentsOffset(&p,
+                d->contentsX()+d->clipped_viewport->x(),
+                d->contentsY()+d->clipped_viewport->y(),
+                ex, ey, ew, eh);
+        }
+    } else {
+        r &= d->viewport->rect();
+        int ex = r.x() + d->contentsX();
+        int ey = r.y() + d->contentsY();
+        int ew = r.width();
+        int eh = r.height();
+        drawContentsOffset(&p, d->contentsX(), d->contentsY(), ex, ey, ew, eh);
+    }
+}
+
+
+/*!
+    To provide simple processing of events on the contents, this
+    function receives all resize events sent to the viewport.
+
+    The default implementation does nothing. The \a event parameter is
+    ignored.
+
+    \sa QWidget::resizeEvent()
+*/
+void Q3ScrollView::viewportResizeEvent(QResizeEvent * /* event */)
+{
+}
+
+/*! \internal
+
+  To provide simple processing of events on the contents, this
+  function receives all mouse press events sent to the viewport,
+  translates the event and calls contentsMousePressEvent().
+
+  \sa contentsMousePressEvent(), QWidget::mousePressEvent()
+*/
+void Q3ScrollView::viewportMousePressEvent(QMouseEvent* e)
+{
+    QMouseEvent ce(e->type(), viewportToContents(e->pos()),
+        e->globalPos(), e->button(), e->state());
+    contentsMousePressEvent(&ce);
+    if (!ce.isAccepted())
+        e->ignore();
+}
+
+/*!\internal
+
+  To provide simple processing of events on the contents, this function
+  receives all mouse release events sent to the viewport, translates
+  the event and calls contentsMouseReleaseEvent().
+
+  \sa QWidget::mouseReleaseEvent()
+*/
+void Q3ScrollView::viewportMouseReleaseEvent(QMouseEvent* e)
+{
+    QMouseEvent ce(e->type(), viewportToContents(e->pos()),
+        e->globalPos(), e->button(), e->state());
+    contentsMouseReleaseEvent(&ce);
+    if (!ce.isAccepted())
+        e->ignore();
+}
+
+/*!\internal
+
+  To provide simple processing of events on the contents, this function
+  receives all mouse double click events sent to the viewport,
+  translates the event and calls contentsMouseDoubleClickEvent().
+
+  \sa QWidget::mouseDoubleClickEvent()
+*/
+void Q3ScrollView::viewportMouseDoubleClickEvent(QMouseEvent* e)
+{
+    QMouseEvent ce(e->type(), viewportToContents(e->pos()),
+        e->globalPos(), e->button(), e->state());
+    contentsMouseDoubleClickEvent(&ce);
+    if (!ce.isAccepted())
+        e->ignore();
+}
+
+/*!\internal
+
+  To provide simple processing of events on the contents, this function
+  receives all mouse move events sent to the viewport, translates the
+  event and calls contentsMouseMoveEvent().
+
+  \sa QWidget::mouseMoveEvent()
+*/
+void Q3ScrollView::viewportMouseMoveEvent(QMouseEvent* e)
+{
+    QMouseEvent ce(e->type(), viewportToContents(e->pos()),
+        e->globalPos(), e->button(), e->state());
+    contentsMouseMoveEvent(&ce);
+    if (!ce.isAccepted())
+        e->ignore();
+}
+
+#ifndef QT_NO_DRAGANDDROP
+
+/*!\internal
+
+  To provide simple processing of events on the contents, this function
+  receives all drag enter events sent to the viewport, translates the
+  event and calls contentsDragEnterEvent().
+
+  \sa QWidget::dragEnterEvent()
+*/
+void Q3ScrollView::viewportDragEnterEvent(QDragEnterEvent* e)
+{
+    e->setPoint(viewportToContents(e->pos()));
+    contentsDragEnterEvent(e);
+    e->setPoint(contentsToViewport(e->pos()));
+}
+
+/*!\internal
+
+  To provide simple processing of events on the contents, this function
+  receives all drag move events sent to the viewport, translates the
+  event and calls contentsDragMoveEvent().
+
+  \sa QWidget::dragMoveEvent()
+*/
+void Q3ScrollView::viewportDragMoveEvent(QDragMoveEvent* e)
+{
+    e->setPoint(viewportToContents(e->pos()));
+    contentsDragMoveEvent(e);
+    e->setPoint(contentsToViewport(e->pos()));
+}
+
+/*!\internal
+
+  To provide simple processing of events on the contents, this function
+  receives all drag leave events sent to the viewport and calls
+  contentsDragLeaveEvent().
+
+  \sa QWidget::dragLeaveEvent()
+*/
+void Q3ScrollView::viewportDragLeaveEvent(QDragLeaveEvent* e)
+{
+    contentsDragLeaveEvent(e);
+}
+
+/*!\internal
+
+  To provide simple processing of events on the contents, this function
+  receives all drop events sent to the viewport, translates the event
+  and calls contentsDropEvent().
+
+  \sa QWidget::dropEvent()
+*/
+void Q3ScrollView::viewportDropEvent(QDropEvent* e)
+{
+    e->setPoint(viewportToContents(e->pos()));
+    contentsDropEvent(e);
+    e->setPoint(contentsToViewport(e->pos()));
+}
+
+#endif // QT_NO_DRAGANDDROP
+
+/*!\internal
+
+  To provide simple processing of events on the contents, this function
+  receives all wheel events sent to the viewport, translates the
+  event and calls contentsWheelEvent().
+
+  \sa QWidget::wheelEvent()
+*/
+#ifndef QT_NO_WHEELEVENT
+void Q3ScrollView::viewportWheelEvent(QWheelEvent* e)
+{
+    /*
+       Different than standard mouse events, because wheel events might
+       be sent to the focus widget if the widget-under-mouse doesn't want
+       the event itself.
+    */
+    QWheelEvent ce(viewportToContents(e->pos()),
+        e->globalPos(), e->delta(), e->state());
+    contentsWheelEvent(&ce);
+    if (ce.isAccepted())
+        e->accept();
+    else
+        e->ignore();
+}
+#endif
+
+/*! \internal
+
+  To provide simple processing of events on the contents, this function
+  receives all context menu events sent to the viewport, translates the
+  event and calls contentsContextMenuEvent().
+*/
+void Q3ScrollView::viewportContextMenuEvent(QContextMenuEvent *e)
+{
+    QContextMenuEvent ce(e->reason(), viewportToContents(e->pos()), e->globalPos(), e->state());
+    contentsContextMenuEvent(&ce);
+    if (ce.isAccepted())
+        e->accept();
+    else
+        e->ignore();
+}
+
+/*!
+    Returns the component horizontal scroll bar. It is made available
+    to allow accelerators, autoscrolling, etc.
+
+    It should not be used for other purposes.
+
+    This function never returns 0.
+*/
+QScrollBar* Q3ScrollView::horizontalScrollBar() const
+{
+    return d->hbar;
+}
+
+/*!
+    Returns the component vertical scroll bar. It is made available to
+    allow accelerators, autoscrolling, etc.
+
+    It should not be used for other purposes.
+
+    This function never returns 0.
+*/
+QScrollBar* Q3ScrollView::verticalScrollBar() const {
+    return d->vbar;
+}
+
+
+/*!
+    Scrolls the content so that the point (\a x, \a y) is visible with at
+    least 50-pixel margins (if possible, otherwise centered).
+*/
+void Q3ScrollView::ensureVisible(int x, int y)
+{
+    ensureVisible(x, y, 50, 50);
+}
+
+/*!
+    \overload
+
+    Scrolls the content so that the point (\a x, \a y) is visible with at
+    least the \a xmargin and \a ymargin margins (if possible,
+    otherwise centered).
+*/
+void Q3ScrollView::ensureVisible(int x, int y, int xmargin, int ymargin)
+{
+    int pw=visibleWidth();
+    int ph=visibleHeight();
+
+    int cx=-d->contentsX();
+    int cy=-d->contentsY();
+    int cw=d->contentsWidth();
+    int ch=contentsHeight();
+
+    if (pw < xmargin*2)
+        xmargin=pw/2;
+    if (ph < ymargin*2)
+        ymargin=ph/2;
+
+    if (cw <= pw) {
+        xmargin=0;
+        cx=0;
+    }
+    if (ch <= ph) {
+        ymargin=0;
+        cy=0;
+    }
+
+    if (x < -cx+xmargin)
+        cx = -x+xmargin;
+    else if (x >= -cx+pw-xmargin)
+        cx = -x+pw-xmargin;
+
+    if (y < -cy+ymargin)
+        cy = -y+ymargin;
+    else if (y >= -cy+ph-ymargin)
+        cy = -y+ph-ymargin;
+
+    if (cx > 0)
+        cx=0;
+    else if (cx < pw-cw && cw>pw)
+        cx=pw-cw;
+
+    if (cy > 0)
+        cy=0;
+    else if (cy < ph-ch && ch>ph)
+        cy=ph-ch;
+
+    setContentsPos(-cx, -cy);
+}
+
+/*!
+    Scrolls the content so that the point (\a x, \a y) is in the top-left
+    corner.
+*/
+void Q3ScrollView::setContentsPos(int x, int y)
+{
+#if 0
+    // bounds checking...
+    if (QApplication::reverseLayout())
+        if (x > d->contentsWidth() - visibleWidth()) x = d->contentsWidth() - visibleWidth();
+    else
+#endif
+        if (x < 0) x = 0;
+    if (y < 0) y = 0;
+    // Choke signal handling while we update BOTH sliders.
+    d->signal_choke=true;
+    moveContents(-x, -y);
+    d->vbar->setValue(y);
+    d->hbar->setValue(x);
+    d->signal_choke=false;
+}
+
+/*!
+    Scrolls the content by \a dx to the left and \a dy upwards.
+*/
+void Q3ScrollView::scrollBy(int dx, int dy)
+{
+    setContentsPos(QMAX(d->contentsX()+dx, 0), QMAX(d->contentsY()+dy, 0));
+}
+
+/*!
+    Scrolls the content so that the point (\a x, \a y) is in the center
+    of visible area.
+*/
+void Q3ScrollView::center(int x, int y)
+{
+    ensureVisible(x, y, 32000, 32000);
+}
+
+/*!
+    \overload
+
+    Scrolls the content so that the point (\a x, \a y) is visible with
+    the \a xmargin and \a ymargin margins (as fractions of visible
+    the area).
+
+    For example:
+    \list
+    \i Margin 0.0 allows (x, y) to be on the edge of the visible area.
+    \i Margin 0.5 ensures that (x, y) is in middle 50% of the visible area.
+    \i Margin 1.0 ensures that (x, y) is in the center of the visible area.
+    \endlist
+*/
+void Q3ScrollView::center(int x, int y, float xmargin, float ymargin)
+{
+    int pw=visibleWidth();
+    int ph=visibleHeight();
+    ensureVisible(x, y, int(xmargin/2.0*pw+0.5), int(ymargin/2.0*ph+0.5));
+}
+
+
+/*!
+    \fn void Q3ScrollView::contentsMoving(int x, int y)
+
+    This signal is emitted just before the contents are moved to
+    position (\a x, \a y).
+
+    \sa contentsX(), contentsY()
+*/
+
+/*!
+    Moves the contents by (\a x, \a y).
+*/
+void Q3ScrollView::moveContents(int x, int y)
+{
+    if (-x+visibleWidth() > d->contentsWidth())
+#if 0
+        if(QApplication::reverseLayout())
+            x=QMAX(0,-d->contentsWidth()+visibleWidth());
+        else
+#endif
+            x=QMIN(0,-d->contentsWidth()+visibleWidth());
+    if (-y+visibleHeight() > contentsHeight())
+        y=QMIN(0,-contentsHeight()+visibleHeight());
+
+    int dx = x - d->vx;
+    int dy = y - d->vy;
+
+    if (!dx && !dy)
+        return; // Nothing to do
+
+    emit contentsMoving(-x, -y);
+
+    d->vx = x;
+    d->vy = y;
+
+    if (d->clipped_viewport || d->static_bg) {
+        // Cheap move (usually)
+        d->moveAllBy(dx,dy);
+    } else if (/*dx && dy ||*/
+         (QABS(dy) * 5 > visibleHeight() * 4) ||
+         (QABS(dx) * 5 > visibleWidth() * 4)
+       )
+    {
+        // Big move
+        if (viewport()->updatesEnabled())
+            viewport()->update();
+        d->moveAllBy(dx,dy);
+    } else if (!d->fake_scroll || d->contentsWidth() > visibleWidth()) {
+        // Small move
+        clipper()->scroll(dx,dy);
+    }
+    d->hideOrShowAll(this, true);
+}
+
+/*!
+    \property Q3ScrollView::contentsX
+    \brief the X coordinate of the contents that are at the left edge of
+    the viewport.
+*/
+int Q3ScrollView::contentsX() const
+{
+    return d->contentsX();
+}
+
+/*!
+    \property Q3ScrollView::contentsY
+    \brief the Y coordinate of the contents that are at the top edge of
+    the viewport.
+*/
+int Q3ScrollView::contentsY() const
+{
+    return d->contentsY();
+}
+
+/*!
+    \property Q3ScrollView::contentsWidth
+    \brief the width of the contents area
+*/
+int Q3ScrollView::contentsWidth() const
+{
+    return d->contentsWidth();
+}
+
+/*!
+    \property Q3ScrollView::contentsHeight
+    \brief the height of the contents area
+*/
+int Q3ScrollView::contentsHeight() const
+{
+    return d->vheight;
+}
+
+/*!
+    Sets the size of the contents area to \a w pixels wide and \a h
+    pixels high and updates the viewport accordingly.
+*/
+void Q3ScrollView::resizeContents(int w, int h)
+{
+    int ow = d->vwidth;
+    int oh = d->vheight;
+    d->vwidth = w;
+    d->vheight = h;
+
+    d->scrollbar_timer.start(0, true);
+
+    if (d->children.isEmpty() && d->policy == Default)
+        setResizePolicy(Manual);
+
+    if (ow > w) {
+        // Swap
+        int t=w;
+        w=ow;
+        ow=t;
+    }
+    // Refresh area ow..w
+    if (ow < visibleWidth() && w >= 0) {
+        if (ow < 0)
+            ow = 0;
+        if (w > visibleWidth())
+            w = visibleWidth();
+        clipper()->update(d->contentsX()+ow, 0, w-ow, visibleHeight());
+    }
+
+    if (oh > h) {
+        // Swap
+        int t=h;
+        h=oh;
+        oh=t;
+    }
+    // Refresh area oh..h
+    if (oh < visibleHeight() && h >= 0) {
+        if (oh < 0)
+            oh = 0;
+        if (h > visibleHeight())
+            h = visibleHeight();
+        clipper()->update(0, d->contentsY()+oh, visibleWidth(), h-oh);
+    }
+}
+
+/*!
+    Calls update() on a rectangle defined by \a x, \a y, \a w, \a h,
+    translated appropriately. If the rectangle is not visible, nothing
+    is repainted.
+
+    \sa repaintContents()
+*/
+void Q3ScrollView::updateContents(int x, int y, int w, int h)
+{
+    if (!isVisible() || !updatesEnabled())
+        return;
+
+    QWidget* vp = viewport();
+
+    // Translate
+    x -= d->contentsX();
+    y -= d->contentsY();
+
+    if (x < 0) {
+        w += x;
+        x = 0;
+    }
+    if (y < 0) {
+        h += y;
+        y = 0;
+    }
+
+    if (w < 0 || h < 0)
+        return;
+    if (x > visibleWidth() || y > visibleHeight())
+        return;
+
+    if (w > visibleWidth())
+        w = visibleWidth();
+    if (h > visibleHeight())
+        h = visibleHeight();
+
+    if (d->clipped_viewport) {
+        // Translate clipper() to viewport()
+        x -= d->clipped_viewport->x();
+        y -= d->clipped_viewport->y();
+    }
+
+    vp->update(x, y, w, h);
+}
+
+/*!
+    \overload
+
+    Updates the contents in rectangle \a r
+*/
+void Q3ScrollView::updateContents(const QRect& r)
+{
+    updateContents(r.x(), r.y(), r.width(), r.height());
+}
+
+/*!
+    \overload
+*/
+void Q3ScrollView::updateContents()
+{
+    updateContents(d->contentsX(), d->contentsY(), visibleWidth(), visibleHeight());
+}
+
+/*!
+    \overload
+
+    Repaints the contents of rectangle \a r. If \a erase is true the
+    background is cleared using the background color.
+*/
+void Q3ScrollView::repaintContents(const QRect& r, bool erase)
+{
+    repaintContents(r.x(), r.y(), r.width(), r.height(), erase);
+}
+
+
+/*!
+    \overload
+
+    Repaints the contents. If \a erase is true the background is
+    cleared using the background color.
+*/
+void Q3ScrollView::repaintContents(bool erase)
+{
+    repaintContents(d->contentsX(), d->contentsY(), visibleWidth(), visibleHeight(), erase);
+}
+
+
+/*!
+    Calls repaint() on a rectangle defined by \a x, \a y, \a w, \a h,
+    translated appropriately. If the rectangle is not visible, nothing
+    is repainted. If \a erase is true the background is cleared using
+    the background color.
+
+    \sa updateContents()
+*/
+void Q3ScrollView::repaintContents(int x, int y, int w, int h, bool /*erase*/)
+{
+    if (!isVisible() || !updatesEnabled())
+        return;
+
+    QWidget* vp = viewport();
+
+    // Translate logical to clipper()
+    x -= d->contentsX();
+    y -= d->contentsY();
+
+    if (x < 0) {
+        w += x;
+        x = 0;
+    }
+    if (y < 0) {
+        h += y;
+        y = 0;
+    }
+
+    if (w < 0 || h < 0)
+        return;
+    if (w > visibleWidth())
+        w = visibleWidth();
+    if (h > visibleHeight())
+        h = visibleHeight();
+
+    if (d->clipped_viewport) {
+        // Translate clipper() to viewport()
+        x -= d->clipped_viewport->x();
+        y -= d->clipped_viewport->y();
+    }
+
+    vp->update(x, y, w, h);
+}
+
+
+/*!
+    For backward-compatibility only. It is easier to use
+    drawContents(QPainter*,int,int,int,int).
+
+    The default implementation translates the painter appropriately
+    and calls drawContents(QPainter*,int,int,int,int). See
+    drawContents() for an explanation of the parameters \a p, \a
+    offsetx, \a offsety, \a clipx, \a clipy, \a clipw and \a cliph.
+*/
+void Q3ScrollView::drawContentsOffset(QPainter* p, int offsetx, int offsety, int clipx, int clipy, int clipw, int cliph)
+{
+    p->translate(-offsetx,-offsety);
+    drawContents(p, clipx, clipy, clipw, cliph);
+}
+
+/*!
+    \fn void Q3ScrollView::drawContents(QPainter* p, int clipx, int clipy, int clipw, int cliph)
+
+    Reimplement this function if you are viewing a drawing area rather
+    than a widget.
+
+    The function should draw the rectangle (\a clipx, \a clipy, \a
+    clipw, \a cliph) of the contents using painter \a p. The clip
+    rectangle is in the scrollview's coordinates.
+
+    For example:
+    \snippet doc/src/snippets/code/src_qt3support_widgets_q3scrollview.cpp 4
+
+    The clip rectangle and translation of the painter \a p is already
+    set appropriately.
+*/
+void Q3ScrollView::drawContents(QPainter*, int, int, int, int)
+{
+}
+
+
+/*!
+    \reimp
+*/
+void Q3ScrollView::frameChanged()
+{
+    // slight ugle-hack - the listview header needs readjusting when
+    // changing the frame
+    if (Q3ListView *lv = qobject_cast<Q3ListView *>(this))
+        lv->triggerUpdate();
+    Q3Frame::frameChanged();
+    updateScrollBars();
+}
+
+
+/*!
+    Returns the viewport widget of the scrollview. This is the widget
+    containing the contents widget or which is the drawing area.
+*/
+QWidget* Q3ScrollView::viewport() const
+{
+    if (d->clipped_viewport)
+        return  d->clipped_viewport;
+    return d->viewport;
+}
+
+/*!
+    Returns the clipper widget. Contents in the scrollview are
+    ultimately clipped to be inside the clipper widget.
+
+    You should not need to use this function.
+
+    \sa visibleWidth(), visibleHeight()
+*/
+QWidget* Q3ScrollView::clipper() const
+{
+    return d->viewport;
+}
+
+/*!
+    \property Q3ScrollView::visibleWidth
+    \brief the horizontal amount of the content that is visible
+*/
+int Q3ScrollView::visibleWidth() const
+{
+    return clipper()->width();
+}
+
+/*!
+    \property Q3ScrollView::visibleHeight
+    \brief the vertical amount of the content that is visible
+*/
+int Q3ScrollView::visibleHeight() const
+{
+    return clipper()->height();
+}
+
+
+void Q3ScrollView::changeFrameRect(const QRect& r)
+{
+    QRect oldr = frameRect();
+    if (oldr != r) {
+        QRect cr = contentsRect();
+        QRegion fr(frameRect());
+        fr = fr.subtracted(contentsRect());
+        setFrameRect(r);
+        if (isVisible()) {
+            cr = cr.intersected(contentsRect());
+            fr = fr.united(frameRect());
+            fr = fr.subtracted(cr);
+            if (!fr.isEmpty())
+                update(fr);
+        }
+    }
+}
+
+
+/*!
+    Sets the margins around the scrolling area to \a left, \a top, \a
+    right and \a bottom. This is useful for applications such as
+    spreadsheets with "locked" rows and columns. The marginal space is
+    \e inside the frameRect() and is left blank; reimplement
+    drawFrame() or put widgets in the unused area.
+
+    By default all margins are zero.
+
+    \sa frameChanged()
+*/
+void Q3ScrollView::setMargins(int left, int top, int right, int bottom)
+{
+    if (left == d->l_marg &&
+         top == d->t_marg &&
+         right == d->r_marg &&
+         bottom == d->b_marg)
+        return;
+
+    d->l_marg = left;
+    d->t_marg = top;
+    d->r_marg = right;
+    d->b_marg = bottom;
+    updateScrollBars();
+}
+
+
+/*!
+    Returns the left margin.
+
+    \sa setMargins()
+*/
+int Q3ScrollView::leftMargin() const
+{
+    return d->l_marg;
+}
+
+
+/*!
+    Returns the top margin.
+
+    \sa setMargins()
+*/
+int Q3ScrollView::topMargin() const
+{
+    return d->t_marg;
+}
+
+
+/*!
+    Returns the right margin.
+
+    \sa setMargins()
+*/
+int Q3ScrollView::rightMargin() const
+{
+    return d->r_marg;
+}
+
+
+/*!
+    Returns the bottom margin.
+
+    \sa setMargins()
+*/
+int Q3ScrollView::bottomMargin() const
+{
+    return d->b_marg;
+}
+
+/*!
+    \reimp
+*/
+bool Q3ScrollView::focusNextPrevChild(bool next)
+{
+    //  Makes sure that the new focus widget is on-screen, if
+    //  necessary by scrolling the scroll view.
+    bool retval = Q3Frame::focusNextPrevChild(next);
+    if (retval) {
+        QWidget *w = window()->focusWidget();
+        if (isAncestorOf(w)) {
+            QSVChildRec *r = d->ancestorRec(w);
+           if (r && (r->child == w || w->isVisibleTo(r->child))) {
+                QPoint cp = r->child->mapToGlobal(QPoint(0, 0));
+                QPoint cr = w->mapToGlobal(QPoint(0, 0)) - cp;
+                ensureVisible(r->x + cr.x() + w->width()/2, r->y + cr.y() + w->height()/2,
+                              w->width()/2, w->height()/2);
+            }
+        }
+    }
+    return retval;
+}
+
+
+
+/*!
+    When a large numbers of child widgets are in a scrollview,
+    especially if they are close together, the scrolling performance
+    can suffer greatly. If \a y is true the scrollview will use an
+    extra widget to group child widgets.
+
+    Note that you may only call enableClipper() prior to adding
+    widgets.
+*/
+void Q3ScrollView::enableClipper(bool y)
+{
+    if (!d->clipped_viewport == !y)
+        return;
+    if (d->children.count())
+        qFatal("May only call Q3ScrollView::enableClipper() before adding widgets");
+    if (y) {
+        d->clipped_viewport = new QClipperWidget(clipper(), "qt_clipped_viewport", QFlag(d->flags));
+        d->clipped_viewport->setGeometry(-coord_limit/2,-coord_limit/2,
+                                         coord_limit,coord_limit);
+        d->clipped_viewport->setBackgroundMode(d->viewport->backgroundMode());
+        d->viewport->setBackgroundMode(NoBackground); // no exposures for this
+        d->viewport->removeEventFilter(this);
+        d->clipped_viewport->installEventFilter(this);
+        d->clipped_viewport->show();
+    } else {
+        delete d->clipped_viewport;
+        d->clipped_viewport = 0;
+    }
+}
+
+/*!
+    Sets the scrollview to have a static background if \a y is true,
+    or a scrolling background if \a y is false. By default, the
+    background is scrolling.
+
+    Be aware that this mode is quite slow, as a full repaint of the
+    visible area has to be triggered on every contents move.
+
+    \sa hasStaticBackground()
+*/
+void  Q3ScrollView::setStaticBackground(bool y)
+{
+    d->static_bg = y;
+}
+
+/*!
+    Returns true if Q3ScrollView uses a static background; otherwise
+    returns false.
+
+    \sa setStaticBackground()
+*/
+bool Q3ScrollView::hasStaticBackground() const
+{
+    return d->static_bg;
+}
+
+/*!
+    \overload
+
+    Returns the point \a p translated to a point on the viewport()
+    widget.
+*/
+QPoint Q3ScrollView::contentsToViewport(const QPoint& p) const
+{
+    if (d->clipped_viewport) {
+        return QPoint(p.x() - d->contentsX() - d->clipped_viewport->x(),
+                       p.y() - d->contentsY() - d->clipped_viewport->y());
+    } else {
+        return QPoint(p.x() - d->contentsX(),
+                       p.y() - d->contentsY());
+    }
+}
+
+/*!
+    \overload
+
+    Returns the point on the viewport \a vp translated to a point in
+    the contents.
+*/
+QPoint Q3ScrollView::viewportToContents(const QPoint& vp) const
+{
+    if (d->clipped_viewport) {
+        return QPoint(vp.x() + d->contentsX() + d->clipped_viewport->x(),
+                       vp.y() + d->contentsY() + d->clipped_viewport->y());
+    } else {
+        return QPoint(vp.x() + d->contentsX(),
+                       vp.y() + d->contentsY());
+    }
+}
+
+
+/*!
+    Translates a point (\a x, \a y) in the contents to a point (\a vx,
+    \a vy) on the viewport() widget.
+*/
+void Q3ScrollView::contentsToViewport(int x, int y, int& vx, int& vy) const
+{
+    const QPoint v = contentsToViewport(QPoint(x,y));
+    vx = v.x();
+    vy = v.y();
+}
+
+/*!
+    Translates a point (\a vx, \a vy) on the viewport() widget to a
+    point (\a x, \a y) in the contents.
+*/
+void Q3ScrollView::viewportToContents(int vx, int vy, int& x, int& y) const
+{
+    const QPoint c = viewportToContents(QPoint(vx,vy));
+    x = c.x();
+    y = c.y();
+}
+
+/*!
+    \reimp
+*/
+QSize Q3ScrollView::sizeHint() const
+{
+    if (d->use_cached_size_hint && d->cachedSizeHint.isValid())
+        return d->cachedSizeHint;
+
+    constPolish();
+    int f = 2 * frameWidth();
+    int h = fontMetrics().height();
+    QSize sz(f, f);
+    if (d->policy > Manual) {
+        QSVChildRec *r = d->children.first();
+        if (r) {
+            QSize cs = r->child->sizeHint();
+            if (cs.isValid())
+                sz += cs.boundedTo(r->child->maximumSize());
+            else
+                sz += r->child->size();
+        }
+    } else {
+        sz += QSize(d->contentsWidth(), contentsHeight());
+    }
+    if (d->vMode == AlwaysOn)
+        sz.setWidth(sz.width() + d->vbar->sizeHint().width());
+    if (d->hMode == AlwaysOn)
+        sz.setHeight(sz.height() + d->hbar->sizeHint().height());
+    return sz.expandedTo(QSize(12 * h, 8 * h))
+             .boundedTo(QSize(36 * h, 24 * h));
+}
+
+
+/*!
+    \reimp
+*/
+QSize Q3ScrollView::minimumSizeHint() const
+{
+    int h = fontMetrics().height();
+    if (h < 10)
+        h = 10;
+    int f = 2 * frameWidth();
+    return QSize((6 * h) + f, (4 * h) + f);
+}
+
+
+/*!
+    \reimp
+
+    (Implemented to get rid of a compiler warning.)
+*/
+void Q3ScrollView::drawContents(QPainter *)
+{
+}
+
+#ifndef QT_NO_DRAGANDDROP
+
+/*!
+  \internal
+*/
+void Q3ScrollView::startDragAutoScroll()
+{
+    if (!d->autoscroll_timer.isActive()) {
+        d->autoscroll_time = initialScrollTime;
+        d->autoscroll_accel = initialScrollAccel;
+        d->autoscroll_timer.start(d->autoscroll_time);
+    }
+}
+
+
+/*!
+  \internal
+*/
+void Q3ScrollView::stopDragAutoScroll()
+{
+    d->autoscroll_timer.stop();
+}
+
+
+/*!
+  \internal
+*/
+void Q3ScrollView::doDragAutoScroll()
+{
+    QPoint p = d->viewport->mapFromGlobal(QCursor::pos());
+
+    if (d->autoscroll_accel-- <= 0 && d->autoscroll_time) {
+        d->autoscroll_accel = initialScrollAccel;
+        d->autoscroll_time--;
+        d->autoscroll_timer.start(d->autoscroll_time);
+    }
+    int l = QMAX(1, (initialScrollTime- d->autoscroll_time));
+
+    int dx = 0, dy = 0;
+    if (p.y() < autoscroll_margin) {
+        dy = -l;
+    } else if (p.y() > visibleHeight() - autoscroll_margin) {
+        dy = +l;
+    }
+    if (p.x() < autoscroll_margin) {
+        dx = -l;
+    } else if (p.x() > visibleWidth() - autoscroll_margin) {
+        dx = +l;
+    }
+    if (dx || dy) {
+        scrollBy(dx,dy);
+    } else {
+        stopDragAutoScroll();
+    }
+}
+
+
+/*!
+    \property Q3ScrollView::dragAutoScroll
+    \brief whether autoscrolling in drag move events is enabled
+
+    If this property is set to true (the default), the Q3ScrollView
+    automatically scrolls the contents in drag move events if the user
+    moves the cursor close to a border of the view. Of course this
+    works only if the viewport accepts drops. Specifying false
+    disables this autoscroll feature.
+*/
+
+void Q3ScrollView::setDragAutoScroll(bool b)
+{
+    d->drag_autoscroll = b;
+}
+
+bool Q3ScrollView::dragAutoScroll() const
+{
+    return d->drag_autoscroll;
+}
+
+#endif // QT_NO_DRAGANDDROP
+
+/*!\internal
+ */
+void Q3ScrollView::setCachedSizeHint(const QSize &sh) const
+{
+    if (isVisible() && !d->cachedSizeHint.isValid())
+        d->cachedSizeHint = sh;
+}
+
+/*!\internal
+ */
+void Q3ScrollView::disableSizeHintCaching()
+{
+    d->use_cached_size_hint = false;
+}
+
+/*!\internal
+ */
+QSize Q3ScrollView::cachedSizeHint() const
+{
+    return d->use_cached_size_hint ? d->cachedSizeHint : QSize();
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_SCROLLVIEW