util/src/gui/graphicsview/qgraphicsview.cpp
changeset 7 f7bc934e204c
equal deleted inserted replaced
3:41300fa6a67c 7:f7bc934e204c
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 static const int QGRAPHICSVIEW_REGION_RECT_THRESHOLD = 50;
       
    43 
       
    44 static const int QGRAPHICSVIEW_PREALLOC_STYLE_OPTIONS = 503; // largest prime < 2^9
       
    45 
       
    46 /*!
       
    47     \class QGraphicsView
       
    48     \brief The QGraphicsView class provides a widget for displaying the
       
    49     contents of a QGraphicsScene.
       
    50     \since 4.2
       
    51     \ingroup graphicsview-api
       
    52 
       
    53 
       
    54     QGraphicsView visualizes the contents of a QGraphicsScene in a scrollable
       
    55     viewport. To create a scene with geometrical items, see QGraphicsScene's
       
    56     documentation. QGraphicsView is part of \l{The Graphics View Framework}.
       
    57 
       
    58     To visualize a scene, you start by constructing a QGraphicsView object,
       
    59     passing the address of the scene you want to visualize to QGraphicsView's
       
    60     constructor. Alternatively, you can call setScene() to set the scene at a
       
    61     later point. After you call show(), the view will by default scroll to the
       
    62     center of the scene and display any items that are visible at this
       
    63     point. For example:
       
    64 
       
    65     \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsview.cpp 0
       
    66 
       
    67     You can explicitly scroll to any position on the scene by using the
       
    68     scroll bars, or by calling centerOn(). By passing a point to centerOn(),
       
    69     QGraphicsView will scroll its viewport to ensure that the point is
       
    70     centered in the view. An overload is provided for scrolling to a
       
    71     QGraphicsItem, in which case QGraphicsView will see to that the center of
       
    72     the item is centered in the view. If all you want is to ensure that a
       
    73     certain area is visible, (but not necessarily centered,) you can call
       
    74     ensureVisible() instead.
       
    75 
       
    76     QGraphicsView can be used to visualize a whole scene, or only parts of it.
       
    77     The visualized area is by default detected automatically when the view is
       
    78     displayed for the first time (by calling
       
    79     QGraphicsScene::itemsBoundingRect()). To set the visualized area rectangle
       
    80     yourself, you can call setSceneRect(). This will adjust the scroll bars'
       
    81     ranges appropriately. Note that although the scene supports a virtually
       
    82     unlimited size, the range of the scroll bars will never exceed the range of
       
    83     an integer (INT_MIN, INT_MAX). When the scene is larger than the scroll
       
    84     bars' values, you can choose to use translate() to navigate the scene
       
    85     instead.
       
    86 
       
    87     QGraphicsView visualizes the scene by calling render(). By default, the
       
    88     items are drawn onto the viewport by using a regular QPainter, and using
       
    89     default render hints. To change the default render hints that
       
    90     QGraphicsView passes to QPainter when painting items, you can call
       
    91     setRenderHints().
       
    92 
       
    93     By default, QGraphicsView provides a regular QWidget for the viewport
       
    94     widget. You can access this widget by calling viewport(), or you can
       
    95     replace it by calling setViewport(). To render using OpenGL, simply call
       
    96     setViewport(new QGLWidget). QGraphicsView takes ownership of the viewport
       
    97     widget.
       
    98 
       
    99     QGraphicsView supports affine transformations, using QTransform. You can
       
   100     either pass a matrix to setTransform(), or you can call one of the
       
   101     convenience functions rotate(), scale(), translate() or shear(). The most
       
   102     two common transformations are scaling, which is used to implement
       
   103     zooming, and rotation. QGraphicsView keeps the center of the view fixed
       
   104     during a transformation.
       
   105 
       
   106     You can interact with the items on the scene by using the mouse and
       
   107     keyboard. QGraphicsView translates the mouse and key events into \e scene
       
   108     events, (events that inherit QGraphicsSceneEvent,), and forward them to
       
   109     the visualized scene. In the end, it's the individual item that handles
       
   110     the events and reacts to them. For example, if you click on a selectable
       
   111     item, the item will typically let the scene know that it has been
       
   112     selected, and it will also redraw itself to display a selection
       
   113     rectangle. Similiary, if you click and drag the mouse to move a movable
       
   114     item, it's the item that handles the mouse moves and moves itself.  Item
       
   115     interaction is enabled by default, and you can toggle it by calling
       
   116     setInteractive().
       
   117 
       
   118     You can also provide your own custom scene interaction, by creating a
       
   119     subclass of QGraphicsView, and reimplementing the mouse and key event
       
   120     handlers. To simplify how you programmatically interact with items in the
       
   121     view, QGraphicsView provides the mapping functions mapToScene() and
       
   122     mapFromScene(), and the item accessors items() and itemAt(). These
       
   123     functions allow you to map points, rectangles, polygons and paths between
       
   124     view coordinates and scene coordinates, and to find items on the scene
       
   125     using view coordinates.
       
   126 
       
   127     \img graphicsview-view.png
       
   128 
       
   129     \sa QGraphicsScene, QGraphicsItem, QGraphicsSceneEvent
       
   130 */
       
   131 
       
   132 /*!
       
   133     \enum QGraphicsView::ViewportAnchor
       
   134 
       
   135     This enums describe the possible anchors that QGraphicsView can
       
   136     use when the user resizes the view or when the view is
       
   137     transformed.
       
   138 
       
   139     \value NoAnchor No anchor, i.e. the view leaves the scene's
       
   140                     position unchanged.
       
   141     \value AnchorViewCenter The scene point at the center of the view
       
   142                             is used as the anchor.
       
   143     \value AnchorUnderMouse The point under the mouse is used as the anchor.
       
   144 
       
   145     \sa resizeAnchor, transformationAnchor
       
   146 */
       
   147 
       
   148 /*!
       
   149     \enum QGraphicsView::ViewportUpdateMode
       
   150 
       
   151     \since 4.3
       
   152 
       
   153     This enum describes how QGraphicsView updates its viewport when the scene
       
   154     contents change or are exposed.
       
   155 
       
   156     \value FullViewportUpdate When any visible part of the scene changes or is
       
   157     reexposed, QGraphicsView will update the entire viewport. This approach is
       
   158     fastest when QGraphicsView spends more time figuring out what to draw than
       
   159     it would spend drawing (e.g., when very many small items are repeatedly
       
   160     updated). This is the preferred update mode for viewports that do not
       
   161     support partial updates, such as QGLWidget, and for viewports that need to
       
   162     disable scroll optimization.
       
   163 
       
   164     \value MinimalViewportUpdate QGraphicsView will determine the minimal
       
   165     viewport region that requires a redraw, minimizing the time spent drawing
       
   166     by avoiding a redraw of areas that have not changed. This is
       
   167     QGraphicsView's default mode. Although this approach provides the best
       
   168     performance in general, if there are many small visible changes on the
       
   169     scene, QGraphicsView might end up spending more time finding the minimal
       
   170     approach than it will spend drawing.
       
   171 
       
   172     \value SmartViewportUpdate QGraphicsView will attempt to find an optimal
       
   173     update mode by analyzing the areas that require a redraw.
       
   174 
       
   175     \value BoundingRectViewportUpdate The bounding rectangle of all changes in
       
   176     the viewport will be redrawn. This mode has the advantage that
       
   177     QGraphicsView searches only one region for changes, minimizing time spent
       
   178     determining what needs redrawing. The disadvantage is that areas that have
       
   179     not changed also need to be redrawn.
       
   180 
       
   181     \value NoViewportUpdate QGraphicsView will never update its viewport when
       
   182     the scene changes; the user is expected to control all updates. This mode
       
   183     disables all (potentially slow) item visibility testing in QGraphicsView,
       
   184     and is suitable for scenes that either require a fixed frame rate, or where
       
   185     the viewport is otherwise updated externally.
       
   186 
       
   187     \sa viewportUpdateMode
       
   188 */
       
   189 
       
   190 /*!
       
   191     \enum QGraphicsView::OptimizationFlag
       
   192 
       
   193     \since 4.3
       
   194 
       
   195     This enum describes flags that you can enable to improve rendering
       
   196     performance in QGraphicsView. By default, none of these flags are set.
       
   197     Note that setting a flag usually imposes a side effect, and this effect
       
   198     can vary between paint devices and platforms.
       
   199 
       
   200     \value DontClipPainter This value is obsolete and has no effect.
       
   201 
       
   202     \value DontSavePainterState When rendering, QGraphicsView protects the
       
   203     painter state (see QPainter::save()) when rendering the background or
       
   204     foreground, and when rendering each item. This allows you to leave the
       
   205     painter in an altered state (i.e., you can call QPainter::setPen() or
       
   206     QPainter::setBrush() without restoring the state after painting). However,
       
   207     if the items consistently do restore the state, you should enable this
       
   208     flag to prevent QGraphicsView from doing the same.
       
   209 
       
   210     \value DontAdjustForAntialiasing Disables QGraphicsView's antialiasing
       
   211     auto-adjustment of exposed areas. Items that render antialiased lines on
       
   212     the boundaries of their QGraphicsItem::boundingRect() can end up rendering
       
   213     parts of the line outside. To prevent rendering artifacts, QGraphicsView
       
   214     expands all exposed regions by 2 pixels in all directions. If you enable
       
   215     this flag, QGraphicsView will no longer perform these adjustments,
       
   216     minimizing the areas that require redrawing, which improves performance. A
       
   217     common side effect is that items that do draw with antialiasing can leave
       
   218     painting traces behind on the scene as they are moved.
       
   219 
       
   220     \value IndirectPainting Since Qt 4.6, restore the old painting algorithm
       
   221     that calls QGraphicsView::drawItems() and QGraphicsScene::drawItems().
       
   222     To be used only for compatibility with old code.
       
   223 */
       
   224 
       
   225 /*!
       
   226     \enum QGraphicsView::CacheModeFlag
       
   227 
       
   228     This enum describes the flags that you can set for a QGraphicsView's cache
       
   229     mode.
       
   230 
       
   231     \value CacheNone All painting is done directly onto the viewport.
       
   232 
       
   233     \value CacheBackground The background is cached. This affects both custom
       
   234     backgrounds, and backgrounds based on the backgroundBrush property. When
       
   235     this flag is enabled, QGraphicsView will allocate one pixmap with the full
       
   236     size of the viewport.
       
   237 
       
   238     \sa cacheMode
       
   239 */
       
   240 
       
   241 /*!
       
   242     \enum QGraphicsView::DragMode
       
   243 
       
   244     This enum describes the default action for the view when pressing and
       
   245     dragging the mouse over the viewport.
       
   246 
       
   247     \value NoDrag Nothing happens; the mouse event is ignored.
       
   248 
       
   249     \value ScrollHandDrag The cursor changes into a pointing hand, and
       
   250     dragging the mouse around will scroll the scrolbars. This mode works both
       
   251     in \l{QGraphicsView::interactive}{interactive} and non-interactive mode.
       
   252 
       
   253     \value RubberBandDrag A rubber band will appear. Dragging the mouse will
       
   254     set the rubber band geometry, and all items covered by the rubber band are
       
   255     selected. This mode is disabled for non-interactive views.
       
   256 
       
   257     \sa dragMode, QGraphicsScene::setSelectionArea()
       
   258 */
       
   259 
       
   260 #include "qgraphicsview.h"
       
   261 #include "qgraphicsview_p.h"
       
   262 
       
   263 #ifndef QT_NO_GRAPHICSVIEW
       
   264 
       
   265 #include "qgraphicsitem.h"
       
   266 #include "qgraphicsitem_p.h"
       
   267 #include "qgraphicsscene.h"
       
   268 #include "qgraphicsscene_p.h"
       
   269 #include "qgraphicssceneevent.h"
       
   270 #include "qgraphicswidget.h"
       
   271 
       
   272 #include <QtCore/qdatetime.h>
       
   273 #include <QtCore/qdebug.h>
       
   274 #include <QtCore/qmath.h>
       
   275 #include <QtGui/qapplication.h>
       
   276 #include <QtGui/qdesktopwidget.h>
       
   277 #include <QtGui/qevent.h>
       
   278 #include <QtGui/qlayout.h>
       
   279 #include <QtGui/qtransform.h>
       
   280 #include <QtGui/qmatrix.h>
       
   281 #include <QtGui/qpainter.h>
       
   282 #include <QtGui/qscrollbar.h>
       
   283 #include <QtGui/qstyleoption.h>
       
   284 #include <QtGui/qinputcontext.h>
       
   285 #ifdef Q_WS_X11
       
   286 #include <QtGui/qpaintengine.h>
       
   287 #include <private/qt_x11_p.h>
       
   288 #endif
       
   289 
       
   290 #include <private/qevent_p.h>
       
   291 
       
   292 QT_BEGIN_NAMESPACE
       
   293 
       
   294 bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event);
       
   295 
       
   296 inline int q_round_bound(qreal d) //### (int)(qreal) INT_MAX != INT_MAX for single precision
       
   297 {
       
   298     if (d <= (qreal) INT_MIN)
       
   299         return INT_MIN;
       
   300     else if (d >= (qreal) INT_MAX)
       
   301         return INT_MAX;
       
   302     return d >= 0.0 ? int(d + 0.5) : int(d - int(d-1) + 0.5) + int(d-1);
       
   303 }
       
   304 
       
   305 void QGraphicsViewPrivate::translateTouchEvent(QGraphicsViewPrivate *d, QTouchEvent *touchEvent)
       
   306 {
       
   307     QList<QTouchEvent::TouchPoint> touchPoints = touchEvent->touchPoints();
       
   308     for (int i = 0; i < touchPoints.count(); ++i) {
       
   309         QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
       
   310         // the scene will set the item local pos, startPos, lastPos, and rect before delivering to
       
   311         // an item, but for now those functions are returning the view's local coordinates
       
   312         touchPoint.setSceneRect(d->mapToScene(touchPoint.rect()));
       
   313         touchPoint.setStartScenePos(d->mapToScene(touchPoint.startPos()));
       
   314         touchPoint.setLastScenePos(d->mapToScene(touchPoint.lastPos()));
       
   315 
       
   316         // screenPos, startScreenPos, lastScreenPos, and screenRect are already set
       
   317     }
       
   318 
       
   319     touchEvent->setTouchPoints(touchPoints);
       
   320 }
       
   321 
       
   322 /*!
       
   323     \internal
       
   324 */
       
   325 QGraphicsViewPrivate::QGraphicsViewPrivate()
       
   326     : renderHints(QPainter::TextAntialiasing),
       
   327       dragMode(QGraphicsView::NoDrag),
       
   328       sceneInteractionAllowed(true), hasSceneRect(false),
       
   329       connectedToScene(false),
       
   330       mousePressButton(Qt::NoButton),
       
   331       identityMatrix(true),
       
   332       dirtyScroll(true),
       
   333       accelerateScrolling(true),
       
   334       leftIndent(0), topIndent(0),
       
   335       lastMouseEvent(QEvent::None, QPoint(), Qt::NoButton, 0, 0),
       
   336       useLastMouseEvent(false),
       
   337       keepLastCenterPoint(true),
       
   338       alignment(Qt::AlignCenter),
       
   339       transforming(false),
       
   340       transformationAnchor(QGraphicsView::AnchorViewCenter), resizeAnchor(QGraphicsView::NoAnchor),
       
   341       viewportUpdateMode(QGraphicsView::MinimalViewportUpdate),
       
   342       optimizationFlags(0),
       
   343       scene(0),
       
   344 #ifndef QT_NO_RUBBERBAND
       
   345       rubberBanding(false),
       
   346       rubberBandSelectionMode(Qt::IntersectsItemShape),
       
   347 #endif
       
   348       handScrolling(false), handScrollMotions(0), cacheMode(0),
       
   349       mustAllocateStyleOptions(false),
       
   350       mustResizeBackgroundPixmap(true),
       
   351 #ifndef QT_NO_CURSOR
       
   352       hasStoredOriginalCursor(false),
       
   353 #endif
       
   354       lastDragDropEvent(0),
       
   355       fullUpdatePending(true),
       
   356       updateSceneSlotReimplementedChecked(false)
       
   357 {
       
   358     styleOptions.reserve(QGRAPHICSVIEW_PREALLOC_STYLE_OPTIONS);
       
   359 }
       
   360 
       
   361 /*!
       
   362     \internal
       
   363 */
       
   364 void QGraphicsViewPrivate::recalculateContentSize()
       
   365 {
       
   366     Q_Q(QGraphicsView);
       
   367 
       
   368     QSize maxSize = q->maximumViewportSize();
       
   369     int width = maxSize.width();
       
   370     int height = maxSize.height();
       
   371     QRectF viewRect = matrix.mapRect(q->sceneRect());
       
   372 
       
   373     bool frameOnlyAround = (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents, 0, q));
       
   374     if (frameOnlyAround) {
       
   375         if (hbarpolicy == Qt::ScrollBarAlwaysOn)
       
   376             height -= frameWidth * 2;
       
   377         if (vbarpolicy == Qt::ScrollBarAlwaysOn)
       
   378             width -= frameWidth * 2;
       
   379     }
       
   380 
       
   381     // Adjust the maximum width and height of the viewport based on the width
       
   382     // of visible scroll bars.
       
   383     int scrollBarExtent = q->style()->pixelMetric(QStyle::PM_ScrollBarExtent, 0, q);
       
   384     if (frameOnlyAround)
       
   385         scrollBarExtent += frameWidth * 2;
       
   386 
       
   387     bool useHorizontalScrollBar = (viewRect.width() > width) && hbarpolicy != Qt::ScrollBarAlwaysOff;
       
   388     bool useVerticalScrollBar = (viewRect.height() > height) && vbarpolicy != Qt::ScrollBarAlwaysOff;
       
   389     if (useHorizontalScrollBar && !useVerticalScrollBar) {
       
   390         if (viewRect.height() > height - scrollBarExtent)
       
   391             useVerticalScrollBar = true;
       
   392     }
       
   393     if (useVerticalScrollBar && !useHorizontalScrollBar) {
       
   394         if (viewRect.width() > width - scrollBarExtent)
       
   395             useHorizontalScrollBar = true;
       
   396     }
       
   397     if (useHorizontalScrollBar && hbarpolicy != Qt::ScrollBarAlwaysOn)
       
   398         height -= scrollBarExtent;
       
   399     if (useVerticalScrollBar && vbarpolicy != Qt::ScrollBarAlwaysOn)
       
   400         width -= scrollBarExtent;
       
   401 
       
   402     // Setting the ranges of these scroll bars can/will cause the values to
       
   403     // change, and scrollContentsBy() will be called correspondingly. This
       
   404     // will reset the last center point.
       
   405     QPointF savedLastCenterPoint = lastCenterPoint;
       
   406 
       
   407     // Remember the former indent settings
       
   408     qreal oldLeftIndent = leftIndent;
       
   409     qreal oldTopIndent = topIndent;
       
   410 
       
   411     // If the whole scene fits horizontally, we center the scene horizontally,
       
   412     // and ignore the horizontal scroll bars.
       
   413     int left =  q_round_bound(viewRect.left());
       
   414     int right = q_round_bound(viewRect.right() - width);
       
   415     if (left >= right) {
       
   416         hbar->setRange(0, 0);
       
   417 
       
   418         switch (alignment & Qt::AlignHorizontal_Mask) {
       
   419         case Qt::AlignLeft:
       
   420             leftIndent = -viewRect.left();
       
   421             break;
       
   422         case Qt::AlignRight:
       
   423             leftIndent = width - viewRect.width() - viewRect.left() - 1;
       
   424             break;
       
   425         case Qt::AlignHCenter:
       
   426         default:
       
   427             leftIndent = width / 2 - (viewRect.left() + viewRect.right()) / 2;
       
   428             break;
       
   429         }
       
   430     } else {
       
   431         hbar->setRange(left, right);
       
   432         hbar->setPageStep(width);
       
   433         hbar->setSingleStep(width / 20);
       
   434         leftIndent = 0;
       
   435     }
       
   436 
       
   437     // If the whole scene fits vertically, we center the scene vertically, and
       
   438     // ignore the vertical scroll bars.
       
   439     int top = q_round_bound(viewRect.top());
       
   440     int bottom = q_round_bound(viewRect.bottom()  - height);
       
   441     if (top >= bottom) {
       
   442         vbar->setRange(0, 0);
       
   443 
       
   444         switch (alignment & Qt::AlignVertical_Mask) {
       
   445         case Qt::AlignTop:
       
   446             topIndent = -viewRect.top();
       
   447             break;
       
   448         case Qt::AlignBottom:
       
   449             topIndent = height - viewRect.height() - viewRect.top() - 1;
       
   450             break;
       
   451         case Qt::AlignVCenter:
       
   452         default:
       
   453             topIndent = height / 2 - (viewRect.top() + viewRect.bottom()) / 2;
       
   454             break;
       
   455         }
       
   456     } else {
       
   457         vbar->setRange(top, bottom);
       
   458         vbar->setPageStep(height);
       
   459         vbar->setSingleStep(height / 20);
       
   460         topIndent = 0;
       
   461     }
       
   462 
       
   463     // Restorethe center point from before the ranges changed.
       
   464     lastCenterPoint = savedLastCenterPoint;
       
   465 
       
   466     // Issue a full update if the indents change.
       
   467     // ### If the transform is still the same, we can get away with just a
       
   468     // scroll instead.
       
   469     if (oldLeftIndent != leftIndent || oldTopIndent != topIndent) {
       
   470         dirtyScroll = true;
       
   471         updateAll();
       
   472     } else if (q->isRightToLeft() && !leftIndent) {
       
   473         // In reverse mode, the horizontal scroll always changes after the content
       
   474         // size has changed, as the scroll is calculated by summing the min and
       
   475         // max values of the range and subtracting the current value. In normal
       
   476         // mode the scroll remains unchanged unless the indent has changed.
       
   477         dirtyScroll = true;
       
   478     }
       
   479 
       
   480     if (cacheMode & QGraphicsView::CacheBackground) {
       
   481         // Invalidate the background pixmap
       
   482         mustResizeBackgroundPixmap = true;
       
   483     }
       
   484 }
       
   485 
       
   486 /*!
       
   487     \internal
       
   488 */
       
   489 void QGraphicsViewPrivate::centerView(QGraphicsView::ViewportAnchor anchor)
       
   490 {
       
   491     Q_Q(QGraphicsView);
       
   492     switch (anchor) {
       
   493     case QGraphicsView::AnchorUnderMouse: {
       
   494         if (q->underMouse()) {
       
   495             // Last scene pos: lastMouseMoveScenePoint
       
   496             // Current mouse pos:
       
   497             QPointF transformationDiff = q->mapToScene(viewport->rect().center())
       
   498                                          - q->mapToScene(viewport->mapFromGlobal(QCursor::pos()));
       
   499             q->centerOn(lastMouseMoveScenePoint + transformationDiff);
       
   500         } else {
       
   501             q->centerOn(lastCenterPoint);
       
   502         }
       
   503         break;
       
   504     }
       
   505     case QGraphicsView::AnchorViewCenter:
       
   506         q->centerOn(lastCenterPoint);
       
   507         break;
       
   508     case QGraphicsView::NoAnchor:
       
   509         break;
       
   510     }
       
   511 }
       
   512 
       
   513 /*!
       
   514     \internal
       
   515 */
       
   516 void QGraphicsViewPrivate::updateLastCenterPoint()
       
   517 {
       
   518     Q_Q(QGraphicsView);
       
   519     lastCenterPoint = q->mapToScene(viewport->rect().center());
       
   520 }
       
   521 
       
   522 /*!
       
   523     \internal
       
   524 
       
   525     Returns the horizontal scroll value (the X value of the left edge of the
       
   526     viewport).
       
   527 */
       
   528 qint64 QGraphicsViewPrivate::horizontalScroll() const
       
   529 {
       
   530     if (dirtyScroll)
       
   531         const_cast<QGraphicsViewPrivate *>(this)->updateScroll();
       
   532     return scrollX;
       
   533 }
       
   534 
       
   535 /*!
       
   536     \internal
       
   537 
       
   538     Returns the vertical scroll value (the X value of the top edge of the
       
   539     viewport).
       
   540 */
       
   541 qint64 QGraphicsViewPrivate::verticalScroll() const
       
   542 {
       
   543     if (dirtyScroll)
       
   544         const_cast<QGraphicsViewPrivate *>(this)->updateScroll();
       
   545     return scrollY;
       
   546 }
       
   547 
       
   548 /*!
       
   549     \internal
       
   550 
       
   551     Maps the given rectangle to the scene using QTransform::mapRect()
       
   552 */
       
   553 QRectF QGraphicsViewPrivate::mapRectToScene(const QRect &rect) const
       
   554 {
       
   555     if (dirtyScroll)
       
   556         const_cast<QGraphicsViewPrivate *>(this)->updateScroll();
       
   557     QRectF scrolled = QRectF(rect.translated(scrollX, scrollY));
       
   558     return identityMatrix ? scrolled : matrix.inverted().mapRect(scrolled);
       
   559 }
       
   560 
       
   561 
       
   562 /*!
       
   563     \internal
       
   564 
       
   565     Maps the given rectangle from the scene using QTransform::mapRect()
       
   566 */
       
   567 QRectF QGraphicsViewPrivate::mapRectFromScene(const QRectF &rect) const
       
   568 {
       
   569     if (dirtyScroll)
       
   570         const_cast<QGraphicsViewPrivate *>(this)->updateScroll();
       
   571     return (identityMatrix ? rect : matrix.mapRect(rect)).translated(-scrollX, -scrollY);
       
   572 }
       
   573 
       
   574 /*!
       
   575     \internal
       
   576 */
       
   577 void QGraphicsViewPrivate::updateScroll()
       
   578 {
       
   579     Q_Q(QGraphicsView);
       
   580     scrollX = qint64(-leftIndent);
       
   581     if (q->isRightToLeft()) {
       
   582         if (!leftIndent) {
       
   583             scrollX += hbar->minimum();
       
   584             scrollX += hbar->maximum();
       
   585             scrollX -= hbar->value();
       
   586         }
       
   587     } else {
       
   588         scrollX += hbar->value();
       
   589     }
       
   590 
       
   591     scrollY = qint64(vbar->value() - topIndent);
       
   592 
       
   593     dirtyScroll = false;
       
   594 }
       
   595 
       
   596 /*!
       
   597     \internal
       
   598 */
       
   599 void QGraphicsViewPrivate::replayLastMouseEvent()
       
   600 {
       
   601     if (!useLastMouseEvent || !scene)
       
   602         return;
       
   603     mouseMoveEventHandler(&lastMouseEvent);
       
   604 }
       
   605 
       
   606 /*!
       
   607     \internal
       
   608 */
       
   609 void QGraphicsViewPrivate::storeMouseEvent(QMouseEvent *event)
       
   610 {
       
   611     useLastMouseEvent = true;
       
   612     lastMouseEvent = QMouseEvent(QEvent::MouseMove, event->pos(), event->globalPos(),
       
   613                                  event->button(), event->buttons(), event->modifiers());
       
   614 }
       
   615 
       
   616 void QGraphicsViewPrivate::mouseMoveEventHandler(QMouseEvent *event)
       
   617 {
       
   618     Q_Q(QGraphicsView);
       
   619 
       
   620     storeMouseEvent(event);
       
   621     lastMouseEvent.setAccepted(false);
       
   622 
       
   623     if (!sceneInteractionAllowed)
       
   624         return;
       
   625     if (handScrolling)
       
   626         return;
       
   627     if (!scene)
       
   628         return;
       
   629 
       
   630     QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMouseMove);
       
   631     mouseEvent.setWidget(viewport);
       
   632     mouseEvent.setButtonDownScenePos(mousePressButton, mousePressScenePoint);
       
   633     mouseEvent.setButtonDownScreenPos(mousePressButton, mousePressScreenPoint);
       
   634     mouseEvent.setScenePos(q->mapToScene(event->pos()));
       
   635     mouseEvent.setScreenPos(event->globalPos());
       
   636     mouseEvent.setLastScenePos(lastMouseMoveScenePoint);
       
   637     mouseEvent.setLastScreenPos(lastMouseMoveScreenPoint);
       
   638     mouseEvent.setButtons(event->buttons());
       
   639     mouseEvent.setButton(event->button());
       
   640     mouseEvent.setModifiers(event->modifiers());
       
   641     lastMouseMoveScenePoint = mouseEvent.scenePos();
       
   642     lastMouseMoveScreenPoint = mouseEvent.screenPos();
       
   643     mouseEvent.setAccepted(false);
       
   644     if (event->spontaneous())
       
   645         qt_sendSpontaneousEvent(scene, &mouseEvent);
       
   646     else
       
   647         QApplication::sendEvent(scene, &mouseEvent);
       
   648 
       
   649     // Remember whether the last event was accepted or not.
       
   650     lastMouseEvent.setAccepted(mouseEvent.isAccepted());
       
   651 
       
   652     if (mouseEvent.isAccepted() && mouseEvent.buttons() != 0) {
       
   653         // The event was delivered to a mouse grabber; the press is likely to
       
   654         // have set a cursor, and we must not change it.
       
   655         return;
       
   656     }
       
   657 
       
   658 #ifndef QT_NO_CURSOR
       
   659     // If all the items ignore hover events, we don't look-up any items
       
   660     // in QGraphicsScenePrivate::dispatchHoverEvent, hence the
       
   661     // cachedItemsUnderMouse list will be empty. We therefore do the look-up
       
   662     // for cursor items here if not all items use the default cursor.
       
   663     if (scene->d_func()->allItemsIgnoreHoverEvents && !scene->d_func()->allItemsUseDefaultCursor
       
   664         && scene->d_func()->cachedItemsUnderMouse.isEmpty()) {
       
   665         scene->d_func()->cachedItemsUnderMouse = scene->d_func()->itemsAtPosition(mouseEvent.screenPos(),
       
   666                                                                                   mouseEvent.scenePos(),
       
   667                                                                                   mouseEvent.widget());
       
   668     }
       
   669     // Find the topmost item under the mouse with a cursor.
       
   670     foreach (QGraphicsItem *item, scene->d_func()->cachedItemsUnderMouse) {
       
   671         if (item->hasCursor()) {
       
   672             _q_setViewportCursor(item->cursor());
       
   673             return;
       
   674         }
       
   675     }
       
   676 
       
   677     // No items with cursors found; revert to the view cursor.
       
   678     if (hasStoredOriginalCursor) {
       
   679         // Restore the original viewport cursor.
       
   680         hasStoredOriginalCursor = false;
       
   681         viewport->setCursor(originalCursor);
       
   682     }
       
   683 #endif
       
   684 }
       
   685 
       
   686 /*!
       
   687     \internal
       
   688 */
       
   689 #ifndef QT_NO_RUBBERBAND
       
   690 QRegion QGraphicsViewPrivate::rubberBandRegion(const QWidget *widget, const QRect &rect) const
       
   691 {
       
   692     QStyleHintReturnMask mask;
       
   693     QStyleOptionRubberBand option;
       
   694     option.initFrom(widget);
       
   695     option.rect = rect;
       
   696     option.opaque = false;
       
   697     option.shape = QRubberBand::Rectangle;
       
   698 
       
   699     QRegion tmp;
       
   700     tmp += rect;
       
   701     if (widget->style()->styleHint(QStyle::SH_RubberBand_Mask, &option, widget, &mask))
       
   702         tmp &= mask.region;
       
   703     return tmp;
       
   704 }
       
   705 #endif
       
   706 
       
   707 /*!
       
   708     \internal
       
   709 */
       
   710 #ifndef QT_NO_CURSOR
       
   711 void QGraphicsViewPrivate::_q_setViewportCursor(const QCursor &cursor)
       
   712 {
       
   713     if (!hasStoredOriginalCursor) {
       
   714         hasStoredOriginalCursor = true;
       
   715         originalCursor = viewport->cursor();
       
   716     }
       
   717     viewport->setCursor(cursor);
       
   718 }
       
   719 #endif
       
   720 
       
   721 /*!
       
   722     \internal
       
   723 */
       
   724 #ifndef QT_NO_CURSOR
       
   725 void QGraphicsViewPrivate::_q_unsetViewportCursor()
       
   726 {
       
   727     Q_Q(QGraphicsView);
       
   728     foreach (QGraphicsItem *item, q->items(lastMouseEvent.pos())) {
       
   729         if (item->hasCursor()) {
       
   730             _q_setViewportCursor(item->cursor());
       
   731             return;
       
   732         }
       
   733     }
       
   734 
       
   735     // Restore the original viewport cursor.
       
   736     hasStoredOriginalCursor = false;
       
   737     if (dragMode == QGraphicsView::ScrollHandDrag)
       
   738         viewport->setCursor(Qt::OpenHandCursor);
       
   739     else
       
   740         viewport->setCursor(originalCursor);
       
   741 }
       
   742 #endif
       
   743 
       
   744 /*!
       
   745     \internal
       
   746 */
       
   747 void QGraphicsViewPrivate::storeDragDropEvent(const QGraphicsSceneDragDropEvent *event)
       
   748 {
       
   749     delete lastDragDropEvent;
       
   750     lastDragDropEvent = new QGraphicsSceneDragDropEvent(event->type());
       
   751     lastDragDropEvent->setScenePos(event->scenePos());
       
   752     lastDragDropEvent->setScreenPos(event->screenPos());
       
   753     lastDragDropEvent->setButtons(event->buttons());
       
   754     lastDragDropEvent->setModifiers(event->modifiers());
       
   755     lastDragDropEvent->setPossibleActions(event->possibleActions());
       
   756     lastDragDropEvent->setProposedAction(event->proposedAction());
       
   757     lastDragDropEvent->setDropAction(event->dropAction());
       
   758     lastDragDropEvent->setMimeData(event->mimeData());
       
   759     lastDragDropEvent->setWidget(event->widget());
       
   760     lastDragDropEvent->setSource(event->source());
       
   761 }
       
   762 
       
   763 /*!
       
   764     \internal
       
   765 */
       
   766 void QGraphicsViewPrivate::populateSceneDragDropEvent(QGraphicsSceneDragDropEvent *dest,
       
   767                                                       QDropEvent *source)
       
   768 {
       
   769 #ifndef QT_NO_DRAGANDDROP
       
   770     Q_Q(QGraphicsView);
       
   771     dest->setScenePos(q->mapToScene(source->pos()));
       
   772     dest->setScreenPos(q->mapToGlobal(source->pos()));
       
   773     dest->setButtons(source->mouseButtons());
       
   774     dest->setModifiers(source->keyboardModifiers());
       
   775     dest->setPossibleActions(source->possibleActions());
       
   776     dest->setProposedAction(source->proposedAction());
       
   777     dest->setDropAction(source->dropAction());
       
   778     dest->setMimeData(source->mimeData());
       
   779     dest->setWidget(viewport);
       
   780     dest->setSource(source->source());
       
   781 #else
       
   782     Q_UNUSED(dest)
       
   783     Q_UNUSED(source)
       
   784 #endif
       
   785 }
       
   786 
       
   787 /*!
       
   788     \internal
       
   789 */
       
   790 QRect QGraphicsViewPrivate::mapToViewRect(const QGraphicsItem *item, const QRectF &rect) const
       
   791 {
       
   792     Q_Q(const QGraphicsView);
       
   793     if (dirtyScroll)
       
   794         const_cast<QGraphicsViewPrivate *>(this)->updateScroll();
       
   795 
       
   796     if (item->d_ptr->itemIsUntransformable()) {
       
   797         QTransform itv = item->deviceTransform(q->viewportTransform());
       
   798         return itv.mapRect(rect).toAlignedRect();
       
   799     }
       
   800 
       
   801     // Translate-only
       
   802     // COMBINE
       
   803     QPointF offset;
       
   804     const QGraphicsItem *parentItem = item;
       
   805     const QGraphicsItemPrivate *itemd;
       
   806     do {
       
   807         itemd = parentItem->d_ptr.data();
       
   808         if (itemd->transformData)
       
   809             break;
       
   810         offset += itemd->pos;
       
   811     } while ((parentItem = itemd->parent));
       
   812 
       
   813     QRectF baseRect = rect.translated(offset.x(), offset.y());
       
   814     if (!parentItem) {
       
   815         if (identityMatrix) {
       
   816             baseRect.translate(-scrollX, -scrollY);
       
   817             return baseRect.toAlignedRect();
       
   818         }
       
   819         return matrix.mapRect(baseRect).translated(-scrollX, -scrollY).toAlignedRect();
       
   820     }
       
   821 
       
   822     QTransform tr = parentItem->sceneTransform();
       
   823     if (!identityMatrix)
       
   824         tr *= matrix;
       
   825     QRectF r = tr.mapRect(baseRect);
       
   826     r.translate(-scrollX, -scrollY);
       
   827     return r.toAlignedRect();
       
   828 }
       
   829 
       
   830 /*!
       
   831     \internal
       
   832 */
       
   833 QRegion QGraphicsViewPrivate::mapToViewRegion(const QGraphicsItem *item, const QRectF &rect) const
       
   834 {
       
   835     Q_Q(const QGraphicsView);
       
   836     if (dirtyScroll)
       
   837         const_cast<QGraphicsViewPrivate *>(this)->updateScroll();
       
   838 
       
   839     // Accurate bounding region
       
   840     QTransform itv = item->deviceTransform(q->viewportTransform());
       
   841     return item->boundingRegion(itv) & itv.mapRect(rect).toAlignedRect();
       
   842 }
       
   843 
       
   844 /*!
       
   845     \internal
       
   846 */
       
   847 void QGraphicsViewPrivate::processPendingUpdates()
       
   848 {
       
   849     if (!scene)
       
   850         return;
       
   851 
       
   852     if (fullUpdatePending) {
       
   853         viewport->update();
       
   854     } else if (viewportUpdateMode == QGraphicsView::BoundingRectViewportUpdate) {
       
   855         if (optimizationFlags & QGraphicsView::DontAdjustForAntialiasing)
       
   856             viewport->update(dirtyBoundingRect.adjusted(-1, -1, 1, 1));
       
   857         else
       
   858             viewport->update(dirtyBoundingRect.adjusted(-2, -2, 2, 2));
       
   859     } else {
       
   860         viewport->update(dirtyRegion); // Already adjusted in updateRect/Region.
       
   861     }
       
   862 
       
   863     dirtyBoundingRect = QRect();
       
   864     dirtyRegion = QRegion();
       
   865 }
       
   866 
       
   867 static inline bool intersectsViewport(const QRect &r, int width, int height)
       
   868 { return !(r.left() > width) && !(r.right() < 0) && !(r.top() >= height) && !(r.bottom() < 0); }
       
   869 
       
   870 static inline bool containsViewport(const QRect &r, int width, int height)
       
   871 { return r.left() <= 0 && r.top() <= 0 && r.right() >= width - 1 && r.bottom() >= height - 1; }
       
   872 
       
   873 static inline void QRect_unite(QRect *rect, const QRect &other)
       
   874 {
       
   875     if (rect->isEmpty()) {
       
   876         *rect = other;
       
   877     } else {
       
   878         rect->setCoords(qMin(rect->left(), other.left()), qMin(rect->top(), other.top()),
       
   879                         qMax(rect->right(), other.right()), qMax(rect->bottom(), other.bottom()));
       
   880     }
       
   881 }
       
   882 
       
   883 bool QGraphicsViewPrivate::updateRegion(const QRegion &r)
       
   884 {
       
   885     if (fullUpdatePending || viewportUpdateMode == QGraphicsView::NoViewportUpdate || r.isEmpty())
       
   886         return false;
       
   887 
       
   888     const QRect boundingRect = r.boundingRect();
       
   889     if (!intersectsViewport(boundingRect, viewport->width(), viewport->height()))
       
   890         return false; // Update region outside viewport.
       
   891 
       
   892     switch (viewportUpdateMode) {
       
   893     case QGraphicsView::FullViewportUpdate:
       
   894         fullUpdatePending = true;
       
   895         viewport->update();
       
   896         break;
       
   897     case QGraphicsView::BoundingRectViewportUpdate:
       
   898         QRect_unite(&dirtyBoundingRect, boundingRect);
       
   899         if (containsViewport(dirtyBoundingRect, viewport->width(), viewport->height())) {
       
   900             fullUpdatePending = true;
       
   901             viewport->update();
       
   902         }
       
   903         break;
       
   904     case QGraphicsView::SmartViewportUpdate: // ### DEPRECATE
       
   905     case QGraphicsView::MinimalViewportUpdate:
       
   906     {
       
   907         const QVector<QRect> &rects = r.rects();
       
   908         for (int i = 0; i < rects.size(); ++i) {
       
   909             if (optimizationFlags & QGraphicsView::DontAdjustForAntialiasing)
       
   910                 dirtyRegion += rects.at(i).adjusted(-1, -1, 1, 1);
       
   911             else
       
   912                 dirtyRegion += rects.at(i).adjusted(-2, -2, 2, 2);
       
   913         }
       
   914         break;
       
   915     }
       
   916     default:
       
   917         break;
       
   918     }
       
   919 
       
   920     return true;
       
   921 }
       
   922 
       
   923 bool QGraphicsViewPrivate::updateRect(const QRect &r)
       
   924 {
       
   925     if (fullUpdatePending || viewportUpdateMode == QGraphicsView::NoViewportUpdate
       
   926         || !intersectsViewport(r, viewport->width(), viewport->height())) {
       
   927         return false;
       
   928     }
       
   929 
       
   930     switch (viewportUpdateMode) {
       
   931     case QGraphicsView::FullViewportUpdate:
       
   932         fullUpdatePending = true;
       
   933         viewport->update();
       
   934         break;
       
   935     case QGraphicsView::BoundingRectViewportUpdate:
       
   936         QRect_unite(&dirtyBoundingRect, r);
       
   937         if (containsViewport(dirtyBoundingRect, viewport->width(), viewport->height())) {
       
   938             fullUpdatePending = true;
       
   939             viewport->update();
       
   940         }
       
   941         break;
       
   942     case QGraphicsView::SmartViewportUpdate: // ### DEPRECATE
       
   943     case QGraphicsView::MinimalViewportUpdate:
       
   944         if (optimizationFlags & QGraphicsView::DontAdjustForAntialiasing)
       
   945             dirtyRegion += r.adjusted(-1, -1, 1, 1);
       
   946         else
       
   947             dirtyRegion += r.adjusted(-2, -2, 2, 2);
       
   948         break;
       
   949     default:
       
   950         break;
       
   951     }
       
   952 
       
   953     return true;
       
   954 }
       
   955 
       
   956 QStyleOptionGraphicsItem *QGraphicsViewPrivate::allocStyleOptionsArray(int numItems)
       
   957 {
       
   958     if (mustAllocateStyleOptions || (numItems > styleOptions.capacity()))
       
   959         // too many items, let's allocate on-the-fly
       
   960         return new QStyleOptionGraphicsItem[numItems];
       
   961 
       
   962     // expand only whenever necessary
       
   963     if (numItems > styleOptions.size())
       
   964         styleOptions.resize(numItems);
       
   965 
       
   966     mustAllocateStyleOptions = true;
       
   967     return styleOptions.data();
       
   968 }
       
   969 
       
   970 void QGraphicsViewPrivate::freeStyleOptionsArray(QStyleOptionGraphicsItem *array)
       
   971 {
       
   972     mustAllocateStyleOptions = false;
       
   973     if (array != styleOptions.data())
       
   974         delete [] array;
       
   975 }
       
   976 
       
   977 extern QPainterPath qt_regionToPath(const QRegion &region);
       
   978 
       
   979 /*!
       
   980     ### Adjustments in findItems: mapToScene(QRect) forces us to adjust the
       
   981     input rectangle by (0, 0, 1, 1), because it uses QRect::bottomRight()
       
   982     (etc) when mapping the rectangle to a polygon (which is _wrong_). In
       
   983     addition, as QGraphicsItem::boundingRect() is defined in logical space,
       
   984     but the default pen for QPainter is cosmetic with a width of 0, QPainter
       
   985     is at risk of painting 1 pixel outside the bounding rect. Therefore we
       
   986     must search for items with an adjustment of (-1, -1, 1, 1).
       
   987 */
       
   988 QList<QGraphicsItem *> QGraphicsViewPrivate::findItems(const QRegion &exposedRegion, bool *allItems,
       
   989                                                        const QTransform &viewTransform) const
       
   990 {
       
   991     Q_Q(const QGraphicsView);
       
   992 
       
   993     // Step 1) If all items are contained within the expose region, then
       
   994     // return a list of all visible items. ### the scene's growing bounding
       
   995     // rect does not take into account untransformable items.
       
   996     const QRectF exposedRegionSceneBounds = q->mapToScene(exposedRegion.boundingRect().adjusted(-1, -1, 1, 1))
       
   997                                             .boundingRect();
       
   998     if (exposedRegionSceneBounds.contains(scene->sceneRect())) {
       
   999         Q_ASSERT(allItems);
       
  1000         *allItems = true;
       
  1001 
       
  1002         // All items are guaranteed within the exposed region.
       
  1003         return scene->items(Qt::AscendingOrder);
       
  1004     }
       
  1005 
       
  1006     // Step 2) If the expose region is a simple rect and the view is only
       
  1007     // translated or scaled, search for items using
       
  1008     // QGraphicsScene::items(QRectF).
       
  1009     bool simpleRectLookup =  exposedRegion.rectCount() == 1 && matrix.type() <= QTransform::TxScale;
       
  1010     if (simpleRectLookup) {
       
  1011         return scene->items(exposedRegionSceneBounds,
       
  1012                             Qt::IntersectsItemBoundingRect,
       
  1013                             Qt::AscendingOrder, viewTransform);
       
  1014     }
       
  1015 
       
  1016     // If the region is complex or the view has a complex transform, adjust
       
  1017     // the expose region, convert it to a path, and then search for items
       
  1018     // using QGraphicsScene::items(QPainterPath);
       
  1019     QRegion adjustedRegion;
       
  1020     foreach (const QRect &r, exposedRegion.rects())
       
  1021         adjustedRegion += r.adjusted(-1, -1, 1, 1);
       
  1022 
       
  1023     const QPainterPath exposedScenePath(q->mapToScene(qt_regionToPath(adjustedRegion)));
       
  1024     return scene->items(exposedScenePath, Qt::IntersectsItemBoundingRect,
       
  1025                         Qt::AscendingOrder, viewTransform);
       
  1026 }
       
  1027 
       
  1028 /*!
       
  1029     \internal
       
  1030 
       
  1031     Enables input methods for the view if and only if the current focus item of
       
  1032     the scene accepts input methods. Call function whenever that condition has
       
  1033     potentially changed.
       
  1034 */
       
  1035 void QGraphicsViewPrivate::updateInputMethodSensitivity()
       
  1036 {
       
  1037     Q_Q(QGraphicsView);
       
  1038     bool enabled = scene && scene->focusItem()
       
  1039                    && (scene->focusItem()->flags() & QGraphicsItem::ItemAcceptsInputMethod);
       
  1040     q->setAttribute(Qt::WA_InputMethodEnabled, enabled);
       
  1041     q->viewport()->setAttribute(Qt::WA_InputMethodEnabled, enabled);
       
  1042 }
       
  1043 
       
  1044 /*!
       
  1045     Constructs a QGraphicsView. \a parent is passed to QWidget's constructor.
       
  1046 */
       
  1047 QGraphicsView::QGraphicsView(QWidget *parent)
       
  1048     : QAbstractScrollArea(*new QGraphicsViewPrivate, parent)
       
  1049 {
       
  1050     setViewport(0);
       
  1051     setAcceptDrops(true);
       
  1052     setBackgroundRole(QPalette::Base);
       
  1053     // Investigate leaving these disabled by default.
       
  1054     setAttribute(Qt::WA_InputMethodEnabled);
       
  1055     viewport()->setAttribute(Qt::WA_InputMethodEnabled);
       
  1056 }
       
  1057 
       
  1058 /*!
       
  1059     Constructs a QGraphicsView and sets the visualized scene to \a
       
  1060     scene. \a parent is passed to QWidget's constructor.
       
  1061 */
       
  1062 QGraphicsView::QGraphicsView(QGraphicsScene *scene, QWidget *parent)
       
  1063     : QAbstractScrollArea(*new QGraphicsViewPrivate, parent)
       
  1064 {
       
  1065     setScene(scene);
       
  1066     setViewport(0);
       
  1067     setAcceptDrops(true);
       
  1068     setBackgroundRole(QPalette::Base);
       
  1069     // Investigate leaving these disabled by default.
       
  1070     setAttribute(Qt::WA_InputMethodEnabled);
       
  1071     viewport()->setAttribute(Qt::WA_InputMethodEnabled);
       
  1072 }
       
  1073 
       
  1074 /*!
       
  1075   \internal
       
  1076  */
       
  1077 QGraphicsView::QGraphicsView(QGraphicsViewPrivate &dd, QWidget *parent)
       
  1078   : QAbstractScrollArea(dd, parent)
       
  1079 {
       
  1080     setViewport(0);
       
  1081     setAcceptDrops(true);
       
  1082     setBackgroundRole(QPalette::Base);
       
  1083     // Investigate leaving these disabled by default.
       
  1084     setAttribute(Qt::WA_InputMethodEnabled);
       
  1085     viewport()->setAttribute(Qt::WA_InputMethodEnabled);
       
  1086 }
       
  1087 
       
  1088 /*!
       
  1089     Destructs the QGraphicsView object.
       
  1090 */
       
  1091 QGraphicsView::~QGraphicsView()
       
  1092 {
       
  1093     Q_D(QGraphicsView);
       
  1094     if (d->scene)
       
  1095         d->scene->d_func()->views.removeAll(this);
       
  1096     delete d->lastDragDropEvent;
       
  1097 }
       
  1098 
       
  1099 /*!
       
  1100     \reimp
       
  1101 */
       
  1102 QSize QGraphicsView::sizeHint() const
       
  1103 {
       
  1104     Q_D(const QGraphicsView);
       
  1105     if (d->scene) {
       
  1106         QSizeF baseSize = d->matrix.mapRect(sceneRect()).size();
       
  1107         baseSize += QSizeF(d->frameWidth * 2, d->frameWidth * 2);
       
  1108         return baseSize.boundedTo((3 * QApplication::desktop()->size()) / 4).toSize();
       
  1109     }
       
  1110     return QAbstractScrollArea::sizeHint();
       
  1111 }
       
  1112 
       
  1113 /*!
       
  1114     \property QGraphicsView::renderHints
       
  1115     \brief the default render hints for the view
       
  1116 
       
  1117     These hints are
       
  1118     used to initialize QPainter before each visible item is drawn. QPainter
       
  1119     uses render hints to toggle rendering features such as antialiasing and
       
  1120     smooth pixmap transformation.
       
  1121 
       
  1122     QPainter::TextAntialiasing is enabled by default.
       
  1123 
       
  1124     Example:
       
  1125 
       
  1126     \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsview.cpp 1
       
  1127 */
       
  1128 QPainter::RenderHints QGraphicsView::renderHints() const
       
  1129 {
       
  1130     Q_D(const QGraphicsView);
       
  1131     return d->renderHints;
       
  1132 }
       
  1133 void QGraphicsView::setRenderHints(QPainter::RenderHints hints)
       
  1134 {
       
  1135     Q_D(QGraphicsView);
       
  1136     if (hints == d->renderHints)
       
  1137         return;
       
  1138     d->renderHints = hints;
       
  1139     d->updateAll();
       
  1140 }
       
  1141 
       
  1142 /*!
       
  1143     If \a enabled is true, the render hint \a hint is enabled; otherwise it
       
  1144     is disabled.
       
  1145 
       
  1146     \sa renderHints
       
  1147 */
       
  1148 void QGraphicsView::setRenderHint(QPainter::RenderHint hint, bool enabled)
       
  1149 {
       
  1150     Q_D(QGraphicsView);
       
  1151     QPainter::RenderHints oldHints = d->renderHints;
       
  1152     if (enabled)
       
  1153         d->renderHints |= hint;
       
  1154     else
       
  1155         d->renderHints &= ~hint;
       
  1156     if (oldHints != d->renderHints)
       
  1157         d->updateAll();
       
  1158 }
       
  1159 
       
  1160 /*!
       
  1161     \property QGraphicsView::alignment
       
  1162     \brief the alignment of the scene in the view when the whole
       
  1163     scene is visible.
       
  1164 
       
  1165     If the whole scene is visible in the view, (i.e., there are no visible
       
  1166     scroll bars,) the view's alignment will decide where the scene will be
       
  1167     rendered in the view. For example, if the alignment is Qt::AlignCenter,
       
  1168     which is default, the scene will be centered in the view, and if the
       
  1169     alignment is (Qt::AlignLeft | Qt::AlignTop), the scene will be rendered in
       
  1170     the top-left corner of the view.
       
  1171 */
       
  1172 Qt::Alignment QGraphicsView::alignment() const
       
  1173 {
       
  1174     Q_D(const QGraphicsView);
       
  1175     return d->alignment;
       
  1176 }
       
  1177 void QGraphicsView::setAlignment(Qt::Alignment alignment)
       
  1178 {
       
  1179     Q_D(QGraphicsView);
       
  1180     if (d->alignment != alignment) {
       
  1181         d->alignment = alignment;
       
  1182         d->recalculateContentSize();
       
  1183     }
       
  1184 }
       
  1185 
       
  1186 /*!
       
  1187     \property QGraphicsView::transformationAnchor
       
  1188     \brief how the view should position the scene during transformations.
       
  1189 
       
  1190     QGraphicsView uses this property to decide how to position the scene in
       
  1191     the viewport when the transformation matrix changes, and the coordinate
       
  1192     system of the view is transformed. The default behavior, AnchorViewCenter,
       
  1193     ensures that the scene point at the center of the view remains unchanged
       
  1194     during transformations (e.g., when rotating, the scene will appear to
       
  1195     rotate around the center of the view).
       
  1196 
       
  1197     Note that the effect of this property is noticeable when only a part of the
       
  1198     scene is visible (i.e., when there are scroll bars). Otherwise, if the
       
  1199     whole scene fits in the view, QGraphicsScene uses the view \l alignment to
       
  1200     position the scene in the view.
       
  1201 
       
  1202     \sa alignment, resizeAnchor
       
  1203 */
       
  1204 QGraphicsView::ViewportAnchor QGraphicsView::transformationAnchor() const
       
  1205 {
       
  1206     Q_D(const QGraphicsView);
       
  1207     return d->transformationAnchor;
       
  1208 }
       
  1209 void QGraphicsView::setTransformationAnchor(ViewportAnchor anchor)
       
  1210 {
       
  1211     Q_D(QGraphicsView);
       
  1212     d->transformationAnchor = anchor;
       
  1213 
       
  1214     // Ensure mouse tracking is enabled in the case we are using AnchorUnderMouse
       
  1215     // in order to have up-to-date information for centering the view.
       
  1216     if (d->transformationAnchor == AnchorUnderMouse)
       
  1217         d->viewport->setMouseTracking(true);
       
  1218 }
       
  1219 
       
  1220 /*!
       
  1221     \property QGraphicsView::resizeAnchor
       
  1222     \brief how the view should position the scene when the view is resized.
       
  1223 
       
  1224     QGraphicsView uses this property to decide how to position the scene in
       
  1225     the viewport when the viewport widget's size changes. The default
       
  1226     behavior, NoAnchor, leaves the scene's position unchanged during a resize;
       
  1227     the top-left corner of the view will appear to be anchored while resizing.
       
  1228 
       
  1229     Note that the effect of this property is noticeable when only a part of the
       
  1230     scene is visible (i.e., when there are scroll bars). Otherwise, if the
       
  1231     whole scene fits in the view, QGraphicsScene uses the view \l alignment to
       
  1232     position the scene in the view.
       
  1233 
       
  1234     \sa alignment, transformationAnchor, Qt::WNorthWestGravity
       
  1235 */
       
  1236 QGraphicsView::ViewportAnchor QGraphicsView::resizeAnchor() const
       
  1237 {
       
  1238     Q_D(const QGraphicsView);
       
  1239     return d->resizeAnchor;
       
  1240 }
       
  1241 void QGraphicsView::setResizeAnchor(ViewportAnchor anchor)
       
  1242 {
       
  1243     Q_D(QGraphicsView);
       
  1244     d->resizeAnchor = anchor;
       
  1245 
       
  1246     // Ensure mouse tracking is enabled in the case we are using AnchorUnderMouse
       
  1247     // in order to have up-to-date information for centering the view.
       
  1248     if (d->resizeAnchor == AnchorUnderMouse)
       
  1249         d->viewport->setMouseTracking(true);
       
  1250 }
       
  1251 
       
  1252 /*!
       
  1253     \property QGraphicsView::viewportUpdateMode
       
  1254     \brief how the viewport should update its contents.
       
  1255 
       
  1256     \since 4.3
       
  1257 
       
  1258     QGraphicsView uses this property to decide how to update areas of the
       
  1259     scene that have been reexposed or changed. Usually you do not need to
       
  1260     modify this property, but there are some cases where doing so can improve
       
  1261     rendering performance. See the ViewportUpdateMode documentation for
       
  1262     specific details.
       
  1263 
       
  1264     The default value is MinimalViewportUpdate, where QGraphicsView will
       
  1265     update as small an area of the viewport as possible when the contents
       
  1266     change.
       
  1267 
       
  1268     \sa ViewportUpdateMode, cacheMode
       
  1269 */
       
  1270 QGraphicsView::ViewportUpdateMode QGraphicsView::viewportUpdateMode() const
       
  1271 {
       
  1272     Q_D(const QGraphicsView);
       
  1273     return d->viewportUpdateMode;
       
  1274 }
       
  1275 void QGraphicsView::setViewportUpdateMode(ViewportUpdateMode mode)
       
  1276 {
       
  1277     Q_D(QGraphicsView);
       
  1278     d->viewportUpdateMode = mode;
       
  1279 }
       
  1280 
       
  1281 /*!
       
  1282     \property QGraphicsView::optimizationFlags
       
  1283     \brief flags that can be used to tune QGraphicsView's performance.
       
  1284 
       
  1285     \since 4.3
       
  1286 
       
  1287     QGraphicsView uses clipping, extra bounding rect adjustments, and certain
       
  1288     other aids to improve rendering quality and performance for the common
       
  1289     case graphics scene. However, depending on the target platform, the scene,
       
  1290     and the viewport in use, some of these operations can degrade performance.
       
  1291 
       
  1292     The effect varies from flag to flag; see the OptimizationFlags
       
  1293     documentation for details.
       
  1294 
       
  1295     By default, no optimization flags are enabled.
       
  1296 
       
  1297     \sa setOptimizationFlag()
       
  1298 */
       
  1299 QGraphicsView::OptimizationFlags QGraphicsView::optimizationFlags() const
       
  1300 {
       
  1301     Q_D(const QGraphicsView);
       
  1302     return d->optimizationFlags;
       
  1303 }
       
  1304 void QGraphicsView::setOptimizationFlags(OptimizationFlags flags)
       
  1305 {
       
  1306     Q_D(QGraphicsView);
       
  1307     d->optimizationFlags = flags;
       
  1308 }
       
  1309 
       
  1310 /*!
       
  1311     Enables \a flag if \a enabled is true; otherwise disables \a flag.
       
  1312 
       
  1313     \sa optimizationFlags
       
  1314 */
       
  1315 void QGraphicsView::setOptimizationFlag(OptimizationFlag flag, bool enabled)
       
  1316 {
       
  1317     Q_D(QGraphicsView);
       
  1318     if (enabled)
       
  1319         d->optimizationFlags |= flag;
       
  1320     else
       
  1321         d->optimizationFlags &= ~flag;
       
  1322 }
       
  1323 
       
  1324 /*!
       
  1325     \property QGraphicsView::dragMode
       
  1326     \brief the behavior for dragging the mouse over the scene while
       
  1327     the left mouse button is pressed.
       
  1328 
       
  1329     This property defines what should happen when the user clicks on the scene
       
  1330     background and drags the mouse (e.g., scrolling the viewport contents
       
  1331     using a pointing hand cursor, or selecting multiple items with a rubber
       
  1332     band). The default value, NoDrag, does nothing.
       
  1333 
       
  1334     This behavior only affects mouse clicks that are not handled by any item.
       
  1335     You can define a custom behavior by creating a subclass of QGraphicsView
       
  1336     and reimplementing mouseMoveEvent().
       
  1337 */
       
  1338 QGraphicsView::DragMode QGraphicsView::dragMode() const
       
  1339 {
       
  1340     Q_D(const QGraphicsView);
       
  1341     return d->dragMode;
       
  1342 }
       
  1343 void QGraphicsView::setDragMode(DragMode mode)
       
  1344 {
       
  1345     Q_D(QGraphicsView);
       
  1346     if (d->dragMode == mode)
       
  1347         return;
       
  1348 
       
  1349 #ifndef QT_NO_CURSOR
       
  1350     if (d->dragMode == ScrollHandDrag)
       
  1351         viewport()->unsetCursor();
       
  1352 #endif
       
  1353 
       
  1354     // If dragMode is unset while dragging, e.g. via a keyEvent, we
       
  1355     // don't unset the handScrolling state. When enabling scrolling
       
  1356     // again the mouseMoveEvent will automatically start scrolling,
       
  1357     // without a mousePress
       
  1358     if (d->dragMode == ScrollHandDrag && mode == NoDrag && d->handScrolling)
       
  1359         d->handScrolling = false;
       
  1360 
       
  1361     d->dragMode = mode;
       
  1362 
       
  1363 #ifndef QT_NO_CURSOR
       
  1364     if (d->dragMode == ScrollHandDrag) {
       
  1365         // Forget the stored viewport cursor when we enter scroll hand drag mode.
       
  1366         d->hasStoredOriginalCursor = false;
       
  1367         viewport()->setCursor(Qt::OpenHandCursor);
       
  1368     }
       
  1369 #endif
       
  1370 }
       
  1371 
       
  1372 #ifndef QT_NO_RUBBERBAND
       
  1373 /*!
       
  1374     \property QGraphicsView::rubberBandSelectionMode
       
  1375     \brief the behavior for selecting items with a rubber band selection rectangle.
       
  1376     \since 4.3
       
  1377 
       
  1378     This property defines how items are selected when using the RubberBandDrag
       
  1379     drag mode.
       
  1380 
       
  1381     The default value is Qt::IntersectsItemShape; all items whose shape
       
  1382     intersects with or is contained by the rubber band are selected.
       
  1383 
       
  1384     \sa dragMode, items()
       
  1385 */
       
  1386 Qt::ItemSelectionMode QGraphicsView::rubberBandSelectionMode() const
       
  1387 {
       
  1388     Q_D(const QGraphicsView);
       
  1389     return d->rubberBandSelectionMode;
       
  1390 }
       
  1391 void QGraphicsView::setRubberBandSelectionMode(Qt::ItemSelectionMode mode)
       
  1392 {
       
  1393     Q_D(QGraphicsView);
       
  1394     d->rubberBandSelectionMode = mode;
       
  1395 }
       
  1396 #endif
       
  1397 
       
  1398 /*!
       
  1399     \property QGraphicsView::cacheMode
       
  1400     \brief which parts of the view are cached
       
  1401 
       
  1402     QGraphicsView can cache pre-rendered content in a QPixmap, which is then
       
  1403     drawn onto the viewport. The purpose of such caching is to speed up the
       
  1404     total rendering time for areas that are slow to render.  Texture, gradient
       
  1405     and alpha blended backgrounds, for example, can be notibly slow to render;
       
  1406     especially with a transformed view. The CacheBackground flag enables
       
  1407     caching of the view's background. For example:
       
  1408 
       
  1409     \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsview.cpp 2
       
  1410 
       
  1411     The cache is invalidated every time the view is transformed. However, when
       
  1412     scrolling, only partial invalidation is required.
       
  1413 
       
  1414     By default, nothing is cached.
       
  1415 
       
  1416     \sa resetCachedContent(), QPixmapCache
       
  1417 */
       
  1418 QGraphicsView::CacheMode QGraphicsView::cacheMode() const
       
  1419 {
       
  1420     Q_D(const QGraphicsView);
       
  1421     return d->cacheMode;
       
  1422 }
       
  1423 void QGraphicsView::setCacheMode(CacheMode mode)
       
  1424 {
       
  1425     Q_D(QGraphicsView);
       
  1426     if (mode == d->cacheMode)
       
  1427         return;
       
  1428     d->cacheMode = mode;
       
  1429     resetCachedContent();
       
  1430 }
       
  1431 
       
  1432 /*!
       
  1433     Resets any cached content. Calling this function will clear
       
  1434     QGraphicsView's cache. If the current cache mode is \l CacheNone, this
       
  1435     function does nothing.
       
  1436 
       
  1437     This function is called automatically for you when the backgroundBrush or
       
  1438     QGraphicsScene::backgroundBrush properties change; you only need to call
       
  1439     this function if you have reimplemented QGraphicsScene::drawBackground()
       
  1440     or QGraphicsView::drawBackground() to draw a custom background, and need
       
  1441     to trigger a full redraw.
       
  1442 
       
  1443     \sa cacheMode()
       
  1444 */
       
  1445 void QGraphicsView::resetCachedContent()
       
  1446 {
       
  1447     Q_D(QGraphicsView);
       
  1448     if (d->cacheMode == CacheNone)
       
  1449         return;
       
  1450 
       
  1451     if (d->cacheMode & CacheBackground) {
       
  1452         // Background caching is enabled.
       
  1453         d->mustResizeBackgroundPixmap = true;
       
  1454         d->updateAll();
       
  1455     } else if (d->mustResizeBackgroundPixmap) {
       
  1456         // Background caching is disabled.
       
  1457         // Cleanup, free some resources.
       
  1458         d->mustResizeBackgroundPixmap = false;
       
  1459         d->backgroundPixmap = QPixmap();
       
  1460         d->backgroundPixmapExposed = QRegion();
       
  1461     }
       
  1462 }
       
  1463 
       
  1464 /*!
       
  1465     Invalidates and schedules a redraw of \a layers inside \a rect. \a rect is
       
  1466     in scene coordinates. Any cached content for \a layers inside \a rect is
       
  1467     unconditionally invalidated and redrawn.
       
  1468 
       
  1469     You can call this function to notify QGraphicsView of changes to the
       
  1470     background or the foreground of the scene. It is commonly used for scenes
       
  1471     with tile-based backgrounds to notify changes when QGraphicsView has
       
  1472     enabled background caching.
       
  1473 
       
  1474     Note that QGraphicsView currently supports background caching only (see
       
  1475     QGraphicsView::CacheBackground). This function is equivalent to calling update() if any
       
  1476     layer but QGraphicsScene::BackgroundLayer is passed.
       
  1477 
       
  1478     \sa QGraphicsScene::invalidate(), update()
       
  1479 */
       
  1480 void QGraphicsView::invalidateScene(const QRectF &rect, QGraphicsScene::SceneLayers layers)
       
  1481 {
       
  1482     Q_D(QGraphicsView);
       
  1483     if ((layers & QGraphicsScene::BackgroundLayer) && !d->mustResizeBackgroundPixmap) {
       
  1484         QRect viewRect = mapFromScene(rect).boundingRect();
       
  1485         if (viewport()->rect().intersects(viewRect)) {
       
  1486             // The updated background area is exposed; schedule this area for
       
  1487             // redrawing.
       
  1488             d->backgroundPixmapExposed += viewRect;
       
  1489             if (d->scene)
       
  1490                 d->scene->update(rect);
       
  1491         }
       
  1492     }
       
  1493 }
       
  1494 
       
  1495 /*!
       
  1496     \property QGraphicsView::interactive
       
  1497     \brief whether the view allowed scene interaction.
       
  1498 
       
  1499     If enabled, this view is set to allow scene interaction. Otherwise, this
       
  1500     view will not allow interaction, and any mouse or key events are ignored
       
  1501     (i.e., it will act as a read-only view).
       
  1502 
       
  1503     By default, this property is true.
       
  1504 */
       
  1505 bool QGraphicsView::isInteractive() const
       
  1506 {
       
  1507     Q_D(const QGraphicsView);
       
  1508     return d->sceneInteractionAllowed;
       
  1509 }
       
  1510 void QGraphicsView::setInteractive(bool allowed)
       
  1511 {
       
  1512     Q_D(QGraphicsView);
       
  1513     d->sceneInteractionAllowed = allowed;
       
  1514 }
       
  1515 
       
  1516 /*!
       
  1517     Returns a pointer to the scene that is currently visualized in the
       
  1518     view. If no scene is currently visualized, 0 is returned.
       
  1519 
       
  1520     \sa setScene()
       
  1521 */
       
  1522 QGraphicsScene *QGraphicsView::scene() const
       
  1523 {
       
  1524     Q_D(const QGraphicsView);
       
  1525     return d->scene;
       
  1526 }
       
  1527 
       
  1528 /*!
       
  1529     Sets the current scene to \a scene. If \a scene is already being
       
  1530     viewed, this function does nothing.
       
  1531 
       
  1532     When a scene is set on a view, the QGraphicsScene::changed() signal
       
  1533     is automatically connected to this view's updateScene() slot, and the
       
  1534     view's scroll bars are adjusted to fit the size of the scene.
       
  1535 */
       
  1536 void QGraphicsView::setScene(QGraphicsScene *scene)
       
  1537 {
       
  1538     Q_D(QGraphicsView);
       
  1539     if (d->scene == scene)
       
  1540         return;
       
  1541 
       
  1542     // Always update the viewport when the scene changes.
       
  1543     d->updateAll();
       
  1544 
       
  1545     // Remove the previously assigned scene.
       
  1546     if (d->scene) {
       
  1547         disconnect(d->scene, SIGNAL(changed(QList<QRectF>)),
       
  1548                    this, SLOT(updateScene(QList<QRectF>)));
       
  1549         disconnect(d->scene, SIGNAL(sceneRectChanged(QRectF)),
       
  1550                    this, SLOT(updateSceneRect(QRectF)));
       
  1551         d->scene->d_func()->removeView(this);
       
  1552         d->connectedToScene = false;
       
  1553 
       
  1554         if (isActiveWindow() && isVisible()) {
       
  1555             QEvent windowDeactivate(QEvent::WindowDeactivate);
       
  1556             QApplication::sendEvent(d->scene, &windowDeactivate);
       
  1557         }
       
  1558         if(hasFocus())
       
  1559             d->scene->clearFocus();
       
  1560     }
       
  1561 
       
  1562     // Assign the new scene and update the contents (scrollbars, etc.)).
       
  1563     if ((d->scene = scene)) {
       
  1564         connect(d->scene, SIGNAL(sceneRectChanged(QRectF)),
       
  1565                 this, SLOT(updateSceneRect(QRectF)));
       
  1566         d->updateSceneSlotReimplementedChecked = false;
       
  1567         d->scene->d_func()->addView(this);
       
  1568         d->recalculateContentSize();
       
  1569         d->lastCenterPoint = sceneRect().center();
       
  1570         d->keepLastCenterPoint = true;
       
  1571         // We are only interested in mouse tracking if items accept
       
  1572         // hover events or use non-default cursors.
       
  1573         if (!d->scene->d_func()->allItemsIgnoreHoverEvents
       
  1574             || !d->scene->d_func()->allItemsUseDefaultCursor) {
       
  1575             d->viewport->setMouseTracking(true);
       
  1576         }
       
  1577 
       
  1578         // enable touch events if any items is interested in them
       
  1579         if (!d->scene->d_func()->allItemsIgnoreTouchEvents)
       
  1580             d->viewport->setAttribute(Qt::WA_AcceptTouchEvents);
       
  1581 
       
  1582         if (isActiveWindow() && isVisible()) {
       
  1583             QEvent windowActivate(QEvent::WindowActivate);
       
  1584             QApplication::sendEvent(d->scene, &windowActivate);
       
  1585         }
       
  1586     } else {
       
  1587         d->recalculateContentSize();
       
  1588     }
       
  1589 
       
  1590     d->updateInputMethodSensitivity();
       
  1591 
       
  1592     if (d->scene && hasFocus())
       
  1593         d->scene->setFocus();
       
  1594 }
       
  1595 
       
  1596 /*!
       
  1597     \property QGraphicsView::sceneRect
       
  1598     \brief the area of the scene visualized by this view.
       
  1599 
       
  1600     The scene rectangle defines the extent of the scene, and in the view's case,
       
  1601     this means the area of the scene that you can navigate using the scroll
       
  1602     bars.
       
  1603 
       
  1604     If unset, or if a null QRectF is set, this property has the same value as
       
  1605     QGraphicsScene::sceneRect, and it changes with
       
  1606     QGraphicsScene::sceneRect. Otherwise, the view's scene rect is unaffected
       
  1607     by the scene.
       
  1608 
       
  1609     Note that, although the scene supports a virtually unlimited size, the
       
  1610     range of the scroll bars will never exceed the range of an integer
       
  1611     (INT_MIN, INT_MAX). When the scene is larger than the scroll bars' values,
       
  1612     you can choose to use translate() to navigate the scene instead.
       
  1613 
       
  1614     By default, this property contains a rectangle at the origin with zero
       
  1615     width and height.
       
  1616 
       
  1617     \sa QGraphicsScene::sceneRect
       
  1618 */
       
  1619 QRectF QGraphicsView::sceneRect() const
       
  1620 {
       
  1621     Q_D(const QGraphicsView);
       
  1622     if (d->hasSceneRect)
       
  1623         return d->sceneRect;
       
  1624     if (d->scene)
       
  1625         return d->scene->sceneRect();
       
  1626     return QRectF();
       
  1627 }
       
  1628 void QGraphicsView::setSceneRect(const QRectF &rect)
       
  1629 {
       
  1630     Q_D(QGraphicsView);
       
  1631     d->hasSceneRect = !rect.isNull();
       
  1632     d->sceneRect = rect;
       
  1633     d->recalculateContentSize();
       
  1634 }
       
  1635 
       
  1636 /*!
       
  1637     Returns the current transformation matrix for the view. If no current
       
  1638     transformation is set, the identity matrix is returned.
       
  1639 
       
  1640     \sa setMatrix(), transform(), rotate(), scale(), shear(), translate()
       
  1641 */
       
  1642 QMatrix QGraphicsView::matrix() const
       
  1643 {
       
  1644     Q_D(const QGraphicsView);
       
  1645     return d->matrix.toAffine();
       
  1646 }
       
  1647 
       
  1648 /*!
       
  1649     Sets the view's current transformation matrix to \a matrix.
       
  1650 
       
  1651     If \a combine is true, then \a matrix is combined with the current matrix;
       
  1652     otherwise, \a matrix \e replaces the current matrix. \a combine is false
       
  1653     by default.
       
  1654 
       
  1655     The transformation matrix tranforms the scene into view coordinates. Using
       
  1656     the default transformation, provided by the identity matrix, one pixel in
       
  1657     the view represents one unit in the scene (e.g., a 10x10 rectangular item
       
  1658     is drawn using 10x10 pixels in the view). If a 2x2 scaling matrix is
       
  1659     applied, the scene will be drawn in 1:2 (e.g., a 10x10 rectangular item is
       
  1660     then drawn using 20x20 pixels in the view).
       
  1661 
       
  1662     Example:
       
  1663 
       
  1664     \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsview.cpp 3
       
  1665 
       
  1666     To simplify interation with items using a transformed view, QGraphicsView
       
  1667     provides mapTo... and mapFrom... functions that can translate between
       
  1668     scene and view coordinates. For example, you can call mapToScene() to map
       
  1669     a view coordinate to a floating point scene coordinate, or mapFromScene()
       
  1670     to map from floating point scene coordinates to view coordinates.
       
  1671 
       
  1672     \sa matrix(), setTransform(), rotate(), scale(), shear(), translate()
       
  1673 */
       
  1674 void QGraphicsView::setMatrix(const QMatrix &matrix, bool combine)
       
  1675 {
       
  1676     setTransform(QTransform(matrix), combine);
       
  1677 }
       
  1678 
       
  1679 /*!
       
  1680     Resets the view transformation matrix to the identity matrix.
       
  1681 
       
  1682     \sa resetTransform()
       
  1683 */
       
  1684 void QGraphicsView::resetMatrix()
       
  1685 {
       
  1686     resetTransform();
       
  1687 }
       
  1688 
       
  1689 /*!
       
  1690     Rotates the current view transformation \a angle degrees clockwise.
       
  1691 
       
  1692     \sa setTransform(), transform(), scale(), shear(), translate()
       
  1693 */
       
  1694 void QGraphicsView::rotate(qreal angle)
       
  1695 {
       
  1696     Q_D(QGraphicsView);
       
  1697     QTransform matrix = d->matrix;
       
  1698     matrix.rotate(angle);
       
  1699     setTransform(matrix);
       
  1700 }
       
  1701 
       
  1702 /*!
       
  1703     Scales the current view transformation by (\a sx, \a sy).
       
  1704 
       
  1705     \sa setTransform(), transform(), rotate(), shear(), translate()
       
  1706 */
       
  1707 void QGraphicsView::scale(qreal sx, qreal sy)
       
  1708 {
       
  1709     Q_D(QGraphicsView);
       
  1710     QTransform matrix = d->matrix;
       
  1711     matrix.scale(sx, sy);
       
  1712     setTransform(matrix);
       
  1713 }
       
  1714 
       
  1715 /*!
       
  1716     Shears the current view transformation by (\a sh, \a sv).
       
  1717 
       
  1718     \sa setTransform(), transform(), rotate(), scale(), translate()
       
  1719 */
       
  1720 void QGraphicsView::shear(qreal sh, qreal sv)
       
  1721 {
       
  1722     Q_D(QGraphicsView);
       
  1723     QTransform matrix = d->matrix;
       
  1724     matrix.shear(sh, sv);
       
  1725     setTransform(matrix);
       
  1726 }
       
  1727 
       
  1728 /*!
       
  1729     Translates the current view transformation by (\a dx, \a dy).
       
  1730 
       
  1731     \sa setTransform(), transform(), rotate(), shear()
       
  1732 */
       
  1733 void QGraphicsView::translate(qreal dx, qreal dy)
       
  1734 {
       
  1735     Q_D(QGraphicsView);
       
  1736     QTransform matrix = d->matrix;
       
  1737     matrix.translate(dx, dy);
       
  1738     setTransform(matrix);
       
  1739 }
       
  1740 
       
  1741 /*!
       
  1742     Scrolls the contents of the viewport to ensure that the scene
       
  1743     coordinate \a pos, is centered in the view.
       
  1744 
       
  1745     Because \a pos is a floating point coordinate, and the scroll bars operate
       
  1746     on integer coordinates, the centering is only an approximation.
       
  1747 
       
  1748     \note If the item is close to or outside the border, it will be visible
       
  1749     in the view, but not centered.
       
  1750 
       
  1751     \sa ensureVisible()
       
  1752 */
       
  1753 void QGraphicsView::centerOn(const QPointF &pos)
       
  1754 {
       
  1755     Q_D(QGraphicsView);
       
  1756     qreal width = viewport()->width();
       
  1757     qreal height = viewport()->height();
       
  1758     QPointF viewPoint = d->matrix.map(pos);
       
  1759     QPointF oldCenterPoint = pos;
       
  1760 
       
  1761     if (!d->leftIndent) {
       
  1762         if (isRightToLeft()) {
       
  1763             qint64 horizontal = 0;
       
  1764             horizontal += horizontalScrollBar()->minimum();
       
  1765             horizontal += horizontalScrollBar()->maximum();
       
  1766             horizontal -= int(viewPoint.x() - width / 2.0);
       
  1767             horizontalScrollBar()->setValue(horizontal);
       
  1768         } else {
       
  1769             horizontalScrollBar()->setValue(int(viewPoint.x() - width / 2.0));
       
  1770         }
       
  1771     }
       
  1772     if (!d->topIndent)
       
  1773         verticalScrollBar()->setValue(int(viewPoint.y() - height / 2.0));
       
  1774     d->lastCenterPoint = oldCenterPoint;
       
  1775 }
       
  1776 
       
  1777 /*!
       
  1778     \fn QGraphicsView::centerOn(qreal x, qreal y)
       
  1779     \overload
       
  1780 
       
  1781     This function is provided for convenience. It's equivalent to calling
       
  1782     centerOn(QPointF(\a x, \a y)).
       
  1783 */
       
  1784 
       
  1785 /*!
       
  1786     \overload
       
  1787 
       
  1788     Scrolls the contents of the viewport to ensure that \a item
       
  1789     is centered in the view.
       
  1790 
       
  1791     \sa ensureVisible()
       
  1792 */
       
  1793 void QGraphicsView::centerOn(const QGraphicsItem *item)
       
  1794 {
       
  1795     centerOn(item->sceneBoundingRect().center());
       
  1796 }
       
  1797 
       
  1798 /*!
       
  1799     Scrolls the contents of the viewport so that the scene rectangle \a rect
       
  1800     is visible, with margins specified in pixels by \a xmargin and \a
       
  1801     ymargin. If the specified rect cannot be reached, the contents are
       
  1802     scrolled to the nearest valid position. The default value for both margins
       
  1803     is 50 pixels.
       
  1804 
       
  1805     \sa centerOn()
       
  1806 */
       
  1807 void QGraphicsView::ensureVisible(const QRectF &rect, int xmargin, int ymargin)
       
  1808 {
       
  1809     Q_D(QGraphicsView);
       
  1810     Q_UNUSED(xmargin);
       
  1811     Q_UNUSED(ymargin);
       
  1812     qreal width = viewport()->width();
       
  1813     qreal height = viewport()->height();
       
  1814     QRectF viewRect = d->matrix.mapRect(rect);
       
  1815 
       
  1816     qreal left = d->horizontalScroll();
       
  1817     qreal right = left + width;
       
  1818     qreal top = d->verticalScroll();
       
  1819     qreal bottom = top + height;
       
  1820 
       
  1821     if (viewRect.left() <= left + xmargin) {
       
  1822         // need to scroll from the left
       
  1823         if (!d->leftIndent)
       
  1824             horizontalScrollBar()->setValue(int(viewRect.left() - xmargin - 0.5));
       
  1825     }
       
  1826     if (viewRect.right() >= right - xmargin) {
       
  1827         // need to scroll from the right
       
  1828         if (!d->leftIndent)
       
  1829             horizontalScrollBar()->setValue(int(viewRect.right() - width + xmargin + 0.5));
       
  1830     }
       
  1831     if (viewRect.top() <= top + ymargin) {
       
  1832         // need to scroll from the top
       
  1833         if (!d->topIndent)
       
  1834             verticalScrollBar()->setValue(int(viewRect.top() - ymargin - 0.5));
       
  1835     }
       
  1836     if (viewRect.bottom() >= bottom - ymargin) {
       
  1837         // need to scroll from the bottom
       
  1838         if (!d->topIndent)
       
  1839             verticalScrollBar()->setValue(int(viewRect.bottom() - height + ymargin + 0.5));
       
  1840     }
       
  1841 }
       
  1842 
       
  1843 /*!
       
  1844     \fn QGraphicsView::ensureVisible(qreal x, qreal y, qreal w, qreal h,
       
  1845     int xmargin, int ymargin)
       
  1846     \overload
       
  1847 
       
  1848     This function is provided for convenience. It's equivalent to calling
       
  1849     ensureVisible(QRectF(\a x, \a y, \a w, \a h), \a xmargin, \a ymargin).
       
  1850 */
       
  1851 
       
  1852 /*!
       
  1853     \overload
       
  1854 
       
  1855     Scrolls the contents of the viewport so that the center of item \a item is
       
  1856     visible, with margins specified in pixels by \a xmargin and \a ymargin. If
       
  1857     the specified point cannot be reached, the contents are scrolled to the
       
  1858     nearest valid position. The default value for both margins is 50 pixels.
       
  1859 
       
  1860     \sa centerOn()
       
  1861 */
       
  1862 void QGraphicsView::ensureVisible(const QGraphicsItem *item, int xmargin, int ymargin)
       
  1863 {
       
  1864     ensureVisible(item->sceneBoundingRect(), xmargin, ymargin);
       
  1865 }
       
  1866 
       
  1867 /*!
       
  1868     Scales the view matrix and scrolls the scroll bars to ensure that the
       
  1869     scene rectangle \a rect fits inside the viewport. \a rect must be inside
       
  1870     the scene rect; otherwise, fitInView() cannot guarantee that the whole
       
  1871     rect is visible.
       
  1872 
       
  1873     This function keeps the view's rotation, translation, or shear. The view
       
  1874     is scaled according to \a aspectRatioMode. \a rect will be centered in the
       
  1875     view if it does not fit tightly.
       
  1876 
       
  1877     It's common to call fitInView() from inside a reimplementation of
       
  1878     resizeEvent(), to ensure that the whole scene, or parts of the scene,
       
  1879     scales automatically to fit the new size of the viewport as the view is
       
  1880     resized. Note though, that calling fitInView() from inside resizeEvent()
       
  1881     can lead to unwanted resize recursion, if the new transformation toggles
       
  1882     the automatic state of the scrollbars. You can toggle the scrollbar
       
  1883     policies to always on or always off to prevent this (see
       
  1884     horizontalScrollBarPolicy() and verticalScrollBarPolicy()).
       
  1885 
       
  1886     If \a rect is empty, or if the viewport is too small, this
       
  1887     function will do nothing.
       
  1888 
       
  1889     \sa setTransform(), ensureVisible(), centerOn()
       
  1890 */
       
  1891 void QGraphicsView::fitInView(const QRectF &rect, Qt::AspectRatioMode aspectRatioMode)
       
  1892 {
       
  1893     Q_D(QGraphicsView);
       
  1894     if (!d->scene || rect.isNull())
       
  1895         return;
       
  1896 
       
  1897     // Reset the view scale to 1:1.
       
  1898     QRectF unity = d->matrix.mapRect(QRectF(0, 0, 1, 1));
       
  1899     if (unity.isEmpty())
       
  1900         return;
       
  1901     scale(1 / unity.width(), 1 / unity.height());
       
  1902 
       
  1903     // Find the ideal x / y scaling ratio to fit \a rect in the view.
       
  1904     int margin = 2;
       
  1905     QRectF viewRect = viewport()->rect().adjusted(margin, margin, -margin, -margin);
       
  1906     if (viewRect.isEmpty())
       
  1907         return;
       
  1908     QRectF sceneRect = d->matrix.mapRect(rect);
       
  1909     if (sceneRect.isEmpty())
       
  1910         return;
       
  1911     qreal xratio = viewRect.width() / sceneRect.width();
       
  1912     qreal yratio = viewRect.height() / sceneRect.height();
       
  1913 
       
  1914     // Respect the aspect ratio mode.
       
  1915     switch (aspectRatioMode) {
       
  1916     case Qt::KeepAspectRatio:
       
  1917         xratio = yratio = qMin(xratio, yratio);
       
  1918         break;
       
  1919     case Qt::KeepAspectRatioByExpanding:
       
  1920         xratio = yratio = qMax(xratio, yratio);
       
  1921         break;
       
  1922     case Qt::IgnoreAspectRatio:
       
  1923         break;
       
  1924     }
       
  1925 
       
  1926     // Scale and center on the center of \a rect.
       
  1927     scale(xratio, yratio);
       
  1928     centerOn(rect.center());
       
  1929 }
       
  1930 
       
  1931 /*!
       
  1932     \fn void QGraphicsView::fitInView(qreal x, qreal y, qreal w, qreal h,
       
  1933     Qt::AspectRatioMode aspectRatioMode = Qt::IgnoreAspectRatio)
       
  1934 
       
  1935     \overload
       
  1936 
       
  1937     This convenience function is equivalent to calling
       
  1938     fitInView(QRectF(\a x, \a y, \a w, \a h), \a aspectRatioMode).
       
  1939 
       
  1940     \sa ensureVisible(), centerOn()
       
  1941 */
       
  1942 
       
  1943 /*!
       
  1944     \overload
       
  1945 
       
  1946     Ensures that \a item fits tightly inside the view, scaling the view
       
  1947     according to \a aspectRatioMode.
       
  1948 
       
  1949     \sa ensureVisible(), centerOn()
       
  1950 */
       
  1951 void QGraphicsView::fitInView(const QGraphicsItem *item, Qt::AspectRatioMode aspectRatioMode)
       
  1952 {
       
  1953     QPainterPath path = item->isClipped() ? item->clipPath() : item->shape();
       
  1954     if (item->d_ptr->hasTranslateOnlySceneTransform()) {
       
  1955         path.translate(item->d_ptr->sceneTransform.dx(), item->d_ptr->sceneTransform.dy());
       
  1956         fitInView(path.boundingRect(), aspectRatioMode);
       
  1957     } else {
       
  1958         fitInView(item->d_ptr->sceneTransform.map(path).boundingRect(), aspectRatioMode);
       
  1959     }
       
  1960 }
       
  1961 
       
  1962 /*!
       
  1963     Renders the \a source rect, which is in view coordinates, from the scene
       
  1964     into \a target, which is in paint device coordinates, using \a
       
  1965     painter. This function is useful for capturing the contents of the view
       
  1966     onto a paint device, such as a QImage (e.g., to take a screenshot), or for
       
  1967     printing to QPrinter. For example:
       
  1968 
       
  1969     \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsview.cpp 4
       
  1970 
       
  1971     If \a source is a null rect, this function will use viewport()->rect() to
       
  1972     determine what to draw. If \a target is a null rect, the full dimensions
       
  1973     of \a painter's paint device (e.g., for a QPrinter, the page size) will be
       
  1974     used.
       
  1975 
       
  1976     The source rect contents will be transformed according to \a
       
  1977     aspectRatioMode to fit into the target rect. By default, the aspect ratio
       
  1978     is kept, and \a source is scaled to fit in \a target.
       
  1979 
       
  1980     \sa QGraphicsScene::render()
       
  1981 */
       
  1982 void QGraphicsView::render(QPainter *painter, const QRectF &target, const QRect &source,
       
  1983                            Qt::AspectRatioMode aspectRatioMode)
       
  1984 {
       
  1985     // ### Switch to using the recursive rendering algorithm instead.
       
  1986 
       
  1987     Q_D(QGraphicsView);
       
  1988     if (!d->scene || !(painter && painter->isActive()))
       
  1989         return;
       
  1990 
       
  1991     // Default source rect = viewport rect
       
  1992     QRect sourceRect = source;
       
  1993     if (source.isNull())
       
  1994         sourceRect = viewport()->rect();
       
  1995 
       
  1996     // Default target rect = device rect
       
  1997     QRectF targetRect = target;
       
  1998     if (target.isNull()) {
       
  1999         if (painter->device()->devType() == QInternal::Picture)
       
  2000             targetRect = sourceRect;
       
  2001         else
       
  2002             targetRect.setRect(0, 0, painter->device()->width(), painter->device()->height());
       
  2003     }
       
  2004 
       
  2005     // Find the ideal x / y scaling ratio to fit \a source into \a target.
       
  2006     qreal xratio = targetRect.width() / sourceRect.width();
       
  2007     qreal yratio = targetRect.height() / sourceRect.height();
       
  2008 
       
  2009     // Scale according to the aspect ratio mode.
       
  2010     switch (aspectRatioMode) {
       
  2011     case Qt::KeepAspectRatio:
       
  2012         xratio = yratio = qMin(xratio, yratio);
       
  2013         break;
       
  2014     case Qt::KeepAspectRatioByExpanding:
       
  2015         xratio = yratio = qMax(xratio, yratio);
       
  2016         break;
       
  2017     case Qt::IgnoreAspectRatio:
       
  2018         break;
       
  2019     }
       
  2020 
       
  2021     // Find all items to draw, and reverse the list (we want to draw
       
  2022     // in reverse order).
       
  2023     QPolygonF sourceScenePoly = mapToScene(sourceRect.adjusted(-1, -1, 1, 1));
       
  2024     QList<QGraphicsItem *> itemList = d->scene->items(sourceScenePoly,
       
  2025                                                       Qt::IntersectsItemBoundingRect);
       
  2026     QGraphicsItem **itemArray = new QGraphicsItem *[itemList.size()];
       
  2027     int numItems = itemList.size();
       
  2028     for (int i = 0; i < numItems; ++i)
       
  2029         itemArray[numItems - i - 1] = itemList.at(i);
       
  2030     itemList.clear();
       
  2031 
       
  2032     // Setup painter matrix.
       
  2033     QTransform moveMatrix = QTransform::fromTranslate(-d->horizontalScroll(), -d->verticalScroll());
       
  2034     QTransform painterMatrix = d->matrix * moveMatrix;
       
  2035     painterMatrix *= QTransform()
       
  2036                      .translate(targetRect.left(), targetRect.top())
       
  2037                      .scale(xratio, yratio)
       
  2038                      .translate(-sourceRect.left(), -sourceRect.top());
       
  2039 
       
  2040     // Generate the style options
       
  2041     QStyleOptionGraphicsItem *styleOptionArray = d->allocStyleOptionsArray(numItems);
       
  2042     for (int i = 0; i < numItems; ++i)
       
  2043         itemArray[i]->d_ptr->initStyleOption(&styleOptionArray[i], painterMatrix, targetRect.toRect());
       
  2044 
       
  2045     painter->save();
       
  2046 
       
  2047     // Clip in device coordinates to avoid QRegion transformations.
       
  2048     painter->setClipRect(targetRect);
       
  2049     QPainterPath path;
       
  2050     path.addPolygon(sourceScenePoly);
       
  2051     path.closeSubpath();
       
  2052     painter->setClipPath(painterMatrix.map(path), Qt::IntersectClip);
       
  2053 
       
  2054     // Transform the painter.
       
  2055     painter->setTransform(painterMatrix, true);
       
  2056 
       
  2057     // Render the scene.
       
  2058     QRectF sourceSceneRect = sourceScenePoly.boundingRect();
       
  2059     drawBackground(painter, sourceSceneRect);
       
  2060     drawItems(painter, numItems, itemArray, styleOptionArray);
       
  2061     drawForeground(painter, sourceSceneRect);
       
  2062 
       
  2063     delete [] itemArray;
       
  2064     d->freeStyleOptionsArray(styleOptionArray);
       
  2065 
       
  2066     painter->restore();
       
  2067 }
       
  2068 
       
  2069 /*!
       
  2070     Returns a list of all the items in the associated scene, in descending
       
  2071     stacking order (i.e., the first item in the returned list is the uppermost
       
  2072     item).
       
  2073 
       
  2074     \sa QGraphicsScene::items(), {QGraphicsItem#Sorting}{Sorting}
       
  2075 */
       
  2076 QList<QGraphicsItem *> QGraphicsView::items() const
       
  2077 {
       
  2078     Q_D(const QGraphicsView);
       
  2079     if (!d->scene)
       
  2080         return QList<QGraphicsItem *>();
       
  2081     return d->scene->items();
       
  2082 }
       
  2083 
       
  2084 /*!
       
  2085     Returns a list of all the items at the position \a pos in the view. The
       
  2086     items are listed in descending stacking order (i.e., the first item in the
       
  2087     list is the uppermost item, and the last item is the lowermost item). \a
       
  2088     pos is in viewport coordinates.
       
  2089 
       
  2090     This function is most commonly called from within mouse event handlers in
       
  2091     a subclass in QGraphicsView. \a pos is in untransformed viewport
       
  2092     coordinates, just like QMouseEvent::pos().
       
  2093 
       
  2094     \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsview.cpp 5
       
  2095 
       
  2096     \sa QGraphicsScene::items(), {QGraphicsItem#Sorting}{Sorting}
       
  2097 */
       
  2098 QList<QGraphicsItem *> QGraphicsView::items(const QPoint &pos) const
       
  2099 {
       
  2100     Q_D(const QGraphicsView);
       
  2101     if (!d->scene)
       
  2102         return QList<QGraphicsItem *>();
       
  2103     // ### Unify these two, and use the items(QPointF) version in
       
  2104     // QGraphicsScene instead. The scene items function could use the viewport
       
  2105     // transform to map the point to a rect/polygon.
       
  2106     if ((d->identityMatrix || d->matrix.type() <= QTransform::TxScale)) {
       
  2107         // Use the rect version
       
  2108         QTransform xinv = viewportTransform().inverted();
       
  2109         return d->scene->items(xinv.mapRect(QRectF(pos.x(), pos.y(), 1, 1)),
       
  2110                                Qt::IntersectsItemShape,
       
  2111                                Qt::DescendingOrder,
       
  2112                                viewportTransform());
       
  2113     }
       
  2114     // Use the polygon version
       
  2115     return d->scene->items(mapToScene(pos.x(), pos.y(), 1, 1),
       
  2116                            Qt::IntersectsItemShape,
       
  2117                            Qt::DescendingOrder,
       
  2118                            viewportTransform());
       
  2119 }
       
  2120 
       
  2121 /*!
       
  2122     \fn QGraphicsView::items(int x, int y) const
       
  2123 
       
  2124     This function is provided for convenience. It's equivalent to calling
       
  2125     items(QPoint(\a x, \a y)).
       
  2126 */
       
  2127 
       
  2128 /*!
       
  2129     \overload
       
  2130 
       
  2131     Returns a list of all the items that, depending on \a mode, are either
       
  2132     contained by or intersect with \a rect. \a rect is in viewport
       
  2133     coordinates.
       
  2134 
       
  2135     The default value for \a mode is Qt::IntersectsItemShape; all items whose
       
  2136     exact shape intersects with or is contained by \a rect are returned.
       
  2137 
       
  2138     The items are sorted in descending stacking order (i.e., the first item in
       
  2139     the returned list is the uppermost item).
       
  2140 
       
  2141     \sa itemAt(), items(), mapToScene(), {QGraphicsItem#Sorting}{Sorting}
       
  2142 */
       
  2143 QList<QGraphicsItem *> QGraphicsView::items(const QRect &rect, Qt::ItemSelectionMode mode) const
       
  2144 {
       
  2145     Q_D(const QGraphicsView);
       
  2146     if (!d->scene)
       
  2147         return QList<QGraphicsItem *>();
       
  2148     return d->scene->items(mapToScene(rect), mode, Qt::DescendingOrder, viewportTransform());
       
  2149 }
       
  2150 
       
  2151 /*!
       
  2152     \fn QList<QGraphicsItem *> QGraphicsView::items(int x, int y, int w, int h, Qt::ItemSelectionMode mode) const
       
  2153     \since 4.3
       
  2154 
       
  2155     This convenience function is equivalent to calling items(QRectF(\a x, \a
       
  2156     y, \a w, \a h), \a mode).
       
  2157 */
       
  2158 
       
  2159 /*!
       
  2160     \overload
       
  2161 
       
  2162     Returns a list of all the items that, depending on \a mode, are either
       
  2163     contained by or intersect with \a polygon. \a polygon is in viewport
       
  2164     coordinates.
       
  2165 
       
  2166     The default value for \a mode is Qt::IntersectsItemShape; all items whose
       
  2167     exact shape intersects with or is contained by \a polygon are returned.
       
  2168 
       
  2169     The items are sorted by descending stacking order (i.e., the first item in
       
  2170     the returned list is the uppermost item).
       
  2171 
       
  2172     \sa itemAt(), items(), mapToScene(), {QGraphicsItem#Sorting}{Sorting}
       
  2173 */
       
  2174 QList<QGraphicsItem *> QGraphicsView::items(const QPolygon &polygon, Qt::ItemSelectionMode mode) const
       
  2175 {
       
  2176     Q_D(const QGraphicsView);
       
  2177     if (!d->scene)
       
  2178         return QList<QGraphicsItem *>();
       
  2179     return d->scene->items(mapToScene(polygon), mode, Qt::DescendingOrder, viewportTransform());
       
  2180 }
       
  2181 
       
  2182 /*!
       
  2183     \overload
       
  2184 
       
  2185     Returns a list of all the items that, depending on \a mode, are either
       
  2186     contained by or intersect with \a path. \a path is in viewport
       
  2187     coordinates.
       
  2188 
       
  2189     The default value for \a mode is Qt::IntersectsItemShape; all items whose
       
  2190     exact shape intersects with or is contained by \a path are returned.
       
  2191 
       
  2192     \sa itemAt(), items(), mapToScene(), {QGraphicsItem#Sorting}{Sorting}
       
  2193 */
       
  2194 QList<QGraphicsItem *> QGraphicsView::items(const QPainterPath &path, Qt::ItemSelectionMode mode) const
       
  2195 {
       
  2196     Q_D(const QGraphicsView);
       
  2197     if (!d->scene)
       
  2198         return QList<QGraphicsItem *>();
       
  2199     return d->scene->items(mapToScene(path), mode, Qt::DescendingOrder, viewportTransform());
       
  2200 }
       
  2201 
       
  2202 /*!
       
  2203     Returns the item at position \a pos, which is in viewport coordinates.
       
  2204     If there are several items at this position, this function returns
       
  2205     the topmost item.
       
  2206 
       
  2207     Example:
       
  2208 
       
  2209     \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsview.cpp 6
       
  2210 
       
  2211     \sa items(), {QGraphicsItem#Sorting}{Sorting}
       
  2212 */
       
  2213 QGraphicsItem *QGraphicsView::itemAt(const QPoint &pos) const
       
  2214 {
       
  2215     Q_D(const QGraphicsView);
       
  2216     if (!d->scene)
       
  2217         return 0;
       
  2218     QList<QGraphicsItem *> itemsAtPos = items(pos);
       
  2219     return itemsAtPos.isEmpty() ? 0 : itemsAtPos.first();
       
  2220 }
       
  2221 
       
  2222 /*!
       
  2223     \overload
       
  2224     \fn QGraphicsItem *QGraphicsView::itemAt(int x, int y) const
       
  2225 
       
  2226     This function is provided for convenience. It's equivalent to
       
  2227     calling itemAt(QPoint(\a x, \a y)).
       
  2228 */
       
  2229 
       
  2230 /*!
       
  2231     Returns the viewport coordinate \a point mapped to scene coordinates.
       
  2232 
       
  2233     Note: It can be useful to map the whole rectangle covered by the pixel at
       
  2234     \a point instead of the point itself. To do this, you can call
       
  2235     mapToScene(QRect(\a point, QSize(2, 2))).
       
  2236 
       
  2237     \sa mapFromScene()
       
  2238 */
       
  2239 QPointF QGraphicsView::mapToScene(const QPoint &point) const
       
  2240 {
       
  2241     Q_D(const QGraphicsView);
       
  2242     QPointF p = point;
       
  2243     p.rx() += d->horizontalScroll();
       
  2244     p.ry() += d->verticalScroll();
       
  2245     return d->identityMatrix ? p : d->matrix.inverted().map(p);
       
  2246 }
       
  2247 
       
  2248 /*!
       
  2249     \fn QGraphicsView::mapToScene(int x, int y) const
       
  2250 
       
  2251     This function is provided for convenience. It's equivalent to calling
       
  2252     mapToScene(QPoint(\a x, \a y)).
       
  2253 */
       
  2254 
       
  2255 /*!
       
  2256     Returns the viewport rectangle \a rect mapped to a scene coordinate
       
  2257     polygon.
       
  2258 
       
  2259     \sa mapFromScene()
       
  2260 */
       
  2261 QPolygonF QGraphicsView::mapToScene(const QRect &rect) const
       
  2262 {
       
  2263     Q_D(const QGraphicsView);
       
  2264     if (!rect.isValid())
       
  2265         return QPolygonF();
       
  2266 
       
  2267     QPointF scrollOffset(d->horizontalScroll(), d->verticalScroll());
       
  2268     QRect r = rect.adjusted(0, 0, 1, 1);
       
  2269     QPointF tl = scrollOffset + r.topLeft();
       
  2270     QPointF tr = scrollOffset + r.topRight();
       
  2271     QPointF br = scrollOffset + r.bottomRight();
       
  2272     QPointF bl = scrollOffset + r.bottomLeft();
       
  2273 
       
  2274     QPolygonF poly(4);
       
  2275     if (!d->identityMatrix) {
       
  2276         QTransform x = d->matrix.inverted();
       
  2277         poly[0] = x.map(tl);
       
  2278         poly[1] = x.map(tr);
       
  2279         poly[2] = x.map(br);
       
  2280         poly[3] = x.map(bl);
       
  2281     } else {
       
  2282         poly[0] = tl;
       
  2283         poly[1] = tr;
       
  2284         poly[2] = br;
       
  2285         poly[3] = bl;
       
  2286     }
       
  2287     return poly;
       
  2288 }
       
  2289 
       
  2290 /*!
       
  2291     \fn QGraphicsView::mapToScene(int x, int y, int w, int h) const
       
  2292 
       
  2293     This function is provided for convenience. It's equivalent to calling
       
  2294     mapToScene(QRect(\a x, \a y, \a w, \a h)).
       
  2295 */
       
  2296 
       
  2297 /*!
       
  2298     Returns the viewport polygon \a polygon mapped to a scene coordinate
       
  2299     polygon.
       
  2300 
       
  2301     \sa mapFromScene()
       
  2302 */
       
  2303 QPolygonF QGraphicsView::mapToScene(const QPolygon &polygon) const
       
  2304 {
       
  2305     QPolygonF poly;
       
  2306     foreach (const QPoint &point, polygon)
       
  2307         poly << mapToScene(point);
       
  2308     return poly;
       
  2309 }
       
  2310 
       
  2311 /*!
       
  2312     Returns the viewport painter path \a path mapped to a scene coordinate
       
  2313     painter path.
       
  2314 
       
  2315     \sa mapFromScene()
       
  2316 */
       
  2317 QPainterPath QGraphicsView::mapToScene(const QPainterPath &path) const
       
  2318 {
       
  2319     Q_D(const QGraphicsView);
       
  2320     QTransform matrix = QTransform::fromTranslate(d->horizontalScroll(), d->verticalScroll());
       
  2321     matrix *= d->matrix.inverted();
       
  2322     return matrix.map(path);
       
  2323 }
       
  2324 
       
  2325 /*!
       
  2326     Returns the scene coordinate \a point to viewport coordinates.
       
  2327 
       
  2328     \sa mapToScene()
       
  2329 */
       
  2330 QPoint QGraphicsView::mapFromScene(const QPointF &point) const
       
  2331 {
       
  2332     Q_D(const QGraphicsView);
       
  2333     QPointF p = d->identityMatrix ? point : d->matrix.map(point);
       
  2334     p.rx() -= d->horizontalScroll();
       
  2335     p.ry() -= d->verticalScroll();
       
  2336     return p.toPoint();
       
  2337 }
       
  2338 
       
  2339 /*!
       
  2340     \fn QGraphicsView::mapFromScene(qreal x, qreal y) const
       
  2341 
       
  2342     This function is provided for convenience. It's equivalent to
       
  2343     calling mapFromScene(QPointF(\a x, \a y)).
       
  2344 */
       
  2345 
       
  2346 /*!
       
  2347     Returns the scene rectangle \a rect to a viewport coordinate
       
  2348     polygon.
       
  2349 
       
  2350     \sa mapToScene()
       
  2351 */
       
  2352 QPolygon QGraphicsView::mapFromScene(const QRectF &rect) const
       
  2353 {
       
  2354     Q_D(const QGraphicsView);
       
  2355     QPointF tl;
       
  2356     QPointF tr;
       
  2357     QPointF br;
       
  2358     QPointF bl;
       
  2359     if (!d->identityMatrix) {
       
  2360         const QTransform &x = d->matrix;
       
  2361         tl = x.map(rect.topLeft());
       
  2362         tr = x.map(rect.topRight());
       
  2363         br = x.map(rect.bottomRight());
       
  2364         bl = x.map(rect.bottomLeft());
       
  2365     } else {
       
  2366         tl = rect.topLeft();
       
  2367         tr = rect.topRight();
       
  2368         br = rect.bottomRight();
       
  2369         bl = rect.bottomLeft();
       
  2370     }
       
  2371     QPointF scrollOffset(d->horizontalScroll(), d->verticalScroll());
       
  2372     tl -= scrollOffset;
       
  2373     tr -= scrollOffset;
       
  2374     br -= scrollOffset;
       
  2375     bl -= scrollOffset;
       
  2376 
       
  2377     QPolygon poly(4);
       
  2378     poly[0] = tl.toPoint();
       
  2379     poly[1] = tr.toPoint();
       
  2380     poly[2] = br.toPoint();
       
  2381     poly[3] = bl.toPoint();
       
  2382     return poly;
       
  2383 }
       
  2384 
       
  2385 /*!
       
  2386     \fn QGraphicsView::mapFromScene(qreal x, qreal y, qreal w, qreal h) const
       
  2387 
       
  2388     This function is provided for convenience. It's equivalent to
       
  2389     calling mapFromScene(QRectF(\a x, \a y, \a w, \a h)).
       
  2390 */
       
  2391 
       
  2392 /*!
       
  2393     Returns the scene coordinate polygon \a polygon to a viewport coordinate
       
  2394     polygon.
       
  2395 
       
  2396     \sa mapToScene()
       
  2397 */
       
  2398 QPolygon QGraphicsView::mapFromScene(const QPolygonF &polygon) const
       
  2399 {
       
  2400     QPolygon poly;
       
  2401     foreach (const QPointF &point, polygon)
       
  2402         poly << mapFromScene(point);
       
  2403     return poly;
       
  2404 }
       
  2405 
       
  2406 /*!
       
  2407     Returns the scene coordinate painter path \a path to a viewport coordinate
       
  2408     painter path.
       
  2409 
       
  2410     \sa mapToScene()
       
  2411 */
       
  2412 QPainterPath QGraphicsView::mapFromScene(const QPainterPath &path) const
       
  2413 {
       
  2414     Q_D(const QGraphicsView);
       
  2415     QTransform matrix = d->matrix;
       
  2416     matrix *= QTransform::fromTranslate(-d->horizontalScroll(), -d->verticalScroll());
       
  2417     return matrix.map(path);
       
  2418 }
       
  2419 
       
  2420 /*!
       
  2421     \reimp
       
  2422 */
       
  2423 QVariant QGraphicsView::inputMethodQuery(Qt::InputMethodQuery query) const
       
  2424 {
       
  2425     Q_D(const QGraphicsView);
       
  2426     if (!d->scene)
       
  2427         return QVariant();
       
  2428 
       
  2429     QVariant value = d->scene->inputMethodQuery(query);
       
  2430     if (value.type() == QVariant::RectF)
       
  2431         value = mapFromScene(value.toRectF()).boundingRect();
       
  2432     else if (value.type() == QVariant::PointF)
       
  2433         value = mapFromScene(value.toPointF());
       
  2434     else if (value.type() == QVariant::Rect)
       
  2435         value = mapFromScene(value.toRect()).boundingRect();
       
  2436     else if (value.type() == QVariant::Point)
       
  2437         value = mapFromScene(value.toPoint());
       
  2438     return value;
       
  2439 }
       
  2440 
       
  2441 /*!
       
  2442     \property QGraphicsView::backgroundBrush
       
  2443     \brief the background brush of the scene.
       
  2444 
       
  2445     This property sets the background brush for the scene in this view. It is
       
  2446     used to override the scene's own background, and defines the behavior of
       
  2447     drawBackground(). To provide custom background drawing for this view, you
       
  2448     can reimplement drawBackground() instead.
       
  2449 
       
  2450     By default, this property contains a brush with the Qt::NoBrush pattern.
       
  2451 
       
  2452     \sa QGraphicsScene::backgroundBrush, foregroundBrush
       
  2453 */
       
  2454 QBrush QGraphicsView::backgroundBrush() const
       
  2455 {
       
  2456     Q_D(const QGraphicsView);
       
  2457     return d->backgroundBrush;
       
  2458 }
       
  2459 void QGraphicsView::setBackgroundBrush(const QBrush &brush)
       
  2460 {
       
  2461     Q_D(QGraphicsView);
       
  2462     d->backgroundBrush = brush;
       
  2463     d->updateAll();
       
  2464 
       
  2465     if (d->cacheMode & CacheBackground) {
       
  2466         // Invalidate the background pixmap
       
  2467         d->mustResizeBackgroundPixmap = true;
       
  2468     }
       
  2469 }
       
  2470 
       
  2471 /*!
       
  2472     \property QGraphicsView::foregroundBrush
       
  2473     \brief the foreground brush of the scene.
       
  2474 
       
  2475     This property sets the foreground brush for the scene in this view. It is
       
  2476     used to override the scene's own foreground, and defines the behavior of
       
  2477     drawForeground(). To provide custom foreground drawing for this view, you
       
  2478     can reimplement drawForeground() instead.
       
  2479 
       
  2480     By default, this property contains a brush with the Qt::NoBrush pattern.
       
  2481 
       
  2482     \sa QGraphicsScene::foregroundBrush, backgroundBrush
       
  2483 */
       
  2484 QBrush QGraphicsView::foregroundBrush() const
       
  2485 {
       
  2486     Q_D(const QGraphicsView);
       
  2487     return d->foregroundBrush;
       
  2488 }
       
  2489 void QGraphicsView::setForegroundBrush(const QBrush &brush)
       
  2490 {
       
  2491     Q_D(QGraphicsView);
       
  2492     d->foregroundBrush = brush;
       
  2493     d->updateAll();
       
  2494 }
       
  2495 
       
  2496 /*!
       
  2497     Schedules an update of the scene rectangles \a rects.
       
  2498 
       
  2499     \sa QGraphicsScene::changed()
       
  2500 */
       
  2501 void QGraphicsView::updateScene(const QList<QRectF> &rects)
       
  2502 {
       
  2503     // ### Note: Since 4.5, this slot is only called if the user explicitly
       
  2504     // establishes a connection between the scene and the view, as the scene
       
  2505     // and view are no longer connected. We need to keep it working (basically
       
  2506     // leave it as it is), but the new delivery path is through
       
  2507     // QGraphicsScenePrivate::itemUpdate().
       
  2508     Q_D(QGraphicsView);
       
  2509     if (d->fullUpdatePending || d->viewportUpdateMode == QGraphicsView::NoViewportUpdate)
       
  2510         return;
       
  2511 
       
  2512     // Extract and reset dirty scene rect info.
       
  2513     QVector<QRect> dirtyViewportRects;
       
  2514     const QVector<QRect> &dirtyRects = d->dirtyRegion.rects();
       
  2515     for (int i = 0; i < dirtyRects.size(); ++i)
       
  2516         dirtyViewportRects += dirtyRects.at(i);
       
  2517     d->dirtyRegion = QRegion();
       
  2518     d->dirtyBoundingRect = QRect();
       
  2519 
       
  2520     bool fullUpdate = !d->accelerateScrolling || d->viewportUpdateMode == QGraphicsView::FullViewportUpdate;
       
  2521     bool boundingRectUpdate = (d->viewportUpdateMode == QGraphicsView::BoundingRectViewportUpdate)
       
  2522                               || (d->viewportUpdateMode == QGraphicsView::SmartViewportUpdate
       
  2523                                   && ((dirtyViewportRects.size() + rects.size()) >= QGRAPHICSVIEW_REGION_RECT_THRESHOLD));
       
  2524 
       
  2525     QRegion updateRegion;
       
  2526     QRect boundingRect;
       
  2527     QRect viewportRect = viewport()->rect();
       
  2528     bool redraw = false;
       
  2529     QTransform transform = viewportTransform();
       
  2530 
       
  2531     // Convert scene rects to viewport rects.
       
  2532     foreach (const QRectF &rect, rects) {
       
  2533         QRect xrect = transform.mapRect(rect).toRect();
       
  2534         if (!(d->optimizationFlags & DontAdjustForAntialiasing))
       
  2535             xrect.adjust(-2, -2, 2, 2);
       
  2536         if (!viewportRect.intersects(xrect))
       
  2537             continue;
       
  2538         dirtyViewportRects << xrect;
       
  2539     }
       
  2540 
       
  2541     foreach (const QRect &rect, dirtyViewportRects) {
       
  2542         // Add the exposed rect to the update region. In rect update
       
  2543         // mode, we only count the bounding rect of items.
       
  2544         if (!boundingRectUpdate) {
       
  2545             updateRegion += rect;
       
  2546         } else {
       
  2547             boundingRect |= rect;
       
  2548         }
       
  2549         redraw = true;
       
  2550         if (fullUpdate) {
       
  2551             // If fullUpdate is true and we found a visible dirty rect,
       
  2552             // we're done.
       
  2553             break;
       
  2554         }
       
  2555     }
       
  2556 
       
  2557     if (!redraw)
       
  2558         return;
       
  2559 
       
  2560     if (fullUpdate)
       
  2561         viewport()->update();
       
  2562     else if (boundingRectUpdate)
       
  2563         viewport()->update(boundingRect);
       
  2564     else
       
  2565         viewport()->update(updateRegion);
       
  2566 }
       
  2567 
       
  2568 /*!
       
  2569     Notifies QGraphicsView that the scene's scene rect has changed.  \a rect
       
  2570     is the new scene rect. If the view already has an explicitly set scene
       
  2571     rect, this function does nothing.
       
  2572 
       
  2573     \sa sceneRect, QGraphicsScene::sceneRectChanged()
       
  2574 */
       
  2575 void QGraphicsView::updateSceneRect(const QRectF &rect)
       
  2576 {
       
  2577     Q_D(QGraphicsView);
       
  2578     if (!d->hasSceneRect) {
       
  2579         d->sceneRect = rect;
       
  2580         d->recalculateContentSize();
       
  2581     }
       
  2582 }
       
  2583 
       
  2584 /*!
       
  2585     This slot is called by QAbstractScrollArea after setViewport() has been
       
  2586     called. Reimplement this function in a subclass of QGraphicsView to
       
  2587     initialize the new viewport \a widget before it is used.
       
  2588 
       
  2589     \sa setViewport()
       
  2590 */
       
  2591 void QGraphicsView::setupViewport(QWidget *widget)
       
  2592 {
       
  2593     Q_D(QGraphicsView);
       
  2594 
       
  2595     if (!widget) {
       
  2596         qWarning("QGraphicsView::setupViewport: cannot initialize null widget");
       
  2597         return;
       
  2598     }
       
  2599 
       
  2600     const bool isGLWidget = widget->inherits("QGLWidget");
       
  2601 
       
  2602     d->accelerateScrolling = !(isGLWidget);
       
  2603 
       
  2604     widget->setFocusPolicy(Qt::StrongFocus);
       
  2605 
       
  2606     if (!isGLWidget) {
       
  2607         // autoFillBackground enables scroll acceleration.
       
  2608         widget->setAutoFillBackground(true);
       
  2609     }
       
  2610 
       
  2611     // We are only interested in mouse tracking if items
       
  2612     // accept hover events or use non-default cursors or if
       
  2613     // AnchorUnderMouse is used as transformation or resize anchor.
       
  2614     if ((d->scene && (!d->scene->d_func()->allItemsIgnoreHoverEvents
       
  2615                      || !d->scene->d_func()->allItemsUseDefaultCursor))
       
  2616         || d->transformationAnchor == AnchorUnderMouse
       
  2617         || d->resizeAnchor == AnchorUnderMouse) {
       
  2618         widget->setMouseTracking(true);
       
  2619     }
       
  2620 
       
  2621     // enable touch events if any items is interested in them
       
  2622     if (d->scene && !d->scene->d_func()->allItemsIgnoreTouchEvents)
       
  2623         widget->setAttribute(Qt::WA_AcceptTouchEvents);
       
  2624 
       
  2625     widget->setAcceptDrops(acceptDrops());
       
  2626 }
       
  2627 
       
  2628 /*!
       
  2629     \reimp
       
  2630 */
       
  2631 bool QGraphicsView::event(QEvent *event)
       
  2632 {
       
  2633     Q_D(QGraphicsView);
       
  2634 
       
  2635     if (d->sceneInteractionAllowed) {
       
  2636         switch (event->type()) {
       
  2637         case QEvent::ShortcutOverride:
       
  2638             if (d->scene)
       
  2639                 return QApplication::sendEvent(d->scene, event);
       
  2640             break;
       
  2641         case QEvent::KeyPress:
       
  2642             if (d->scene) {
       
  2643                 QKeyEvent *k = static_cast<QKeyEvent *>(event);
       
  2644                 if (k->key() == Qt::Key_Tab || k->key() == Qt::Key_Backtab) {
       
  2645                     // Send the key events to the scene. This will invoke the
       
  2646                     // scene's tab focus handling, and if the event is
       
  2647                     // accepted, we return (prevent further event delivery),
       
  2648                     // and the base implementation will call QGraphicsView's
       
  2649                     // focusNextPrevChild() function. If the event is ignored,
       
  2650                     // we fall back to standard tab focus handling.
       
  2651                     QApplication::sendEvent(d->scene, event);
       
  2652                     if (event->isAccepted())
       
  2653                         return true;
       
  2654                     // Ensure the event doesn't propagate just because the
       
  2655                     // scene ignored it. If the event propagates, then tab
       
  2656                     // handling will be called twice (this and parent).
       
  2657                     event->accept();
       
  2658                 }
       
  2659             }
       
  2660             break;
       
  2661         default:
       
  2662             break;
       
  2663         }
       
  2664     }
       
  2665 
       
  2666     return QAbstractScrollArea::event(event);
       
  2667 }
       
  2668 
       
  2669 /*!
       
  2670     \reimp
       
  2671 */
       
  2672 bool QGraphicsView::viewportEvent(QEvent *event)
       
  2673 {
       
  2674     Q_D(QGraphicsView);
       
  2675     if (!d->scene)
       
  2676         return QAbstractScrollArea::viewportEvent(event);
       
  2677 
       
  2678     switch (event->type()) {
       
  2679     case QEvent::Enter:
       
  2680         QApplication::sendEvent(d->scene, event);
       
  2681         break;
       
  2682     case QEvent::WindowActivate:
       
  2683         QApplication::sendEvent(d->scene, event);
       
  2684         break;
       
  2685     case QEvent::WindowDeactivate:
       
  2686         // ### This is a temporary fix for until we get proper mouse
       
  2687         // grab events. mouseGrabberItem should be set to 0 if we lose
       
  2688         // the mouse grab.
       
  2689         // Remove all popups when the scene loses focus.
       
  2690         if (!d->scene->d_func()->popupWidgets.isEmpty())
       
  2691             d->scene->d_func()->removePopup(d->scene->d_func()->popupWidgets.first());
       
  2692         QApplication::sendEvent(d->scene, event);
       
  2693         break;
       
  2694     case QEvent::Show:
       
  2695         if (d->scene && isActiveWindow()) {
       
  2696             QEvent windowActivate(QEvent::WindowActivate);
       
  2697             QApplication::sendEvent(d->scene, &windowActivate);
       
  2698         }
       
  2699         break;
       
  2700     case QEvent::Hide:
       
  2701         // spontaneous event will generate a WindowDeactivate.
       
  2702         if (!event->spontaneous() && d->scene && isActiveWindow()) {
       
  2703             QEvent windowDeactivate(QEvent::WindowDeactivate);
       
  2704             QApplication::sendEvent(d->scene, &windowDeactivate);
       
  2705         }
       
  2706         break;
       
  2707     case QEvent::Leave:
       
  2708         // ### This is a temporary fix for until we get proper mouse grab
       
  2709         // events. activeMouseGrabberItem should be set to 0 if we lose the
       
  2710         // mouse grab.
       
  2711         if ((QApplication::activePopupWidget() && QApplication::activePopupWidget() != window())
       
  2712             || (QApplication::activeModalWidget() && QApplication::activeModalWidget() != window())
       
  2713             || (QApplication::activeWindow() != window())) {
       
  2714             if (!d->scene->d_func()->popupWidgets.isEmpty())
       
  2715                 d->scene->d_func()->removePopup(d->scene->d_func()->popupWidgets.first());
       
  2716         }
       
  2717         d->useLastMouseEvent = false;
       
  2718         QApplication::sendEvent(d->scene, event);
       
  2719         break;
       
  2720 #ifndef QT_NO_TOOLTIP
       
  2721     case QEvent::ToolTip: {
       
  2722         QHelpEvent *toolTip = static_cast<QHelpEvent *>(event);
       
  2723         QGraphicsSceneHelpEvent helpEvent(QEvent::GraphicsSceneHelp);
       
  2724         helpEvent.setWidget(viewport());
       
  2725         helpEvent.setScreenPos(toolTip->globalPos());
       
  2726         helpEvent.setScenePos(mapToScene(toolTip->pos()));
       
  2727         QApplication::sendEvent(d->scene, &helpEvent);
       
  2728         toolTip->setAccepted(helpEvent.isAccepted());
       
  2729         return true;
       
  2730     }
       
  2731 #endif
       
  2732     case QEvent::Paint:
       
  2733         // Reset full update
       
  2734         d->fullUpdatePending = false;
       
  2735         d->dirtyScrollOffset = QPoint();
       
  2736         if (d->scene) {
       
  2737             // Check if this view reimplements the updateScene slot; if it
       
  2738             // does, we can't do direct update delivery and have to fall back
       
  2739             // to connecting the changed signal.
       
  2740             if (!d->updateSceneSlotReimplementedChecked) {
       
  2741                 d->updateSceneSlotReimplementedChecked = true;
       
  2742                 const QMetaObject *mo = metaObject();
       
  2743                 if (mo != &QGraphicsView::staticMetaObject) {
       
  2744                     if (mo->indexOfSlot("updateScene(QList<QRectF>)")
       
  2745                         != QGraphicsView::staticMetaObject.indexOfSlot("updateScene(QList<QRectF>)")) {
       
  2746                         connect(d->scene, SIGNAL(changed(QList<QRectF>)),
       
  2747                                 this, SLOT(updateScene(QList<QRectF>)));
       
  2748                     }
       
  2749                 }
       
  2750             }
       
  2751         }
       
  2752         break;
       
  2753     case QEvent::TouchBegin:
       
  2754     case QEvent::TouchUpdate:
       
  2755     case QEvent::TouchEnd:
       
  2756     {
       
  2757         if (!isEnabled())
       
  2758             return false;
       
  2759 
       
  2760         if (d->scene && d->sceneInteractionAllowed) {
       
  2761             // Convert and deliver the touch event to the scene.
       
  2762             QTouchEvent *touchEvent = static_cast<QTouchEvent *>(event);
       
  2763             touchEvent->setWidget(viewport());
       
  2764             QGraphicsViewPrivate::translateTouchEvent(d, touchEvent);
       
  2765             (void) QApplication::sendEvent(d->scene, touchEvent);
       
  2766         }
       
  2767 
       
  2768         return true;
       
  2769     }
       
  2770     case QEvent::Gesture:
       
  2771     case QEvent::GestureOverride:
       
  2772     {
       
  2773         if (!isEnabled())
       
  2774             return false;
       
  2775 
       
  2776         if (d->scene && d->sceneInteractionAllowed) {
       
  2777             QGestureEvent *gestureEvent = static_cast<QGestureEvent *>(event);
       
  2778             gestureEvent->setWidget(viewport());
       
  2779             (void) QApplication::sendEvent(d->scene, gestureEvent);
       
  2780         }
       
  2781         return true;
       
  2782     }
       
  2783     default:
       
  2784         break;
       
  2785     }
       
  2786 
       
  2787     return QAbstractScrollArea::viewportEvent(event);
       
  2788 }
       
  2789 
       
  2790 #ifndef QT_NO_CONTEXTMENU
       
  2791 /*!
       
  2792     \reimp
       
  2793 */
       
  2794 void QGraphicsView::contextMenuEvent(QContextMenuEvent *event)
       
  2795 {
       
  2796     Q_D(QGraphicsView);
       
  2797     if (!d->scene || !d->sceneInteractionAllowed)
       
  2798         return;
       
  2799 
       
  2800     d->mousePressViewPoint = event->pos();
       
  2801     d->mousePressScenePoint = mapToScene(d->mousePressViewPoint);
       
  2802     d->mousePressScreenPoint = event->globalPos();
       
  2803     d->lastMouseMoveScenePoint = d->mousePressScenePoint;
       
  2804     d->lastMouseMoveScreenPoint = d->mousePressScreenPoint;
       
  2805 
       
  2806     QGraphicsSceneContextMenuEvent contextEvent(QEvent::GraphicsSceneContextMenu);
       
  2807     contextEvent.setWidget(viewport());
       
  2808     contextEvent.setScenePos(d->mousePressScenePoint);
       
  2809     contextEvent.setScreenPos(d->mousePressScreenPoint);
       
  2810     contextEvent.setModifiers(event->modifiers());
       
  2811     contextEvent.setReason((QGraphicsSceneContextMenuEvent::Reason)(event->reason()));
       
  2812     contextEvent.setAccepted(event->isAccepted());
       
  2813     QApplication::sendEvent(d->scene, &contextEvent);
       
  2814     event->setAccepted(contextEvent.isAccepted());
       
  2815 }
       
  2816 #endif // QT_NO_CONTEXTMENU
       
  2817 
       
  2818 /*!
       
  2819     \reimp
       
  2820 */
       
  2821 void QGraphicsView::dropEvent(QDropEvent *event)
       
  2822 {
       
  2823 #ifndef QT_NO_DRAGANDDROP
       
  2824     Q_D(QGraphicsView);
       
  2825     if (!d->scene || !d->sceneInteractionAllowed)
       
  2826         return;
       
  2827 
       
  2828     // Generate a scene event.
       
  2829     QGraphicsSceneDragDropEvent sceneEvent(QEvent::GraphicsSceneDrop);
       
  2830     d->populateSceneDragDropEvent(&sceneEvent, event);
       
  2831 
       
  2832     // Send it to the scene.
       
  2833     QApplication::sendEvent(d->scene, &sceneEvent);
       
  2834 
       
  2835     // Accept the originating event if the scene accepted the scene event.
       
  2836     event->setAccepted(sceneEvent.isAccepted());
       
  2837     if (sceneEvent.isAccepted())
       
  2838         event->setDropAction(sceneEvent.dropAction());
       
  2839 
       
  2840     delete d->lastDragDropEvent;
       
  2841     d->lastDragDropEvent = 0;
       
  2842 
       
  2843 #else
       
  2844     Q_UNUSED(event)
       
  2845 #endif
       
  2846 }
       
  2847 
       
  2848 /*!
       
  2849     \reimp
       
  2850 */
       
  2851 void QGraphicsView::dragEnterEvent(QDragEnterEvent *event)
       
  2852 {
       
  2853 #ifndef QT_NO_DRAGANDDROP
       
  2854     Q_D(QGraphicsView);
       
  2855     if (!d->scene || !d->sceneInteractionAllowed)
       
  2856         return;
       
  2857 
       
  2858     // Disable replaying of mouse move events.
       
  2859     d->useLastMouseEvent = false;
       
  2860 
       
  2861     // Generate a scene event.
       
  2862     QGraphicsSceneDragDropEvent sceneEvent(QEvent::GraphicsSceneDragEnter);
       
  2863     d->populateSceneDragDropEvent(&sceneEvent, event);
       
  2864 
       
  2865     // Store it for later use.
       
  2866     d->storeDragDropEvent(&sceneEvent);
       
  2867 
       
  2868     // Send it to the scene.
       
  2869     QApplication::sendEvent(d->scene, &sceneEvent);
       
  2870 
       
  2871     // Accept the originating event if the scene accepted the scene event.
       
  2872     if (sceneEvent.isAccepted()) {
       
  2873         event->setAccepted(true);
       
  2874         event->setDropAction(sceneEvent.dropAction());
       
  2875     }
       
  2876 #else
       
  2877     Q_UNUSED(event)
       
  2878 #endif
       
  2879 }
       
  2880 
       
  2881 /*!
       
  2882     \reimp
       
  2883 */
       
  2884 void QGraphicsView::dragLeaveEvent(QDragLeaveEvent *event)
       
  2885 {
       
  2886 #ifndef QT_NO_DRAGANDDROP
       
  2887     Q_D(QGraphicsView);
       
  2888     if (!d->scene || !d->sceneInteractionAllowed)
       
  2889         return;
       
  2890     if (!d->lastDragDropEvent) {
       
  2891         qWarning("QGraphicsView::dragLeaveEvent: drag leave received before drag enter");
       
  2892         return;
       
  2893     }
       
  2894 
       
  2895     // Generate a scene event.
       
  2896     QGraphicsSceneDragDropEvent sceneEvent(QEvent::GraphicsSceneDragLeave);
       
  2897     sceneEvent.setScenePos(d->lastDragDropEvent->scenePos());
       
  2898     sceneEvent.setScreenPos(d->lastDragDropEvent->screenPos());
       
  2899     sceneEvent.setButtons(d->lastDragDropEvent->buttons());
       
  2900     sceneEvent.setModifiers(d->lastDragDropEvent->modifiers());
       
  2901     sceneEvent.setPossibleActions(d->lastDragDropEvent->possibleActions());
       
  2902     sceneEvent.setProposedAction(d->lastDragDropEvent->proposedAction());
       
  2903     sceneEvent.setDropAction(d->lastDragDropEvent->dropAction());
       
  2904     sceneEvent.setMimeData(d->lastDragDropEvent->mimeData());
       
  2905     sceneEvent.setWidget(d->lastDragDropEvent->widget());
       
  2906     sceneEvent.setSource(d->lastDragDropEvent->source());
       
  2907     delete d->lastDragDropEvent;
       
  2908     d->lastDragDropEvent = 0;
       
  2909 
       
  2910     // Send it to the scene.
       
  2911     QApplication::sendEvent(d->scene, &sceneEvent);
       
  2912 
       
  2913     // Accept the originating event if the scene accepted the scene event.
       
  2914     if (sceneEvent.isAccepted())
       
  2915         event->setAccepted(true);
       
  2916 #else
       
  2917     Q_UNUSED(event)
       
  2918 #endif
       
  2919 }
       
  2920 
       
  2921 /*!
       
  2922     \reimp
       
  2923 */
       
  2924 void QGraphicsView::dragMoveEvent(QDragMoveEvent *event)
       
  2925 {
       
  2926 #ifndef QT_NO_DRAGANDDROP
       
  2927     Q_D(QGraphicsView);
       
  2928     if (!d->scene || !d->sceneInteractionAllowed)
       
  2929         return;
       
  2930 
       
  2931     // Generate a scene event.
       
  2932     QGraphicsSceneDragDropEvent sceneEvent(QEvent::GraphicsSceneDragMove);
       
  2933     d->populateSceneDragDropEvent(&sceneEvent, event);
       
  2934 
       
  2935     // Store it for later use.
       
  2936     d->storeDragDropEvent(&sceneEvent);
       
  2937 
       
  2938     // Send it to the scene.
       
  2939     QApplication::sendEvent(d->scene, &sceneEvent);
       
  2940 
       
  2941     // Ignore the originating event if the scene ignored the scene event.
       
  2942     event->setAccepted(sceneEvent.isAccepted());
       
  2943     if (sceneEvent.isAccepted())
       
  2944         event->setDropAction(sceneEvent.dropAction());
       
  2945 #else
       
  2946     Q_UNUSED(event)
       
  2947 #endif
       
  2948 }
       
  2949 
       
  2950 /*!
       
  2951     \reimp
       
  2952 */
       
  2953 void QGraphicsView::focusInEvent(QFocusEvent *event)
       
  2954 {
       
  2955     Q_D(QGraphicsView);
       
  2956     d->updateInputMethodSensitivity();
       
  2957     QAbstractScrollArea::focusInEvent(event);
       
  2958     if (d->scene)
       
  2959         QApplication::sendEvent(d->scene, event);
       
  2960     // Pass focus on if the scene cannot accept focus.
       
  2961     if (!d->scene || !event->isAccepted())
       
  2962         QAbstractScrollArea::focusInEvent(event);
       
  2963 }
       
  2964 
       
  2965 /*!
       
  2966     \reimp
       
  2967 */
       
  2968 bool QGraphicsView::focusNextPrevChild(bool next)
       
  2969 {
       
  2970     return QAbstractScrollArea::focusNextPrevChild(next);
       
  2971 }
       
  2972 
       
  2973 /*!
       
  2974     \reimp
       
  2975 */
       
  2976 void QGraphicsView::focusOutEvent(QFocusEvent *event)
       
  2977 {
       
  2978     Q_D(QGraphicsView);
       
  2979     QAbstractScrollArea::focusOutEvent(event);
       
  2980     if (d->scene)
       
  2981         QApplication::sendEvent(d->scene, event);
       
  2982 }
       
  2983 
       
  2984 /*!
       
  2985     \reimp
       
  2986 */
       
  2987 void QGraphicsView::keyPressEvent(QKeyEvent *event)
       
  2988 {
       
  2989     Q_D(QGraphicsView);
       
  2990     if (!d->scene || !d->sceneInteractionAllowed) {
       
  2991         QAbstractScrollArea::keyPressEvent(event);
       
  2992         return;
       
  2993     }
       
  2994     QApplication::sendEvent(d->scene, event);
       
  2995     if (!event->isAccepted())
       
  2996         QAbstractScrollArea::keyPressEvent(event);
       
  2997 }
       
  2998 
       
  2999 /*!
       
  3000     \reimp
       
  3001 */
       
  3002 void QGraphicsView::keyReleaseEvent(QKeyEvent *event)
       
  3003 {
       
  3004     Q_D(QGraphicsView);
       
  3005     if (!d->scene || !d->sceneInteractionAllowed)
       
  3006         return;
       
  3007     QApplication::sendEvent(d->scene, event);
       
  3008     if (!event->isAccepted())
       
  3009         QAbstractScrollArea::keyReleaseEvent(event);
       
  3010 }
       
  3011 
       
  3012 /*!
       
  3013     \reimp
       
  3014 */
       
  3015 void QGraphicsView::mouseDoubleClickEvent(QMouseEvent *event)
       
  3016 {
       
  3017     Q_D(QGraphicsView);
       
  3018     if (!d->scene || !d->sceneInteractionAllowed)
       
  3019         return;
       
  3020 
       
  3021     d->storeMouseEvent(event);
       
  3022     d->mousePressViewPoint = event->pos();
       
  3023     d->mousePressScenePoint = mapToScene(d->mousePressViewPoint);
       
  3024     d->mousePressScreenPoint = event->globalPos();
       
  3025     d->lastMouseMoveScenePoint = d->mousePressScenePoint;
       
  3026     d->lastMouseMoveScreenPoint = d->mousePressScreenPoint;
       
  3027     d->mousePressButton = event->button();
       
  3028 
       
  3029     QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMouseDoubleClick);
       
  3030     mouseEvent.setWidget(viewport());
       
  3031     mouseEvent.setButtonDownScenePos(d->mousePressButton, d->mousePressScenePoint);
       
  3032     mouseEvent.setButtonDownScreenPos(d->mousePressButton, d->mousePressScreenPoint);
       
  3033     mouseEvent.setScenePos(mapToScene(d->mousePressViewPoint));
       
  3034     mouseEvent.setScreenPos(d->mousePressScreenPoint);
       
  3035     mouseEvent.setLastScenePos(d->lastMouseMoveScenePoint);
       
  3036     mouseEvent.setLastScreenPos(d->lastMouseMoveScreenPoint);
       
  3037     mouseEvent.setButtons(event->buttons());
       
  3038     mouseEvent.setButtons(event->buttons());
       
  3039     mouseEvent.setAccepted(false);
       
  3040     mouseEvent.setButton(event->button());
       
  3041     mouseEvent.setModifiers(event->modifiers());
       
  3042     if (event->spontaneous())
       
  3043         qt_sendSpontaneousEvent(d->scene, &mouseEvent);
       
  3044     else
       
  3045         QApplication::sendEvent(d->scene, &mouseEvent);
       
  3046 }
       
  3047 
       
  3048 /*!
       
  3049     \reimp
       
  3050 */
       
  3051 void QGraphicsView::mousePressEvent(QMouseEvent *event)
       
  3052 {
       
  3053     Q_D(QGraphicsView);
       
  3054 
       
  3055     // Store this event for replaying, finding deltas, and for
       
  3056     // scroll-dragging; even in non-interactive mode, scroll hand dragging is
       
  3057     // allowed, so we store the event at the very top of this function.
       
  3058     d->storeMouseEvent(event);
       
  3059     d->lastMouseEvent.setAccepted(false);
       
  3060 
       
  3061     if (d->sceneInteractionAllowed) {
       
  3062         // Store some of the event's button-down data.
       
  3063         d->mousePressViewPoint = event->pos();
       
  3064         d->mousePressScenePoint = mapToScene(d->mousePressViewPoint);
       
  3065         d->mousePressScreenPoint = event->globalPos();
       
  3066         d->lastMouseMoveScenePoint = d->mousePressScenePoint;
       
  3067         d->lastMouseMoveScreenPoint = d->mousePressScreenPoint;
       
  3068         d->mousePressButton = event->button();
       
  3069 
       
  3070         if (d->scene) {
       
  3071             // Convert and deliver the mouse event to the scene.
       
  3072             QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMousePress);
       
  3073             mouseEvent.setWidget(viewport());
       
  3074             mouseEvent.setButtonDownScenePos(d->mousePressButton, d->mousePressScenePoint);
       
  3075             mouseEvent.setButtonDownScreenPos(d->mousePressButton, d->mousePressScreenPoint);
       
  3076             mouseEvent.setScenePos(d->mousePressScenePoint);
       
  3077             mouseEvent.setScreenPos(d->mousePressScreenPoint);
       
  3078             mouseEvent.setLastScenePos(d->lastMouseMoveScenePoint);
       
  3079             mouseEvent.setLastScreenPos(d->lastMouseMoveScreenPoint);
       
  3080             mouseEvent.setButtons(event->buttons());
       
  3081             mouseEvent.setButton(event->button());
       
  3082             mouseEvent.setModifiers(event->modifiers());
       
  3083             mouseEvent.setAccepted(false);
       
  3084             if (event->spontaneous())
       
  3085                 qt_sendSpontaneousEvent(d->scene, &mouseEvent);
       
  3086             else
       
  3087                 QApplication::sendEvent(d->scene, &mouseEvent);
       
  3088 
       
  3089             // Update the original mouse event accepted state.
       
  3090             bool isAccepted = mouseEvent.isAccepted();
       
  3091             event->setAccepted(isAccepted);
       
  3092 
       
  3093             // Update the last mouse event accepted state.
       
  3094             d->lastMouseEvent.setAccepted(isAccepted);
       
  3095 
       
  3096             if (isAccepted)
       
  3097                 return;
       
  3098         }
       
  3099     }
       
  3100 
       
  3101 #ifndef QT_NO_RUBBERBAND
       
  3102     if (d->dragMode == QGraphicsView::RubberBandDrag && !d->rubberBanding) {
       
  3103         if (d->sceneInteractionAllowed) {
       
  3104             // Rubberbanding is only allowed in interactive mode.
       
  3105             event->accept();
       
  3106             d->rubberBanding = true;
       
  3107             d->rubberBandRect = QRect();
       
  3108             if (d->scene) {
       
  3109                 // Initiating a rubber band always clears the selection.
       
  3110                 d->scene->clearSelection();
       
  3111             }
       
  3112         }
       
  3113     } else
       
  3114 #endif
       
  3115         if (d->dragMode == QGraphicsView::ScrollHandDrag && event->button() == Qt::LeftButton) {
       
  3116             // Left-button press in scroll hand mode initiates hand scrolling.
       
  3117             event->accept();
       
  3118             d->handScrolling = true;
       
  3119             d->handScrollMotions = 0;
       
  3120 #ifndef QT_NO_CURSOR
       
  3121             viewport()->setCursor(Qt::ClosedHandCursor);
       
  3122 #endif
       
  3123         }
       
  3124 }
       
  3125 
       
  3126 /*!
       
  3127     \reimp
       
  3128 */
       
  3129 void QGraphicsView::mouseMoveEvent(QMouseEvent *event)
       
  3130 {
       
  3131     Q_D(QGraphicsView);
       
  3132 
       
  3133 #ifndef QT_NO_RUBBERBAND
       
  3134     if (d->dragMode == QGraphicsView::RubberBandDrag && d->sceneInteractionAllowed) {
       
  3135         d->storeMouseEvent(event);
       
  3136         if (d->rubberBanding) {
       
  3137             // Check for enough drag distance
       
  3138             if ((d->mousePressViewPoint - event->pos()).manhattanLength()
       
  3139                 < QApplication::startDragDistance()) {
       
  3140                 return;
       
  3141             }
       
  3142 
       
  3143             // Update old rubberband
       
  3144             if (d->viewportUpdateMode != QGraphicsView::NoViewportUpdate && !d->rubberBandRect.isEmpty()) {
       
  3145                 if (d->viewportUpdateMode != FullViewportUpdate)
       
  3146                     viewport()->update(d->rubberBandRegion(viewport(), d->rubberBandRect));
       
  3147                 else
       
  3148                     d->updateAll();
       
  3149             }
       
  3150 
       
  3151             // Stop rubber banding if the user has let go of all buttons (even
       
  3152             // if we didn't get the release events).
       
  3153             if (!event->buttons()) {
       
  3154                 d->rubberBanding = false;
       
  3155                 d->rubberBandRect = QRect();
       
  3156                 return;
       
  3157             }
       
  3158 
       
  3159             // Update rubberband position
       
  3160             const QPoint &mp = d->mousePressViewPoint;
       
  3161             QPoint ep = event->pos();
       
  3162             d->rubberBandRect = QRect(qMin(mp.x(), ep.x()), qMin(mp.y(), ep.y()),
       
  3163                                       qAbs(mp.x() - ep.x()) + 1, qAbs(mp.y() - ep.y()) + 1);
       
  3164 
       
  3165             // Update new rubberband
       
  3166             if (d->viewportUpdateMode != QGraphicsView::NoViewportUpdate){
       
  3167                 if (d->viewportUpdateMode != FullViewportUpdate)
       
  3168                     viewport()->update(d->rubberBandRegion(viewport(), d->rubberBandRect));
       
  3169                 else
       
  3170                     d->updateAll();
       
  3171             }
       
  3172             // Set the new selection area
       
  3173             QPainterPath selectionArea;
       
  3174             selectionArea.addPolygon(mapToScene(d->rubberBandRect));
       
  3175             selectionArea.closeSubpath();
       
  3176             if (d->scene)
       
  3177                 d->scene->setSelectionArea(selectionArea, d->rubberBandSelectionMode,
       
  3178                                            viewportTransform());
       
  3179             return;
       
  3180         }
       
  3181     } else
       
  3182 #endif // QT_NO_RUBBERBAND
       
  3183     if (d->dragMode == QGraphicsView::ScrollHandDrag) {
       
  3184         if (d->handScrolling) {
       
  3185             QScrollBar *hBar = horizontalScrollBar();
       
  3186             QScrollBar *vBar = verticalScrollBar();
       
  3187             QPoint delta = event->pos() - d->lastMouseEvent.pos();
       
  3188             hBar->setValue(hBar->value() + (isRightToLeft() ? delta.x() : -delta.x()));
       
  3189             vBar->setValue(vBar->value() - delta.y());
       
  3190 
       
  3191             // Detect how much we've scrolled to disambiguate scrolling from
       
  3192             // clicking.
       
  3193             ++d->handScrollMotions;
       
  3194         }
       
  3195     }
       
  3196 
       
  3197     d->mouseMoveEventHandler(event);
       
  3198 }
       
  3199 
       
  3200 /*!
       
  3201     \reimp
       
  3202 */
       
  3203 void QGraphicsView::mouseReleaseEvent(QMouseEvent *event)
       
  3204 {
       
  3205     Q_D(QGraphicsView);
       
  3206 
       
  3207 #ifndef QT_NO_RUBBERBAND
       
  3208     if (d->dragMode == QGraphicsView::RubberBandDrag && d->sceneInteractionAllowed && !event->buttons()) {
       
  3209         if (d->rubberBanding) {
       
  3210             if (d->viewportUpdateMode != QGraphicsView::NoViewportUpdate){
       
  3211                 if (d->viewportUpdateMode != FullViewportUpdate)
       
  3212                     viewport()->update(d->rubberBandRegion(viewport(), d->rubberBandRect));
       
  3213                 else
       
  3214                     d->updateAll();
       
  3215             }
       
  3216             d->rubberBanding = false;
       
  3217             d->rubberBandRect = QRect();
       
  3218         }
       
  3219     } else
       
  3220 #endif
       
  3221     if (d->dragMode == QGraphicsView::ScrollHandDrag && event->button() == Qt::LeftButton) {
       
  3222 #ifndef QT_NO_CURSOR
       
  3223         // Restore the open hand cursor. ### There might be items
       
  3224         // under the mouse that have a valid cursor at this time, so
       
  3225         // we could repeat the steps from mouseMoveEvent().
       
  3226         viewport()->setCursor(Qt::OpenHandCursor);
       
  3227 #endif
       
  3228         d->handScrolling = false;
       
  3229 
       
  3230         if (d->scene && d->sceneInteractionAllowed && !d->lastMouseEvent.isAccepted() && d->handScrollMotions <= 6) {
       
  3231             // If we've detected very little motion during the hand drag, and
       
  3232             // no item accepted the last event, we'll interpret that as a
       
  3233             // click to the scene, and reset the selection.
       
  3234             d->scene->clearSelection();
       
  3235         }
       
  3236     }
       
  3237 
       
  3238     d->storeMouseEvent(event);
       
  3239 
       
  3240     if (!d->sceneInteractionAllowed)
       
  3241         return;
       
  3242 
       
  3243     if (!d->scene)
       
  3244         return;
       
  3245 
       
  3246     QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMouseRelease);
       
  3247     mouseEvent.setWidget(viewport());
       
  3248     mouseEvent.setButtonDownScenePos(d->mousePressButton, d->mousePressScenePoint);
       
  3249     mouseEvent.setButtonDownScreenPos(d->mousePressButton, d->mousePressScreenPoint);
       
  3250     mouseEvent.setScenePos(mapToScene(event->pos()));
       
  3251     mouseEvent.setScreenPos(event->globalPos());
       
  3252     mouseEvent.setLastScenePos(d->lastMouseMoveScenePoint);
       
  3253     mouseEvent.setLastScreenPos(d->lastMouseMoveScreenPoint);
       
  3254     mouseEvent.setButtons(event->buttons());
       
  3255     mouseEvent.setButton(event->button());
       
  3256     mouseEvent.setModifiers(event->modifiers());
       
  3257     mouseEvent.setAccepted(false);
       
  3258     if (event->spontaneous())
       
  3259         qt_sendSpontaneousEvent(d->scene, &mouseEvent);
       
  3260     else
       
  3261         QApplication::sendEvent(d->scene, &mouseEvent);
       
  3262 
       
  3263     // Update the last mouse event selected state.
       
  3264     d->lastMouseEvent.setAccepted(mouseEvent.isAccepted());
       
  3265 
       
  3266 #ifndef QT_NO_CURSOR
       
  3267     if (mouseEvent.isAccepted() && mouseEvent.buttons() == 0 && viewport()->testAttribute(Qt::WA_SetCursor)) {
       
  3268         // The last mouse release on the viewport will trigger clearing the cursor.
       
  3269         d->_q_unsetViewportCursor();
       
  3270     }
       
  3271 #endif
       
  3272 }
       
  3273 
       
  3274 #ifndef QT_NO_WHEELEVENT
       
  3275 /*!
       
  3276     \reimp
       
  3277 */
       
  3278 void QGraphicsView::wheelEvent(QWheelEvent *event)
       
  3279 {
       
  3280     Q_D(QGraphicsView);
       
  3281     if (!d->scene || !d->sceneInteractionAllowed) {
       
  3282         QAbstractScrollArea::wheelEvent(event);
       
  3283         return;
       
  3284     }
       
  3285 
       
  3286     event->ignore();
       
  3287 
       
  3288     QGraphicsSceneWheelEvent wheelEvent(QEvent::GraphicsSceneWheel);
       
  3289     wheelEvent.setWidget(viewport());
       
  3290     wheelEvent.setScenePos(mapToScene(event->pos()));
       
  3291     wheelEvent.setScreenPos(event->globalPos());
       
  3292     wheelEvent.setButtons(event->buttons());
       
  3293     wheelEvent.setModifiers(event->modifiers());
       
  3294     wheelEvent.setDelta(event->delta());
       
  3295     wheelEvent.setOrientation(event->orientation());
       
  3296     wheelEvent.setAccepted(false);
       
  3297     QApplication::sendEvent(d->scene, &wheelEvent);
       
  3298     event->setAccepted(wheelEvent.isAccepted());
       
  3299     if (!event->isAccepted())
       
  3300         QAbstractScrollArea::wheelEvent(event);
       
  3301 }
       
  3302 #endif // QT_NO_WHEELEVENT
       
  3303 
       
  3304 /*!
       
  3305     \reimp
       
  3306 */
       
  3307 void QGraphicsView::paintEvent(QPaintEvent *event)
       
  3308 {
       
  3309     Q_D(QGraphicsView);
       
  3310     if (!d->scene) {
       
  3311         QAbstractScrollArea::paintEvent(event);
       
  3312         return;
       
  3313     }
       
  3314 
       
  3315     // Set up painter state protection.
       
  3316     d->scene->d_func()->painterStateProtection = !(d->optimizationFlags & DontSavePainterState);
       
  3317 
       
  3318     // Determine the exposed region
       
  3319     d->exposedRegion = event->region();
       
  3320     QRectF exposedSceneRect = mapToScene(d->exposedRegion.boundingRect()).boundingRect();
       
  3321 
       
  3322     // Set up the painter
       
  3323     QPainter painter(viewport());
       
  3324 #ifndef QT_NO_RUBBERBAND
       
  3325     if (d->rubberBanding && !d->rubberBandRect.isEmpty())
       
  3326         painter.save();
       
  3327 #endif
       
  3328     // Set up render hints
       
  3329     painter.setRenderHints(painter.renderHints(), false);
       
  3330     painter.setRenderHints(d->renderHints, true);
       
  3331 
       
  3332     // Set up viewport transform
       
  3333     const bool viewTransformed = isTransformed();
       
  3334     if (viewTransformed)
       
  3335         painter.setWorldTransform(viewportTransform());
       
  3336     const QTransform viewTransform = painter.worldTransform();
       
  3337 
       
  3338     // Draw background
       
  3339     if ((d->cacheMode & CacheBackground)
       
  3340 #ifdef Q_WS_X11
       
  3341         && X11->use_xrender
       
  3342 #endif
       
  3343         ) {
       
  3344         // Recreate the background pixmap, and flag the whole background as
       
  3345         // exposed.
       
  3346         if (d->mustResizeBackgroundPixmap) {
       
  3347             d->backgroundPixmap = QPixmap(viewport()->size());
       
  3348             QBrush bgBrush = viewport()->palette().brush(viewport()->backgroundRole());
       
  3349             if (!bgBrush.isOpaque())
       
  3350                 d->backgroundPixmap.fill(Qt::transparent);
       
  3351             QPainter p(&d->backgroundPixmap);
       
  3352             p.fillRect(0, 0, d->backgroundPixmap.width(), d->backgroundPixmap.height(), bgBrush);
       
  3353             d->backgroundPixmapExposed = QRegion(viewport()->rect());
       
  3354             d->mustResizeBackgroundPixmap = false;
       
  3355         }
       
  3356 
       
  3357         // Redraw exposed areas
       
  3358         if (!d->backgroundPixmapExposed.isEmpty()) {
       
  3359             QPainter backgroundPainter(&d->backgroundPixmap);
       
  3360             backgroundPainter.setClipRegion(d->backgroundPixmapExposed, Qt::ReplaceClip);
       
  3361             if (viewTransformed)
       
  3362                 backgroundPainter.setTransform(viewTransform);
       
  3363             QRectF backgroundExposedSceneRect = mapToScene(d->backgroundPixmapExposed.boundingRect()).boundingRect();
       
  3364             drawBackground(&backgroundPainter, backgroundExposedSceneRect);
       
  3365             d->backgroundPixmapExposed = QRegion();
       
  3366         }
       
  3367 
       
  3368         // Blit the background from the background pixmap
       
  3369         if (viewTransformed) {
       
  3370             painter.setWorldTransform(QTransform());
       
  3371             painter.drawPixmap(QPoint(), d->backgroundPixmap);
       
  3372             painter.setWorldTransform(viewTransform);
       
  3373         } else {
       
  3374             painter.drawPixmap(QPoint(), d->backgroundPixmap);
       
  3375         }
       
  3376     } else {
       
  3377         if (!(d->optimizationFlags & DontSavePainterState))
       
  3378             painter.save();
       
  3379         drawBackground(&painter, exposedSceneRect);
       
  3380         if (!(d->optimizationFlags & DontSavePainterState))
       
  3381             painter.restore();
       
  3382     }
       
  3383 
       
  3384     // Items
       
  3385     if (!(d->optimizationFlags & IndirectPainting)) {
       
  3386         d->scene->d_func()->drawItems(&painter, viewTransformed ? &viewTransform : 0,
       
  3387                                       &d->exposedRegion, viewport());
       
  3388         // Make sure the painter's world transform is restored correctly when
       
  3389         // drawing without painter state protection (DontSavePainterState).
       
  3390         // We only change the worldTransform() so there's no need to do a full-blown
       
  3391         // save() and restore(). Also note that we don't have to do this in case of
       
  3392         // IndirectPainting (the else branch), because in that case we always save()
       
  3393         // and restore() in QGraphicsScene::drawItems().
       
  3394         if (!d->scene->d_func()->painterStateProtection)
       
  3395             painter.setWorldTransform(viewTransform);
       
  3396     } else {
       
  3397         // Make sure we don't have unpolished items before we draw
       
  3398         if (!d->scene->d_func()->unpolishedItems.isEmpty())
       
  3399             d->scene->d_func()->_q_polishItems();
       
  3400         // We reset updateAll here (after we've issued polish events)
       
  3401         // so that we can discard update requests coming from polishEvent().
       
  3402         d->scene->d_func()->updateAll = false;
       
  3403 
       
  3404         // Find all exposed items
       
  3405         bool allItems = false;
       
  3406         QList<QGraphicsItem *> itemList = d->findItems(d->exposedRegion, &allItems, viewTransform);
       
  3407         if (!itemList.isEmpty()) {
       
  3408             // Generate the style options.
       
  3409             const int numItems = itemList.size();
       
  3410             QGraphicsItem **itemArray = &itemList[0]; // Relies on QList internals, but is perfectly valid.
       
  3411             QStyleOptionGraphicsItem *styleOptionArray = d->allocStyleOptionsArray(numItems);
       
  3412             QTransform transform(Qt::Uninitialized);
       
  3413             for (int i = 0; i < numItems; ++i) {
       
  3414                 QGraphicsItem *item = itemArray[i];
       
  3415                 QGraphicsItemPrivate *itemd = item->d_ptr.data();
       
  3416                 itemd->initStyleOption(&styleOptionArray[i], viewTransform, d->exposedRegion, allItems);
       
  3417                 // Cache the item's area in view coordinates.
       
  3418                 // Note that we have to do this here in case the base class implementation
       
  3419                 // (QGraphicsScene::drawItems) is not called. If it is, we'll do this
       
  3420                 // operation twice, but that's the price one has to pay for using indirect
       
  3421                 // painting :-/.
       
  3422                 const QRectF brect = adjustedItemEffectiveBoundingRect(item);
       
  3423                 if (!itemd->itemIsUntransformable()) {
       
  3424                     transform = item->sceneTransform();
       
  3425                     if (viewTransformed)
       
  3426                         transform *= viewTransform;
       
  3427                 } else {
       
  3428                     transform = item->deviceTransform(viewTransform);
       
  3429                 }
       
  3430                 itemd->paintedViewBoundingRects.insert(d->viewport, transform.mapRect(brect).toRect());
       
  3431             }
       
  3432             // Draw the items.
       
  3433             drawItems(&painter, numItems, itemArray, styleOptionArray);
       
  3434             d->freeStyleOptionsArray(styleOptionArray);
       
  3435         }
       
  3436     }
       
  3437 
       
  3438     // Foreground
       
  3439     drawForeground(&painter, exposedSceneRect);
       
  3440 
       
  3441 #ifndef QT_NO_RUBBERBAND
       
  3442     // Rubberband
       
  3443     if (d->rubberBanding && !d->rubberBandRect.isEmpty()) {
       
  3444         painter.restore();
       
  3445         QStyleOptionRubberBand option;
       
  3446         option.initFrom(viewport());
       
  3447         option.rect = d->rubberBandRect;
       
  3448         option.shape = QRubberBand::Rectangle;
       
  3449 
       
  3450         QStyleHintReturnMask mask;
       
  3451         if (viewport()->style()->styleHint(QStyle::SH_RubberBand_Mask, &option, viewport(), &mask)) {
       
  3452             // painter clipping for masked rubberbands
       
  3453             painter.setClipRegion(mask.region, Qt::IntersectClip);
       
  3454         }
       
  3455 
       
  3456         viewport()->style()->drawControl(QStyle::CE_RubberBand, &option, &painter, viewport());
       
  3457     }
       
  3458 #endif
       
  3459 
       
  3460     painter.end();
       
  3461 
       
  3462     // Restore painter state protection.
       
  3463     d->scene->d_func()->painterStateProtection = true;
       
  3464 }
       
  3465 
       
  3466 /*!
       
  3467     \reimp
       
  3468 */
       
  3469 void QGraphicsView::resizeEvent(QResizeEvent *event)
       
  3470 {
       
  3471     Q_D(QGraphicsView);
       
  3472     // Save the last center point - the resize may scroll the view, which
       
  3473     // changes the center point.
       
  3474     QPointF oldLastCenterPoint = d->lastCenterPoint;
       
  3475 
       
  3476     QAbstractScrollArea::resizeEvent(event);
       
  3477     d->recalculateContentSize();
       
  3478 
       
  3479     // Restore the center point again.
       
  3480     if (d->resizeAnchor == NoAnchor && !d->keepLastCenterPoint) {
       
  3481         d->updateLastCenterPoint();
       
  3482     } else {
       
  3483         d->lastCenterPoint = oldLastCenterPoint;
       
  3484     }
       
  3485     d->centerView(d->resizeAnchor);
       
  3486     d->keepLastCenterPoint = false;
       
  3487 
       
  3488     if (d->cacheMode & CacheBackground) {
       
  3489         // Invalidate the background pixmap
       
  3490         d->mustResizeBackgroundPixmap = true;
       
  3491     }
       
  3492 }
       
  3493 
       
  3494 /*!
       
  3495     \reimp
       
  3496 */
       
  3497 void QGraphicsView::scrollContentsBy(int dx, int dy)
       
  3498 {
       
  3499     Q_D(QGraphicsView);
       
  3500     d->dirtyScroll = true;
       
  3501     if (d->transforming)
       
  3502         return;
       
  3503     if (isRightToLeft())
       
  3504         dx = -dx;
       
  3505 
       
  3506     if (d->viewportUpdateMode != QGraphicsView::NoViewportUpdate) {
       
  3507         if (d->viewportUpdateMode != QGraphicsView::FullViewportUpdate) {
       
  3508             if (d->accelerateScrolling) {
       
  3509 #ifndef QT_NO_RUBBERBAND
       
  3510                 // Update new and old rubberband regions
       
  3511                 if (!d->rubberBandRect.isEmpty()) {
       
  3512                     QRegion rubberBandRegion(d->rubberBandRegion(viewport(), d->rubberBandRect));
       
  3513                     rubberBandRegion += rubberBandRegion.translated(-dx, -dy);
       
  3514                     viewport()->update(rubberBandRegion);
       
  3515                 }
       
  3516 #endif
       
  3517                 d->dirtyScrollOffset.rx() += dx;
       
  3518                 d->dirtyScrollOffset.ry() += dy;
       
  3519                 d->dirtyRegion.translate(dx, dy);
       
  3520                 viewport()->scroll(dx, dy);
       
  3521             } else {
       
  3522                 d->updateAll();
       
  3523             }
       
  3524         } else {
       
  3525             d->updateAll();
       
  3526         }
       
  3527     }
       
  3528 
       
  3529     d->updateLastCenterPoint();
       
  3530 
       
  3531     if ((d->cacheMode & CacheBackground)
       
  3532 #ifdef Q_WS_X11
       
  3533         && X11->use_xrender
       
  3534 #endif
       
  3535         ) {
       
  3536         // Scroll the background pixmap
       
  3537         QRegion exposed;
       
  3538         if (!d->backgroundPixmap.isNull())
       
  3539             d->backgroundPixmap.scroll(dx, dy, d->backgroundPixmap.rect(), &exposed);
       
  3540 
       
  3541         // Invalidate the background pixmap
       
  3542         d->backgroundPixmapExposed.translate(dx, dy);
       
  3543         d->backgroundPixmapExposed += exposed;
       
  3544     }
       
  3545 
       
  3546     // Always replay on scroll.
       
  3547     if (d->sceneInteractionAllowed)
       
  3548         d->replayLastMouseEvent();
       
  3549 }
       
  3550 
       
  3551 /*!
       
  3552     \reimp
       
  3553 */
       
  3554 void QGraphicsView::showEvent(QShowEvent *event)
       
  3555 {
       
  3556     Q_D(QGraphicsView);
       
  3557     d->recalculateContentSize();
       
  3558     d->centerView(d->transformationAnchor);
       
  3559     QAbstractScrollArea::showEvent(event);
       
  3560 }
       
  3561 
       
  3562 /*!
       
  3563     \reimp
       
  3564 */
       
  3565 void QGraphicsView::inputMethodEvent(QInputMethodEvent *event)
       
  3566 {
       
  3567     Q_D(QGraphicsView);
       
  3568     if (d->scene)
       
  3569         QApplication::sendEvent(d->scene, event);
       
  3570 }
       
  3571 
       
  3572 /*!
       
  3573     Draws the background of the scene using \a painter, before any items and
       
  3574     the foreground are drawn. Reimplement this function to provide a custom
       
  3575     background for this view.
       
  3576 
       
  3577     If all you want is to define a color, texture or gradient for the
       
  3578     background, you can call setBackgroundBrush() instead.
       
  3579 
       
  3580     All painting is done in \e scene coordinates. \a rect is the exposed
       
  3581     rectangle.
       
  3582 
       
  3583     The default implementation fills \a rect using the view's backgroundBrush.
       
  3584     If no such brush is defined (the default), the scene's drawBackground()
       
  3585     function is called instead.
       
  3586 
       
  3587     \sa drawForeground(), QGraphicsScene::drawBackground()
       
  3588 */
       
  3589 void QGraphicsView::drawBackground(QPainter *painter, const QRectF &rect)
       
  3590 {
       
  3591     Q_D(QGraphicsView);
       
  3592     if (d->scene && d->backgroundBrush.style() == Qt::NoBrush) {
       
  3593         d->scene->drawBackground(painter, rect);
       
  3594         return;
       
  3595     }
       
  3596 
       
  3597     painter->fillRect(rect, d->backgroundBrush);
       
  3598 }
       
  3599 
       
  3600 /*!
       
  3601     Draws the foreground of the scene using \a painter, after the background
       
  3602     and all items are drawn. Reimplement this function to provide a custom
       
  3603     foreground for this view.
       
  3604 
       
  3605     If all you want is to define a color, texture or gradient for the
       
  3606     foreground, you can call setForegroundBrush() instead.
       
  3607 
       
  3608     All painting is done in \e scene coordinates. \a rect is the exposed
       
  3609     rectangle.
       
  3610 
       
  3611     The default implementation fills \a rect using the view's foregroundBrush.
       
  3612     If no such brush is defined (the default), the scene's drawForeground()
       
  3613     function is called instead.
       
  3614 
       
  3615     \sa drawBackground(), QGraphicsScene::drawForeground()
       
  3616 */
       
  3617 void QGraphicsView::drawForeground(QPainter *painter, const QRectF &rect)
       
  3618 {
       
  3619     Q_D(QGraphicsView);
       
  3620     if (d->scene && d->foregroundBrush.style() == Qt::NoBrush) {
       
  3621         d->scene->drawForeground(painter, rect);
       
  3622         return;
       
  3623     }
       
  3624 
       
  3625     painter->fillRect(rect, d->foregroundBrush);
       
  3626 }
       
  3627 
       
  3628 /*!
       
  3629     \obsolete 
       
  3630 
       
  3631     Draws the items \a items in the scene using \a painter, after the
       
  3632     background and before the foreground are drawn. \a numItems is the number
       
  3633     of items in \a items and options in \a options. \a options is a list of
       
  3634     styleoptions; one for each item. Reimplement this function to provide
       
  3635     custom item drawing for this view.
       
  3636 
       
  3637     The default implementation calls the scene's drawItems() function.
       
  3638 
       
  3639     Since Qt 4.6, this function is not called anymore unless
       
  3640     the QGraphicsView::IndirectPainting flag is given as an Optimization
       
  3641     flag.
       
  3642 
       
  3643     \sa drawForeground(), drawBackground(), QGraphicsScene::drawItems()
       
  3644 */
       
  3645 void QGraphicsView::drawItems(QPainter *painter, int numItems,
       
  3646                               QGraphicsItem *items[],
       
  3647                               const QStyleOptionGraphicsItem options[])
       
  3648 {
       
  3649     Q_D(QGraphicsView);
       
  3650     if (d->scene) {
       
  3651         QWidget *widget = painter->device() == viewport() ? viewport() : 0;
       
  3652         d->scene->drawItems(painter, numItems, items, options, widget);
       
  3653     }
       
  3654 }
       
  3655 
       
  3656 /*!
       
  3657     Returns the current transformation matrix for the view. If no current
       
  3658     transformation is set, the identity matrix is returned.
       
  3659 
       
  3660     \sa setTransform(), rotate(), scale(), shear(), translate()
       
  3661 */
       
  3662 QTransform QGraphicsView::transform() const
       
  3663 {
       
  3664     Q_D(const QGraphicsView);
       
  3665     return d->matrix;
       
  3666 }
       
  3667 
       
  3668 /*!
       
  3669     Returns a matrix that maps viewport coordinates to scene coordinates.
       
  3670 
       
  3671     \sa mapToScene(), mapFromScene()
       
  3672 */
       
  3673 QTransform QGraphicsView::viewportTransform() const
       
  3674 {
       
  3675     Q_D(const QGraphicsView);
       
  3676     QTransform moveMatrix = QTransform::fromTranslate(-d->horizontalScroll(), -d->verticalScroll());
       
  3677     return d->identityMatrix ? moveMatrix : d->matrix * moveMatrix;
       
  3678 }
       
  3679 
       
  3680 /*!
       
  3681     \since 4.6
       
  3682 
       
  3683     Returns true if the view is transformed (i.e., a non-identity transform
       
  3684     has been assigned, or the scrollbars are adjusted).
       
  3685 
       
  3686     \sa setTransform(), horizontalScrollBar(), verticalScrollBar()
       
  3687 */
       
  3688 bool QGraphicsView::isTransformed() const
       
  3689 {
       
  3690     Q_D(const QGraphicsView);
       
  3691     return !d->identityMatrix || d->horizontalScroll() || d->verticalScroll();
       
  3692 }
       
  3693 
       
  3694 /*!
       
  3695     Sets the view's current transformation matrix to \a matrix.
       
  3696 
       
  3697     If \a combine is true, then \a matrix is combined with the current matrix;
       
  3698     otherwise, \a matrix \e replaces the current matrix. \a combine is false
       
  3699     by default.
       
  3700 
       
  3701     The transformation matrix tranforms the scene into view coordinates. Using
       
  3702     the default transformation, provided by the identity matrix, one pixel in
       
  3703     the view represents one unit in the scene (e.g., a 10x10 rectangular item
       
  3704     is drawn using 10x10 pixels in the view). If a 2x2 scaling matrix is
       
  3705     applied, the scene will be drawn in 1:2 (e.g., a 10x10 rectangular item is
       
  3706     then drawn using 20x20 pixels in the view).
       
  3707 
       
  3708     Example:
       
  3709 
       
  3710     \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsview.cpp 7
       
  3711 
       
  3712     To simplify interation with items using a transformed view, QGraphicsView
       
  3713     provides mapTo... and mapFrom... functions that can translate between
       
  3714     scene and view coordinates. For example, you can call mapToScene() to map
       
  3715     a view coordiate to a floating point scene coordinate, or mapFromScene()
       
  3716     to map from floating point scene coordinates to view coordinates.
       
  3717 
       
  3718     \sa transform(), rotate(), scale(), shear(), translate()
       
  3719 */
       
  3720 void QGraphicsView::setTransform(const QTransform &matrix, bool combine )
       
  3721 {
       
  3722     Q_D(QGraphicsView);
       
  3723     QTransform oldMatrix = d->matrix;
       
  3724     if (!combine)
       
  3725         d->matrix = matrix;
       
  3726     else
       
  3727         d->matrix = matrix * d->matrix;
       
  3728     if (oldMatrix == d->matrix)
       
  3729         return;
       
  3730 
       
  3731     d->identityMatrix = d->matrix.isIdentity();
       
  3732     d->transforming = true;
       
  3733     if (d->scene) {
       
  3734         d->recalculateContentSize();
       
  3735         d->centerView(d->transformationAnchor);
       
  3736     } else {
       
  3737         d->updateLastCenterPoint();
       
  3738     }
       
  3739 
       
  3740     if (d->sceneInteractionAllowed)
       
  3741         d->replayLastMouseEvent();
       
  3742     d->transforming = false;
       
  3743 
       
  3744     // Any matrix operation requires a full update.
       
  3745     d->updateAll();
       
  3746 }
       
  3747 
       
  3748 /*!
       
  3749     Resets the view transformation to the identity matrix.
       
  3750 
       
  3751     \sa transform(), setTransform()
       
  3752 */
       
  3753 void QGraphicsView::resetTransform()
       
  3754 {
       
  3755     setTransform(QTransform());
       
  3756 }
       
  3757 
       
  3758 QPointF QGraphicsViewPrivate::mapToScene(const QPointF &point) const
       
  3759 {
       
  3760     QPointF p = point;
       
  3761     p.rx() += horizontalScroll();
       
  3762     p.ry() += verticalScroll();
       
  3763     return identityMatrix ? p : matrix.inverted().map(p);
       
  3764 }
       
  3765 
       
  3766 QRectF QGraphicsViewPrivate::mapToScene(const QRectF &rect) const
       
  3767 {
       
  3768     QPointF scrollOffset(horizontalScroll(), verticalScroll());
       
  3769     QPointF tl = scrollOffset + rect.topLeft();
       
  3770     QPointF tr = scrollOffset + rect.topRight();
       
  3771     QPointF br = scrollOffset + rect.bottomRight();
       
  3772     QPointF bl = scrollOffset + rect.bottomLeft();
       
  3773 
       
  3774     QPolygonF poly(4);
       
  3775     if (!identityMatrix) {
       
  3776         QTransform x = matrix.inverted();
       
  3777         poly[0] = x.map(tl);
       
  3778         poly[1] = x.map(tr);
       
  3779         poly[2] = x.map(br);
       
  3780         poly[3] = x.map(bl);
       
  3781     } else {
       
  3782         poly[0] = tl;
       
  3783         poly[1] = tr;
       
  3784         poly[2] = br;
       
  3785         poly[3] = bl;
       
  3786     }
       
  3787     return poly.boundingRect();
       
  3788 }
       
  3789 
       
  3790 QT_END_NAMESPACE
       
  3791 
       
  3792 #include "moc_qgraphicsview.cpp"
       
  3793 
       
  3794 #endif // QT_NO_GRAPHICSVIEW