src/gui/widgets/qmdiarea.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 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 /*!
       
    43     \class QMdiArea
       
    44     \brief The QMdiArea widget provides an area in which MDI windows are displayed.
       
    45     \since 4.3
       
    46     \ingroup mainwindow-classes
       
    47 
       
    48 
       
    49     QMdiArea functions, essentially, like a window manager for MDI
       
    50     windows. For instance, it draws the windows it manages on itself
       
    51     and arranges them in a cascading or tile pattern. QMdiArea is
       
    52     commonly used as the center widget in a QMainWindow to create MDI
       
    53     applications, but can also be placed in any layout. The following
       
    54     code adds an area to a main window:
       
    55 
       
    56     \snippet doc/src/snippets/mdiareasnippets.cpp 0
       
    57 
       
    58     Unlike the window managers for top-level windows, all window flags
       
    59     (Qt::WindowFlags) are supported by QMdiArea as long as the flags
       
    60     are supported by the current widget style. If a specific flag is
       
    61     not supported by the style (e.g., the
       
    62     \l{Qt::}{WindowShadeButtonHint}), you can still shade the window
       
    63     with showShaded().
       
    64 
       
    65     Subwindows in QMdiArea are instances of QMdiSubWindow. They
       
    66     are added to an MDI area with addSubWindow(). It is common to pass
       
    67     a QWidget, which is set as the internal widget, to this function,
       
    68     but it is also possible to pass a QMdiSubWindow directly.The class
       
    69     inherits QWidget, and you can use the same API as with a normal
       
    70     top-level window when programming. QMdiSubWindow also has behavior
       
    71     that is specific to MDI windows. See the QMdiSubWindow class
       
    72     description for more details.
       
    73 
       
    74     A subwindow becomes active when it gets the keyboard focus, or
       
    75     when setFocus() is called. The user activates a window by moving
       
    76     focus in the usual ways. The MDI area emits the
       
    77     subWindowActivated() signal when the active window changes, and
       
    78     the activeSubWindow() function returns the active subwindow.
       
    79 
       
    80     The convenience function subWindowList() returns a list of all
       
    81     subwindows. This information could be used in a popup menu
       
    82     containing a list of windows, for example.
       
    83 
       
    84     The subwindows are sorted by the current
       
    85     \l{QMdiArea::}{WindowOrder}. This is used for the subWindowList()
       
    86     and for activateNextSubWindow() and acivatePreviousSubWindow().
       
    87     Also, it is used when cascading or tiling the windows with
       
    88     cascadeSubWindows() and tileSubWindows().
       
    89 
       
    90     QMdiArea provides two built-in layout strategies for
       
    91     subwindows: cascadeSubWindows() and tileSubWindows(). Both are
       
    92     slots and are easily connected to menu entries.
       
    93 
       
    94     \table
       
    95     \row \o \inlineimage mdi-cascade.png
       
    96          \o \inlineimage mdi-tile.png
       
    97     \endtable
       
    98 
       
    99     \note The default scroll bar property for QMdiArea is Qt::ScrollBarAlwaysOff.
       
   100 
       
   101     \sa QMdiSubWindow
       
   102 */
       
   103 
       
   104 /*!
       
   105     \fn QMdiArea::subWindowActivated(QMdiSubWindow *window)
       
   106 
       
   107     QMdiArea emits this signal after \a window has been activated. When \a
       
   108     window is 0, QMdiArea has just deactivated its last active window, and
       
   109     there are no active windows on the workspace.
       
   110 
       
   111     \sa QMdiArea::activeSubWindow()
       
   112 */
       
   113 
       
   114 /*!
       
   115     \enum QMdiArea::AreaOption
       
   116 
       
   117     This enum describes options that customize the behavior of the
       
   118     QMdiArea.
       
   119 
       
   120     \value DontMaximizeSubWindowOnActivation When the active subwindow
       
   121     is maximized, the default behavior is to maximize the next
       
   122     subwindow that is activated. Set this option if you do not want
       
   123     this behavior.
       
   124 */
       
   125 
       
   126 /*!
       
   127     \enum QMdiArea::WindowOrder
       
   128 
       
   129     Specifies the criteria to use for ordering the list of child windows
       
   130     returned by subWindowList(). The functions cascadeSubWindows() and
       
   131     tileSubWindows() follow this order when arranging the windows.
       
   132 
       
   133     \value CreationOrder The windows are returned in the order of
       
   134     their creation.
       
   135 
       
   136     \value StackingOrder The windows are returned in the order in
       
   137     which they are stacked, with the top-most window being last in
       
   138     the list.
       
   139 
       
   140     \value ActivationHistoryOrder The windows are returned in the order in
       
   141     which they were activated.
       
   142 
       
   143     \sa subWindowList()
       
   144 */
       
   145 
       
   146 /*!
       
   147     \enum QMdiArea::ViewMode
       
   148     \since 4.4
       
   149 
       
   150     This enum describes the view mode of the area; i.e. how sub-windows
       
   151     will be displayed.
       
   152 
       
   153     \value SubWindowView Display sub-windows with window frames (default).
       
   154     \value TabbedView Display sub-windows with tabs in a tab bar.
       
   155 
       
   156     \sa setViewMode()
       
   157 */
       
   158 
       
   159 #include "qmdiarea_p.h"
       
   160 
       
   161 #ifndef QT_NO_MDIAREA
       
   162 
       
   163 #include <QApplication>
       
   164 #include <QStyle>
       
   165 #if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
       
   166 #include <QMacStyle>
       
   167 #endif
       
   168 #include <QChildEvent>
       
   169 #include <QResizeEvent>
       
   170 #include <QScrollBar>
       
   171 #include <QtAlgorithms>
       
   172 #include <QMutableListIterator>
       
   173 #include <QPainter>
       
   174 #include <QFontMetrics>
       
   175 #include <QStyleOption>
       
   176 #include <QDesktopWidget>
       
   177 #include <QDebug>
       
   178 #include <qmath.h>
       
   179 #include <private/qlayoutengine_p.h>
       
   180 
       
   181 QT_BEGIN_NAMESPACE
       
   182 
       
   183 using namespace QMdi;
       
   184 
       
   185 // Asserts in debug mode, gives warning otherwise.
       
   186 static bool sanityCheck(const QMdiSubWindow * const child, const char *where)
       
   187 {
       
   188     if (!child) {
       
   189         const char error[] = "null pointer";
       
   190         Q_ASSERT_X(false, where, error);
       
   191         qWarning("%s:%s", where, error);
       
   192         return false;
       
   193     }
       
   194     return true;
       
   195 }
       
   196 
       
   197 static bool sanityCheck(const QList<QWidget *> &widgets, const int index, const char *where)
       
   198 {
       
   199     if (index < 0 || index >= widgets.size()) {
       
   200         const char error[] = "index out of range";
       
   201         Q_ASSERT_X(false, where, error);
       
   202         qWarning("%s:%s", where, error);
       
   203         return false;
       
   204     }
       
   205     if (!widgets.at(index)) {
       
   206         const char error[] = "null pointer";
       
   207         Q_ASSERT_X(false, where, error);
       
   208         qWarning("%s:%s", where, error);
       
   209         return false;
       
   210     }
       
   211     return true;
       
   212 }
       
   213 
       
   214 static void setIndex(int *index, int candidate, int min, int max, bool isIncreasing)
       
   215 {
       
   216     if (!index)
       
   217         return;
       
   218 
       
   219     if (isIncreasing) {
       
   220         if (candidate > max)
       
   221             *index = min;
       
   222         else
       
   223             *index = qMax(candidate, min);
       
   224     } else {
       
   225         if (candidate < min)
       
   226             *index = max;
       
   227         else
       
   228             *index = qMin(candidate, max);
       
   229     }
       
   230     Q_ASSERT(*index >= min && *index <= max);
       
   231 }
       
   232 
       
   233 static inline bool useScrollBar(const QRect &childrenRect, const QSize &maxViewportSize,
       
   234                                 Qt::Orientation orientation)
       
   235 {
       
   236     if (orientation == Qt::Horizontal)
       
   237         return  childrenRect.width() > maxViewportSize.width()
       
   238                 || childrenRect.left() < 0
       
   239                 || childrenRect.right() >= maxViewportSize.width();
       
   240     else
       
   241         return childrenRect.height() > maxViewportSize.height()
       
   242                || childrenRect.top() < 0
       
   243                || childrenRect.bottom() >= maxViewportSize.height();
       
   244 }
       
   245 
       
   246 // Returns the closest mdi area containing the widget (if any).
       
   247 static inline QMdiArea *mdiAreaParent(QWidget *widget)
       
   248 {
       
   249     if (!widget)
       
   250         return 0;
       
   251 
       
   252     QWidget *parent = widget->parentWidget();
       
   253     while (parent) {
       
   254         if (QMdiArea *area = qobject_cast<QMdiArea *>(parent))
       
   255             return area;
       
   256         parent = parent->parentWidget();
       
   257     }
       
   258     return 0;
       
   259 }
       
   260 
       
   261 #ifndef QT_NO_TABWIDGET
       
   262 static inline QTabBar::Shape tabBarShapeFrom(QTabWidget::TabShape shape, QTabWidget::TabPosition position)
       
   263 {
       
   264     const bool rounded = (shape == QTabWidget::Rounded);
       
   265     if (position == QTabWidget::North)
       
   266         return rounded ? QTabBar::RoundedNorth : QTabBar::TriangularNorth;
       
   267     if (position == QTabWidget::South)
       
   268         return rounded ? QTabBar::RoundedSouth : QTabBar::TriangularSouth;
       
   269     if (position == QTabWidget::East)
       
   270         return rounded ? QTabBar::RoundedEast : QTabBar::TriangularEast;
       
   271     if (position == QTabWidget::West)
       
   272         return rounded ? QTabBar::RoundedWest : QTabBar::TriangularWest;
       
   273     return QTabBar::RoundedNorth;
       
   274 }
       
   275 #endif // QT_NO_TABWIDGET
       
   276 
       
   277 static inline QString tabTextFor(QMdiSubWindow *subWindow)
       
   278 {
       
   279     if (!subWindow)
       
   280         return QString();
       
   281 
       
   282     QString title = subWindow->windowTitle();
       
   283     if (subWindow->isWindowModified()) {
       
   284         title.replace(QLatin1String("[*]"), QLatin1String("*"));
       
   285     } else {
       
   286         extern QString qt_setWindowTitle_helperHelper(const QString&, const QWidget*);
       
   287         title = qt_setWindowTitle_helperHelper(title, subWindow);
       
   288     }
       
   289 
       
   290     return title.isEmpty() ? QMdiArea::tr("(Untitled)") : title;
       
   291 }
       
   292 
       
   293 /*!
       
   294     \internal
       
   295 */
       
   296 void RegularTiler::rearrange(QList<QWidget *> &widgets, const QRect &domain) const
       
   297 {
       
   298     if (widgets.isEmpty())
       
   299         return;
       
   300 
       
   301     const int n = widgets.size();
       
   302     const int ncols = qMax(qCeil(qSqrt(qreal(n))), 1);
       
   303     const int nrows = qMax((n % ncols) ? (n / ncols + 1) : (n / ncols), 1);
       
   304     const int nspecial = (n % ncols) ? (ncols - n % ncols) : 0;
       
   305     const int dx = domain.width()  / ncols;
       
   306     const int dy = domain.height() / nrows;
       
   307 
       
   308     int i = 0;
       
   309     for (int row = 0; row < nrows; ++row) {
       
   310         const int y1 = int(row * (dy + 1));
       
   311         for (int col = 0; col < ncols; ++col) {
       
   312             if (row == 1 && col < nspecial)
       
   313                 continue;
       
   314             const int x1 = int(col * (dx + 1));
       
   315             int x2 = int(x1 + dx);
       
   316             int y2 = int(y1 + dy);
       
   317             if (row == 0 && col < nspecial) {
       
   318                 y2 *= 2;
       
   319                 if (nrows != 2)
       
   320                     y2 += 1;
       
   321                 else
       
   322                     y2 = domain.bottom();
       
   323             }
       
   324             if (col == ncols - 1 && x2 != domain.right())
       
   325                 x2 = domain.right();
       
   326             if (row == nrows - 1 && y2 != domain.bottom())
       
   327                 y2 = domain.bottom();
       
   328             if (!sanityCheck(widgets, i, "RegularTiler"))
       
   329                 continue;
       
   330             QWidget *widget = widgets.at(i++);
       
   331             QRect newGeometry = QRect(QPoint(x1, y1), QPoint(x2, y2));
       
   332             widget->setGeometry(QStyle::visualRect(widget->layoutDirection(), domain, newGeometry));
       
   333         }
       
   334     }
       
   335 }
       
   336 
       
   337 /*!
       
   338     \internal
       
   339 */
       
   340 void SimpleCascader::rearrange(QList<QWidget *> &widgets, const QRect &domain) const
       
   341 {
       
   342     if (widgets.isEmpty())
       
   343         return;
       
   344 
       
   345     // Tunables:
       
   346     const int topOffset = 0;
       
   347     const int bottomOffset = 50;
       
   348     const int leftOffset = 0;
       
   349     const int rightOffset = 100;
       
   350     const int dx = 10;
       
   351 
       
   352     QStyleOptionTitleBar options;
       
   353     options.initFrom(widgets.at(0));
       
   354     int titleBarHeight = widgets.at(0)->style()->pixelMetric(QStyle::PM_TitleBarHeight, &options, widgets.at(0));
       
   355 #if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
       
   356     // ### Remove this after the mac style has been fixed
       
   357     if (qobject_cast<QMacStyle *>(widgets.at(0)->style()))
       
   358         titleBarHeight -= 4;
       
   359 #endif
       
   360     const QFontMetrics fontMetrics = QFontMetrics(QApplication::font("QWorkspaceTitleBar"));
       
   361     const int dy = qMax(titleBarHeight - (titleBarHeight - fontMetrics.height()) / 2, 1);
       
   362 
       
   363     const int n = widgets.size();
       
   364     const int nrows = qMax((domain.height() - (topOffset + bottomOffset)) / dy, 1);
       
   365     const int ncols = qMax(n / nrows + ((n % nrows) ? 1 : 0), 1);
       
   366     const int dcol = (domain.width() - (leftOffset + rightOffset)) / ncols;
       
   367 
       
   368     int i = 0;
       
   369     for (int row = 0; row < nrows; ++row) {
       
   370         for (int col = 0; col < ncols; ++col) {
       
   371             const int x = leftOffset + row * dx + col * dcol;
       
   372             const int y = topOffset + row * dy;
       
   373             if (!sanityCheck(widgets, i, "SimpleCascader"))
       
   374                 continue;
       
   375             QWidget *widget = widgets.at(i++);
       
   376             QRect newGeometry = QRect(QPoint(x, y), widget->sizeHint());
       
   377             widget->setGeometry(QStyle::visualRect(widget->layoutDirection(), domain, newGeometry));
       
   378             if (i == n)
       
   379                 return;
       
   380         }
       
   381     }
       
   382 }
       
   383 
       
   384 /*!
       
   385     \internal
       
   386 */
       
   387 void IconTiler::rearrange(QList<QWidget *> &widgets, const QRect &domain) const
       
   388 {
       
   389     if (widgets.isEmpty() || !sanityCheck(widgets, 0, "IconTiler"))
       
   390         return;
       
   391 
       
   392     const int n = widgets.size();
       
   393     const int width = widgets.at(0)->width();
       
   394     const int height = widgets.at(0)->height();
       
   395     const int ncols = qMax(domain.width() / width, 1);
       
   396     const int nrows = n / ncols + ((n % ncols) ? 1 : 0);
       
   397 
       
   398     int i = 0;
       
   399     for (int row = 0; row < nrows; ++row) {
       
   400         for (int col = 0; col < ncols; ++col) {
       
   401             const int x = col * width;
       
   402             const int y = domain.height() - height - row * height;
       
   403             if (!sanityCheck(widgets, i, "IconTiler"))
       
   404                 continue;
       
   405             QWidget *widget = widgets.at(i++);
       
   406             QPoint newPos(x, y);
       
   407             QRect newGeometry = QRect(newPos.x(), newPos.y(), widget->width(), widget->height());
       
   408             widget->setGeometry(QStyle::visualRect(widget->layoutDirection(), domain, newGeometry));
       
   409             if (i == n)
       
   410                 return;
       
   411         }
       
   412     }
       
   413 }
       
   414 
       
   415 /*!
       
   416     \internal
       
   417     Calculates the accumulated overlap (intersection area) between 'source' and 'rects'.
       
   418 */
       
   419 int MinOverlapPlacer::accumulatedOverlap(const QRect &source, const QList<QRect> &rects)
       
   420 {
       
   421     int accOverlap = 0;
       
   422     foreach (const QRect &rect, rects) {
       
   423         QRect intersection = source.intersected(rect);
       
   424         accOverlap += intersection.width() * intersection.height();
       
   425     }
       
   426     return accOverlap;
       
   427 }
       
   428 
       
   429 
       
   430 /*!
       
   431     \internal
       
   432     Finds among 'source' the rectangle with the minimum accumulated overlap with the
       
   433     rectangles in 'rects'.
       
   434 */
       
   435 QRect MinOverlapPlacer::findMinOverlapRect(const QList<QRect> &source, const QList<QRect> &rects)
       
   436 {
       
   437     int minAccOverlap = -1;
       
   438     QRect minAccOverlapRect;
       
   439     foreach (const QRect &srcRect, source) {
       
   440         const int accOverlap = accumulatedOverlap(srcRect, rects);
       
   441         if (accOverlap < minAccOverlap || minAccOverlap == -1) {
       
   442             minAccOverlap = accOverlap;
       
   443             minAccOverlapRect = srcRect;
       
   444         }
       
   445     }
       
   446     return minAccOverlapRect;
       
   447 }
       
   448 
       
   449 /*!
       
   450     \internal
       
   451     Gets candidates for the final placement.
       
   452 */
       
   453 void MinOverlapPlacer::getCandidatePlacements(const QSize &size, const QList<QRect> &rects,
       
   454                                               const QRect &domain,QList<QRect> &candidates)
       
   455 {
       
   456     QSet<int> xset;
       
   457     QSet<int> yset;
       
   458     xset << domain.left() << domain.right() - size.width() + 1;
       
   459     yset << domain.top();
       
   460     if (domain.bottom() - size.height() + 1 >= 0)
       
   461         yset << domain.bottom() - size.height() + 1;
       
   462     foreach (const QRect &rect, rects) {
       
   463         xset << rect.right() + 1;
       
   464         yset << rect.bottom() + 1;
       
   465     }
       
   466 
       
   467     QList<int> xlist = xset.values();
       
   468     qSort(xlist.begin(), xlist.end());
       
   469     QList<int> ylist = yset.values();
       
   470     qSort(ylist.begin(), ylist.end());
       
   471 
       
   472     foreach (int y, ylist)
       
   473         foreach (int x, xlist)
       
   474             candidates << QRect(QPoint(x, y), size);
       
   475 }
       
   476 
       
   477 /*!
       
   478     \internal
       
   479     Finds all rectangles in 'source' not completely inside 'domain'. The result is stored
       
   480     in 'result' and also removed from 'source'.
       
   481 */
       
   482 void MinOverlapPlacer::findNonInsiders(const QRect &domain, QList<QRect> &source,
       
   483                                        QList<QRect> &result)
       
   484 {
       
   485     QMutableListIterator<QRect> it(source);
       
   486     while (it.hasNext()) {
       
   487         const QRect srcRect = it.next();
       
   488         if (!domain.contains(srcRect)) {
       
   489             result << srcRect;
       
   490             it.remove();
       
   491         }
       
   492     }
       
   493 }
       
   494 
       
   495 /*!
       
   496    \internal
       
   497     Finds all rectangles in 'source' that overlaps 'domain' by the maximum overlap area
       
   498     between 'domain' and any rectangle in 'source'. The result is stored in 'result'.
       
   499 */
       
   500 void MinOverlapPlacer::findMaxOverlappers(const QRect &domain, const QList<QRect> &source,
       
   501                                           QList<QRect> &result)
       
   502 {
       
   503     int maxOverlap = -1;
       
   504     foreach (const QRect &srcRect, source) {
       
   505         QRect intersection = domain.intersected(srcRect);
       
   506         const int overlap = intersection.width() * intersection.height();
       
   507         if (overlap >= maxOverlap || maxOverlap == -1) {
       
   508             if (overlap > maxOverlap) {
       
   509                 maxOverlap = overlap;
       
   510                 result.clear();
       
   511             }
       
   512             result << srcRect;
       
   513         }
       
   514     }
       
   515 }
       
   516 
       
   517 /*!
       
   518    \internal
       
   519     Finds among the rectangles in 'source' the best placement. Here, 'best' means the
       
   520     placement that overlaps the rectangles in 'rects' as little as possible while at the
       
   521     same time being as much as possible inside 'domain'.
       
   522 */
       
   523 QPoint MinOverlapPlacer::findBestPlacement(const QRect &domain, const QList<QRect> &rects,
       
   524                                            QList<QRect> &source)
       
   525 {
       
   526     QList<QRect> nonInsiders;
       
   527     findNonInsiders(domain, source, nonInsiders);
       
   528 
       
   529     if (!source.empty())
       
   530         return findMinOverlapRect(source, rects).topLeft();
       
   531 
       
   532     QList<QRect> maxOverlappers;
       
   533     findMaxOverlappers(domain, nonInsiders, maxOverlappers);
       
   534     return findMinOverlapRect(maxOverlappers, rects).topLeft();
       
   535 }
       
   536 
       
   537 
       
   538 /*!
       
   539     \internal
       
   540     Places the rectangle defined by 'size' relative to 'rects' and 'domain' so that it
       
   541     overlaps 'rects' as little as possible and 'domain' as much as possible.
       
   542     Returns the position of the resulting rectangle.
       
   543 */
       
   544 QPoint MinOverlapPlacer::place(const QSize &size, const QList<QRect> &rects,
       
   545                                const QRect &domain) const
       
   546 {
       
   547     if (size.isEmpty() || !domain.isValid())
       
   548         return QPoint();
       
   549     foreach (const QRect &rect, rects) {
       
   550         if (!rect.isValid())
       
   551             return QPoint();
       
   552     }
       
   553 
       
   554     QList<QRect> candidates;
       
   555     getCandidatePlacements(size, rects, domain, candidates);
       
   556     return findBestPlacement(domain, rects, candidates);
       
   557 }
       
   558 
       
   559 #ifndef QT_NO_TABBAR
       
   560 class QMdiAreaTabBar : public QTabBar
       
   561 {
       
   562 public:
       
   563     QMdiAreaTabBar(QWidget *parent) : QTabBar(parent) {}
       
   564 
       
   565 protected:
       
   566     void mousePressEvent(QMouseEvent *event);
       
   567 #ifndef QT_NO_CONTEXTMENU
       
   568     void contextMenuEvent(QContextMenuEvent *event);
       
   569 #endif
       
   570 
       
   571 private:
       
   572     QMdiSubWindow *subWindowFromIndex(int index) const;
       
   573 };
       
   574 
       
   575 /*!
       
   576     \internal
       
   577 */
       
   578 void QMdiAreaTabBar::mousePressEvent(QMouseEvent *event)
       
   579 {
       
   580     if (event->button() != Qt::MidButton) {
       
   581         QTabBar::mousePressEvent(event);
       
   582         return;
       
   583     }
       
   584 
       
   585     QMdiSubWindow *subWindow = subWindowFromIndex(tabAt(event->pos()));
       
   586     if (!subWindow) {
       
   587         event->ignore();
       
   588         return;
       
   589     }
       
   590 
       
   591     subWindow->close();
       
   592 }
       
   593 
       
   594 #ifndef QT_NO_CONTEXTMENU
       
   595 /*!
       
   596     \internal
       
   597 */
       
   598 void QMdiAreaTabBar::contextMenuEvent(QContextMenuEvent *event)
       
   599 {
       
   600     QPointer<QMdiSubWindow> subWindow = subWindowFromIndex(tabAt(event->pos()));
       
   601     if (!subWindow || subWindow->isHidden()) {
       
   602         event->ignore();
       
   603         return;
       
   604     }
       
   605 
       
   606 #ifndef QT_NO_MENU
       
   607     QMdiSubWindowPrivate *subWindowPrivate = subWindow->d_func();
       
   608     if (!subWindowPrivate->systemMenu) {
       
   609         event->ignore();
       
   610         return;
       
   611     }
       
   612 
       
   613     QMdiSubWindow *currentSubWindow = subWindowFromIndex(currentIndex());
       
   614     Q_ASSERT(currentSubWindow);
       
   615 
       
   616     // We don't want these actions to show up in the system menu when the
       
   617     // current sub-window is maximized, i.e. covers the entire viewport.
       
   618     if (currentSubWindow->isMaximized()) {
       
   619         subWindowPrivate->setVisible(QMdiSubWindowPrivate::MoveAction, false);
       
   620         subWindowPrivate->setVisible(QMdiSubWindowPrivate::ResizeAction, false);
       
   621         subWindowPrivate->setVisible(QMdiSubWindowPrivate::MinimizeAction, false);
       
   622         subWindowPrivate->setVisible(QMdiSubWindowPrivate::MaximizeAction, false);
       
   623         subWindowPrivate->setVisible(QMdiSubWindowPrivate::MaximizeAction, false);
       
   624         subWindowPrivate->setVisible(QMdiSubWindowPrivate::StayOnTopAction, false);
       
   625     }
       
   626 
       
   627     // Show system menu.
       
   628     subWindowPrivate->systemMenu->exec(event->globalPos());
       
   629     if (!subWindow)
       
   630         return;
       
   631 
       
   632     // Restore action visibility.
       
   633     subWindowPrivate->updateActions();
       
   634 #endif // QT_NO_MENU
       
   635 }
       
   636 #endif // QT_NO_CONTEXTMENU
       
   637 
       
   638 /*!
       
   639     \internal
       
   640 */
       
   641 QMdiSubWindow *QMdiAreaTabBar::subWindowFromIndex(int index) const
       
   642 {
       
   643     if (index < 0 || index >= count())
       
   644         return 0;
       
   645 
       
   646     QMdiArea *mdiArea = qobject_cast<QMdiArea *>(parentWidget());
       
   647     Q_ASSERT(mdiArea);
       
   648 
       
   649     const QList<QMdiSubWindow *> subWindows = mdiArea->subWindowList();
       
   650     Q_ASSERT(index < subWindows.size());
       
   651 
       
   652     QMdiSubWindow *subWindow = mdiArea->subWindowList().at(index);
       
   653     Q_ASSERT(subWindow);
       
   654 
       
   655     return subWindow;
       
   656 }
       
   657 #endif // QT_NO_TABBAR
       
   658 
       
   659 /*!
       
   660     \internal
       
   661 */
       
   662 QMdiAreaPrivate::QMdiAreaPrivate()
       
   663     : cascader(0),
       
   664       regularTiler(0),
       
   665       iconTiler(0),
       
   666       placer(0),
       
   667 #ifndef QT_NO_RUBBERBAND
       
   668       rubberBand(0),
       
   669 #endif
       
   670 #ifndef QT_NO_TABBAR
       
   671       tabBar(0),
       
   672 #endif
       
   673       activationOrder(QMdiArea::CreationOrder),
       
   674       viewMode(QMdiArea::SubWindowView),
       
   675 #ifndef QT_NO_TABBAR
       
   676       documentMode(false),
       
   677 #endif
       
   678 #ifndef QT_NO_TABWIDGET
       
   679       tabShape(QTabWidget::Rounded),
       
   680       tabPosition(QTabWidget::North),
       
   681 #endif
       
   682       ignoreGeometryChange(false),
       
   683       ignoreWindowStateChange(false),
       
   684       isActivated(false),
       
   685       isSubWindowsTiled(false),
       
   686       showActiveWindowMaximized(false),
       
   687       tileCalledFromResizeEvent(false),
       
   688       updatesDisabledByUs(false),
       
   689       inViewModeChange(false),
       
   690       indexToNextWindow(-1),
       
   691       indexToPreviousWindow(-1),
       
   692       indexToHighlighted(-1),
       
   693       indexToLastActiveTab(-1),
       
   694       resizeTimerId(-1),
       
   695       tabToPreviousTimerId(-1)
       
   696 {
       
   697 }
       
   698 
       
   699 /*!
       
   700     \internal
       
   701 */
       
   702 void QMdiAreaPrivate::_q_deactivateAllWindows(QMdiSubWindow *aboutToActivate)
       
   703 {
       
   704     if (ignoreWindowStateChange)
       
   705         return;
       
   706 
       
   707     Q_Q(QMdiArea);
       
   708     if (!aboutToActivate)
       
   709         aboutToBecomeActive = qobject_cast<QMdiSubWindow *>(q->sender());
       
   710     else
       
   711         aboutToBecomeActive = aboutToActivate;
       
   712     Q_ASSERT(aboutToBecomeActive);
       
   713 
       
   714     foreach (QMdiSubWindow *child, childWindows) {
       
   715         if (!sanityCheck(child, "QMdiArea::deactivateAllWindows") || aboutToBecomeActive == child)
       
   716             continue;
       
   717         // We don't want to handle signals caused by child->showNormal().
       
   718         ignoreWindowStateChange = true;
       
   719         if(!(options & QMdiArea::DontMaximizeSubWindowOnActivation) && !showActiveWindowMaximized)
       
   720             showActiveWindowMaximized = child->isMaximized() && child->isVisible();
       
   721         if (showActiveWindowMaximized && child->isMaximized()) {
       
   722             if (q->updatesEnabled()) {
       
   723                 updatesDisabledByUs = true;
       
   724                 q->setUpdatesEnabled(false);
       
   725             }
       
   726             child->showNormal();
       
   727         }
       
   728         if (child->isMinimized() && !child->isShaded() && !windowStaysOnTop(child))
       
   729             child->lower();
       
   730         ignoreWindowStateChange = false;
       
   731         child->d_func()->setActive(false);
       
   732     }
       
   733 }
       
   734 
       
   735 /*!
       
   736     \internal
       
   737 */
       
   738 void QMdiAreaPrivate::_q_processWindowStateChanged(Qt::WindowStates oldState,
       
   739                                                    Qt::WindowStates newState)
       
   740 {
       
   741     if (ignoreWindowStateChange)
       
   742         return;
       
   743 
       
   744     Q_Q(QMdiArea);
       
   745     QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(q->sender());
       
   746     if (!child)
       
   747         return;
       
   748 
       
   749     // windowActivated
       
   750     if (!(oldState & Qt::WindowActive) && (newState & Qt::WindowActive))
       
   751         emitWindowActivated(child);
       
   752     // windowDeactivated
       
   753     else if ((oldState & Qt::WindowActive) && !(newState & Qt::WindowActive))
       
   754         resetActiveWindow(child);
       
   755 
       
   756     // windowMinimized
       
   757     if (!(oldState & Qt::WindowMinimized) && (newState & Qt::WindowMinimized)) {
       
   758         isSubWindowsTiled = false;
       
   759         arrangeMinimizedSubWindows();
       
   760     // windowMaximized
       
   761     } else if (!(oldState & Qt::WindowMaximized) && (newState & Qt::WindowMaximized)) {
       
   762         internalRaise(child);
       
   763     // windowRestored
       
   764     } else if (!(newState & (Qt::WindowMaximized | Qt::WindowMinimized))) {
       
   765         internalRaise(child);
       
   766         if (oldState & Qt::WindowMinimized)
       
   767             arrangeMinimizedSubWindows();
       
   768     }
       
   769 }
       
   770 
       
   771 void QMdiAreaPrivate::_q_currentTabChanged(int index)
       
   772 {
       
   773 #ifdef QT_NO_TABBAR
       
   774     Q_UNUSED(index);
       
   775 #else
       
   776     if (!tabBar || index < 0)
       
   777         return;
       
   778 
       
   779     // If the previous active sub-window was hidden, disable the tab.
       
   780     if (indexToLastActiveTab >= 0 && indexToLastActiveTab < tabBar->count()
       
   781         && indexToLastActiveTab < childWindows.count()) {
       
   782         QMdiSubWindow *lastActive = childWindows.at(indexToLastActiveTab);
       
   783         if (lastActive && lastActive->isHidden())
       
   784             tabBar->setTabEnabled(indexToLastActiveTab, false);
       
   785     }
       
   786 
       
   787     indexToLastActiveTab = index;
       
   788     Q_ASSERT(childWindows.size() > index);
       
   789     QMdiSubWindow *subWindow = childWindows.at(index);
       
   790     Q_ASSERT(subWindow);
       
   791     activateWindow(subWindow);
       
   792 #endif // QT_NO_TABBAR
       
   793 }
       
   794 
       
   795 /*!
       
   796     \internal
       
   797 */
       
   798 void QMdiAreaPrivate::appendChild(QMdiSubWindow *child)
       
   799 {
       
   800     Q_Q(QMdiArea);
       
   801     Q_ASSERT(child && childWindows.indexOf(child) == -1);
       
   802 
       
   803     if (child->parent() != viewport)
       
   804         child->setParent(viewport, child->windowFlags());
       
   805     childWindows.append(QPointer<QMdiSubWindow>(child));
       
   806 
       
   807     if (!child->testAttribute(Qt::WA_Resized) && q->isVisible()) {
       
   808         QSize newSize(child->sizeHint().boundedTo(viewport->size()));
       
   809         child->resize(newSize.expandedTo(qSmartMinSize(child)));
       
   810     }
       
   811 
       
   812     if (!placer)
       
   813         placer = new MinOverlapPlacer;
       
   814     place(placer, child);
       
   815 
       
   816     if (hbarpolicy != Qt::ScrollBarAlwaysOff)
       
   817         child->setOption(QMdiSubWindow::AllowOutsideAreaHorizontally, true);
       
   818     else
       
   819         child->setOption(QMdiSubWindow::AllowOutsideAreaHorizontally, false);
       
   820 
       
   821     if (vbarpolicy != Qt::ScrollBarAlwaysOff)
       
   822         child->setOption(QMdiSubWindow::AllowOutsideAreaVertically, true);
       
   823     else
       
   824         child->setOption(QMdiSubWindow::AllowOutsideAreaVertically, false);
       
   825 
       
   826     internalRaise(child);
       
   827     indicesToActivatedChildren.prepend(childWindows.size() - 1);
       
   828     Q_ASSERT(indicesToActivatedChildren.size() == childWindows.size());
       
   829 
       
   830 #ifndef QT_NO_TABBAR
       
   831     if (tabBar) {
       
   832         tabBar->addTab(child->windowIcon(), tabTextFor(child));
       
   833         updateTabBarGeometry();
       
   834         if (childWindows.count() == 1 && !(options & QMdiArea::DontMaximizeSubWindowOnActivation))
       
   835             showActiveWindowMaximized = true;
       
   836     }
       
   837 #endif
       
   838 
       
   839     if (!(child->windowFlags() & Qt::SubWindow))
       
   840         child->setWindowFlags(Qt::SubWindow);
       
   841     child->installEventFilter(q);
       
   842 
       
   843     QObject::connect(child, SIGNAL(aboutToActivate()), q, SLOT(_q_deactivateAllWindows()));
       
   844     QObject::connect(child, SIGNAL(windowStateChanged(Qt::WindowStates, Qt::WindowStates)),
       
   845                      q, SLOT(_q_processWindowStateChanged(Qt::WindowStates, Qt::WindowStates)));
       
   846 }
       
   847 
       
   848 /*!
       
   849     \internal
       
   850 */
       
   851 void QMdiAreaPrivate::place(Placer *placer, QMdiSubWindow *child)
       
   852 {
       
   853     if (!placer || !child)
       
   854         return;
       
   855 
       
   856     Q_Q(QMdiArea);
       
   857     if (!q->isVisible()) {
       
   858         // The window is only laid out when it's added to QMdiArea,
       
   859         // so there's no need to check that we don't have it in the
       
   860         // list already. appendChild() ensures that.
       
   861         pendingPlacements.append(child);
       
   862         return;
       
   863     }
       
   864 
       
   865     QList<QRect> rects;
       
   866     QRect parentRect = q->rect();
       
   867     foreach (QMdiSubWindow *window, childWindows) {
       
   868         if (!sanityCheck(window, "QMdiArea::place") || window == child || !window->isVisibleTo(q)
       
   869                 || !window->testAttribute(Qt::WA_Moved)) {
       
   870             continue;
       
   871         }
       
   872         QRect occupiedGeometry;
       
   873         if (window->isMaximized()) {
       
   874             occupiedGeometry = QRect(window->d_func()->oldGeometry.topLeft(),
       
   875                                      window->d_func()->restoreSize);
       
   876         } else {
       
   877             occupiedGeometry = window->geometry();
       
   878         }
       
   879         rects.append(QStyle::visualRect(child->layoutDirection(), parentRect, occupiedGeometry));
       
   880     }
       
   881     QPoint newPos = placer->place(child->size(), rects, parentRect);
       
   882     QRect newGeometry = QRect(newPos.x(), newPos.y(), child->width(), child->height());
       
   883     child->setGeometry(QStyle::visualRect(child->layoutDirection(), parentRect, newGeometry));
       
   884 }
       
   885 
       
   886 /*!
       
   887     \internal
       
   888 */
       
   889 void QMdiAreaPrivate::rearrange(Rearranger *rearranger)
       
   890 {
       
   891     if (!rearranger)
       
   892         return;
       
   893 
       
   894     Q_Q(QMdiArea);
       
   895     if (!q->isVisible()) {
       
   896         // Compress if we already have the rearranger in the list.
       
   897         int index = pendingRearrangements.indexOf(rearranger);
       
   898         if (index != -1)
       
   899             pendingRearrangements.move(index, pendingRearrangements.size() - 1);
       
   900         else
       
   901             pendingRearrangements.append(rearranger);
       
   902         return;
       
   903     }
       
   904 
       
   905     QList<QWidget *> widgets;
       
   906     const bool reverseList = rearranger->type() == Rearranger::RegularTiler;
       
   907     const QList<QMdiSubWindow *> subWindows = subWindowList(activationOrder, reverseList);
       
   908     QSize minSubWindowSize;
       
   909     foreach (QMdiSubWindow *child, subWindows) {
       
   910         if (!sanityCheck(child, "QMdiArea::rearrange") || !child->isVisible())
       
   911             continue;
       
   912         if (rearranger->type() == Rearranger::IconTiler) {
       
   913             if (child->isMinimized() && !child->isShaded() && !(child->windowFlags() & Qt::FramelessWindowHint))
       
   914                 widgets.append(child);
       
   915         } else {
       
   916             if (child->isMinimized() && !child->isShaded())
       
   917                 continue;
       
   918             if (child->isMaximized() || child->isShaded())
       
   919                 child->showNormal();
       
   920             minSubWindowSize = minSubWindowSize.expandedTo(child->minimumSize())
       
   921                                .expandedTo(child->d_func()->internalMinimumSize);
       
   922             widgets.append(child);
       
   923         }
       
   924     }
       
   925 
       
   926     if (active && rearranger->type() == Rearranger::RegularTiler) {
       
   927         // Move active window in front if necessary. That's the case if we
       
   928         // have any windows with staysOnTopHint set.
       
   929         int indexToActive = widgets.indexOf((QWidget *)active);
       
   930         if (indexToActive > 0)
       
   931             widgets.move(indexToActive, 0);
       
   932     }
       
   933 
       
   934     QRect domain = viewport->rect();
       
   935     if (rearranger->type() == Rearranger::RegularTiler && !widgets.isEmpty())
       
   936         domain = resizeToMinimumTileSize(minSubWindowSize, widgets.count());
       
   937 
       
   938     rearranger->rearrange(widgets, domain);
       
   939 
       
   940     if (rearranger->type() == Rearranger::RegularTiler && !widgets.isEmpty()) {
       
   941         isSubWindowsTiled = true;
       
   942         updateScrollBars();
       
   943     } else if (rearranger->type() == Rearranger::SimpleCascader) {
       
   944         isSubWindowsTiled = false;
       
   945     }
       
   946 }
       
   947 
       
   948 /*!
       
   949     \internal
       
   950 
       
   951     Arranges all minimized windows at the bottom of the workspace.
       
   952 */
       
   953 void QMdiAreaPrivate::arrangeMinimizedSubWindows()
       
   954 {
       
   955     if (!iconTiler)
       
   956         iconTiler = new IconTiler;
       
   957     rearrange(iconTiler);
       
   958 }
       
   959 
       
   960 /*!
       
   961     \internal
       
   962 */
       
   963 void QMdiAreaPrivate::activateWindow(QMdiSubWindow *child)
       
   964 {
       
   965     if (childWindows.isEmpty()) {
       
   966         Q_ASSERT(!child);
       
   967         Q_ASSERT(!active);
       
   968         return;
       
   969     }
       
   970 
       
   971     if (!child) {
       
   972         if (active) {
       
   973             Q_ASSERT(active->d_func()->isActive);
       
   974             active->d_func()->setActive(false);
       
   975             resetActiveWindow();
       
   976         }
       
   977         return;
       
   978     }
       
   979 
       
   980     if (child->isHidden() || child == active)
       
   981         return;
       
   982     child->d_func()->setActive(true);
       
   983 }
       
   984 
       
   985 /*!
       
   986     \internal
       
   987 */
       
   988 void QMdiAreaPrivate::activateCurrentWindow()
       
   989 {
       
   990     QMdiSubWindow *current = q_func()->currentSubWindow();
       
   991     if (current && !isExplicitlyDeactivated(current)) {
       
   992         current->d_func()->activationEnabled = true;
       
   993         current->d_func()->setActive(true, /*changeFocus=*/false);
       
   994     }
       
   995 }
       
   996 
       
   997 void QMdiAreaPrivate::activateHighlightedWindow()
       
   998 {
       
   999     if (indexToHighlighted < 0)
       
  1000         return;
       
  1001 
       
  1002     Q_ASSERT(indexToHighlighted < childWindows.size());
       
  1003     if (tabToPreviousTimerId != -1)
       
  1004         activateWindow(nextVisibleSubWindow(-1, QMdiArea::ActivationHistoryOrder));
       
  1005     else
       
  1006         activateWindow(childWindows.at(indexToHighlighted));
       
  1007 #ifndef QT_NO_RUBBERBAND
       
  1008     hideRubberBand();
       
  1009 #endif
       
  1010 }
       
  1011 
       
  1012 /*!
       
  1013     \internal
       
  1014 */
       
  1015 void QMdiAreaPrivate::emitWindowActivated(QMdiSubWindow *activeWindow)
       
  1016 {
       
  1017     Q_Q(QMdiArea);
       
  1018     Q_ASSERT(activeWindow);
       
  1019     if (activeWindow == active)
       
  1020         return;
       
  1021     Q_ASSERT(activeWindow->d_func()->isActive);
       
  1022 
       
  1023     if (!aboutToBecomeActive)
       
  1024         _q_deactivateAllWindows(activeWindow);
       
  1025     Q_ASSERT(aboutToBecomeActive);
       
  1026 
       
  1027     // This is true only if 'DontMaximizeSubWindowOnActivation' is disabled
       
  1028     // and the previous active window was maximized.
       
  1029     if (showActiveWindowMaximized) {
       
  1030         if (!activeWindow->isMaximized())
       
  1031             activeWindow->showMaximized();
       
  1032         showActiveWindowMaximized = false;
       
  1033     }
       
  1034 
       
  1035     // Put in front to update activation order.
       
  1036     const int indexToActiveWindow = childWindows.indexOf(activeWindow);
       
  1037     Q_ASSERT(indexToActiveWindow != -1);
       
  1038     const int index = indicesToActivatedChildren.indexOf(indexToActiveWindow);
       
  1039     Q_ASSERT(index != -1);
       
  1040     indicesToActivatedChildren.move(index, 0);
       
  1041     internalRaise(activeWindow);
       
  1042 
       
  1043     if (updatesDisabledByUs) {
       
  1044         q->setUpdatesEnabled(true);
       
  1045         updatesDisabledByUs = false;
       
  1046     }
       
  1047 
       
  1048     Q_ASSERT(aboutToBecomeActive == activeWindow);
       
  1049     active = activeWindow;
       
  1050     aboutToBecomeActive = 0;
       
  1051     Q_ASSERT(active->d_func()->isActive);
       
  1052 
       
  1053 #ifndef QT_NO_TABBAR
       
  1054     if (tabBar && tabBar->currentIndex() != indexToActiveWindow)
       
  1055         tabBar->setCurrentIndex(indexToActiveWindow);
       
  1056 #endif
       
  1057 
       
  1058     if (active->isMaximized() && scrollBarsEnabled())
       
  1059         updateScrollBars();
       
  1060 
       
  1061     emit q->subWindowActivated(active);
       
  1062 }
       
  1063 
       
  1064 /*!
       
  1065     \internal
       
  1066 */
       
  1067 void QMdiAreaPrivate::resetActiveWindow(QMdiSubWindow *deactivatedWindow)
       
  1068 {
       
  1069     Q_Q(QMdiArea);
       
  1070     if (deactivatedWindow) {
       
  1071         if (deactivatedWindow != active)
       
  1072             return;
       
  1073         active = 0;
       
  1074         if ((aboutToBecomeActive || isActivated || lastWindowAboutToBeDestroyed())
       
  1075             && !isExplicitlyDeactivated(deactivatedWindow) && !q->window()->isMinimized()) {
       
  1076             return;
       
  1077         }
       
  1078         emit q->subWindowActivated(0);
       
  1079         return;
       
  1080     }
       
  1081 
       
  1082     if (aboutToBecomeActive)
       
  1083         return;
       
  1084 
       
  1085     active = 0;
       
  1086     emit q->subWindowActivated(0);
       
  1087 }
       
  1088 
       
  1089 /*!
       
  1090     \internal
       
  1091 */
       
  1092 void QMdiAreaPrivate::updateActiveWindow(int removedIndex, bool activeRemoved)
       
  1093 {
       
  1094     Q_ASSERT(indicesToActivatedChildren.size() == childWindows.size());
       
  1095 
       
  1096 #ifndef QT_NO_TABBAR
       
  1097     if (tabBar && removedIndex >= 0) {
       
  1098         tabBar->blockSignals(true);
       
  1099         tabBar->removeTab(removedIndex);
       
  1100         updateTabBarGeometry();
       
  1101         tabBar->blockSignals(false);
       
  1102     }
       
  1103 #endif
       
  1104 
       
  1105     if (childWindows.isEmpty()) {
       
  1106         showActiveWindowMaximized = false;
       
  1107         resetActiveWindow();
       
  1108         return;
       
  1109     }
       
  1110 
       
  1111     if (indexToHighlighted >= 0) {
       
  1112 #ifndef QT_NO_RUBBERBAND
       
  1113         // Hide rubber band if highlighted window is removed.
       
  1114         if (indexToHighlighted == removedIndex)
       
  1115             hideRubberBand();
       
  1116         else
       
  1117 #endif
       
  1118         // or update index if necessary.
       
  1119         if (indexToHighlighted > removedIndex)
       
  1120             --indexToHighlighted;
       
  1121     }
       
  1122 
       
  1123     // Update indices list
       
  1124     for (int i = 0; i < indicesToActivatedChildren.size(); ++i) {
       
  1125         int *index = &indicesToActivatedChildren[i];
       
  1126         if (*index > removedIndex)
       
  1127             --*index;
       
  1128     }
       
  1129 
       
  1130     if (!activeRemoved)
       
  1131         return;
       
  1132 
       
  1133     // Activate next window.
       
  1134     QMdiSubWindow *next = nextVisibleSubWindow(0, activationOrder, removedIndex);
       
  1135     if (next)
       
  1136         activateWindow(next);
       
  1137 }
       
  1138 
       
  1139 /*!
       
  1140     \internal
       
  1141 */
       
  1142 void QMdiAreaPrivate::updateScrollBars()
       
  1143 {
       
  1144     if (ignoreGeometryChange || !scrollBarsEnabled())
       
  1145         return;
       
  1146 
       
  1147     Q_Q(QMdiArea);
       
  1148     QSize maxSize = q->maximumViewportSize();
       
  1149     QSize hbarExtent = hbar->sizeHint();
       
  1150     QSize vbarExtent = vbar->sizeHint();
       
  1151 
       
  1152     if (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents, 0, q)) {
       
  1153         const int doubleFrameWidth = frameWidth * 2;
       
  1154         if (hbarpolicy == Qt::ScrollBarAlwaysOn)
       
  1155             maxSize.rheight() -= doubleFrameWidth;
       
  1156         if (vbarpolicy == Qt::ScrollBarAlwaysOn)
       
  1157             maxSize.rwidth() -= doubleFrameWidth;
       
  1158         hbarExtent.rheight() += doubleFrameWidth;
       
  1159         vbarExtent.rwidth() += doubleFrameWidth;
       
  1160     }
       
  1161 
       
  1162     const QRect childrenRect = active && active->isMaximized()
       
  1163                                ? active->geometry() : viewport->childrenRect();
       
  1164     bool useHorizontalScrollBar = useScrollBar(childrenRect, maxSize, Qt::Horizontal);
       
  1165     bool useVerticalScrollBar = useScrollBar(childrenRect, maxSize, Qt::Vertical);
       
  1166 
       
  1167     if (useHorizontalScrollBar && !useVerticalScrollBar) {
       
  1168         const QSize max = maxSize - QSize(0, hbarExtent.height());
       
  1169         useVerticalScrollBar = useScrollBar(childrenRect, max, Qt::Vertical);
       
  1170     }
       
  1171 
       
  1172     if (useVerticalScrollBar && !useHorizontalScrollBar) {
       
  1173         const QSize max = maxSize - QSize(vbarExtent.width(), 0);
       
  1174         useHorizontalScrollBar = useScrollBar(childrenRect, max, Qt::Horizontal);
       
  1175     }
       
  1176 
       
  1177     if (useHorizontalScrollBar && hbarpolicy != Qt::ScrollBarAlwaysOn)
       
  1178         maxSize.rheight() -= hbarExtent.height();
       
  1179     if (useVerticalScrollBar && vbarpolicy != Qt::ScrollBarAlwaysOn)
       
  1180         maxSize.rwidth() -= vbarExtent.width();
       
  1181 
       
  1182     QRect viewportRect(QPoint(0, 0), maxSize);
       
  1183     const int startX = q->isLeftToRight() ? childrenRect.left() : viewportRect.right()
       
  1184                                                                   - childrenRect.right();
       
  1185 
       
  1186     // Horizontal scroll bar.
       
  1187     if (isSubWindowsTiled && hbar->value() != 0)
       
  1188         hbar->setValue(0);
       
  1189     const int xOffset = startX + hbar->value();
       
  1190     hbar->setRange(qMin(0, xOffset),
       
  1191                    qMax(0, xOffset + childrenRect.width() - viewportRect.width()));
       
  1192     hbar->setPageStep(childrenRect.width());
       
  1193     hbar->setSingleStep(childrenRect.width() / 20);
       
  1194 
       
  1195     // Vertical scroll bar.
       
  1196     if (isSubWindowsTiled && vbar->value() != 0)
       
  1197         vbar->setValue(0);
       
  1198     const int yOffset = childrenRect.top() + vbar->value();
       
  1199     vbar->setRange(qMin(0, yOffset),
       
  1200                    qMax(0, yOffset + childrenRect.height() - viewportRect.height()));
       
  1201     vbar->setPageStep(childrenRect.height());
       
  1202     vbar->setSingleStep(childrenRect.height() / 20);
       
  1203 }
       
  1204 
       
  1205 /*!
       
  1206     \internal
       
  1207 */
       
  1208 void QMdiAreaPrivate::internalRaise(QMdiSubWindow *mdiChild) const
       
  1209 {
       
  1210     if (!sanityCheck(mdiChild, "QMdiArea::internalRaise") || childWindows.size() < 2)
       
  1211         return;
       
  1212 
       
  1213     QMdiSubWindow *stackUnderChild = 0;
       
  1214     if (!windowStaysOnTop(mdiChild)) {
       
  1215         foreach (QObject *object, viewport->children()) {
       
  1216             QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(object);
       
  1217             if (!child || !childWindows.contains(child))
       
  1218                 continue;
       
  1219             if (!child->isHidden() && windowStaysOnTop(child)) {
       
  1220                 if (stackUnderChild)
       
  1221                     child->stackUnder(stackUnderChild);
       
  1222                 else
       
  1223                     child->raise();
       
  1224                 stackUnderChild = child;
       
  1225             }
       
  1226         }
       
  1227     }
       
  1228 
       
  1229     if (stackUnderChild)
       
  1230         mdiChild->stackUnder(stackUnderChild);
       
  1231     else
       
  1232         mdiChild->raise();
       
  1233 }
       
  1234 
       
  1235 QRect QMdiAreaPrivate::resizeToMinimumTileSize(const QSize &minSubWindowSize, int subWindowCount)
       
  1236 {
       
  1237     Q_Q(QMdiArea);
       
  1238     if (!minSubWindowSize.isValid() || subWindowCount <= 0)
       
  1239         return viewport->rect();
       
  1240 
       
  1241     // Calculate minimum size.
       
  1242     const int columns = qMax(qCeil(qSqrt(qreal(subWindowCount))), 1);
       
  1243     const int rows = qMax((subWindowCount % columns) ? (subWindowCount / columns + 1)
       
  1244                                                      : (subWindowCount / columns), 1);
       
  1245     const int minWidth = minSubWindowSize.width() * columns;
       
  1246     const int minHeight = minSubWindowSize.height() * rows;
       
  1247 
       
  1248     // Increase area size if necessary. Scroll bars are provided if we're not able
       
  1249     // to resize to the minimum size.
       
  1250     if (!tileCalledFromResizeEvent) {
       
  1251         QWidget *topLevel = q;
       
  1252         // Find the topLevel for this area, either a real top-level or a sub-window.
       
  1253         while (topLevel && !topLevel->isWindow() && topLevel->windowType() != Qt::SubWindow)
       
  1254             topLevel = topLevel->parentWidget();
       
  1255         // We don't want sub-subwindows to be placed at the edge, thus add 2 pixels.
       
  1256         int minAreaWidth = minWidth + left + right + 2;
       
  1257         int minAreaHeight = minHeight + top + bottom + 2;
       
  1258         if (hbar->isVisible())
       
  1259             minAreaHeight += hbar->height();
       
  1260         if (vbar->isVisible())
       
  1261             minAreaWidth += vbar->width();
       
  1262         if (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents, 0, q)) {
       
  1263             const int frame = q->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, 0, q);
       
  1264             minAreaWidth += 2 * frame;
       
  1265             minAreaHeight += 2 * frame;
       
  1266         }
       
  1267         const QSize diff = QSize(minAreaWidth, minAreaHeight).expandedTo(q->size()) - q->size();
       
  1268         topLevel->resize(topLevel->size() + diff);
       
  1269     }
       
  1270 
       
  1271     QRect domain = viewport->rect();
       
  1272 
       
  1273     // Adjust domain width and provide horizontal scroll bar.
       
  1274     if (domain.width() < minWidth) {
       
  1275         domain.setWidth(minWidth);
       
  1276         if (hbarpolicy == Qt::ScrollBarAlwaysOff)
       
  1277             q->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
       
  1278         else
       
  1279             hbar->setValue(0);
       
  1280     }
       
  1281     // Adjust domain height and provide vertical scroll bar.
       
  1282     if (domain.height() < minHeight) {
       
  1283         domain.setHeight(minHeight);
       
  1284         if (vbarpolicy  == Qt::ScrollBarAlwaysOff)
       
  1285             q->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
       
  1286         else
       
  1287             vbar->setValue(0);
       
  1288     }
       
  1289     return domain;
       
  1290 }
       
  1291 
       
  1292 /*!
       
  1293     \internal
       
  1294 */
       
  1295 bool QMdiAreaPrivate::scrollBarsEnabled() const
       
  1296 {
       
  1297     return hbarpolicy != Qt::ScrollBarAlwaysOff || vbarpolicy != Qt::ScrollBarAlwaysOff;
       
  1298 }
       
  1299 
       
  1300 /*!
       
  1301     \internal
       
  1302 */
       
  1303 bool QMdiAreaPrivate::lastWindowAboutToBeDestroyed() const
       
  1304 {
       
  1305     if (childWindows.count() != 1)
       
  1306         return false;
       
  1307 
       
  1308     QMdiSubWindow *last = childWindows.at(0);
       
  1309     if (!last)
       
  1310         return true;
       
  1311 
       
  1312     if (!last->testAttribute(Qt::WA_DeleteOnClose))
       
  1313         return false;
       
  1314 
       
  1315     return last->d_func()->data.is_closing;
       
  1316 }
       
  1317 
       
  1318 /*!
       
  1319     \internal
       
  1320 */
       
  1321 void QMdiAreaPrivate::setChildActivationEnabled(bool enable, bool onlyNextActivationEvent) const
       
  1322 {
       
  1323     foreach (QMdiSubWindow *subWindow, childWindows) {
       
  1324         if (!subWindow || !subWindow->isVisible())
       
  1325             continue;
       
  1326         if (onlyNextActivationEvent)
       
  1327             subWindow->d_func()->ignoreNextActivationEvent = !enable;
       
  1328         else
       
  1329             subWindow->d_func()->activationEnabled = enable;
       
  1330     }
       
  1331 }
       
  1332 
       
  1333 /*!
       
  1334     \internal
       
  1335     \reimp
       
  1336 */
       
  1337 void QMdiAreaPrivate::scrollBarPolicyChanged(Qt::Orientation orientation, Qt::ScrollBarPolicy policy)
       
  1338 {
       
  1339     if (childWindows.isEmpty())
       
  1340         return;
       
  1341 
       
  1342     const QMdiSubWindow::SubWindowOption option = orientation == Qt::Horizontal ?
       
  1343         QMdiSubWindow::AllowOutsideAreaHorizontally : QMdiSubWindow::AllowOutsideAreaVertically;
       
  1344     const bool enable = policy != Qt::ScrollBarAlwaysOff;
       
  1345     foreach (QMdiSubWindow *child, childWindows) {
       
  1346         if (!sanityCheck(child, "QMdiArea::scrollBarPolicyChanged"))
       
  1347             continue;
       
  1348         child->setOption(option, enable);
       
  1349     }
       
  1350     updateScrollBars();
       
  1351 }
       
  1352 
       
  1353 QList<QMdiSubWindow*>
       
  1354 QMdiAreaPrivate::subWindowList(QMdiArea::WindowOrder order, bool reversed) const
       
  1355 {
       
  1356     QList<QMdiSubWindow *> list;
       
  1357     if (childWindows.isEmpty())
       
  1358         return list;
       
  1359 
       
  1360     if (order == QMdiArea::CreationOrder) {
       
  1361         foreach (QMdiSubWindow *child, childWindows) {
       
  1362             if (!child)
       
  1363                 continue;
       
  1364             if (!reversed)
       
  1365                 list.append(child);
       
  1366             else
       
  1367                 list.prepend(child);
       
  1368         }
       
  1369     } else if (order == QMdiArea::StackingOrder) {
       
  1370         foreach (QObject *object, viewport->children()) {
       
  1371             QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(object);
       
  1372             if (!child || !childWindows.contains(child))
       
  1373                 continue;
       
  1374             if (!reversed)
       
  1375                 list.append(child);
       
  1376             else
       
  1377                 list.prepend(child);
       
  1378         }
       
  1379     } else { // ActivationHistoryOrder
       
  1380         Q_ASSERT(indicesToActivatedChildren.size() == childWindows.size());
       
  1381         for (int i = indicesToActivatedChildren.count() - 1; i >= 0; --i) {
       
  1382             QMdiSubWindow *child = childWindows.at(indicesToActivatedChildren.at(i));
       
  1383             if (!child)
       
  1384                 continue;
       
  1385             if (!reversed)
       
  1386                 list.append(child);
       
  1387             else
       
  1388                 list.prepend(child);
       
  1389         }
       
  1390     }
       
  1391     return list;
       
  1392 }
       
  1393 
       
  1394 /*!
       
  1395     \internal
       
  1396 */
       
  1397 void QMdiAreaPrivate::disconnectSubWindow(QObject *subWindow)
       
  1398 {
       
  1399     if (!subWindow)
       
  1400         return;
       
  1401 
       
  1402     Q_Q(QMdiArea);
       
  1403     QObject::disconnect(subWindow, 0, q, 0);
       
  1404     subWindow->removeEventFilter(q);
       
  1405 }
       
  1406 
       
  1407 /*!
       
  1408     \internal
       
  1409 */
       
  1410 QMdiSubWindow *QMdiAreaPrivate::nextVisibleSubWindow(int increaseFactor, QMdiArea::WindowOrder order,
       
  1411                                                      int removedIndex, int fromIndex) const
       
  1412 {
       
  1413     if (childWindows.isEmpty())
       
  1414         return 0;
       
  1415 
       
  1416     Q_Q(const QMdiArea);
       
  1417     const QList<QMdiSubWindow *> subWindows = q->subWindowList(order);
       
  1418     QMdiSubWindow *current = 0;
       
  1419 
       
  1420     if (removedIndex < 0) {
       
  1421         if (fromIndex >= 0 && fromIndex < subWindows.size())
       
  1422             current = childWindows.at(fromIndex);
       
  1423         else
       
  1424             current = q->currentSubWindow();
       
  1425     }
       
  1426 
       
  1427     // There's no current sub-window (removed or deactivated),
       
  1428     // so we have to pick the last active or the next in creation order.
       
  1429     if (!current) {
       
  1430         if (removedIndex >= 0 && order == QMdiArea::CreationOrder) {
       
  1431             int candidateIndex = -1;
       
  1432             setIndex(&candidateIndex, removedIndex, 0, subWindows.size() - 1, true);
       
  1433             current = childWindows.at(candidateIndex);
       
  1434         } else {
       
  1435             current = subWindows.back();
       
  1436         }
       
  1437     }
       
  1438     Q_ASSERT(current);
       
  1439 
       
  1440     // Find the index for the current sub-window in the given activation order
       
  1441     const int indexToCurrent = subWindows.indexOf(current);
       
  1442     const bool increasing = increaseFactor > 0 ? true : false;
       
  1443 
       
  1444     // and use that index + increseFactor as a candidate.
       
  1445     int index = -1;
       
  1446     setIndex(&index, indexToCurrent + increaseFactor, 0, subWindows.size() - 1, increasing);
       
  1447     Q_ASSERT(index != -1);
       
  1448 
       
  1449     // Try to find another window if the candidate is hidden.
       
  1450     while (subWindows.at(index)->isHidden()) {
       
  1451         setIndex(&index, index + increaseFactor, 0, subWindows.size() - 1, increasing);
       
  1452         if (index == indexToCurrent)
       
  1453             break;
       
  1454     }
       
  1455 
       
  1456     if (!subWindows.at(index)->isHidden())
       
  1457         return subWindows.at(index);
       
  1458     return 0;
       
  1459 }
       
  1460 
       
  1461 /*!
       
  1462     \internal
       
  1463 */
       
  1464 void QMdiAreaPrivate::highlightNextSubWindow(int increaseFactor)
       
  1465 {
       
  1466     if (childWindows.size() == 1)
       
  1467         return;
       
  1468 
       
  1469     Q_Q(QMdiArea);
       
  1470     // There's no highlighted sub-window atm, use current.
       
  1471     if (indexToHighlighted < 0) {
       
  1472         QMdiSubWindow *current = q->currentSubWindow();
       
  1473         if (!current)
       
  1474             return;
       
  1475         indexToHighlighted = childWindows.indexOf(current);
       
  1476     }
       
  1477 
       
  1478     Q_ASSERT(indexToHighlighted >= 0);
       
  1479     Q_ASSERT(indexToHighlighted < childWindows.size());
       
  1480 
       
  1481     QMdiSubWindow *highlight = nextVisibleSubWindow(increaseFactor, activationOrder, -1, indexToHighlighted);
       
  1482     if (!highlight)
       
  1483         return;
       
  1484 
       
  1485 #ifndef QT_NO_RUBBERBAND
       
  1486     if (!rubberBand) {
       
  1487         rubberBand = new QRubberBand(QRubberBand::Rectangle, viewport);
       
  1488         // For accessibility to identify this special widget.
       
  1489         rubberBand->setObjectName(QLatin1String("qt_rubberband"));
       
  1490         rubberBand->setWindowFlags(rubberBand->windowFlags() | Qt::WindowStaysOnTopHint);
       
  1491     }
       
  1492 #endif
       
  1493 
       
  1494     // Only highlight if we're not switching back to the previously active window (Ctrl-Tab once).
       
  1495 #ifndef QT_NO_RUBBERBAND
       
  1496     if (tabToPreviousTimerId == -1)
       
  1497         showRubberBandFor(highlight);
       
  1498 #endif
       
  1499 
       
  1500     indexToHighlighted = childWindows.indexOf(highlight);
       
  1501     Q_ASSERT(indexToHighlighted >= 0);
       
  1502 }
       
  1503 
       
  1504 /*!
       
  1505     \internal
       
  1506     \since 4.4
       
  1507 */
       
  1508 void QMdiAreaPrivate::setViewMode(QMdiArea::ViewMode mode)
       
  1509 {
       
  1510     Q_Q(QMdiArea);
       
  1511     if (viewMode == mode || inViewModeChange)
       
  1512         return;
       
  1513 
       
  1514     // Just a guard since we cannot set viewMode = mode here.
       
  1515     inViewModeChange = true;
       
  1516 
       
  1517 #ifndef QT_NO_TABBAR
       
  1518     if (mode == QMdiArea::TabbedView) {
       
  1519         Q_ASSERT(!tabBar);
       
  1520         tabBar = new QMdiAreaTabBar(q);
       
  1521         tabBar->setDocumentMode(documentMode);
       
  1522 #ifndef QT_NO_TABWIDGET
       
  1523         tabBar->setShape(tabBarShapeFrom(tabShape, tabPosition));
       
  1524 #endif
       
  1525 
       
  1526         isSubWindowsTiled = false;
       
  1527 
       
  1528         foreach (QMdiSubWindow *subWindow, childWindows)
       
  1529             tabBar->addTab(subWindow->windowIcon(), tabTextFor(subWindow));
       
  1530 
       
  1531         QMdiSubWindow *current = q->currentSubWindow();
       
  1532         if (current) {
       
  1533             tabBar->setCurrentIndex(childWindows.indexOf(current));
       
  1534             // Restore sub-window (i.e. cleanup buttons in menu bar and window title).
       
  1535             if (current->isMaximized())
       
  1536                 current->showNormal();
       
  1537 
       
  1538             viewMode = mode;
       
  1539 
       
  1540             // Now, maximize it.
       
  1541             if (!q->testOption(QMdiArea::DontMaximizeSubWindowOnActivation)) {
       
  1542                 current->showMaximized();
       
  1543             }
       
  1544         } else {
       
  1545             viewMode = mode;
       
  1546         }
       
  1547 
       
  1548         if (q->isVisible())
       
  1549             tabBar->show();
       
  1550         updateTabBarGeometry();
       
  1551 
       
  1552         QObject::connect(tabBar, SIGNAL(currentChanged(int)), q, SLOT(_q_currentTabChanged(int)));
       
  1553     } else
       
  1554 #endif // QT_NO_TABBAR
       
  1555     { // SubWindowView
       
  1556 #ifndef QT_NO_TABBAR
       
  1557         delete tabBar;
       
  1558         tabBar = 0;
       
  1559 #endif // QT_NO_TABBAR
       
  1560 
       
  1561         viewMode = mode;
       
  1562         q->setViewportMargins(0, 0, 0, 0);
       
  1563         indexToLastActiveTab = -1;
       
  1564 
       
  1565         QMdiSubWindow *current = q->currentSubWindow();
       
  1566         if (current && current->isMaximized())
       
  1567             current->showNormal();
       
  1568     }
       
  1569 
       
  1570     Q_ASSERT(viewMode == mode);
       
  1571     inViewModeChange = false;
       
  1572 }
       
  1573 
       
  1574 #ifndef QT_NO_TABBAR
       
  1575 /*!
       
  1576     \internal
       
  1577 */
       
  1578 void QMdiAreaPrivate::updateTabBarGeometry()
       
  1579 {
       
  1580     if (!tabBar)
       
  1581         return;
       
  1582 
       
  1583     Q_Q(QMdiArea);
       
  1584 #ifndef QT_NO_TABWIDGET
       
  1585     Q_ASSERT(tabBarShapeFrom(tabShape, tabPosition) == tabBar->shape());
       
  1586 #endif
       
  1587     const QSize tabBarSizeHint = tabBar->sizeHint();
       
  1588 
       
  1589     int areaHeight = q->height();
       
  1590     if (hbar && hbar->isVisible())
       
  1591         areaHeight -= hbar->height();
       
  1592 
       
  1593     int areaWidth = q->width();
       
  1594     if (vbar && vbar->isVisible())
       
  1595         areaWidth -= vbar->width();
       
  1596 
       
  1597     QRect tabBarRect;
       
  1598 #ifndef QT_NO_TABWIDGET
       
  1599     switch (tabPosition) {
       
  1600     case QTabWidget::North:
       
  1601         q->setViewportMargins(0, tabBarSizeHint.height(), 0, 0);
       
  1602         tabBarRect = QRect(0, 0, areaWidth, tabBarSizeHint.height());
       
  1603         break;
       
  1604     case QTabWidget::South:
       
  1605         q->setViewportMargins(0, 0, 0, tabBarSizeHint.height());
       
  1606         tabBarRect = QRect(0, areaHeight - tabBarSizeHint.height(), areaWidth, tabBarSizeHint.height());
       
  1607         break;
       
  1608     case QTabWidget::East:
       
  1609         if (q->layoutDirection() == Qt::LeftToRight)
       
  1610             q->setViewportMargins(0, 0, tabBarSizeHint.width(), 0);
       
  1611         else
       
  1612             q->setViewportMargins(tabBarSizeHint.width(), 0, 0, 0);
       
  1613         tabBarRect = QRect(areaWidth - tabBarSizeHint.width(), 0, tabBarSizeHint.width(), areaHeight);
       
  1614         break;
       
  1615     case QTabWidget::West:
       
  1616         if (q->layoutDirection() == Qt::LeftToRight)
       
  1617             q->setViewportMargins(tabBarSizeHint.width(), 0, 0, 0);
       
  1618         else
       
  1619             q->setViewportMargins(0, 0, tabBarSizeHint.width(), 0);
       
  1620         tabBarRect = QRect(0, 0, tabBarSizeHint.width(), areaHeight);
       
  1621         break;
       
  1622     default:
       
  1623         break;
       
  1624     }
       
  1625 #endif // QT_NO_TABWIDGET
       
  1626 
       
  1627     tabBar->setGeometry(QStyle::visualRect(q->layoutDirection(), q->contentsRect(), tabBarRect));
       
  1628 }
       
  1629 
       
  1630 /*!
       
  1631     \internal
       
  1632 */
       
  1633 void QMdiAreaPrivate::refreshTabBar()
       
  1634 {
       
  1635     if (!tabBar)
       
  1636         return;
       
  1637 
       
  1638     tabBar->setDocumentMode(documentMode);
       
  1639 #ifndef QT_NO_TABWIDGET
       
  1640     tabBar->setShape(tabBarShapeFrom(tabShape, tabPosition));
       
  1641 #endif
       
  1642     updateTabBarGeometry();
       
  1643 }
       
  1644 #endif // QT_NO_TABBAR
       
  1645 
       
  1646 /*!
       
  1647     Constructs an empty mdi area. \a parent is passed to QWidget's
       
  1648     constructor.
       
  1649 */
       
  1650 QMdiArea::QMdiArea(QWidget *parent)
       
  1651     : QAbstractScrollArea(*new QMdiAreaPrivate, parent)
       
  1652 {
       
  1653     setBackground(palette().brush(QPalette::Dark));
       
  1654     setFrameStyle(QFrame::NoFrame);
       
  1655     setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
       
  1656     setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
       
  1657     setViewport(0);
       
  1658     setFocusPolicy(Qt::NoFocus);
       
  1659     QApplication::instance()->installEventFilter(this);
       
  1660 }
       
  1661 
       
  1662 /*!
       
  1663     Destroys the MDI area.
       
  1664 */
       
  1665 QMdiArea::~QMdiArea()
       
  1666 {
       
  1667     Q_D(QMdiArea);
       
  1668     delete d->cascader;
       
  1669     d->cascader = 0;
       
  1670 
       
  1671     delete d->regularTiler;
       
  1672     d->regularTiler = 0;
       
  1673 
       
  1674     delete d->iconTiler;
       
  1675     d->iconTiler = 0;
       
  1676 
       
  1677     delete d->placer;
       
  1678     d->placer = 0;
       
  1679 }
       
  1680 
       
  1681 /*!
       
  1682     \reimp
       
  1683 */
       
  1684 QSize QMdiArea::sizeHint() const
       
  1685 {
       
  1686     // Calculate a proper scale factor for QDesktopWidget::size().
       
  1687     // This also takes into account that we can have nested workspaces.
       
  1688     int nestedCount = 0;
       
  1689     QWidget *widget = this->parentWidget();
       
  1690     while (widget) {
       
  1691         if (qobject_cast<QMdiArea *>(widget))
       
  1692             ++nestedCount;
       
  1693         widget = widget->parentWidget();
       
  1694     }
       
  1695     const int scaleFactor = 3 * (nestedCount + 1);
       
  1696 
       
  1697     QSize desktopSize = QApplication::desktop()->size();
       
  1698     QSize size(desktopSize.width() * 2 / scaleFactor, desktopSize.height() * 2 / scaleFactor);
       
  1699     foreach (QMdiSubWindow *child, d_func()->childWindows) {
       
  1700         if (!sanityCheck(child, "QMdiArea::sizeHint"))
       
  1701             continue;
       
  1702         size = size.expandedTo(child->sizeHint());
       
  1703     }
       
  1704     return size.expandedTo(QApplication::globalStrut());
       
  1705 }
       
  1706 
       
  1707 /*!
       
  1708     \reimp
       
  1709 */
       
  1710 QSize QMdiArea::minimumSizeHint() const
       
  1711 {
       
  1712     Q_D(const QMdiArea);
       
  1713     QSize size(style()->pixelMetric(QStyle::PM_MdiSubWindowMinimizedWidth, 0, this),
       
  1714                style()->pixelMetric(QStyle::PM_TitleBarHeight, 0, this));
       
  1715     size = size.expandedTo(QAbstractScrollArea::minimumSizeHint());
       
  1716     if (!d->scrollBarsEnabled()) {
       
  1717         foreach (QMdiSubWindow *child, d->childWindows) {
       
  1718             if (!sanityCheck(child, "QMdiArea::sizeHint"))
       
  1719                 continue;
       
  1720             size = size.expandedTo(child->minimumSizeHint());
       
  1721         }
       
  1722     }
       
  1723     return size.expandedTo(QApplication::globalStrut());
       
  1724 }
       
  1725 
       
  1726 /*!
       
  1727     Returns a pointer to the current subwindow, or 0 if there is
       
  1728     no current subwindow.
       
  1729 
       
  1730     This function will return the same as activeSubWindow() if
       
  1731     the QApplication containing QMdiArea is active.
       
  1732 
       
  1733     \sa activeSubWindow(), QApplication::activeWindow()
       
  1734 */
       
  1735 QMdiSubWindow *QMdiArea::currentSubWindow() const
       
  1736 {
       
  1737     Q_D(const QMdiArea);
       
  1738     if (d->childWindows.isEmpty())
       
  1739         return 0;
       
  1740 
       
  1741     if (d->active)
       
  1742         return d->active;
       
  1743 
       
  1744     if (d->isActivated && !window()->isMinimized())
       
  1745         return 0;
       
  1746 
       
  1747     Q_ASSERT(d->indicesToActivatedChildren.count() > 0);
       
  1748     int index = d->indicesToActivatedChildren.at(0);
       
  1749     Q_ASSERT(index >= 0 && index < d->childWindows.size());
       
  1750     QMdiSubWindow *current = d->childWindows.at(index);
       
  1751     Q_ASSERT(current);
       
  1752     return current;
       
  1753 }
       
  1754 
       
  1755 /*!
       
  1756     Returns a pointer to the current active subwindow. If no
       
  1757     window is currently active, 0 is returned.
       
  1758 
       
  1759     Subwindows are treated as top-level windows with respect to
       
  1760     window state, i.e., if a widget outside the MDI area is the active
       
  1761     window, no subwindow will be active. Note that if a widget in the
       
  1762     window in which the MDI area lives gains focus, the window will be
       
  1763     activated.
       
  1764 
       
  1765     \sa setActiveSubWindow(), Qt::WindowState
       
  1766 */
       
  1767 QMdiSubWindow *QMdiArea::activeSubWindow() const
       
  1768 {
       
  1769     Q_D(const QMdiArea);
       
  1770     return d->active;
       
  1771 }
       
  1772 
       
  1773 /*!
       
  1774     Activates the subwindow \a window. If \a window is 0, any
       
  1775     current active window is deactivated.
       
  1776 
       
  1777     \sa activeSubWindow()
       
  1778 */
       
  1779 void QMdiArea::setActiveSubWindow(QMdiSubWindow *window)
       
  1780 {
       
  1781     Q_D(QMdiArea);
       
  1782     if (!window) {
       
  1783         d->activateWindow(0);
       
  1784         return;
       
  1785     }
       
  1786 
       
  1787     if (d->childWindows.isEmpty()) {
       
  1788         qWarning("QMdiArea::setActiveSubWindow: workspace is empty");
       
  1789         return;
       
  1790     }
       
  1791 
       
  1792     if (d->childWindows.indexOf(window) == -1) {
       
  1793         qWarning("QMdiArea::setActiveSubWindow: window is not inside workspace");
       
  1794         return;
       
  1795     }
       
  1796 
       
  1797     d->activateWindow(window);
       
  1798 }
       
  1799 
       
  1800 /*!
       
  1801     Closes the active subwindow.
       
  1802 
       
  1803     \sa closeAllSubWindows()
       
  1804 */
       
  1805 void QMdiArea::closeActiveSubWindow()
       
  1806 {
       
  1807     Q_D(QMdiArea);
       
  1808     if (d->active)
       
  1809         d->active->close();
       
  1810 }
       
  1811 
       
  1812 /*!
       
  1813     Returns a list of all subwindows in the MDI area. If \a order is
       
  1814     CreationOrder (the default), the windows are sorted in the order
       
  1815     in which they were inserted into the workspace. If \a order is
       
  1816     StackingOrder, the windows are listed in their stacking order,
       
  1817     with the topmost window as the last item in the list. If \a order
       
  1818     is ActivationHistoryOrder, the windows are listed according to
       
  1819     their recent activation history.
       
  1820 
       
  1821     \sa WindowOrder
       
  1822 */
       
  1823 QList<QMdiSubWindow *> QMdiArea::subWindowList(WindowOrder order) const
       
  1824 {
       
  1825     Q_D(const QMdiArea);
       
  1826     return d->subWindowList(order, false);
       
  1827 }
       
  1828 
       
  1829 /*!
       
  1830     Closes all subwindows by sending a QCloseEvent to each window.
       
  1831     You may receive subWindowActivated() signals from subwindows
       
  1832     before they are closed (if the MDI area activates the subwindow
       
  1833     when another is closing).
       
  1834 
       
  1835     Subwindows that ignore the close event will remain open.
       
  1836 
       
  1837     \sa closeActiveSubWindow()
       
  1838 */
       
  1839 void QMdiArea::closeAllSubWindows()
       
  1840 {
       
  1841     Q_D(QMdiArea);
       
  1842     if (d->childWindows.isEmpty())
       
  1843         return;
       
  1844 
       
  1845     d->isSubWindowsTiled = false;
       
  1846     foreach (QMdiSubWindow *child, d->childWindows) {
       
  1847         if (!sanityCheck(child, "QMdiArea::closeAllSubWindows"))
       
  1848             continue;
       
  1849         child->close();
       
  1850     }
       
  1851 
       
  1852     d->updateScrollBars();
       
  1853 }
       
  1854 
       
  1855 /*!
       
  1856     Gives the keyboard focus to the next window in the list of child
       
  1857     windows.  The windows are activated in the order in which they are
       
  1858     created (CreationOrder).
       
  1859 
       
  1860     \sa activatePreviousSubWindow()
       
  1861 */
       
  1862 void QMdiArea::activateNextSubWindow()
       
  1863 {
       
  1864     Q_D(QMdiArea);
       
  1865     if (d->childWindows.isEmpty())
       
  1866         return;
       
  1867 
       
  1868     QMdiSubWindow *next = d->nextVisibleSubWindow(1, d->activationOrder);
       
  1869     if (next)
       
  1870         d->activateWindow(next);
       
  1871 }
       
  1872 
       
  1873 /*!
       
  1874     Gives the keyboard focus to the previous window in the list of
       
  1875     child windows. The windows are activated in the order in which
       
  1876     they are created (CreationOrder).
       
  1877 
       
  1878     \sa activateNextSubWindow()
       
  1879 */
       
  1880 void QMdiArea::activatePreviousSubWindow()
       
  1881 {
       
  1882     Q_D(QMdiArea);
       
  1883     if (d->childWindows.isEmpty())
       
  1884         return;
       
  1885 
       
  1886     QMdiSubWindow *previous = d->nextVisibleSubWindow(-1, d->activationOrder);
       
  1887     if (previous)
       
  1888         d->activateWindow(previous);
       
  1889 }
       
  1890 
       
  1891 /*!
       
  1892     Adds \a widget as a new subwindow to the MDI area.  If \a
       
  1893     windowFlags are non-zero, they will override the flags set on the
       
  1894     widget.
       
  1895 
       
  1896     The \a widget can be either a QMdiSubWindow or another QWidget
       
  1897     (in which case the MDI area will create a subwindow and set the \a
       
  1898     widget as the internal widget).
       
  1899 
       
  1900     \note Once the subwindow has been added, its parent will be the
       
  1901     \e{viewport widget} of the QMdiArea.
       
  1902 
       
  1903     \snippet doc/src/snippets/mdiareasnippets.cpp 1
       
  1904 
       
  1905     When you create your own subwindow, you must set the
       
  1906     Qt::WA_DeleteOnClose widget attribute if you want the window to be
       
  1907     deleted when closed in the MDI area. If not, the window will be
       
  1908     hidden and the MDI area will not activate the next subwindow.
       
  1909 
       
  1910     Returns the QMdiSubWindow that is added to the MDI area.
       
  1911 
       
  1912     \sa removeSubWindow()
       
  1913 */
       
  1914 QMdiSubWindow *QMdiArea::addSubWindow(QWidget *widget, Qt::WindowFlags windowFlags)
       
  1915 {
       
  1916     if (!widget) {
       
  1917         qWarning("QMdiArea::addSubWindow: null pointer to widget");
       
  1918         return 0;
       
  1919     }
       
  1920 
       
  1921     Q_D(QMdiArea);
       
  1922     // QWidget::setParent clears focusWidget so store it
       
  1923     QWidget *childFocus = widget->focusWidget();
       
  1924     QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(widget);
       
  1925 
       
  1926     // Widget is already a QMdiSubWindow
       
  1927     if (child) {
       
  1928         if (d->childWindows.indexOf(child) != -1) {
       
  1929             qWarning("QMdiArea::addSubWindow: window is already added");
       
  1930             return child;
       
  1931         }
       
  1932         child->setParent(viewport(), windowFlags ? windowFlags : child->windowFlags());
       
  1933     // Create a QMdiSubWindow
       
  1934     } else {
       
  1935         child = new QMdiSubWindow(viewport(), windowFlags);
       
  1936         child->setAttribute(Qt::WA_DeleteOnClose);
       
  1937         child->setWidget(widget);
       
  1938         Q_ASSERT(child->testAttribute(Qt::WA_DeleteOnClose));
       
  1939     }
       
  1940 
       
  1941     if (childFocus)
       
  1942         childFocus->setFocus();
       
  1943     d->appendChild(child);
       
  1944     return child;
       
  1945 }
       
  1946 
       
  1947 /*!
       
  1948     Removes \a widget from the MDI area. The \a widget must be
       
  1949     either a QMdiSubWindow or a widget that is the internal widget of
       
  1950     a subwindow. Note that the subwindow is not deleted by QMdiArea
       
  1951     and that its parent is set to 0.
       
  1952 
       
  1953     \sa addSubWindow()
       
  1954 */
       
  1955 void QMdiArea::removeSubWindow(QWidget *widget)
       
  1956 {
       
  1957     if (!widget) {
       
  1958         qWarning("QMdiArea::removeSubWindow: null pointer to widget");
       
  1959         return;
       
  1960     }
       
  1961 
       
  1962     Q_D(QMdiArea);
       
  1963     if (d->childWindows.isEmpty())
       
  1964         return;
       
  1965 
       
  1966     if (QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(widget)) {
       
  1967         int index = d->childWindows.indexOf(child);
       
  1968         if (index == -1) {
       
  1969             qWarning("QMdiArea::removeSubWindow: window is not inside workspace");
       
  1970             return;
       
  1971         }
       
  1972         d->disconnectSubWindow(child);
       
  1973         d->childWindows.removeAll(child);
       
  1974         d->indicesToActivatedChildren.removeAll(index);
       
  1975         d->updateActiveWindow(index, d->active == child);
       
  1976         child->setParent(0);
       
  1977         return;
       
  1978     }
       
  1979 
       
  1980     bool found = false;
       
  1981     foreach (QMdiSubWindow *child, d->childWindows) {
       
  1982         if (!sanityCheck(child, "QMdiArea::removeSubWindow"))
       
  1983             continue;
       
  1984         if (child->widget() == widget) {
       
  1985             child->setWidget(0);
       
  1986             Q_ASSERT(!child->widget());
       
  1987             found = true;
       
  1988             break;
       
  1989         }
       
  1990     }
       
  1991 
       
  1992     if (!found)
       
  1993         qWarning("QMdiArea::removeSubWindow: widget is not child of any window inside QMdiArea");
       
  1994 }
       
  1995 
       
  1996 /*!
       
  1997     \property QMdiArea::background
       
  1998     \brief the background brush for the workspace
       
  1999 
       
  2000     This property sets the background brush for the workspace area
       
  2001     itself. By default, it is a gray color, but can be any brush
       
  2002     (e.g., colors, gradients or pixmaps).
       
  2003 */
       
  2004 QBrush QMdiArea::background() const
       
  2005 {
       
  2006     return d_func()->background;
       
  2007 }
       
  2008 
       
  2009 void QMdiArea::setBackground(const QBrush &brush)
       
  2010 {
       
  2011     Q_D(QMdiArea);
       
  2012     if (d->background != brush) {
       
  2013         d->background = brush;
       
  2014         d->viewport->setAttribute(Qt::WA_OpaquePaintEvent, brush.isOpaque());
       
  2015         update();
       
  2016     }
       
  2017 }
       
  2018 
       
  2019 
       
  2020 /*!
       
  2021     \property QMdiArea::activationOrder
       
  2022     \brief the ordering criteria for subwindow lists
       
  2023     \since 4.4
       
  2024 
       
  2025     This property specifies the ordering criteria for the list of
       
  2026     subwindows returned by subWindowList(). By default, it is the window
       
  2027     creation order.
       
  2028 
       
  2029     \sa subWindowList()
       
  2030 */
       
  2031 QMdiArea::WindowOrder QMdiArea::activationOrder() const
       
  2032 {
       
  2033     Q_D(const QMdiArea);
       
  2034     return d->activationOrder;
       
  2035 }
       
  2036 
       
  2037 void QMdiArea::setActivationOrder(WindowOrder order)
       
  2038 {
       
  2039     Q_D(QMdiArea);
       
  2040     if (order != d->activationOrder)
       
  2041         d->activationOrder = order;
       
  2042 }
       
  2043 
       
  2044 /*!
       
  2045     If \a on is true, \a option is enabled on the MDI area; otherwise
       
  2046     it is disabled. See AreaOption for the effect of each option.
       
  2047 
       
  2048     \sa AreaOption, testOption()
       
  2049 */
       
  2050 void QMdiArea::setOption(AreaOption option, bool on)
       
  2051 {
       
  2052     Q_D(QMdiArea);
       
  2053     if (on && !(d->options & option))
       
  2054         d->options |= option;
       
  2055     else if (!on && (d->options & option))
       
  2056         d->options &= ~option;
       
  2057 }
       
  2058 
       
  2059 /*!
       
  2060     Returns true if \a option is enabled; otherwise returns false.
       
  2061 
       
  2062     \sa AreaOption, setOption()
       
  2063 */
       
  2064 bool QMdiArea::testOption(AreaOption option) const
       
  2065 {
       
  2066     return d_func()->options & option;
       
  2067 }
       
  2068 
       
  2069 /*!
       
  2070     \property QMdiArea::viewMode
       
  2071     \brief the way sub-windows are displayed in the QMdiArea.
       
  2072     \since 4.4
       
  2073 
       
  2074     By default, the SubWindowView is used to display sub-windows.
       
  2075 
       
  2076     \sa ViewMode, setTabShape(), setTabPosition()
       
  2077 */
       
  2078 QMdiArea::ViewMode QMdiArea::viewMode() const
       
  2079 {
       
  2080     Q_D(const QMdiArea);
       
  2081     return d->viewMode;
       
  2082 }
       
  2083 
       
  2084 void QMdiArea::setViewMode(ViewMode mode)
       
  2085 {
       
  2086     Q_D(QMdiArea);
       
  2087     d->setViewMode(mode);
       
  2088 }
       
  2089 
       
  2090 #ifndef QT_NO_TABBAR
       
  2091 /*!
       
  2092     \property QMdiArea::documentMode
       
  2093     \brief whether the tab bar is set to document mode in tabbed view mode.
       
  2094     \since 4.5
       
  2095 
       
  2096     Document mode is disabled by default.
       
  2097 
       
  2098     \sa QTabBar::documentMode, setViewMode()
       
  2099 */
       
  2100 bool QMdiArea::documentMode() const
       
  2101 {
       
  2102     Q_D(const QMdiArea);
       
  2103     return d->documentMode;
       
  2104 }
       
  2105 
       
  2106 void QMdiArea::setDocumentMode(bool enabled)
       
  2107 {
       
  2108     Q_D(QMdiArea);
       
  2109     if (d->documentMode == enabled)
       
  2110         return;
       
  2111 
       
  2112     d->documentMode = enabled;
       
  2113     d->refreshTabBar();
       
  2114 }
       
  2115 #endif // QT_NO_TABBAR
       
  2116 
       
  2117 #ifndef QT_NO_TABWIDGET
       
  2118 /*!
       
  2119     \property QMdiArea::tabShape
       
  2120     \brief the shape of the tabs in tabbed view mode.
       
  2121     \since 4.4
       
  2122 
       
  2123     Possible values for this property are QTabWidget::Rounded
       
  2124     (default) or QTabWidget::Triangular.
       
  2125 
       
  2126     \sa QTabWidget::TabShape, setViewMode()
       
  2127 */
       
  2128 QTabWidget::TabShape QMdiArea::tabShape() const
       
  2129 {
       
  2130     Q_D(const QMdiArea);
       
  2131     return d->tabShape;
       
  2132 }
       
  2133 
       
  2134 void QMdiArea::setTabShape(QTabWidget::TabShape shape)
       
  2135 {
       
  2136     Q_D(QMdiArea);
       
  2137     if (d->tabShape == shape)
       
  2138         return;
       
  2139 
       
  2140     d->tabShape = shape;
       
  2141     d->refreshTabBar();
       
  2142 }
       
  2143 
       
  2144 /*!
       
  2145     \property QMdiArea::tabPosition
       
  2146     \brief the position of the tabs in tabbed view mode.
       
  2147     \since 4.4
       
  2148 
       
  2149     Possible values for this property are described by the
       
  2150     QTabWidget::TabPosition enum.
       
  2151 
       
  2152     \sa QTabWidget::TabPosition, setViewMode()
       
  2153 */
       
  2154 QTabWidget::TabPosition QMdiArea::tabPosition() const
       
  2155 {
       
  2156     Q_D(const QMdiArea);
       
  2157     return d->tabPosition;
       
  2158 }
       
  2159 
       
  2160 void QMdiArea::setTabPosition(QTabWidget::TabPosition position)
       
  2161 {
       
  2162     Q_D(QMdiArea);
       
  2163     if (d->tabPosition == position)
       
  2164         return;
       
  2165 
       
  2166     d->tabPosition = position;
       
  2167     d->refreshTabBar();
       
  2168 }
       
  2169 #endif // QT_NO_TABWIDGET
       
  2170 
       
  2171 /*!
       
  2172     \reimp
       
  2173 */
       
  2174 void QMdiArea::childEvent(QChildEvent *childEvent)
       
  2175 {
       
  2176     Q_D(QMdiArea);
       
  2177     if (childEvent->type() == QEvent::ChildPolished) {
       
  2178         if (QMdiSubWindow *mdiChild = qobject_cast<QMdiSubWindow *>(childEvent->child())) {
       
  2179             if (d->childWindows.indexOf(mdiChild) == -1)
       
  2180                 d->appendChild(mdiChild);
       
  2181         }
       
  2182     }
       
  2183 }
       
  2184 
       
  2185 /*!
       
  2186     \reimp
       
  2187 */
       
  2188 void QMdiArea::resizeEvent(QResizeEvent *resizeEvent)
       
  2189 {
       
  2190     Q_D(QMdiArea);
       
  2191     if (d->childWindows.isEmpty()) {
       
  2192         resizeEvent->ignore();
       
  2193         return;
       
  2194     }
       
  2195 
       
  2196 #ifndef QT_NO_TABBAR
       
  2197     d->updateTabBarGeometry();
       
  2198 #endif
       
  2199 
       
  2200     // Re-tile the views if we're in tiled mode. Re-tile means we will change
       
  2201     // the geometry of the children, which in turn means 'isSubWindowsTiled'
       
  2202     // is set to false, so we have to update the state at the end.
       
  2203     if (d->isSubWindowsTiled) {
       
  2204         d->tileCalledFromResizeEvent = true;
       
  2205         tileSubWindows();
       
  2206         d->tileCalledFromResizeEvent = false;
       
  2207         d->isSubWindowsTiled = true;
       
  2208         d->startResizeTimer();
       
  2209         // We don't have scroll bars or any maximized views.
       
  2210         return;
       
  2211     }
       
  2212 
       
  2213     // Resize maximized views.
       
  2214     bool hasMaximizedSubWindow = false;
       
  2215     foreach (QMdiSubWindow *child, d->childWindows) {
       
  2216         if (sanityCheck(child, "QMdiArea::resizeEvent") && child->isMaximized()
       
  2217                 && child->size() != resizeEvent->size()) {
       
  2218             child->resize(resizeEvent->size());
       
  2219             if (!hasMaximizedSubWindow)
       
  2220                 hasMaximizedSubWindow = true;
       
  2221         }
       
  2222     }
       
  2223 
       
  2224     d->updateScrollBars();
       
  2225 
       
  2226     // Minimized views are stacked under maximized views so there's
       
  2227     // no need to re-arrange minimized views on-demand. Start a timer
       
  2228     // just to make things faster with subsequent resize events.
       
  2229     if (hasMaximizedSubWindow)
       
  2230         d->startResizeTimer();
       
  2231     else
       
  2232         d->arrangeMinimizedSubWindows();
       
  2233 }
       
  2234 
       
  2235 /*!
       
  2236     \reimp
       
  2237 */
       
  2238 void QMdiArea::timerEvent(QTimerEvent *timerEvent)
       
  2239 {
       
  2240     Q_D(QMdiArea);
       
  2241     if (timerEvent->timerId() == d->resizeTimerId) {
       
  2242         killTimer(d->resizeTimerId);
       
  2243         d->resizeTimerId = -1;
       
  2244         d->arrangeMinimizedSubWindows();
       
  2245     } else if (timerEvent->timerId() == d->tabToPreviousTimerId) {
       
  2246         killTimer(d->tabToPreviousTimerId);
       
  2247         d->tabToPreviousTimerId = -1;
       
  2248         if (d->indexToHighlighted < 0)
       
  2249             return;
       
  2250 #ifndef QT_NO_RUBBERBAND
       
  2251         // We're not doing a "quick switch" ... show rubber band.
       
  2252         Q_ASSERT(d->indexToHighlighted < d->childWindows.size());
       
  2253         Q_ASSERT(d->rubberBand);
       
  2254         d->showRubberBandFor(d->childWindows.at(d->indexToHighlighted));
       
  2255 #endif
       
  2256     }
       
  2257 }
       
  2258 
       
  2259 /*!
       
  2260     \reimp
       
  2261 */
       
  2262 void QMdiArea::showEvent(QShowEvent *showEvent)
       
  2263 {
       
  2264     Q_D(QMdiArea);
       
  2265     if (!d->pendingRearrangements.isEmpty()) {
       
  2266         bool skipPlacement = false;
       
  2267         foreach (Rearranger *rearranger, d->pendingRearrangements) {
       
  2268             // If this is the case, we don't have to lay out pending child windows
       
  2269             // since the rearranger will find a placement for them.
       
  2270             if (rearranger->type() != Rearranger::IconTiler && !skipPlacement)
       
  2271                 skipPlacement = true;
       
  2272             d->rearrange(rearranger);
       
  2273         }
       
  2274         d->pendingRearrangements.clear();
       
  2275 
       
  2276         if (skipPlacement && !d->pendingPlacements.isEmpty())
       
  2277             d->pendingPlacements.clear();
       
  2278     }
       
  2279 
       
  2280     if (!d->pendingPlacements.isEmpty()) {
       
  2281         foreach (QMdiSubWindow *window, d->pendingPlacements) {
       
  2282             if (!window)
       
  2283                 continue;
       
  2284             if (!window->testAttribute(Qt::WA_Resized)) {
       
  2285                 QSize newSize(window->sizeHint().boundedTo(viewport()->size()));
       
  2286                 window->resize(newSize.expandedTo(qSmartMinSize(window)));
       
  2287             }
       
  2288             if (!window->testAttribute(Qt::WA_Moved) && !window->isMinimized()
       
  2289                     && !window->isMaximized()) {
       
  2290                 d->place(d->placer, window);
       
  2291             }
       
  2292         }
       
  2293         d->pendingPlacements.clear();
       
  2294     }
       
  2295 
       
  2296     d->setChildActivationEnabled(true);
       
  2297     d->activateCurrentWindow();
       
  2298 
       
  2299     QAbstractScrollArea::showEvent(showEvent);
       
  2300 }
       
  2301 
       
  2302 /*!
       
  2303     \reimp
       
  2304 */
       
  2305 bool QMdiArea::viewportEvent(QEvent *event)
       
  2306 {
       
  2307     Q_D(QMdiArea);
       
  2308     switch (event->type()) {
       
  2309     case QEvent::ChildRemoved: {
       
  2310         d->isSubWindowsTiled = false;
       
  2311         QObject *removedChild = static_cast<QChildEvent *>(event)->child();
       
  2312         for (int i = 0; i < d->childWindows.size(); ++i) {
       
  2313             QObject *child = d->childWindows.at(i);
       
  2314             if (!child || child == removedChild || !child->parent()
       
  2315                     || child->parent() != viewport()) {
       
  2316                 if (!testOption(DontMaximizeSubWindowOnActivation)) {
       
  2317                     // In this case we can only rely on the child being a QObject
       
  2318                     // (or 0), but let's try and see if we can get more information.
       
  2319                     QWidget *mdiChild = qobject_cast<QWidget *>(removedChild);
       
  2320                     if (mdiChild && mdiChild->isMaximized())
       
  2321                         d->showActiveWindowMaximized = true;
       
  2322                 }
       
  2323                 d->disconnectSubWindow(child);
       
  2324                 const bool activeRemoved = i == d->indicesToActivatedChildren.at(0);
       
  2325                 d->childWindows.removeAt(i);
       
  2326                 d->indicesToActivatedChildren.removeAll(i);
       
  2327                 d->updateActiveWindow(i, activeRemoved);
       
  2328                 d->arrangeMinimizedSubWindows();
       
  2329                 break;
       
  2330             }
       
  2331         }
       
  2332         d->updateScrollBars();
       
  2333         break;
       
  2334     }
       
  2335     case QEvent::Destroy:
       
  2336         d->isSubWindowsTiled = false;
       
  2337         d->resetActiveWindow();
       
  2338         d->childWindows.clear();
       
  2339         qWarning("QMdiArea: Deleting the view port is undefined, use setViewport instead.");
       
  2340         break;
       
  2341     default:
       
  2342         break;
       
  2343     }
       
  2344     return QAbstractScrollArea::viewportEvent(event);
       
  2345 }
       
  2346 
       
  2347 /*!
       
  2348     \reimp
       
  2349 */
       
  2350 void QMdiArea::scrollContentsBy(int dx, int dy)
       
  2351 {
       
  2352     Q_D(QMdiArea);
       
  2353     const bool wasSubWindowsTiled = d->isSubWindowsTiled;
       
  2354     d->ignoreGeometryChange = true;
       
  2355     viewport()->scroll(isLeftToRight() ? dx : -dx, dy);
       
  2356     d->arrangeMinimizedSubWindows();
       
  2357     d->ignoreGeometryChange = false;
       
  2358     if (wasSubWindowsTiled)
       
  2359         d->isSubWindowsTiled = true;
       
  2360 }
       
  2361 
       
  2362 /*!
       
  2363     Arranges all child windows in a tile pattern.
       
  2364 
       
  2365     \sa cascadeSubWindows()
       
  2366 */
       
  2367 void QMdiArea::tileSubWindows()
       
  2368 {
       
  2369     Q_D(QMdiArea);
       
  2370     if (!d->regularTiler)
       
  2371         d->regularTiler = new RegularTiler;
       
  2372     d->rearrange(d->regularTiler);
       
  2373 }
       
  2374 
       
  2375 /*!
       
  2376     Arranges all the child windows in a cascade pattern.
       
  2377 
       
  2378     \sa tileSubWindows()
       
  2379 */
       
  2380 void QMdiArea::cascadeSubWindows()
       
  2381 {
       
  2382     Q_D(QMdiArea);
       
  2383     if (!d->cascader)
       
  2384         d->cascader = new SimpleCascader;
       
  2385     d->rearrange(d->cascader);
       
  2386 }
       
  2387 
       
  2388 /*!
       
  2389     \reimp
       
  2390 */
       
  2391 bool QMdiArea::event(QEvent *event)
       
  2392 {
       
  2393     Q_D(QMdiArea);
       
  2394     switch (event->type()) {
       
  2395 #ifdef Q_WS_WIN
       
  2396     // QWidgetPrivate::hide_helper activates another sub-window when closing a
       
  2397     // modal dialog on Windows (see activateWindow() inside the the ifdef).
       
  2398     case QEvent::WindowUnblocked:
       
  2399         d->activateCurrentWindow();
       
  2400         break;
       
  2401 #endif
       
  2402     case QEvent::WindowActivate: {
       
  2403         d->isActivated = true;
       
  2404         if (d->childWindows.isEmpty())
       
  2405             break;
       
  2406         if (!d->active)
       
  2407             d->activateCurrentWindow();
       
  2408         d->setChildActivationEnabled(false, true);
       
  2409         break;
       
  2410     }
       
  2411     case QEvent::WindowDeactivate:
       
  2412         d->isActivated = false;
       
  2413         d->setChildActivationEnabled(false, true);
       
  2414         break;
       
  2415     case QEvent::StyleChange:
       
  2416         // Re-tile the views if we're in tiled mode. Re-tile means we will change
       
  2417         // the geometry of the children, which in turn means 'isSubWindowsTiled'
       
  2418         // is set to false, so we have to update the state at the end.
       
  2419         if (d->isSubWindowsTiled) {
       
  2420             tileSubWindows();
       
  2421             d->isSubWindowsTiled = true;
       
  2422         }
       
  2423         break;
       
  2424     case QEvent::WindowIconChange:
       
  2425         foreach (QMdiSubWindow *window, d->childWindows) {
       
  2426             if (sanityCheck(window, "QMdiArea::WindowIconChange"))
       
  2427                 QApplication::sendEvent(window, event);
       
  2428         }
       
  2429         break;
       
  2430     case QEvent::Hide:
       
  2431         d->setActive(d->active, false, false);
       
  2432         d->setChildActivationEnabled(false);
       
  2433         break;
       
  2434 #ifndef QT_NO_TABBAR
       
  2435     case QEvent::LayoutDirectionChange:
       
  2436         d->updateTabBarGeometry();
       
  2437         break;
       
  2438 #endif
       
  2439     default:
       
  2440         break;
       
  2441     }
       
  2442     return QAbstractScrollArea::event(event);
       
  2443 }
       
  2444 
       
  2445 /*!
       
  2446     \reimp
       
  2447 */
       
  2448 bool QMdiArea::eventFilter(QObject *object, QEvent *event)
       
  2449 {
       
  2450     if (!object)
       
  2451         return QAbstractScrollArea::eventFilter(object, event);
       
  2452 
       
  2453     Q_D(QMdiArea);
       
  2454     // Global key events with Ctrl modifier.
       
  2455     if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) {
       
  2456 
       
  2457         QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
       
  2458         // Ingore key events without a Ctrl modifier (except for press/release on the modifier itself).
       
  2459 #ifdef Q_WS_MAC
       
  2460         if (!(keyEvent->modifiers() & Qt::MetaModifier) && keyEvent->key() != Qt::Key_Meta)
       
  2461 #else
       
  2462         if (!(keyEvent->modifiers() & Qt::ControlModifier) && keyEvent->key() != Qt::Key_Control)
       
  2463 #endif
       
  2464             return QAbstractScrollArea::eventFilter(object, event);
       
  2465 
       
  2466         // Find closest mdi area (in case we have a nested workspace).
       
  2467         QMdiArea *area = mdiAreaParent(static_cast<QWidget *>(object));
       
  2468         if (!area)
       
  2469             return QAbstractScrollArea::eventFilter(object, event);
       
  2470 
       
  2471         const bool keyPress = (event->type() == QEvent::KeyPress) ? true : false;
       
  2472 
       
  2473         // 1) Ctrl-Tab once -> activate the previously active window.
       
  2474         // 2) Ctrl-Tab (Tab, Tab, ...) -> iterate through all windows (activateNextSubWindow()).
       
  2475         // 3) Ctrl-Shift-Tab (Tab, Tab, ...) -> iterate through all windows in the opposite
       
  2476         //    direction (activatePreviousSubWindow())
       
  2477         switch (keyEvent->key()) {
       
  2478 #ifdef Q_WS_MAC
       
  2479         case Qt::Key_Meta:
       
  2480 #else
       
  2481         case Qt::Key_Control:
       
  2482 #endif
       
  2483             if (keyPress)
       
  2484                 area->d_func()->startTabToPreviousTimer();
       
  2485             else
       
  2486                 area->d_func()->activateHighlightedWindow();
       
  2487             break;
       
  2488         case Qt::Key_Tab:
       
  2489         case Qt::Key_Backtab:
       
  2490             if (keyPress)
       
  2491                 area->d_func()->highlightNextSubWindow(keyEvent->key() == Qt::Key_Tab ? 1 : -1);
       
  2492             return true;
       
  2493 #ifndef QT_NO_RUBBERBAND
       
  2494         case Qt::Key_Escape:
       
  2495             area->d_func()->hideRubberBand();
       
  2496             break;
       
  2497 #endif
       
  2498         default:
       
  2499             break;
       
  2500         }
       
  2501         return QAbstractScrollArea::eventFilter(object, event);
       
  2502     }
       
  2503 
       
  2504     QMdiSubWindow *subWindow = qobject_cast<QMdiSubWindow *>(object);
       
  2505 
       
  2506     if (!subWindow) {
       
  2507         // QApplication events:
       
  2508         if (event->type() == QEvent::ApplicationActivate && !d->active
       
  2509             && isVisible() && !window()->isMinimized()) {
       
  2510             d->activateCurrentWindow();
       
  2511         } else if (event->type() == QEvent::ApplicationDeactivate && d->active) {
       
  2512             d->setActive(d->active, false, false);
       
  2513         }
       
  2514         return QAbstractScrollArea::eventFilter(object, event);
       
  2515     }
       
  2516 
       
  2517     // QMdiSubWindow events:
       
  2518     switch (event->type()) {
       
  2519     case QEvent::Move:
       
  2520     case QEvent::Resize:
       
  2521         if (d->tileCalledFromResizeEvent)
       
  2522             break;
       
  2523         d->updateScrollBars();
       
  2524         if (!subWindow->isMinimized())
       
  2525             d->isSubWindowsTiled = false;
       
  2526         break;
       
  2527     case QEvent::Show:
       
  2528 #ifndef QT_NO_TABBAR
       
  2529         if (d->tabBar) {
       
  2530             const int tabIndex = d->childWindows.indexOf(subWindow);
       
  2531             if (!d->tabBar->isTabEnabled(tabIndex))
       
  2532                 d->tabBar->setTabEnabled(tabIndex, true);
       
  2533         }
       
  2534 #endif // QT_NO_TABBAR
       
  2535         // fall through
       
  2536     case QEvent::Hide:
       
  2537         d->isSubWindowsTiled = false;
       
  2538         break;
       
  2539 #ifndef QT_NO_RUBBERBAND
       
  2540     case QEvent::Close:
       
  2541         if (d->childWindows.indexOf(subWindow) == d->indexToHighlighted)
       
  2542             d->hideRubberBand();
       
  2543         break;
       
  2544 #endif
       
  2545 #ifndef QT_NO_TABBAR
       
  2546     case QEvent::WindowTitleChange:
       
  2547     case QEvent::ModifiedChange:
       
  2548         if (d->tabBar)
       
  2549             d->tabBar->setTabText(d->childWindows.indexOf(subWindow), tabTextFor(subWindow));
       
  2550         break;
       
  2551     case QEvent::WindowIconChange:
       
  2552         if (d->tabBar)
       
  2553             d->tabBar->setTabIcon(d->childWindows.indexOf(subWindow), subWindow->windowIcon());
       
  2554         break;
       
  2555 #endif // QT_NO_TABBAR
       
  2556     default:
       
  2557         break;
       
  2558     }
       
  2559     return QAbstractScrollArea::eventFilter(object, event);
       
  2560 }
       
  2561 
       
  2562 /*!
       
  2563     \reimp
       
  2564 */
       
  2565 void QMdiArea::paintEvent(QPaintEvent *paintEvent)
       
  2566 {
       
  2567     Q_D(QMdiArea);
       
  2568     QPainter painter(d->viewport);
       
  2569     const QVector<QRect> &exposedRects = paintEvent->region().rects();
       
  2570     for (int i = 0; i < exposedRects.size(); ++i)
       
  2571         painter.fillRect(exposedRects.at(i), d->background);
       
  2572 }
       
  2573 
       
  2574 /*!
       
  2575     This slot is called by QAbstractScrollArea after setViewport() has been
       
  2576     called. Reimplement this function in a subclass of QMdiArea to
       
  2577     initialize the new \a viewport before it is used.
       
  2578 
       
  2579     \sa setViewport()
       
  2580 */
       
  2581 void QMdiArea::setupViewport(QWidget *viewport)
       
  2582 {
       
  2583     Q_D(QMdiArea);
       
  2584     if (viewport)
       
  2585         viewport->setAttribute(Qt::WA_OpaquePaintEvent, d->background.isOpaque());
       
  2586     foreach (QMdiSubWindow *child, d->childWindows) {
       
  2587         if (!sanityCheck(child, "QMdiArea::setupViewport"))
       
  2588             continue;
       
  2589         child->setParent(viewport, child->windowFlags());
       
  2590     }
       
  2591 }
       
  2592 
       
  2593 QT_END_NAMESPACE
       
  2594 
       
  2595 #include "moc_qmdiarea.cpp"
       
  2596 
       
  2597 #endif // QT_NO_MDIAREA