Mac: disable transient scrollbar animations for non-QScrollBars
[profile/ivi/qtbase.git] / src / widgets / widgets / qabstractscrollarea.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.  For licensing terms and
14 ** conditions see http://qt.digia.com/licensing.  For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights.  These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file.  Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qabstractscrollarea.h"
43
44 #ifndef QT_NO_SCROLLAREA
45
46 #include "qscrollbar.h"
47 #include "qapplication.h"
48 #include "qstyle.h"
49 #include "qstyleoption.h"
50 #include "qevent.h"
51 #include "qdebug.h"
52 #include "qboxlayout.h"
53 #include "qpainter.h"
54 #include "qmargins.h"
55 #include "qheaderview.h"
56
57 #include <QDebug>
58
59 #include "qabstractscrollarea_p.h"
60 #include "qscrollbar_p.h"
61 #include <qwidget.h>
62
63 #include <private/qapplication_p.h>
64
65 #ifdef Q_WS_MAC
66 #include <private/qt_mac_p.h>
67 #include <private/qt_cocoa_helpers_mac_p.h>
68 #endif
69 #ifdef Q_OS_WIN
70 #  include <qlibrary.h>
71 #  include <qt_windows.h>
72 #endif
73
74 QT_BEGIN_NAMESPACE
75
76 /*!
77     \class QAbstractScrollArea
78     \brief The QAbstractScrollArea widget provides a scrolling area with
79     on-demand scroll bars.
80
81     \ingroup abstractwidgets
82     \inmodule QtWidgets
83
84     QAbstractScrollArea is a low-level abstraction of a scrolling
85     area. The area provides a central widget called the viewport, in
86     which the contents of the area is to be scrolled (i.e, the
87     visible parts of the contents are rendered in the viewport).
88
89     Next to the viewport is a vertical scroll bar, and below is a
90     horizontal scroll bar. When all of the area contents fits in the
91     viewport, each scroll bar can be either visible or hidden
92     depending on the scroll bar's Qt::ScrollBarPolicy. When a scroll
93     bar is hidden, the viewport expands in order to cover all
94     available space. When a scroll bar becomes visible again, the
95     viewport shrinks in order to make room for the scroll bar.
96
97     It is possible to reserve a margin area around the viewport, see
98     setViewportMargins(). The feature is mostly used to place a
99     QHeaderView widget above or beside the scrolling area. Subclasses
100     of QAbstractScrollArea should implement margins.
101
102     When inheriting QAbstractScrollArea, you need to do the
103     following:
104
105     \list
106         \li Control the scroll bars by setting their
107            range, value, page step, and tracking their
108            movements.
109         \li Draw the contents of the area in the viewport according
110            to the values of the scroll bars.
111         \li Handle events received by the viewport in
112            viewportEvent() - notably resize events.
113         \li Use \c{viewport->update()} to update the contents of the
114           viewport instead of \l{QWidget::update()}{update()}
115           as all painting operations take place on the viewport.
116     \endlist
117
118     With a scroll bar policy of Qt::ScrollBarAsNeeded (the default),
119     QAbstractScrollArea shows scroll bars when they provide a non-zero
120     scrolling range, and hides them otherwise.
121
122     The scroll bars and viewport should be updated whenever the viewport
123     receives a resize event or the size of the contents changes.
124     The viewport also needs to be updated when the scroll bars
125     values change. The initial values of the scroll bars are often
126     set when the area receives new contents.
127
128     We give a simple example, in which we have implemented a scroll area
129     that can scroll any QWidget. We make the widget a child of the
130     viewport; this way, we do not have to calculate which part of
131     the widget to draw but can simply move the widget with
132     QWidget::move(). When the area contents or the viewport size
133     changes, we do the following:
134
135     \snippet myscrollarea.cpp 1
136
137     When the scroll bars change value, we need to update the widget
138     position, i.e., find the part of the widget that is to be drawn in
139     the viewport:
140
141     \snippet myscrollarea.cpp 0
142
143     In order to track scroll bar movements, reimplement the virtual
144     function scrollContentsBy(). In order to fine-tune scrolling
145     behavior, connect to a scroll bar's
146     QAbstractSlider::actionTriggered() signal and adjust the \l
147     QAbstractSlider::sliderPosition as you wish.
148
149     For convenience, QAbstractScrollArea makes all viewport events
150     available in the virtual viewportEvent() handler. QWidget's
151     specialized handlers are remapped to viewport events in the cases
152     where this makes sense. The remapped specialized handlers are:
153     paintEvent(), mousePressEvent(), mouseReleaseEvent(),
154     mouseDoubleClickEvent(), mouseMoveEvent(), wheelEvent(),
155     dragEnterEvent(), dragMoveEvent(), dragLeaveEvent(), dropEvent(),
156     contextMenuEvent(),  and resizeEvent().
157
158     QScrollArea, which inherits QAbstractScrollArea, provides smooth
159     scrolling for any QWidget (i.e., the widget is scrolled pixel by
160     pixel). You only need to subclass QAbstractScrollArea if you need
161     more specialized behavior. This is, for instance, true if the
162     entire contents of the area is not suitable for being drawn on a
163     QWidget or if you do not want smooth scrolling.
164
165     \sa QScrollArea
166 */
167
168 QAbstractScrollAreaPrivate::QAbstractScrollAreaPrivate()
169     :hbar(0), vbar(0), vbarpolicy(Qt::ScrollBarAsNeeded), hbarpolicy(Qt::ScrollBarAsNeeded),
170      viewport(0), cornerWidget(0), left(0), top(0), right(0), bottom(0),
171      xoffset(0), yoffset(0), viewportFilter(0)
172 #ifdef Q_WS_WIN
173      , singleFingerPanEnabled(false)
174 #endif
175 {
176 }
177
178 QAbstractScrollAreaScrollBarContainer::QAbstractScrollAreaScrollBarContainer(Qt::Orientation orientation, QWidget *parent)
179     :QWidget(parent), scrollBar(new QScrollBar(orientation, this)),
180      layout(new QBoxLayout(orientation == Qt::Horizontal ? QBoxLayout::LeftToRight : QBoxLayout::TopToBottom)),
181      orientation(orientation)
182 {
183     setLayout(layout);
184     layout->setMargin(0);
185     layout->setSpacing(0);
186     layout->addWidget(scrollBar);
187     layout->setSizeConstraint(QLayout::SetMaximumSize);
188 }
189
190 /*! \internal
191     Adds a widget to the scroll bar container.
192 */
193 void QAbstractScrollAreaScrollBarContainer::addWidget(QWidget *widget, LogicalPosition position)
194 {
195     QSizePolicy policy = widget->sizePolicy();
196     if (orientation == Qt::Vertical)
197         policy.setHorizontalPolicy(QSizePolicy::Ignored);
198     else
199         policy.setVerticalPolicy(QSizePolicy::Ignored);
200     widget->setSizePolicy(policy);
201     widget->setParent(this);
202
203     const int insertIndex = (position & LogicalLeft) ? 0 : scrollBarLayoutIndex() + 1;
204     layout->insertWidget(insertIndex, widget);
205 }
206
207 /*! \internal
208     Retuns a list of scroll bar widgets for the given position. The scroll bar
209     itself is not returned.
210 */
211 QWidgetList QAbstractScrollAreaScrollBarContainer::widgets(LogicalPosition position)
212 {
213     QWidgetList list;
214     const int scrollBarIndex = scrollBarLayoutIndex();
215     if (position == LogicalLeft) {
216         for (int i = 0; i < scrollBarIndex; ++i)
217             list.append(layout->itemAt(i)->widget());
218     } else if (position == LogicalRight) {
219         const int layoutItemCount = layout->count();
220         for (int i = scrollBarIndex + 1; i < layoutItemCount; ++i)
221             list.append(layout->itemAt(i)->widget());
222     }
223     return list;
224 }
225
226 /*! \internal
227     Returns the layout index for the scroll bar. This needs to be
228     recalculated by a linear search for each use, since items in
229     the layout can be removed at any time (i.e. when a widget is
230     deleted or re-parented).
231 */
232 int QAbstractScrollAreaScrollBarContainer::scrollBarLayoutIndex() const
233 {
234     const int layoutItemCount = layout->count();
235     for (int i = 0; i < layoutItemCount; ++i) {
236         if (qobject_cast<QScrollBar *>(layout->itemAt(i)->widget()))
237             return i;
238     }
239     return -1;
240 }
241
242 /*! \internal
243 */
244 void QAbstractScrollAreaPrivate::replaceScrollBar(QScrollBar *scrollBar,
245                                                   Qt::Orientation orientation)
246 {
247     Q_Q(QAbstractScrollArea);
248
249     QAbstractScrollAreaScrollBarContainer *container = scrollBarContainers[orientation];
250     bool horizontal = (orientation == Qt::Horizontal);
251     QScrollBar *oldBar = horizontal ? hbar : vbar;
252     if (horizontal)
253         hbar = scrollBar;
254     else
255         vbar = scrollBar;
256     scrollBar->setParent(container);
257     container->scrollBar = scrollBar;
258     container->layout->removeWidget(oldBar);
259     container->layout->insertWidget(0, scrollBar);
260     scrollBar->setVisible(oldBar->isVisibleTo(container));
261     scrollBar->setInvertedAppearance(oldBar->invertedAppearance());
262     scrollBar->setInvertedControls(oldBar->invertedControls());
263     scrollBar->setRange(oldBar->minimum(), oldBar->maximum());
264     scrollBar->setOrientation(oldBar->orientation());
265     scrollBar->setPageStep(oldBar->pageStep());
266     scrollBar->setSingleStep(oldBar->singleStep());
267     scrollBar->setSliderDown(oldBar->isSliderDown());
268     scrollBar->setSliderPosition(oldBar->sliderPosition());
269     scrollBar->setTracking(oldBar->hasTracking());
270     scrollBar->setValue(oldBar->value());
271     scrollBar->installEventFilter(q);
272     oldBar->removeEventFilter(q);
273     delete oldBar;
274
275     QObject::connect(scrollBar, SIGNAL(valueChanged(int)),
276                      q, horizontal ? SLOT(_q_hslide(int)) : SLOT(_q_vslide(int)));
277     QObject::connect(scrollBar, SIGNAL(rangeChanged(int,int)),
278                      q, SLOT(_q_showOrHideScrollBars()), Qt::QueuedConnection);
279 }
280
281 void QAbstractScrollAreaPrivate::init()
282 {
283     Q_Q(QAbstractScrollArea);
284     viewport = new QWidget(q);
285     viewport->setObjectName(QLatin1String("qt_scrollarea_viewport"));
286     viewport->setBackgroundRole(QPalette::Base);
287     viewport->setAutoFillBackground(true);
288     scrollBarContainers[Qt::Horizontal] = new QAbstractScrollAreaScrollBarContainer(Qt::Horizontal, q);
289     scrollBarContainers[Qt::Horizontal]->setObjectName(QLatin1String("qt_scrollarea_hcontainer"));
290     hbar = scrollBarContainers[Qt::Horizontal]->scrollBar;
291     hbar->setRange(0,0);
292     scrollBarContainers[Qt::Horizontal]->setVisible(false);
293     hbar->installEventFilter(q);
294     QObject::connect(hbar, SIGNAL(valueChanged(int)), q, SLOT(_q_hslide(int)));
295     QObject::connect(hbar, SIGNAL(rangeChanged(int,int)), q, SLOT(_q_showOrHideScrollBars()), Qt::QueuedConnection);
296     scrollBarContainers[Qt::Vertical] = new QAbstractScrollAreaScrollBarContainer(Qt::Vertical, q);
297     scrollBarContainers[Qt::Vertical]->setObjectName(QLatin1String("qt_scrollarea_vcontainer"));
298     vbar = scrollBarContainers[Qt::Vertical]->scrollBar;
299     vbar->setRange(0,0);
300     scrollBarContainers[Qt::Vertical]->setVisible(false);
301     vbar->installEventFilter(q);
302     QObject::connect(vbar, SIGNAL(valueChanged(int)), q, SLOT(_q_vslide(int)));
303     QObject::connect(vbar, SIGNAL(rangeChanged(int,int)), q, SLOT(_q_showOrHideScrollBars()), Qt::QueuedConnection);
304     viewportFilter.reset(new QAbstractScrollAreaFilter(this));
305     viewport->installEventFilter(viewportFilter.data());
306     viewport->setFocusProxy(q);
307     q->setFocusPolicy(Qt::WheelFocus);
308     q->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
309     q->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
310     layoutChildren();
311 #ifndef Q_WS_MAC
312 #  ifndef QT_NO_GESTURES
313     viewport->grabGesture(Qt::PanGesture);
314 #  endif
315 #endif
316 }
317
318 #ifdef Q_WS_WIN
319 void QAbstractScrollAreaPrivate::setSingleFingerPanEnabled(bool on)
320 {
321     singleFingerPanEnabled = on;
322     QWidgetPrivate *dd = static_cast<QWidgetPrivate *>(QObjectPrivate::get(viewport));
323     if (dd)
324         dd->winSetupGestures();
325 }
326 #endif // Q_WS_WIN
327
328 void QAbstractScrollAreaPrivate::layoutChildren()
329 {
330     Q_Q(QAbstractScrollArea);
331     bool needh = (hbarpolicy == Qt::ScrollBarAlwaysOn
332                   || (hbarpolicy == Qt::ScrollBarAsNeeded && hbar->minimum() < hbar->maximum() && !hbar->sizeHint().isEmpty()));
333
334     bool needv = (vbarpolicy == Qt::ScrollBarAlwaysOn
335                   || (vbarpolicy == Qt::ScrollBarAsNeeded && vbar->minimum() < vbar->maximum() && !vbar->sizeHint().isEmpty()));
336
337     QStyleOption opt(0);
338     opt.init(q);
339     const int scrollOverlap = q->style()->pixelMetric(QStyle::PM_ScrollView_ScrollBarOverlap,
340                                                       &opt, q);
341
342 #ifdef Q_WS_MAC
343     QWidget * const window = q->window();
344
345     // Use small scroll bars for tool windows, to match the native size grip.
346     bool hbarIsSmall = hbar->testAttribute(Qt::WA_MacSmallSize);
347     bool vbarIsSmall = vbar->testAttribute(Qt::WA_MacSmallSize);
348     const Qt::WindowType windowType = window->windowType();
349     if (windowType == Qt::Tool) {
350         if (!hbarIsSmall) {
351             hbar->setAttribute(Qt::WA_MacMiniSize, false);
352             hbar->setAttribute(Qt::WA_MacNormalSize, false);
353             hbar->setAttribute(Qt::WA_MacSmallSize, true);
354         }
355         if (!vbarIsSmall) {
356             vbar->setAttribute(Qt::WA_MacMiniSize, false);
357             vbar->setAttribute(Qt::WA_MacNormalSize, false);
358             vbar->setAttribute(Qt::WA_MacSmallSize, true);
359         }
360     } else {
361         if (hbarIsSmall) {
362             hbar->setAttribute(Qt::WA_MacMiniSize, false);
363             hbar->setAttribute(Qt::WA_MacNormalSize, false);
364             hbar->setAttribute(Qt::WA_MacSmallSize, false);
365         }
366         if (vbarIsSmall) {
367             vbar->setAttribute(Qt::WA_MacMiniSize, false);
368             vbar->setAttribute(Qt::WA_MacNormalSize, false);
369             vbar->setAttribute(Qt::WA_MacSmallSize, false);
370         }
371      }
372 #endif
373
374     const int hsbExt = hbar->sizeHint().height();
375     const int vsbExt = vbar->sizeHint().width();
376     const QPoint extPoint(vsbExt, hsbExt);
377     const QSize extSize(vsbExt, hsbExt);
378
379     const QRect widgetRect = q->rect();
380
381     const bool hasCornerWidget = (cornerWidget != 0);
382
383 // If the scroll bars are at the very right and bottom of the window we
384 // move their positions to be aligned with the size grip.
385 #ifdef Q_WS_MAC
386     // Check if a native sizegrip is present.
387     bool hasMacReverseSizeGrip = false;
388     bool hasMacSizeGrip = false;
389     bool nativeGripPresent = false;
390     if (q->testAttribute(Qt::WA_WState_Created))
391         nativeGripPresent = qt_mac_checkForNativeSizeGrip(q);
392
393     if (nativeGripPresent) {
394         // Look for a native size grip at the visual window bottom right and at the
395         // absolute window bottom right. In reverse mode, the native size grip does not
396         // swich side, so we need to check if it is on the "wrong side".
397         const QPoint scrollAreaBottomRight = q->mapTo(window, widgetRect.bottomRight() - QPoint(frameWidth, frameWidth));
398         const QPoint windowBottomRight = window->rect().bottomRight();
399         const QPoint visualWindowBottomRight = QStyle::visualPos(opt.direction, opt.rect, windowBottomRight);
400         const QPoint offset = windowBottomRight - scrollAreaBottomRight;
401         const QPoint visualOffset = visualWindowBottomRight - scrollAreaBottomRight;
402         hasMacSizeGrip = (visualOffset.manhattanLength() < vsbExt);
403         hasMacReverseSizeGrip = (hasMacSizeGrip == false && (offset.manhattanLength() < hsbExt));
404     }
405 #endif
406
407     QPoint cornerOffset((needv && scrollOverlap == 0) ? vsbExt : 0, (needh && scrollOverlap == 0) ? hsbExt : 0);
408     QRect controlsRect;
409     QRect viewportRect;
410
411     // In FrameOnlyAroundContents mode the frame is drawn between the controls and
412     // the viewport, else the frame rect is equal to the widget rect.
413     if ((frameStyle != QFrame::NoFrame) &&
414         q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents, &opt, q)) {
415         controlsRect = widgetRect;
416         const int extra = scrollOverlap + q->style()->pixelMetric(QStyle::PM_ScrollView_ScrollBarSpacing, &opt, q);
417         const QPoint cornerExtra(needv ? extra : 0, needh ? extra : 0);
418         QRect frameRect = widgetRect;
419         frameRect.adjust(0, 0, -cornerOffset.x() - cornerExtra.x(), -cornerOffset.y() - cornerExtra.y());
420         q->setFrameRect(QStyle::visualRect(opt.direction, opt.rect, frameRect));
421         // The frame rect needs to be in logical coords, however we need to flip
422         // the contentsRect back before passing it on to the viewportRect
423         // since the viewportRect has its logical coords calculated later.
424         viewportRect = QStyle::visualRect(opt.direction, opt.rect, q->contentsRect());
425     } else {
426         q->setFrameRect(QStyle::visualRect(opt.direction, opt.rect, widgetRect));
427         controlsRect = q->contentsRect();
428         viewportRect = QRect(controlsRect.topLeft(), controlsRect.bottomRight() - cornerOffset);
429     }
430
431     cornerOffset = QPoint(needv ? vsbExt : 0, needh ? hsbExt : 0);
432
433     // If we have a corner widget and are only showing one scroll bar, we need to move it
434     // to make room for the corner widget.
435     if (hasCornerWidget && (needv || needh) && scrollOverlap == 0)
436         cornerOffset =  extPoint;
437
438 #ifdef Q_WS_MAC
439     // Also move the scroll bars if they are covered by the native Mac size grip.
440     if (hasMacSizeGrip)
441         cornerOffset =  extPoint;
442 #endif
443
444     // The corner point is where the scroll bar rects, the corner widget rect and the
445     // viewport rect meets.
446     const QPoint cornerPoint(controlsRect.bottomRight() + QPoint(1, 1) - cornerOffset);
447
448     // Some styles paints the corner if both scorllbars are showing and there is
449     // no corner widget. Also, on the Mac we paint if there is a native
450     // (transparent) sizegrip in the area where a corner widget would be.
451     if ((needv && needh && hasCornerWidget == false && scrollOverlap == 0)
452         || ((needv || needh) 
453 #ifdef Q_WS_MAC
454         && hasMacSizeGrip
455 #endif
456         )
457     ) {
458         cornerPaintingRect = QStyle::visualRect(opt.direction, opt.rect, QRect(cornerPoint, extSize));
459     } else {
460         cornerPaintingRect = QRect();
461     }
462
463 #ifdef Q_WS_MAC
464     if (hasMacReverseSizeGrip)
465         reverseCornerPaintingRect = QRect(controlsRect.bottomRight() + QPoint(1, 1) - extPoint, extSize);
466     else
467         reverseCornerPaintingRect = QRect();
468 #endif
469
470     // move the scrollbars away from top/left headers
471     int vHeaderRight = 0;
472     int hHeaderBottom = 0;
473     if (scrollOverlap > 0 && (needv || needh)) {
474         const QList<QHeaderView *> headers = q->findChildren<QHeaderView*>();
475         if (headers.count() <= 2) {
476             Q_FOREACH (const QHeaderView *header, headers) {
477                 const QRect geo = header->geometry();
478                 if (header->orientation() == Qt::Vertical && header->isVisible() && QStyle::visualRect(opt.direction, opt.rect, geo).left() <= opt.rect.width() / 2)
479                     vHeaderRight = QStyle::visualRect(opt.direction, opt.rect, geo).right();
480                 else if (header->orientation() == Qt::Horizontal && header->isVisible() && geo.top() <= q->frameWidth())
481                     hHeaderBottom = geo.bottom();
482              }
483          }
484     }
485
486     if (needh) {
487         QRect horizontalScrollBarRect(QPoint(controlsRect.left() + vHeaderRight, cornerPoint.y()), QPoint(cornerPoint.x() - 1, controlsRect.bottom()));
488 #ifdef Q_WS_MAC
489         if (hasMacReverseSizeGrip)
490             horizontalScrollBarRect.adjust(vsbExt, 0, 0, 0);
491 #endif
492 #ifdef Q_OS_MAC
493         if (!hasCornerWidget && QSysInfo::macVersion() >= QSysInfo::MV_10_8 && q->style()->styleHint(QStyle::SH_ScrollBar_Transient, 0, hbar))
494             horizontalScrollBarRect.adjust(0, 0, cornerOffset.x(), 0);
495 #endif
496         scrollBarContainers[Qt::Horizontal]->setGeometry(QStyle::visualRect(opt.direction, opt.rect, horizontalScrollBarRect));
497         scrollBarContainers[Qt::Horizontal]->raise();
498     }
499
500     if (needv) {
501         QRect verticalScrollBarRect  (QPoint(cornerPoint.x(), controlsRect.top() + hHeaderBottom),  QPoint(controlsRect.right(), cornerPoint.y() - 1));
502 #ifdef Q_OS_MAC
503         if (!hasCornerWidget && QSysInfo::macVersion() >= QSysInfo::MV_10_8 && q->style()->styleHint(QStyle::SH_ScrollBar_Transient, 0, vbar))
504             verticalScrollBarRect.adjust(0, 0, 0, cornerOffset.y());
505 #endif
506         scrollBarContainers[Qt::Vertical]->setGeometry(QStyle::visualRect(opt.direction, opt.rect, verticalScrollBarRect));
507         scrollBarContainers[Qt::Vertical]->raise();
508     }
509
510     if (cornerWidget) {
511         const QRect cornerWidgetRect(cornerPoint, controlsRect.bottomRight());
512         cornerWidget->setGeometry(QStyle::visualRect(opt.direction, opt.rect, cornerWidgetRect));
513     }
514
515     scrollBarContainers[Qt::Horizontal]->setVisible(needh);
516     scrollBarContainers[Qt::Vertical]->setVisible(needv);
517
518     if (q->isRightToLeft())
519         viewportRect.adjust(right, top, -left, -bottom);
520     else
521         viewportRect.adjust(left, top, -right, -bottom);
522
523     viewport->setGeometry(QStyle::visualRect(opt.direction, opt.rect, viewportRect)); // resize the viewport last
524 }
525
526 /*!
527     \internal
528
529     Creates a new QAbstractScrollAreaPrivate, \a dd with the given \a parent.
530 */
531 QAbstractScrollArea::QAbstractScrollArea(QAbstractScrollAreaPrivate &dd, QWidget *parent)
532     :QFrame(dd, parent)
533 {
534     Q_D(QAbstractScrollArea);
535     QT_TRY {
536         d->init();
537     } QT_CATCH(...) {
538         d->viewportFilter.reset();
539         QT_RETHROW;
540     }
541 }
542
543 /*!
544     Constructs a viewport.
545
546     The \a parent argument is sent to the QWidget constructor.
547 */
548 QAbstractScrollArea::QAbstractScrollArea(QWidget *parent)
549     :QFrame(*new QAbstractScrollAreaPrivate, parent)
550 {
551     Q_D(QAbstractScrollArea);
552     QT_TRY {
553         d->init();
554     } QT_CATCH(...) {
555         d->viewportFilter.reset();
556         QT_RETHROW;
557     }
558 }
559
560
561 /*!
562   Destroys the viewport.
563  */
564 QAbstractScrollArea::~QAbstractScrollArea()
565 {
566     Q_D(QAbstractScrollArea);
567     // reset it here, otherwise we'll have a dangling pointer in ~QWidget
568     d->viewportFilter.reset();
569 }
570
571
572 /*!
573   \since 4.2
574   Sets the viewport to be the given \a widget.
575   The QAbstractScrollArea will take ownership of the given \a widget.
576
577   If \a widget is 0, QAbstractScrollArea will assign a new QWidget instance
578   for the viewport.
579
580   \sa viewport()
581 */
582 void QAbstractScrollArea::setViewport(QWidget *widget)
583 {
584     Q_D(QAbstractScrollArea);
585     if (widget != d->viewport) {
586         QWidget *oldViewport = d->viewport;
587         if (!widget)
588             widget = new QWidget;
589         d->viewport = widget;
590         d->viewport->setParent(this);
591         d->viewport->setFocusProxy(this);
592         d->viewport->installEventFilter(d->viewportFilter.data());
593 #ifndef Q_WS_MAC
594 #ifndef QT_NO_GESTURES
595         d->viewport->grabGesture(Qt::PanGesture);
596 #endif
597 #endif
598         d->layoutChildren();
599         if (isVisible())
600             d->viewport->show();
601         setupViewport(widget);
602         delete oldViewport;
603     }
604 }
605
606 /*!
607     Returns the viewport widget.
608
609     Use the QScrollArea::widget() function to retrieve the contents of
610     the viewport widget.
611
612     \sa QScrollArea::widget()
613 */
614 QWidget *QAbstractScrollArea::viewport() const
615 {
616     Q_D(const QAbstractScrollArea);
617     return d->viewport;
618 }
619
620
621 /*!
622 Returns the size of the viewport as if the scroll bars had no valid
623 scrolling range.
624 */
625 // ### still thinking about the name
626 QSize QAbstractScrollArea::maximumViewportSize() const
627 {
628     Q_D(const QAbstractScrollArea);
629     int hsbExt = d->hbar->sizeHint().height();
630     int vsbExt = d->vbar->sizeHint().width();
631
632     int f = 2 * d->frameWidth;
633     QSize max = size() - QSize(f + d->left + d->right, f + d->top + d->bottom);
634     if (d->vbarpolicy == Qt::ScrollBarAlwaysOn)
635         max.rwidth() -= vsbExt;
636     if (d->hbarpolicy == Qt::ScrollBarAlwaysOn)
637         max.rheight() -= hsbExt;
638     return max;
639 }
640
641 /*!
642     \property QAbstractScrollArea::verticalScrollBarPolicy
643     \brief the policy for the vertical scroll bar
644
645     The default policy is Qt::ScrollBarAsNeeded.
646
647     \sa horizontalScrollBarPolicy
648 */
649
650 Qt::ScrollBarPolicy QAbstractScrollArea::verticalScrollBarPolicy() const
651 {
652     Q_D(const QAbstractScrollArea);
653     return d->vbarpolicy;
654 }
655
656 void QAbstractScrollArea::setVerticalScrollBarPolicy(Qt::ScrollBarPolicy policy)
657 {
658     Q_D(QAbstractScrollArea);
659     const Qt::ScrollBarPolicy oldPolicy = d->vbarpolicy;
660     d->vbarpolicy = policy;
661     if (isVisible())
662         d->layoutChildren();
663     if (oldPolicy != d->vbarpolicy)
664         d->scrollBarPolicyChanged(Qt::Vertical, d->vbarpolicy);
665     d->setScrollBarTransient(d->vbar, policy == Qt::ScrollBarAsNeeded);
666 }
667
668
669 /*!
670   Returns the vertical scroll bar.
671
672   \sa verticalScrollBarPolicy, horizontalScrollBar()
673  */
674 QScrollBar *QAbstractScrollArea::verticalScrollBar() const
675 {
676     Q_D(const QAbstractScrollArea);
677     return d->vbar;
678 }
679
680 /*!
681    \since 4.2
682    Replaces the existing vertical scroll bar with \a scrollBar, and sets all
683    the former scroll bar's slider properties on the new scroll bar. The former
684    scroll bar is then deleted.
685
686    QAbstractScrollArea already provides vertical and horizontal scroll bars by
687    default. You can call this function to replace the default vertical
688    scroll bar with your own custom scroll bar.
689
690    \sa verticalScrollBar(), setHorizontalScrollBar()
691 */
692 void QAbstractScrollArea::setVerticalScrollBar(QScrollBar *scrollBar)
693 {
694     Q_D(QAbstractScrollArea);
695     if (!scrollBar) {
696         qWarning("QAbstractScrollArea::setVerticalScrollBar: Cannot set a null scroll bar");
697         return;
698     }
699
700     d->replaceScrollBar(scrollBar, Qt::Vertical);
701 }
702
703 /*!
704     \property QAbstractScrollArea::horizontalScrollBarPolicy
705     \brief the policy for the horizontal scroll bar
706
707     The default policy is Qt::ScrollBarAsNeeded.
708
709     \sa verticalScrollBarPolicy
710 */
711
712 Qt::ScrollBarPolicy QAbstractScrollArea::horizontalScrollBarPolicy() const
713 {
714     Q_D(const QAbstractScrollArea);
715     return d->hbarpolicy;
716 }
717
718 void QAbstractScrollArea::setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy policy)
719 {
720     Q_D(QAbstractScrollArea);
721     const Qt::ScrollBarPolicy oldPolicy = d->hbarpolicy;
722     d->hbarpolicy = policy;
723     if (isVisible())
724         d->layoutChildren();
725     if (oldPolicy != d->hbarpolicy)
726         d->scrollBarPolicyChanged(Qt::Horizontal, d->hbarpolicy);
727     d->setScrollBarTransient(d->hbar, policy == Qt::ScrollBarAsNeeded);
728 }
729
730 /*!
731   Returns the horizontal scroll bar.
732
733   \sa horizontalScrollBarPolicy, verticalScrollBar()
734  */
735 QScrollBar *QAbstractScrollArea::horizontalScrollBar() const
736 {
737     Q_D(const QAbstractScrollArea);
738     return d->hbar;
739 }
740
741 /*!
742     \since 4.2
743
744     Replaces the existing horizontal scroll bar with \a scrollBar, and sets all
745     the former scroll bar's slider properties on the new scroll bar. The former
746     scroll bar is then deleted.
747
748     QAbstractScrollArea already provides horizontal and vertical scroll bars by
749     default. You can call this function to replace the default horizontal
750     scroll bar with your own custom scroll bar.
751
752     \sa horizontalScrollBar(), setVerticalScrollBar()
753 */
754 void QAbstractScrollArea::setHorizontalScrollBar(QScrollBar *scrollBar)
755 {
756     Q_D(QAbstractScrollArea);
757     if (!scrollBar) {
758         qWarning("QAbstractScrollArea::setHorizontalScrollBar: Cannot set a null scroll bar");
759         return;
760     }
761
762     d->replaceScrollBar(scrollBar, Qt::Horizontal);
763 }
764
765 /*!
766     \since 4.2
767
768     Returns the widget in the corner between the two scroll bars.
769
770     By default, no corner widget is present.
771 */
772 QWidget *QAbstractScrollArea::cornerWidget() const
773 {
774     Q_D(const QAbstractScrollArea);
775     return d->cornerWidget;
776 }
777
778 /*!
779     \since 4.2
780
781     Sets the widget in the corner between the two scroll bars to be
782     \a widget.
783
784     You will probably also want to set at least one of the scroll bar
785     modes to \c AlwaysOn.
786
787     Passing 0 shows no widget in the corner.
788
789     Any previous corner widget is hidden.
790
791     You may call setCornerWidget() with the same widget at different
792     times.
793
794     All widgets set here will be deleted by the scroll area when it is
795     destroyed unless you separately reparent the widget after setting
796     some other corner widget (or 0).
797
798     Any \e newly set widget should have no current parent.
799
800     By default, no corner widget is present.
801
802     \sa horizontalScrollBarPolicy, horizontalScrollBarPolicy
803 */
804 void QAbstractScrollArea::setCornerWidget(QWidget *widget)
805 {
806     Q_D(QAbstractScrollArea);
807     QWidget* oldWidget = d->cornerWidget;
808     if (oldWidget != widget) {
809         if (oldWidget)
810             oldWidget->hide();
811         d->cornerWidget = widget;
812
813         if (widget && widget->parentWidget() != this)
814             widget->setParent(this);
815
816         d->layoutChildren();
817         if (widget)
818             widget->show();
819     } else {
820         d->cornerWidget = widget;
821         d->layoutChildren();
822     }
823 }
824
825 /*!
826     \since 4.2
827     Adds \a widget as a scroll bar widget in the location specified
828     by \a alignment.
829
830     Scroll bar widgets are shown next to the horizontal or vertical
831     scroll bar, and can be placed on either side of it. If you want
832     the scroll bar widgets to be always visible, set the
833     scrollBarPolicy for the corresponding scroll bar to \c AlwaysOn.
834
835     \a alignment must be one of Qt::Alignleft and Qt::AlignRight,
836     which maps to the horizontal scroll bar, or Qt::AlignTop and
837     Qt::AlignBottom, which maps to the vertical scroll bar.
838
839     A scroll bar widget can be removed by either re-parenting the
840     widget or deleting it. It's also possible to hide a widget with
841     QWidget::hide()
842
843     The scroll bar widget will be resized to fit the scroll bar
844     geometry for the current style. The following describes the case
845     for scroll bar widgets on the horizontal scroll bar:
846
847     The height of the widget will be set to match the height of the
848     scroll bar. To control the width of the widget, use
849     QWidget::setMinimumWidth and QWidget::setMaximumWidth, or
850     implement QWidget::sizeHint() and set a horizontal size policy.
851     If you want a square widget, call
852     QStyle::pixelMetric(QStyle::PM_ScrollBarExtent) and set the
853     width to this value.
854
855     \sa scrollBarWidgets()
856 */
857 void QAbstractScrollArea::addScrollBarWidget(QWidget *widget, Qt::Alignment alignment)
858 {
859     Q_D(QAbstractScrollArea);
860
861     if (widget == 0)
862         return;
863
864     const Qt::Orientation scrollBarOrientation
865         = ((alignment & Qt::AlignLeft) || (alignment & Qt::AlignRight)) ? Qt::Horizontal : Qt::Vertical;
866     const QAbstractScrollAreaScrollBarContainer::LogicalPosition position
867         = ((alignment & Qt::AlignRight) || (alignment & Qt::AlignBottom))
868           ? QAbstractScrollAreaScrollBarContainer::LogicalRight : QAbstractScrollAreaScrollBarContainer::LogicalLeft;
869     d->scrollBarContainers[scrollBarOrientation]->addWidget(widget, position);
870     d->layoutChildren();
871     if (isHidden() == false)
872         widget->show();
873 }
874
875 /*!
876     \since 4.2
877     Returns a list of the currently set scroll bar widgets. \a alignment
878     can be any combination of the four location flags.
879
880     \sa addScrollBarWidget()
881 */
882 QWidgetList QAbstractScrollArea::scrollBarWidgets(Qt::Alignment alignment)
883 {
884     Q_D(QAbstractScrollArea);
885
886     QWidgetList list;
887
888     if (alignment & Qt::AlignLeft)
889         list += d->scrollBarContainers[Qt::Horizontal]->widgets(QAbstractScrollAreaScrollBarContainer::LogicalLeft);
890     if (alignment & Qt::AlignRight)
891         list += d->scrollBarContainers[Qt::Horizontal]->widgets(QAbstractScrollAreaScrollBarContainer::LogicalRight);
892     if (alignment & Qt::AlignTop)
893         list += d->scrollBarContainers[Qt::Vertical]->widgets(QAbstractScrollAreaScrollBarContainer::LogicalLeft);
894     if (alignment & Qt::AlignBottom)
895         list += d->scrollBarContainers[Qt::Vertical]->widgets(QAbstractScrollAreaScrollBarContainer::LogicalRight);
896
897     return list;
898 }
899
900 /*!
901     Sets the margins around the scrolling area to \a left, \a top, \a
902     right and \a bottom. This is useful for applications such as
903     spreadsheets with "locked" rows and columns. The marginal space is
904     is left blank; put widgets in the unused area.
905
906     Note that this function is frequently called by QTreeView and
907     QTableView, so margins must be implemented by QAbstractScrollArea
908     subclasses. Also, if the subclasses are to be used in item views,
909     they should not call this function.
910
911     By default all margins are zero.
912
913 */
914 void QAbstractScrollArea::setViewportMargins(int left, int top, int right, int bottom)
915 {
916     Q_D(QAbstractScrollArea);
917     d->left = left;
918     d->top = top;
919     d->right = right;
920     d->bottom = bottom;
921     d->layoutChildren();
922 }
923
924 /*!
925     \since 4.6
926     Sets \a margins around the scrolling area. This is useful for
927     applications such as spreadsheets with "locked" rows and columns.
928     The marginal space is is left blank; put widgets in the unused
929     area.
930
931     By default all margins are zero.
932
933 */
934 void QAbstractScrollArea::setViewportMargins(const QMargins &margins)
935 {
936     setViewportMargins(margins.left(), margins.top(),
937                        margins.right(), margins.bottom());
938 }
939
940 /*! \internal */
941 bool QAbstractScrollArea::eventFilter(QObject *o, QEvent *e)
942 {
943     Q_D(QAbstractScrollArea);
944     if ((o == d->hbar || o == d->vbar) && (e->type() == QEvent::HoverEnter || e->type() == QEvent::HoverLeave)) {
945         Qt::ScrollBarPolicy policy = o == d->hbar ? d->vbarpolicy : d->hbarpolicy;
946         if (policy == Qt::ScrollBarAsNeeded) {
947             QScrollBar *sibling = o == d->hbar ? d->vbar : d->hbar;
948             d->setScrollBarTransient(sibling, e->type() == QEvent::HoverLeave);
949         }
950     }
951     return QFrame::eventFilter(o, e);
952 }
953
954 /*!
955     \fn bool QAbstractScrollArea::event(QEvent *event)
956
957     \reimp
958
959     This is the main event handler for the QAbstractScrollArea widget (\e not
960     the scrolling area viewport()). The specified \a event is a general event
961     object that may need to be cast to the appropriate class depending on its
962     type.
963
964     \sa QEvent::type()
965 */
966 bool QAbstractScrollArea::event(QEvent *e)
967 {
968     Q_D(QAbstractScrollArea);
969     switch (e->type()) {
970     case QEvent::AcceptDropsChange:
971         // There was a chance that with accessibility client we get an
972         // event before the viewport was created.
973         // Also, in some cases we might get here from QWidget::event() virtual function which is (indirectly) called
974         // from the viewport constructor at the time when the d->viewport is not yet initialized even without any
975         // accessibility client. See qabstractscrollarea autotest for a test case.
976         if (d->viewport)
977             d->viewport->setAcceptDrops(acceptDrops());
978         break;
979     case QEvent::MouseTrackingChange:
980         d->viewport->setMouseTracking(hasMouseTracking());
981         break;
982     case QEvent::Resize:
983             d->layoutChildren();
984             break;
985     case QEvent::Paint: {
986         QStyleOption option;
987         option.initFrom(this);
988         if (d->cornerPaintingRect.isValid()) {
989             option.rect = d->cornerPaintingRect;
990             QPainter p(this);
991             style()->drawPrimitive(QStyle::PE_PanelScrollAreaCorner, &option, &p, this);
992         }
993 #ifdef Q_WS_MAC
994         if (d->reverseCornerPaintingRect.isValid()) {
995             option.rect = d->reverseCornerPaintingRect;
996             QPainter p(this);
997             style()->drawPrimitive(QStyle::PE_PanelScrollAreaCorner, &option, &p, this);
998         }
999 #endif
1000         }
1001         QFrame::paintEvent((QPaintEvent*)e);
1002         break;
1003 #ifndef QT_NO_CONTEXTMENU
1004     case QEvent::ContextMenu:
1005         if (static_cast<QContextMenuEvent *>(e)->reason() == QContextMenuEvent::Keyboard)
1006            return QFrame::event(e);
1007         e->ignore();
1008         break;
1009 #endif // QT_NO_CONTEXTMENU
1010     case QEvent::MouseButtonPress:
1011     case QEvent::MouseButtonRelease:
1012     case QEvent::MouseButtonDblClick:
1013     case QEvent::MouseMove:
1014     case QEvent::Wheel:
1015 #ifndef QT_NO_DRAGANDDROP
1016     case QEvent::Drop:
1017     case QEvent::DragEnter:
1018     case QEvent::DragMove:
1019     case QEvent::DragLeave:
1020 #endif
1021         // ignore touch events in case they have been propagated from the viewport
1022     case QEvent::TouchBegin:
1023     case QEvent::TouchUpdate:
1024     case QEvent::TouchEnd:
1025         return false;
1026 #ifndef QT_NO_GESTURES
1027     case QEvent::Gesture:
1028     {
1029         QGestureEvent *ge = static_cast<QGestureEvent *>(e);
1030         QPanGesture *g = static_cast<QPanGesture *>(ge->gesture(Qt::PanGesture));
1031         if (g) {
1032             QScrollBar *hBar = horizontalScrollBar();
1033             QScrollBar *vBar = verticalScrollBar();
1034             QPointF delta = g->delta();
1035             if (!delta.isNull()) {
1036                 if (QApplication::isRightToLeft())
1037                     delta.rx() *= -1;
1038                 int newX = hBar->value() - delta.x();
1039                 int newY = vBar->value() - delta.y();
1040                 hBar->setValue(newX);
1041                 vBar->setValue(newY);
1042             }
1043             return true;
1044         }
1045         return false;
1046     }
1047 #endif // QT_NO_GESTURES
1048     case QEvent::ScrollPrepare:
1049     {
1050         QScrollPrepareEvent *se = static_cast<QScrollPrepareEvent *>(e);
1051         if (d->canStartScrollingAt(se->startPos().toPoint())) {
1052             QScrollBar *hBar = horizontalScrollBar();
1053             QScrollBar *vBar = verticalScrollBar();
1054
1055             se->setViewportSize(QSizeF(viewport()->size()));
1056             se->setContentPosRange(QRectF(0, 0, hBar->maximum(), vBar->maximum()));
1057             se->setContentPos(QPointF(hBar->value(), vBar->value()));
1058             se->accept();
1059             return true;
1060         }
1061         return false;
1062     }
1063     case QEvent::Scroll:
1064     {
1065         QScrollEvent *se = static_cast<QScrollEvent *>(e);
1066
1067         QScrollBar *hBar = horizontalScrollBar();
1068         QScrollBar *vBar = verticalScrollBar();
1069         hBar->setValue(se->contentPos().x());
1070         vBar->setValue(se->contentPos().y());
1071
1072 #ifdef Q_WS_WIN
1073         typedef BOOL (*PtrBeginPanningFeedback)(HWND);
1074         typedef BOOL (*PtrUpdatePanningFeedback)(HWND, LONG, LONG, BOOL);
1075         typedef BOOL (*PtrEndPanningFeedback)(HWND, BOOL);
1076
1077         static PtrBeginPanningFeedback ptrBeginPanningFeedback = 0;
1078         static PtrUpdatePanningFeedback ptrUpdatePanningFeedback = 0;
1079         static PtrEndPanningFeedback ptrEndPanningFeedback = 0;
1080
1081         if (!ptrBeginPanningFeedback)
1082             ptrBeginPanningFeedback = (PtrBeginPanningFeedback) QLibrary::resolve(QLatin1String("UxTheme"), "BeginPanningFeedback");
1083         if (!ptrUpdatePanningFeedback)
1084             ptrUpdatePanningFeedback = (PtrUpdatePanningFeedback) QLibrary::resolve(QLatin1String("UxTheme"), "UpdatePanningFeedback");
1085         if (!ptrEndPanningFeedback)
1086             ptrEndPanningFeedback = (PtrEndPanningFeedback) QLibrary::resolve(QLatin1String("UxTheme"), "EndPanningFeedback");
1087
1088         if (ptrBeginPanningFeedback && ptrUpdatePanningFeedback && ptrEndPanningFeedback) {
1089             WId wid = window()->winId();
1090
1091             if (!se->overshootDistance().isNull() && d->overshoot.isNull())
1092                 ptrBeginPanningFeedback(wid);
1093             if (!se->overshootDistance().isNull())
1094                 ptrUpdatePanningFeedback(wid, -se->overshootDistance().x(), -se->overshootDistance().y(), false);
1095             if (se->overshootDistance().isNull() && !d->overshoot.isNull())
1096                 ptrEndPanningFeedback(wid, true);
1097         } else
1098 #endif
1099         {
1100             QPoint delta = d->overshoot - se->overshootDistance().toPoint();
1101             if (!delta.isNull())
1102                 viewport()->move(viewport()->pos() + delta);
1103         }
1104         d->overshoot = se->overshootDistance().toPoint();
1105
1106         return true;
1107     }
1108     case QEvent::StyleChange:
1109     case QEvent::LayoutDirectionChange:
1110     case QEvent::ApplicationLayoutDirectionChange:
1111     case QEvent::LayoutRequest:
1112         d->layoutChildren();
1113         // fall through
1114     default:
1115         return QFrame::event(e);
1116     }
1117     return true;
1118 }
1119
1120 /*!
1121   \fn bool QAbstractScrollArea::viewportEvent(QEvent *event)
1122
1123   The main event handler for the scrolling area (the viewport() widget).
1124   It handles the \a event specified, and can be called by subclasses to
1125   provide reasonable default behavior.
1126
1127   Returns true to indicate to the event system that the event has been
1128   handled, and needs no further processing; otherwise returns false to
1129   indicate that the event should be propagated further.
1130
1131   You can reimplement this function in a subclass, but we recommend
1132   using one of the specialized event handlers instead.
1133
1134   Specialized handlers for viewport events are: paintEvent(),
1135   mousePressEvent(), mouseReleaseEvent(), mouseDoubleClickEvent(),
1136   mouseMoveEvent(), wheelEvent(), dragEnterEvent(), dragMoveEvent(),
1137   dragLeaveEvent(), dropEvent(), contextMenuEvent(), and
1138   resizeEvent().
1139 */
1140 bool QAbstractScrollArea::viewportEvent(QEvent *e)
1141 {
1142     switch (e->type()) {
1143     case QEvent::Resize:
1144     case QEvent::Paint:
1145     case QEvent::MouseButtonPress:
1146     case QEvent::MouseButtonRelease:
1147     case QEvent::MouseButtonDblClick:
1148     case QEvent::TouchBegin:
1149     case QEvent::TouchUpdate:
1150     case QEvent::TouchEnd:
1151     case QEvent::MouseMove:
1152     case QEvent::ContextMenu:
1153 #ifndef QT_NO_WHEELEVENT
1154     case QEvent::Wheel:
1155 #endif
1156 #ifndef QT_NO_DRAGANDDROP
1157     case QEvent::Drop:
1158     case QEvent::DragEnter:
1159     case QEvent::DragMove:
1160     case QEvent::DragLeave:
1161 #endif
1162         return QFrame::event(e);
1163     case QEvent::LayoutRequest:
1164 #ifndef QT_NO_GESTURES
1165     case QEvent::Gesture:
1166     case QEvent::GestureOverride:
1167         return event(e);
1168 #endif
1169     case QEvent::ScrollPrepare:
1170     case QEvent::Scroll:
1171         return event(e);
1172     default:
1173         break;
1174     }
1175     return false; // let the viewport widget handle the event
1176 }
1177
1178 /*!
1179     \fn void QAbstractScrollArea::resizeEvent(QResizeEvent *event)
1180
1181     This event handler can be reimplemented in a subclass to receive
1182     resize events (passed in \a event), for the viewport() widget.
1183
1184     When resizeEvent() is called, the viewport already has its new
1185     geometry: Its new size is accessible through the
1186     QResizeEvent::size() function, and the old size through
1187     QResizeEvent::oldSize().
1188
1189     \sa QWidget::resizeEvent()
1190  */
1191 void QAbstractScrollArea::resizeEvent(QResizeEvent *)
1192 {
1193 }
1194
1195 /*!
1196     \fn void QAbstractScrollArea::paintEvent(QPaintEvent *event)
1197
1198     This event handler can be reimplemented in a subclass to receive
1199     paint events (passed in \a event), for the viewport() widget.
1200
1201     \note If you open a painter, make sure to open it on the viewport().
1202
1203     \sa QWidget::paintEvent()
1204 */
1205 void QAbstractScrollArea::paintEvent(QPaintEvent*)
1206 {
1207 }
1208
1209 /*!
1210     This event handler can be reimplemented in a subclass to receive
1211     mouse press events for the viewport() widget. The event is passed
1212     in \a e.
1213
1214     \sa QWidget::mousePressEvent()
1215 */
1216 void QAbstractScrollArea::mousePressEvent(QMouseEvent *e)
1217 {
1218     e->ignore();
1219 }
1220
1221 /*!
1222     This event handler can be reimplemented in a subclass to receive
1223     mouse release events for the viewport() widget. The event is
1224     passed in \a e.
1225
1226     \sa QWidget::mouseReleaseEvent()
1227 */
1228 void QAbstractScrollArea::mouseReleaseEvent(QMouseEvent *e)
1229 {
1230     e->ignore();
1231 }
1232
1233 /*!
1234     This event handler can be reimplemented in a subclass to receive
1235     mouse double click events for the viewport() widget. The event is
1236     passed in \a e.
1237
1238     \sa QWidget::mouseDoubleClickEvent()
1239 */
1240 void QAbstractScrollArea::mouseDoubleClickEvent(QMouseEvent *e)
1241 {
1242     e->ignore();
1243 }
1244
1245 /*!
1246     This event handler can be reimplemented in a subclass to receive
1247     mouse move events for the viewport() widget. The event is passed
1248     in \a e.
1249
1250     \sa QWidget::mouseMoveEvent()
1251 */
1252 void QAbstractScrollArea::mouseMoveEvent(QMouseEvent *e)
1253 {
1254     e->ignore();
1255 }
1256
1257 /*!
1258     This event handler can be reimplemented in a subclass to receive
1259     wheel events for the viewport() widget. The event is passed in \a
1260     e.
1261
1262     \sa QWidget::wheelEvent()
1263 */
1264 #ifndef QT_NO_WHEELEVENT
1265 void QAbstractScrollArea::wheelEvent(QWheelEvent *e)
1266 {
1267     Q_D(QAbstractScrollArea);
1268     if (static_cast<QWheelEvent*>(e)->orientation() == Qt::Horizontal)
1269         QApplication::sendEvent(d->hbar, e);
1270     else
1271         QApplication::sendEvent(d->vbar, e);
1272 }
1273 #endif
1274
1275 #ifndef QT_NO_CONTEXTMENU
1276 /*!
1277     This event handler can be reimplemented in a subclass to receive
1278     context menu events for the viewport() widget. The event is passed
1279     in \a e.
1280
1281     \sa QWidget::contextMenuEvent()
1282 */
1283 void QAbstractScrollArea::contextMenuEvent(QContextMenuEvent *e)
1284 {
1285     e->ignore();
1286 }
1287 #endif // QT_NO_CONTEXTMENU
1288
1289 /*!
1290     This function is called with key event \a e when key presses
1291     occur. It handles PageUp, PageDown, Up, Down, Left, and Right, and
1292     ignores all other key presses.
1293 */
1294 void QAbstractScrollArea::keyPressEvent(QKeyEvent * e)
1295 {
1296     Q_D(QAbstractScrollArea);
1297     if (false){
1298 #ifndef QT_NO_SHORTCUT
1299     } else if (e == QKeySequence::MoveToPreviousPage) {
1300         d->vbar->triggerAction(QScrollBar::SliderPageStepSub);
1301     } else if (e == QKeySequence::MoveToNextPage) {
1302         d->vbar->triggerAction(QScrollBar::SliderPageStepAdd);
1303 #endif
1304     } else {
1305 #ifdef QT_KEYPAD_NAVIGATION
1306         if (QApplication::keypadNavigationEnabled() && !hasEditFocus()) {
1307             e->ignore();
1308             return;
1309         }
1310 #endif
1311         switch (e->key()) {
1312         case Qt::Key_Up:
1313             d->vbar->triggerAction(QScrollBar::SliderSingleStepSub);
1314             break;
1315         case Qt::Key_Down:
1316             d->vbar->triggerAction(QScrollBar::SliderSingleStepAdd);
1317             break;
1318         case Qt::Key_Left:
1319 #ifdef QT_KEYPAD_NAVIGATION
1320         if (QApplication::keypadNavigationEnabled() && hasEditFocus()
1321             && (!d->hbar->isVisible() || d->hbar->value() == d->hbar->minimum())) {
1322             //if we aren't using the hbar or we are already at the leftmost point ignore
1323             e->ignore();
1324             return;
1325         }
1326 #endif
1327             d->hbar->triggerAction(
1328                 layoutDirection() == Qt::LeftToRight
1329                 ? QScrollBar::SliderSingleStepSub : QScrollBar::SliderSingleStepAdd);
1330             break;
1331         case Qt::Key_Right:
1332 #ifdef QT_KEYPAD_NAVIGATION
1333         if (QApplication::keypadNavigationEnabled() && hasEditFocus()
1334             && (!d->hbar->isVisible() || d->hbar->value() == d->hbar->maximum())) {
1335             //if we aren't using the hbar or we are already at the rightmost point ignore
1336             e->ignore();
1337             return;
1338         }
1339 #endif
1340             d->hbar->triggerAction(
1341                 layoutDirection() == Qt::LeftToRight
1342                 ? QScrollBar::SliderSingleStepAdd : QScrollBar::SliderSingleStepSub);
1343             break;
1344         default:
1345             e->ignore();
1346             return;
1347         }
1348     }
1349     e->accept();
1350 }
1351
1352
1353 #ifndef QT_NO_DRAGANDDROP
1354 /*!
1355     \fn void QAbstractScrollArea::dragEnterEvent(QDragEnterEvent *event)
1356
1357     This event handler can be reimplemented in a subclass to receive
1358     drag enter events (passed in \a event), for the viewport() widget.
1359
1360     \sa QWidget::dragEnterEvent()
1361 */
1362 void QAbstractScrollArea::dragEnterEvent(QDragEnterEvent *)
1363 {
1364 }
1365
1366 /*!
1367     \fn void QAbstractScrollArea::dragMoveEvent(QDragMoveEvent *event)
1368
1369     This event handler can be reimplemented in a subclass to receive
1370     drag move events (passed in \a event), for the viewport() widget.
1371
1372     \sa QWidget::dragMoveEvent()
1373 */
1374 void QAbstractScrollArea::dragMoveEvent(QDragMoveEvent *)
1375 {
1376 }
1377
1378 /*!
1379     \fn void QAbstractScrollArea::dragLeaveEvent(QDragLeaveEvent *event)
1380
1381     This event handler can be reimplemented in a subclass to receive
1382     drag leave events (passed in \a event), for the viewport() widget.
1383
1384     \sa QWidget::dragLeaveEvent()
1385 */
1386 void QAbstractScrollArea::dragLeaveEvent(QDragLeaveEvent *)
1387 {
1388 }
1389
1390 /*!
1391     \fn void QAbstractScrollArea::dropEvent(QDropEvent *event)
1392
1393     This event handler can be reimplemented in a subclass to receive
1394     drop events (passed in \a event), for the viewport() widget.
1395
1396     \sa QWidget::dropEvent()
1397 */
1398 void QAbstractScrollArea::dropEvent(QDropEvent *)
1399 {
1400 }
1401
1402
1403 #endif
1404
1405 /*!
1406     This virtual handler is called when the scroll bars are moved by
1407     \a dx, \a dy, and consequently the viewport's contents should be
1408     scrolled accordingly.
1409
1410     The default implementation simply calls update() on the entire
1411     viewport(), subclasses can reimplement this handler for
1412     optimization purposes, or - like QScrollArea - to move a contents
1413     widget. The parameters \a dx and \a dy are there for convenience,
1414     so that the class knows how much should be scrolled (useful
1415     e.g. when doing pixel-shifts). You may just as well ignore these
1416     values and scroll directly to the position the scroll bars
1417     indicate.
1418
1419     Calling this function in order to scroll programmatically is an
1420     error, use the scroll bars instead (e.g. by calling
1421     QScrollBar::setValue() directly).
1422 */
1423 void QAbstractScrollArea::scrollContentsBy(int, int)
1424 {
1425     viewport()->update();
1426 }
1427
1428 bool QAbstractScrollAreaPrivate::canStartScrollingAt( const QPoint &startPos )
1429 {
1430     Q_Q(QAbstractScrollArea);
1431
1432 #ifndef QT_NO_GRAPHICSVIEW
1433     // don't start scrolling when a drag mode has been set.
1434     // don't start scrolling on a movable item.
1435     if (QGraphicsView *view = qobject_cast<QGraphicsView *>(q)) {
1436         if (view->dragMode() != QGraphicsView::NoDrag)
1437             return false;
1438
1439         QGraphicsItem *childItem = view->itemAt(startPos);
1440
1441         if (childItem && (childItem->flags() & QGraphicsItem::ItemIsMovable))
1442             return false;
1443     }
1444 #endif
1445
1446     // don't start scrolling on a QAbstractSlider
1447     if (qobject_cast<QAbstractSlider *>(q->viewport()->childAt(startPos))) {
1448         return false;
1449     }
1450
1451     return true;
1452 }
1453
1454 void QAbstractScrollAreaPrivate::flashScrollBars()
1455 {
1456     if (hbarpolicy == Qt::ScrollBarAsNeeded)
1457         hbar->d_func()->flash();
1458     if (vbarpolicy == Qt::ScrollBarAsNeeded)
1459         vbar->d_func()->flash();
1460 }
1461
1462 void QAbstractScrollAreaPrivate::setScrollBarTransient(QScrollBar *scrollBar, bool transient)
1463 {
1464     scrollBar->d_func()->setTransient(transient);
1465 }
1466
1467 void QAbstractScrollAreaPrivate::_q_hslide(int x)
1468 {
1469     Q_Q(QAbstractScrollArea);
1470     int dx = xoffset - x;
1471     xoffset = x;
1472     q->scrollContentsBy(dx, 0);
1473     flashScrollBars();
1474 }
1475
1476 void QAbstractScrollAreaPrivate::_q_vslide(int y)
1477 {
1478     Q_Q(QAbstractScrollArea);
1479     int dy = yoffset - y;
1480     yoffset = y;
1481     q->scrollContentsBy(0, dy);
1482     flashScrollBars();
1483 }
1484
1485 void QAbstractScrollAreaPrivate::_q_showOrHideScrollBars()
1486 {
1487     layoutChildren();
1488 #ifdef Q_WS_WIN
1489     // Need to re-subscribe to gestures as the content changes to make sure we
1490     // enable/disable panning when needed.
1491     QWidgetPrivate *dd = static_cast<QWidgetPrivate *>(QObjectPrivate::get(viewport));
1492     if (dd)
1493         dd->winSetupGestures();
1494 #endif // Q_WS_WIN
1495 }
1496
1497 QPoint QAbstractScrollAreaPrivate::contentsOffset() const
1498 {
1499     Q_Q(const QAbstractScrollArea);
1500     QPoint offset;
1501     if (vbar->isVisible())
1502         offset.setY(vbar->value());
1503     if (hbar->isVisible()) {
1504         if (q->isRightToLeft())
1505             offset.setX(hbar->maximum() - hbar->value());
1506         else
1507             offset.setX(hbar->value());
1508     }
1509     return offset;
1510 }
1511
1512 /*!
1513     \reimp
1514
1515 */
1516 QSize QAbstractScrollArea::minimumSizeHint() const
1517 {
1518     Q_D(const QAbstractScrollArea);
1519     int hsbExt = d->hbar->sizeHint().height();
1520     int vsbExt = d->vbar->sizeHint().width();
1521     int extra = 2 * d->frameWidth;
1522     QStyleOption opt;
1523     opt.initFrom(this);
1524     if ((d->frameStyle != QFrame::NoFrame)
1525         && style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents, &opt, this)) {
1526         extra += style()->pixelMetric(QStyle::PM_ScrollView_ScrollBarSpacing, &opt, this);
1527     }
1528     return QSize(d->scrollBarContainers[Qt::Horizontal]->sizeHint().width() + vsbExt + extra,
1529                  d->scrollBarContainers[Qt::Vertical]->sizeHint().height() + hsbExt + extra);
1530 }
1531
1532 /*!
1533     \reimp
1534 */
1535 QSize QAbstractScrollArea::sizeHint() const
1536 {
1537     return QSize(256, 192);
1538 #if 0
1539     Q_D(const QAbstractScrollArea);
1540     int h = qMax(10, fontMetrics().height());
1541     int f = 2 * d->frameWidth;
1542     return QSize((6 * h) + f, (4 * h) + f);
1543 #endif
1544 }
1545
1546 /*!
1547     This slot is called by QAbstractScrollArea after setViewport(\a
1548     viewport) has been called. Reimplement this function in a
1549     subclass of QAbstractScrollArea to initialize the new \a viewport
1550     before it is used.
1551
1552     \sa setViewport()
1553 */
1554 void QAbstractScrollArea::setupViewport(QWidget *viewport)
1555 {
1556     Q_UNUSED(viewport);
1557 }
1558
1559 /*!
1560     \internal
1561
1562     This method is reserved for future use.
1563 */
1564 QSize QAbstractScrollArea::viewportSizeHint() const
1565 {
1566     return QSize();
1567 }
1568
1569 QT_END_NAMESPACE
1570
1571 #include "moc_qabstractscrollarea.cpp"
1572 #include "moc_qabstractscrollarea_p.cpp"
1573
1574 #endif // QT_NO_SCROLLAREA