/****************************************************************************+ −
**+ −
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).+ −
** All rights reserved.+ −
** Contact: Nokia Corporation (qt-info@nokia.com)+ −
**+ −
** This file is part of the QtGui module of the Qt Toolkit.+ −
**+ −
** $QT_BEGIN_LICENSE:LGPL$+ −
** No Commercial Usage+ −
** This file contains pre-release code and may not be distributed.+ −
** You may use this file in accordance with the terms and conditions+ −
** contained in the Technology Preview License Agreement accompanying+ −
** this package.+ −
**+ −
** GNU Lesser General Public License Usage+ −
** Alternatively, this file may be used under the terms of the GNU Lesser+ −
** General Public License version 2.1 as published by the Free Software+ −
** Foundation and appearing in the file LICENSE.LGPL included in the+ −
** packaging of this file. Please review the following information to+ −
** ensure the GNU Lesser General Public License version 2.1 requirements+ −
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.+ −
**+ −
** In addition, as a special exception, Nokia gives you certain additional+ −
** rights. These rights are described in the Nokia Qt LGPL Exception+ −
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.+ −
**+ −
** If you have questions regarding the use of this file, please contact+ −
** Nokia at qt-info@nokia.com.+ −
**+ −
**+ −
**+ −
**+ −
**+ −
**+ −
**+ −
**+ −
** $QT_END_LICENSE$+ −
**+ −
****************************************************************************/+ −
+ −
/*!+ −
\class QMdiArea+ −
\brief The QMdiArea widget provides an area in which MDI windows are displayed.+ −
\since 4.3+ −
\ingroup mainwindow-classes+ −
+ −
+ −
QMdiArea functions, essentially, like a window manager for MDI+ −
windows. For instance, it draws the windows it manages on itself+ −
and arranges them in a cascading or tile pattern. QMdiArea is+ −
commonly used as the center widget in a QMainWindow to create MDI+ −
applications, but can also be placed in any layout. The following+ −
code adds an area to a main window:+ −
+ −
\snippet doc/src/snippets/mdiareasnippets.cpp 0+ −
+ −
Unlike the window managers for top-level windows, all window flags+ −
(Qt::WindowFlags) are supported by QMdiArea as long as the flags+ −
are supported by the current widget style. If a specific flag is+ −
not supported by the style (e.g., the+ −
\l{Qt::}{WindowShadeButtonHint}), you can still shade the window+ −
with showShaded().+ −
+ −
Subwindows in QMdiArea are instances of QMdiSubWindow. They+ −
are added to an MDI area with addSubWindow(). It is common to pass+ −
a QWidget, which is set as the internal widget, to this function,+ −
but it is also possible to pass a QMdiSubWindow directly.The class+ −
inherits QWidget, and you can use the same API as with a normal+ −
top-level window when programming. QMdiSubWindow also has behavior+ −
that is specific to MDI windows. See the QMdiSubWindow class+ −
description for more details.+ −
+ −
A subwindow becomes active when it gets the keyboard focus, or+ −
when setFocus() is called. The user activates a window by moving+ −
focus in the usual ways. The MDI area emits the+ −
subWindowActivated() signal when the active window changes, and+ −
the activeSubWindow() function returns the active subwindow.+ −
+ −
The convenience function subWindowList() returns a list of all+ −
subwindows. This information could be used in a popup menu+ −
containing a list of windows, for example.+ −
+ −
The subwindows are sorted by the current+ −
\l{QMdiArea::}{WindowOrder}. This is used for the subWindowList()+ −
and for activateNextSubWindow() and acivatePreviousSubWindow().+ −
Also, it is used when cascading or tiling the windows with+ −
cascadeSubWindows() and tileSubWindows().+ −
+ −
QMdiArea provides two built-in layout strategies for+ −
subwindows: cascadeSubWindows() and tileSubWindows(). Both are+ −
slots and are easily connected to menu entries.+ −
+ −
\table+ −
\row \o \inlineimage mdi-cascade.png+ −
\o \inlineimage mdi-tile.png+ −
\endtable+ −
+ −
\note The default scroll bar property for QMdiArea is Qt::ScrollBarAlwaysOff.+ −
+ −
\sa QMdiSubWindow+ −
*/+ −
+ −
/*!+ −
\fn QMdiArea::subWindowActivated(QMdiSubWindow *window)+ −
+ −
QMdiArea emits this signal after \a window has been activated. When \a+ −
window is 0, QMdiArea has just deactivated its last active window, and+ −
there are no active windows on the workspace.+ −
+ −
\sa QMdiArea::activeSubWindow()+ −
*/+ −
+ −
/*!+ −
\enum QMdiArea::AreaOption+ −
+ −
This enum describes options that customize the behavior of the+ −
QMdiArea.+ −
+ −
\value DontMaximizeSubWindowOnActivation When the active subwindow+ −
is maximized, the default behavior is to maximize the next+ −
subwindow that is activated. Set this option if you do not want+ −
this behavior.+ −
*/+ −
+ −
/*!+ −
\enum QMdiArea::WindowOrder+ −
+ −
Specifies the criteria to use for ordering the list of child windows+ −
returned by subWindowList(). The functions cascadeSubWindows() and+ −
tileSubWindows() follow this order when arranging the windows.+ −
+ −
\value CreationOrder The windows are returned in the order of+ −
their creation.+ −
+ −
\value StackingOrder The windows are returned in the order in+ −
which they are stacked, with the top-most window being last in+ −
the list.+ −
+ −
\value ActivationHistoryOrder The windows are returned in the order in+ −
which they were activated.+ −
+ −
\sa subWindowList()+ −
*/+ −
+ −
/*!+ −
\enum QMdiArea::ViewMode+ −
\since 4.4+ −
+ −
This enum describes the view mode of the area; i.e. how sub-windows+ −
will be displayed.+ −
+ −
\value SubWindowView Display sub-windows with window frames (default).+ −
\value TabbedView Display sub-windows with tabs in a tab bar.+ −
+ −
\sa setViewMode()+ −
*/+ −
+ −
#include "qmdiarea_p.h"+ −
+ −
#ifndef QT_NO_MDIAREA+ −
+ −
#include <QApplication>+ −
#include <QStyle>+ −
#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)+ −
#include <QMacStyle>+ −
#endif+ −
#include <QChildEvent>+ −
#include <QResizeEvent>+ −
#include <QScrollBar>+ −
#include <QtAlgorithms>+ −
#include <QMutableListIterator>+ −
#include <QPainter>+ −
#include <QFontMetrics>+ −
#include <QStyleOption>+ −
#include <QDesktopWidget>+ −
#include <QDebug>+ −
#include <qmath.h>+ −
#include <private/qlayoutengine_p.h>+ −
+ −
QT_BEGIN_NAMESPACE+ −
+ −
using namespace QMdi;+ −
+ −
// Asserts in debug mode, gives warning otherwise.+ −
static bool sanityCheck(const QMdiSubWindow * const child, const char *where)+ −
{+ −
if (!child) {+ −
const char error[] = "null pointer";+ −
Q_ASSERT_X(false, where, error);+ −
qWarning("%s:%s", where, error);+ −
return false;+ −
}+ −
return true;+ −
}+ −
+ −
static bool sanityCheck(const QList<QWidget *> &widgets, const int index, const char *where)+ −
{+ −
if (index < 0 || index >= widgets.size()) {+ −
const char error[] = "index out of range";+ −
Q_ASSERT_X(false, where, error);+ −
qWarning("%s:%s", where, error);+ −
return false;+ −
}+ −
if (!widgets.at(index)) {+ −
const char error[] = "null pointer";+ −
Q_ASSERT_X(false, where, error);+ −
qWarning("%s:%s", where, error);+ −
return false;+ −
}+ −
return true;+ −
}+ −
+ −
static void setIndex(int *index, int candidate, int min, int max, bool isIncreasing)+ −
{+ −
if (!index)+ −
return;+ −
+ −
if (isIncreasing) {+ −
if (candidate > max)+ −
*index = min;+ −
else+ −
*index = qMax(candidate, min);+ −
} else {+ −
if (candidate < min)+ −
*index = max;+ −
else+ −
*index = qMin(candidate, max);+ −
}+ −
Q_ASSERT(*index >= min && *index <= max);+ −
}+ −
+ −
static inline bool useScrollBar(const QRect &childrenRect, const QSize &maxViewportSize,+ −
Qt::Orientation orientation)+ −
{+ −
if (orientation == Qt::Horizontal)+ −
return childrenRect.width() > maxViewportSize.width()+ −
|| childrenRect.left() < 0+ −
|| childrenRect.right() >= maxViewportSize.width();+ −
else+ −
return childrenRect.height() > maxViewportSize.height()+ −
|| childrenRect.top() < 0+ −
|| childrenRect.bottom() >= maxViewportSize.height();+ −
}+ −
+ −
// Returns the closest mdi area containing the widget (if any).+ −
static inline QMdiArea *mdiAreaParent(QWidget *widget)+ −
{+ −
if (!widget)+ −
return 0;+ −
+ −
QWidget *parent = widget->parentWidget();+ −
while (parent) {+ −
if (QMdiArea *area = qobject_cast<QMdiArea *>(parent))+ −
return area;+ −
parent = parent->parentWidget();+ −
}+ −
return 0;+ −
}+ −
+ −
#ifndef QT_NO_TABWIDGET+ −
static inline QTabBar::Shape tabBarShapeFrom(QTabWidget::TabShape shape, QTabWidget::TabPosition position)+ −
{+ −
const bool rounded = (shape == QTabWidget::Rounded);+ −
if (position == QTabWidget::North)+ −
return rounded ? QTabBar::RoundedNorth : QTabBar::TriangularNorth;+ −
if (position == QTabWidget::South)+ −
return rounded ? QTabBar::RoundedSouth : QTabBar::TriangularSouth;+ −
if (position == QTabWidget::East)+ −
return rounded ? QTabBar::RoundedEast : QTabBar::TriangularEast;+ −
if (position == QTabWidget::West)+ −
return rounded ? QTabBar::RoundedWest : QTabBar::TriangularWest;+ −
return QTabBar::RoundedNorth;+ −
}+ −
#endif // QT_NO_TABWIDGET+ −
+ −
static inline QString tabTextFor(QMdiSubWindow *subWindow)+ −
{+ −
if (!subWindow)+ −
return QString();+ −
+ −
QString title = subWindow->windowTitle();+ −
if (subWindow->isWindowModified()) {+ −
title.replace(QLatin1String("[*]"), QLatin1String("*"));+ −
} else {+ −
extern QString qt_setWindowTitle_helperHelper(const QString&, const QWidget*);+ −
title = qt_setWindowTitle_helperHelper(title, subWindow);+ −
}+ −
+ −
return title.isEmpty() ? QMdiArea::tr("(Untitled)") : title;+ −
}+ −
+ −
/*!+ −
\internal+ −
*/+ −
void RegularTiler::rearrange(QList<QWidget *> &widgets, const QRect &domain) const+ −
{+ −
if (widgets.isEmpty())+ −
return;+ −
+ −
const int n = widgets.size();+ −
const int ncols = qMax(qCeil(qSqrt(qreal(n))), 1);+ −
const int nrows = qMax((n % ncols) ? (n / ncols + 1) : (n / ncols), 1);+ −
const int nspecial = (n % ncols) ? (ncols - n % ncols) : 0;+ −
const int dx = domain.width() / ncols;+ −
const int dy = domain.height() / nrows;+ −
+ −
int i = 0;+ −
for (int row = 0; row < nrows; ++row) {+ −
const int y1 = int(row * (dy + 1));+ −
for (int col = 0; col < ncols; ++col) {+ −
if (row == 1 && col < nspecial)+ −
continue;+ −
const int x1 = int(col * (dx + 1));+ −
int x2 = int(x1 + dx);+ −
int y2 = int(y1 + dy);+ −
if (row == 0 && col < nspecial) {+ −
y2 *= 2;+ −
if (nrows != 2)+ −
y2 += 1;+ −
else+ −
y2 = domain.bottom();+ −
}+ −
if (col == ncols - 1 && x2 != domain.right())+ −
x2 = domain.right();+ −
if (row == nrows - 1 && y2 != domain.bottom())+ −
y2 = domain.bottom();+ −
if (!sanityCheck(widgets, i, "RegularTiler"))+ −
continue;+ −
QWidget *widget = widgets.at(i++);+ −
QRect newGeometry = QRect(QPoint(x1, y1), QPoint(x2, y2));+ −
widget->setGeometry(QStyle::visualRect(widget->layoutDirection(), domain, newGeometry));+ −
}+ −
}+ −
}+ −
+ −
/*!+ −
\internal+ −
*/+ −
void SimpleCascader::rearrange(QList<QWidget *> &widgets, const QRect &domain) const+ −
{+ −
if (widgets.isEmpty())+ −
return;+ −
+ −
// Tunables:+ −
const int topOffset = 0;+ −
const int bottomOffset = 50;+ −
const int leftOffset = 0;+ −
const int rightOffset = 100;+ −
const int dx = 10;+ −
+ −
QStyleOptionTitleBar options;+ −
options.initFrom(widgets.at(0));+ −
int titleBarHeight = widgets.at(0)->style()->pixelMetric(QStyle::PM_TitleBarHeight, &options, widgets.at(0));+ −
#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)+ −
// ### Remove this after the mac style has been fixed+ −
if (qobject_cast<QMacStyle *>(widgets.at(0)->style()))+ −
titleBarHeight -= 4;+ −
#endif+ −
const QFontMetrics fontMetrics = QFontMetrics(QApplication::font("QWorkspaceTitleBar"));+ −
const int dy = qMax(titleBarHeight - (titleBarHeight - fontMetrics.height()) / 2, 1);+ −
+ −
const int n = widgets.size();+ −
const int nrows = qMax((domain.height() - (topOffset + bottomOffset)) / dy, 1);+ −
const int ncols = qMax(n / nrows + ((n % nrows) ? 1 : 0), 1);+ −
const int dcol = (domain.width() - (leftOffset + rightOffset)) / ncols;+ −
+ −
int i = 0;+ −
for (int row = 0; row < nrows; ++row) {+ −
for (int col = 0; col < ncols; ++col) {+ −
const int x = leftOffset + row * dx + col * dcol;+ −
const int y = topOffset + row * dy;+ −
if (!sanityCheck(widgets, i, "SimpleCascader"))+ −
continue;+ −
QWidget *widget = widgets.at(i++);+ −
QRect newGeometry = QRect(QPoint(x, y), widget->sizeHint());+ −
widget->setGeometry(QStyle::visualRect(widget->layoutDirection(), domain, newGeometry));+ −
if (i == n)+ −
return;+ −
}+ −
}+ −
}+ −
+ −
/*!+ −
\internal+ −
*/+ −
void IconTiler::rearrange(QList<QWidget *> &widgets, const QRect &domain) const+ −
{+ −
if (widgets.isEmpty() || !sanityCheck(widgets, 0, "IconTiler"))+ −
return;+ −
+ −
const int n = widgets.size();+ −
const int width = widgets.at(0)->width();+ −
const int height = widgets.at(0)->height();+ −
const int ncols = qMax(domain.width() / width, 1);+ −
const int nrows = n / ncols + ((n % ncols) ? 1 : 0);+ −
+ −
int i = 0;+ −
for (int row = 0; row < nrows; ++row) {+ −
for (int col = 0; col < ncols; ++col) {+ −
const int x = col * width;+ −
const int y = domain.height() - height - row * height;+ −
if (!sanityCheck(widgets, i, "IconTiler"))+ −
continue;+ −
QWidget *widget = widgets.at(i++);+ −
QPoint newPos(x, y);+ −
QRect newGeometry = QRect(newPos.x(), newPos.y(), widget->width(), widget->height());+ −
widget->setGeometry(QStyle::visualRect(widget->layoutDirection(), domain, newGeometry));+ −
if (i == n)+ −
return;+ −
}+ −
}+ −
}+ −
+ −
/*!+ −
\internal+ −
Calculates the accumulated overlap (intersection area) between 'source' and 'rects'.+ −
*/+ −
int MinOverlapPlacer::accumulatedOverlap(const QRect &source, const QList<QRect> &rects)+ −
{+ −
int accOverlap = 0;+ −
foreach (const QRect &rect, rects) {+ −
QRect intersection = source.intersected(rect);+ −
accOverlap += intersection.width() * intersection.height();+ −
}+ −
return accOverlap;+ −
}+ −
+ −
+ −
/*!+ −
\internal+ −
Finds among 'source' the rectangle with the minimum accumulated overlap with the+ −
rectangles in 'rects'.+ −
*/+ −
QRect MinOverlapPlacer::findMinOverlapRect(const QList<QRect> &source, const QList<QRect> &rects)+ −
{+ −
int minAccOverlap = -1;+ −
QRect minAccOverlapRect;+ −
foreach (const QRect &srcRect, source) {+ −
const int accOverlap = accumulatedOverlap(srcRect, rects);+ −
if (accOverlap < minAccOverlap || minAccOverlap == -1) {+ −
minAccOverlap = accOverlap;+ −
minAccOverlapRect = srcRect;+ −
}+ −
}+ −
return minAccOverlapRect;+ −
}+ −
+ −
/*!+ −
\internal+ −
Gets candidates for the final placement.+ −
*/+ −
void MinOverlapPlacer::getCandidatePlacements(const QSize &size, const QList<QRect> &rects,+ −
const QRect &domain,QList<QRect> &candidates)+ −
{+ −
QSet<int> xset;+ −
QSet<int> yset;+ −
xset << domain.left() << domain.right() - size.width() + 1;+ −
yset << domain.top();+ −
if (domain.bottom() - size.height() + 1 >= 0)+ −
yset << domain.bottom() - size.height() + 1;+ −
foreach (const QRect &rect, rects) {+ −
xset << rect.right() + 1;+ −
yset << rect.bottom() + 1;+ −
}+ −
+ −
QList<int> xlist = xset.values();+ −
qSort(xlist.begin(), xlist.end());+ −
QList<int> ylist = yset.values();+ −
qSort(ylist.begin(), ylist.end());+ −
+ −
foreach (int y, ylist)+ −
foreach (int x, xlist)+ −
candidates << QRect(QPoint(x, y), size);+ −
}+ −
+ −
/*!+ −
\internal+ −
Finds all rectangles in 'source' not completely inside 'domain'. The result is stored+ −
in 'result' and also removed from 'source'.+ −
*/+ −
void MinOverlapPlacer::findNonInsiders(const QRect &domain, QList<QRect> &source,+ −
QList<QRect> &result)+ −
{+ −
QMutableListIterator<QRect> it(source);+ −
while (it.hasNext()) {+ −
const QRect srcRect = it.next();+ −
if (!domain.contains(srcRect)) {+ −
result << srcRect;+ −
it.remove();+ −
}+ −
}+ −
}+ −
+ −
/*!+ −
\internal+ −
Finds all rectangles in 'source' that overlaps 'domain' by the maximum overlap area+ −
between 'domain' and any rectangle in 'source'. The result is stored in 'result'.+ −
*/+ −
void MinOverlapPlacer::findMaxOverlappers(const QRect &domain, const QList<QRect> &source,+ −
QList<QRect> &result)+ −
{+ −
int maxOverlap = -1;+ −
foreach (const QRect &srcRect, source) {+ −
QRect intersection = domain.intersected(srcRect);+ −
const int overlap = intersection.width() * intersection.height();+ −
if (overlap >= maxOverlap || maxOverlap == -1) {+ −
if (overlap > maxOverlap) {+ −
maxOverlap = overlap;+ −
result.clear();+ −
}+ −
result << srcRect;+ −
}+ −
}+ −
}+ −
+ −
/*!+ −
\internal+ −
Finds among the rectangles in 'source' the best placement. Here, 'best' means the+ −
placement that overlaps the rectangles in 'rects' as little as possible while at the+ −
same time being as much as possible inside 'domain'.+ −
*/+ −
QPoint MinOverlapPlacer::findBestPlacement(const QRect &domain, const QList<QRect> &rects,+ −
QList<QRect> &source)+ −
{+ −
QList<QRect> nonInsiders;+ −
findNonInsiders(domain, source, nonInsiders);+ −
+ −
if (!source.empty())+ −
return findMinOverlapRect(source, rects).topLeft();+ −
+ −
QList<QRect> maxOverlappers;+ −
findMaxOverlappers(domain, nonInsiders, maxOverlappers);+ −
return findMinOverlapRect(maxOverlappers, rects).topLeft();+ −
}+ −
+ −
+ −
/*!+ −
\internal+ −
Places the rectangle defined by 'size' relative to 'rects' and 'domain' so that it+ −
overlaps 'rects' as little as possible and 'domain' as much as possible.+ −
Returns the position of the resulting rectangle.+ −
*/+ −
QPoint MinOverlapPlacer::place(const QSize &size, const QList<QRect> &rects,+ −
const QRect &domain) const+ −
{+ −
if (size.isEmpty() || !domain.isValid())+ −
return QPoint();+ −
foreach (const QRect &rect, rects) {+ −
if (!rect.isValid())+ −
return QPoint();+ −
}+ −
+ −
QList<QRect> candidates;+ −
getCandidatePlacements(size, rects, domain, candidates);+ −
return findBestPlacement(domain, rects, candidates);+ −
}+ −
+ −
#ifndef QT_NO_TABBAR+ −
class QMdiAreaTabBar : public QTabBar+ −
{+ −
public:+ −
QMdiAreaTabBar(QWidget *parent) : QTabBar(parent) {}+ −
+ −
protected:+ −
void mousePressEvent(QMouseEvent *event);+ −
#ifndef QT_NO_CONTEXTMENU+ −
void contextMenuEvent(QContextMenuEvent *event);+ −
#endif+ −
+ −
private:+ −
QMdiSubWindow *subWindowFromIndex(int index) const;+ −
};+ −
+ −
/*!+ −
\internal+ −
*/+ −
void QMdiAreaTabBar::mousePressEvent(QMouseEvent *event)+ −
{+ −
if (event->button() != Qt::MidButton) {+ −
QTabBar::mousePressEvent(event);+ −
return;+ −
}+ −
+ −
QMdiSubWindow *subWindow = subWindowFromIndex(tabAt(event->pos()));+ −
if (!subWindow) {+ −
event->ignore();+ −
return;+ −
}+ −
+ −
subWindow->close();+ −
}+ −
+ −
#ifndef QT_NO_CONTEXTMENU+ −
/*!+ −
\internal+ −
*/+ −
void QMdiAreaTabBar::contextMenuEvent(QContextMenuEvent *event)+ −
{+ −
QPointer<QMdiSubWindow> subWindow = subWindowFromIndex(tabAt(event->pos()));+ −
if (!subWindow || subWindow->isHidden()) {+ −
event->ignore();+ −
return;+ −
}+ −
+ −
#ifndef QT_NO_MENU+ −
QMdiSubWindowPrivate *subWindowPrivate = subWindow->d_func();+ −
if (!subWindowPrivate->systemMenu) {+ −
event->ignore();+ −
return;+ −
}+ −
+ −
QMdiSubWindow *currentSubWindow = subWindowFromIndex(currentIndex());+ −
Q_ASSERT(currentSubWindow);+ −
+ −
// We don't want these actions to show up in the system menu when the+ −
// current sub-window is maximized, i.e. covers the entire viewport.+ −
if (currentSubWindow->isMaximized()) {+ −
subWindowPrivate->setVisible(QMdiSubWindowPrivate::MoveAction, false);+ −
subWindowPrivate->setVisible(QMdiSubWindowPrivate::ResizeAction, false);+ −
subWindowPrivate->setVisible(QMdiSubWindowPrivate::MinimizeAction, false);+ −
subWindowPrivate->setVisible(QMdiSubWindowPrivate::MaximizeAction, false);+ −
subWindowPrivate->setVisible(QMdiSubWindowPrivate::MaximizeAction, false);+ −
subWindowPrivate->setVisible(QMdiSubWindowPrivate::StayOnTopAction, false);+ −
}+ −
+ −
// Show system menu.+ −
subWindowPrivate->systemMenu->exec(event->globalPos());+ −
if (!subWindow)+ −
return;+ −
+ −
// Restore action visibility.+ −
subWindowPrivate->updateActions();+ −
#endif // QT_NO_MENU+ −
}+ −
#endif // QT_NO_CONTEXTMENU+ −
+ −
/*!+ −
\internal+ −
*/+ −
QMdiSubWindow *QMdiAreaTabBar::subWindowFromIndex(int index) const+ −
{+ −
if (index < 0 || index >= count())+ −
return 0;+ −
+ −
QMdiArea *mdiArea = qobject_cast<QMdiArea *>(parentWidget());+ −
Q_ASSERT(mdiArea);+ −
+ −
const QList<QMdiSubWindow *> subWindows = mdiArea->subWindowList();+ −
Q_ASSERT(index < subWindows.size());+ −
+ −
QMdiSubWindow *subWindow = mdiArea->subWindowList().at(index);+ −
Q_ASSERT(subWindow);+ −
+ −
return subWindow;+ −
}+ −
#endif // QT_NO_TABBAR+ −
+ −
/*!+ −
\internal+ −
*/+ −
QMdiAreaPrivate::QMdiAreaPrivate()+ −
: cascader(0),+ −
regularTiler(0),+ −
iconTiler(0),+ −
placer(0),+ −
#ifndef QT_NO_RUBBERBAND+ −
rubberBand(0),+ −
#endif+ −
#ifndef QT_NO_TABBAR+ −
tabBar(0),+ −
#endif+ −
activationOrder(QMdiArea::CreationOrder),+ −
viewMode(QMdiArea::SubWindowView),+ −
#ifndef QT_NO_TABBAR+ −
documentMode(false),+ −
#endif+ −
#ifndef QT_NO_TABWIDGET+ −
tabShape(QTabWidget::Rounded),+ −
tabPosition(QTabWidget::North),+ −
#endif+ −
ignoreGeometryChange(false),+ −
ignoreWindowStateChange(false),+ −
isActivated(false),+ −
isSubWindowsTiled(false),+ −
showActiveWindowMaximized(false),+ −
tileCalledFromResizeEvent(false),+ −
updatesDisabledByUs(false),+ −
inViewModeChange(false),+ −
indexToNextWindow(-1),+ −
indexToPreviousWindow(-1),+ −
indexToHighlighted(-1),+ −
indexToLastActiveTab(-1),+ −
resizeTimerId(-1),+ −
tabToPreviousTimerId(-1)+ −
{+ −
}+ −
+ −
/*!+ −
\internal+ −
*/+ −
void QMdiAreaPrivate::_q_deactivateAllWindows(QMdiSubWindow *aboutToActivate)+ −
{+ −
if (ignoreWindowStateChange)+ −
return;+ −
+ −
Q_Q(QMdiArea);+ −
if (!aboutToActivate)+ −
aboutToBecomeActive = qobject_cast<QMdiSubWindow *>(q->sender());+ −
else+ −
aboutToBecomeActive = aboutToActivate;+ −
Q_ASSERT(aboutToBecomeActive);+ −
+ −
foreach (QMdiSubWindow *child, childWindows) {+ −
if (!sanityCheck(child, "QMdiArea::deactivateAllWindows") || aboutToBecomeActive == child)+ −
continue;+ −
// We don't want to handle signals caused by child->showNormal().+ −
ignoreWindowStateChange = true;+ −
if(!(options & QMdiArea::DontMaximizeSubWindowOnActivation) && !showActiveWindowMaximized)+ −
showActiveWindowMaximized = child->isMaximized() && child->isVisible();+ −
if (showActiveWindowMaximized && child->isMaximized()) {+ −
if (q->updatesEnabled()) {+ −
updatesDisabledByUs = true;+ −
q->setUpdatesEnabled(false);+ −
}+ −
child->showNormal();+ −
}+ −
if (child->isMinimized() && !child->isShaded() && !windowStaysOnTop(child))+ −
child->lower();+ −
ignoreWindowStateChange = false;+ −
child->d_func()->setActive(false);+ −
}+ −
}+ −
+ −
/*!+ −
\internal+ −
*/+ −
void QMdiAreaPrivate::_q_processWindowStateChanged(Qt::WindowStates oldState,+ −
Qt::WindowStates newState)+ −
{+ −
if (ignoreWindowStateChange)+ −
return;+ −
+ −
Q_Q(QMdiArea);+ −
QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(q->sender());+ −
if (!child)+ −
return;+ −
+ −
// windowActivated+ −
if (!(oldState & Qt::WindowActive) && (newState & Qt::WindowActive))+ −
emitWindowActivated(child);+ −
// windowDeactivated+ −
else if ((oldState & Qt::WindowActive) && !(newState & Qt::WindowActive))+ −
resetActiveWindow(child);+ −
+ −
// windowMinimized+ −
if (!(oldState & Qt::WindowMinimized) && (newState & Qt::WindowMinimized)) {+ −
isSubWindowsTiled = false;+ −
arrangeMinimizedSubWindows();+ −
// windowMaximized+ −
} else if (!(oldState & Qt::WindowMaximized) && (newState & Qt::WindowMaximized)) {+ −
internalRaise(child);+ −
// windowRestored+ −
} else if (!(newState & (Qt::WindowMaximized | Qt::WindowMinimized))) {+ −
internalRaise(child);+ −
if (oldState & Qt::WindowMinimized)+ −
arrangeMinimizedSubWindows();+ −
}+ −
}+ −
+ −
void QMdiAreaPrivate::_q_currentTabChanged(int index)+ −
{+ −
#ifdef QT_NO_TABBAR+ −
Q_UNUSED(index);+ −
#else+ −
if (!tabBar || index < 0)+ −
return;+ −
+ −
// If the previous active sub-window was hidden, disable the tab.+ −
if (indexToLastActiveTab >= 0 && indexToLastActiveTab < tabBar->count()+ −
&& indexToLastActiveTab < childWindows.count()) {+ −
QMdiSubWindow *lastActive = childWindows.at(indexToLastActiveTab);+ −
if (lastActive && lastActive->isHidden())+ −
tabBar->setTabEnabled(indexToLastActiveTab, false);+ −
}+ −
+ −
indexToLastActiveTab = index;+ −
Q_ASSERT(childWindows.size() > index);+ −
QMdiSubWindow *subWindow = childWindows.at(index);+ −
Q_ASSERT(subWindow);+ −
activateWindow(subWindow);+ −
#endif // QT_NO_TABBAR+ −
}+ −
+ −
/*!+ −
\internal+ −
*/+ −
void QMdiAreaPrivate::appendChild(QMdiSubWindow *child)+ −
{+ −
Q_Q(QMdiArea);+ −
Q_ASSERT(child && childWindows.indexOf(child) == -1);+ −
+ −
if (child->parent() != viewport)+ −
child->setParent(viewport, child->windowFlags());+ −
childWindows.append(QPointer<QMdiSubWindow>(child));+ −
+ −
if (!child->testAttribute(Qt::WA_Resized) && q->isVisible()) {+ −
QSize newSize(child->sizeHint().boundedTo(viewport->size()));+ −
child->resize(newSize.expandedTo(qSmartMinSize(child)));+ −
}+ −
+ −
if (!placer)+ −
placer = new MinOverlapPlacer;+ −
place(placer, child);+ −
+ −
if (hbarpolicy != Qt::ScrollBarAlwaysOff)+ −
child->setOption(QMdiSubWindow::AllowOutsideAreaHorizontally, true);+ −
else+ −
child->setOption(QMdiSubWindow::AllowOutsideAreaHorizontally, false);+ −
+ −
if (vbarpolicy != Qt::ScrollBarAlwaysOff)+ −
child->setOption(QMdiSubWindow::AllowOutsideAreaVertically, true);+ −
else+ −
child->setOption(QMdiSubWindow::AllowOutsideAreaVertically, false);+ −
+ −
internalRaise(child);+ −
indicesToActivatedChildren.prepend(childWindows.size() - 1);+ −
Q_ASSERT(indicesToActivatedChildren.size() == childWindows.size());+ −
+ −
#ifndef QT_NO_TABBAR+ −
if (tabBar) {+ −
tabBar->addTab(child->windowIcon(), tabTextFor(child));+ −
updateTabBarGeometry();+ −
if (childWindows.count() == 1 && !(options & QMdiArea::DontMaximizeSubWindowOnActivation))+ −
showActiveWindowMaximized = true;+ −
}+ −
#endif+ −
+ −
if (!(child->windowFlags() & Qt::SubWindow))+ −
child->setWindowFlags(Qt::SubWindow);+ −
child->installEventFilter(q);+ −
+ −
QObject::connect(child, SIGNAL(aboutToActivate()), q, SLOT(_q_deactivateAllWindows()));+ −
QObject::connect(child, SIGNAL(windowStateChanged(Qt::WindowStates,Qt::WindowStates)),+ −
q, SLOT(_q_processWindowStateChanged(Qt::WindowStates,Qt::WindowStates)));+ −
}+ −
+ −
/*!+ −
\internal+ −
*/+ −
void QMdiAreaPrivate::place(Placer *placer, QMdiSubWindow *child)+ −
{+ −
if (!placer || !child)+ −
return;+ −
+ −
Q_Q(QMdiArea);+ −
if (!q->isVisible()) {+ −
// The window is only laid out when it's added to QMdiArea,+ −
// so there's no need to check that we don't have it in the+ −
// list already. appendChild() ensures that.+ −
pendingPlacements.append(child);+ −
return;+ −
}+ −
+ −
QList<QRect> rects;+ −
QRect parentRect = q->rect();+ −
foreach (QMdiSubWindow *window, childWindows) {+ −
if (!sanityCheck(window, "QMdiArea::place") || window == child || !window->isVisibleTo(q)+ −
|| !window->testAttribute(Qt::WA_Moved)) {+ −
continue;+ −
}+ −
QRect occupiedGeometry;+ −
if (window->isMaximized()) {+ −
occupiedGeometry = QRect(window->d_func()->oldGeometry.topLeft(),+ −
window->d_func()->restoreSize);+ −
} else {+ −
occupiedGeometry = window->geometry();+ −
}+ −
rects.append(QStyle::visualRect(child->layoutDirection(), parentRect, occupiedGeometry));+ −
}+ −
QPoint newPos = placer->place(child->size(), rects, parentRect);+ −
QRect newGeometry = QRect(newPos.x(), newPos.y(), child->width(), child->height());+ −
child->setGeometry(QStyle::visualRect(child->layoutDirection(), parentRect, newGeometry));+ −
}+ −
+ −
/*!+ −
\internal+ −
*/+ −
void QMdiAreaPrivate::rearrange(Rearranger *rearranger)+ −
{+ −
if (!rearranger)+ −
return;+ −
+ −
Q_Q(QMdiArea);+ −
if (!q->isVisible()) {+ −
// Compress if we already have the rearranger in the list.+ −
int index = pendingRearrangements.indexOf(rearranger);+ −
if (index != -1)+ −
pendingRearrangements.move(index, pendingRearrangements.size() - 1);+ −
else+ −
pendingRearrangements.append(rearranger);+ −
return;+ −
}+ −
+ −
QList<QWidget *> widgets;+ −
const bool reverseList = rearranger->type() == Rearranger::RegularTiler;+ −
const QList<QMdiSubWindow *> subWindows = subWindowList(activationOrder, reverseList);+ −
QSize minSubWindowSize;+ −
foreach (QMdiSubWindow *child, subWindows) {+ −
if (!sanityCheck(child, "QMdiArea::rearrange") || !child->isVisible())+ −
continue;+ −
if (rearranger->type() == Rearranger::IconTiler) {+ −
if (child->isMinimized() && !child->isShaded() && !(child->windowFlags() & Qt::FramelessWindowHint))+ −
widgets.append(child);+ −
} else {+ −
if (child->isMinimized() && !child->isShaded())+ −
continue;+ −
if (child->isMaximized() || child->isShaded())+ −
child->showNormal();+ −
minSubWindowSize = minSubWindowSize.expandedTo(child->minimumSize())+ −
.expandedTo(child->d_func()->internalMinimumSize);+ −
widgets.append(child);+ −
}+ −
}+ −
+ −
if (active && rearranger->type() == Rearranger::RegularTiler) {+ −
// Move active window in front if necessary. That's the case if we+ −
// have any windows with staysOnTopHint set.+ −
int indexToActive = widgets.indexOf((QWidget *)active);+ −
if (indexToActive > 0)+ −
widgets.move(indexToActive, 0);+ −
}+ −
+ −
QRect domain = viewport->rect();+ −
if (rearranger->type() == Rearranger::RegularTiler && !widgets.isEmpty())+ −
domain = resizeToMinimumTileSize(minSubWindowSize, widgets.count());+ −
+ −
rearranger->rearrange(widgets, domain);+ −
+ −
if (rearranger->type() == Rearranger::RegularTiler && !widgets.isEmpty()) {+ −
isSubWindowsTiled = true;+ −
updateScrollBars();+ −
} else if (rearranger->type() == Rearranger::SimpleCascader) {+ −
isSubWindowsTiled = false;+ −
}+ −
}+ −
+ −
/*!+ −
\internal+ −
+ −
Arranges all minimized windows at the bottom of the workspace.+ −
*/+ −
void QMdiAreaPrivate::arrangeMinimizedSubWindows()+ −
{+ −
if (!iconTiler)+ −
iconTiler = new IconTiler;+ −
rearrange(iconTiler);+ −
}+ −
+ −
/*!+ −
\internal+ −
*/+ −
void QMdiAreaPrivate::activateWindow(QMdiSubWindow *child)+ −
{+ −
if (childWindows.isEmpty()) {+ −
Q_ASSERT(!child);+ −
Q_ASSERT(!active);+ −
return;+ −
}+ −
+ −
if (!child) {+ −
if (active) {+ −
Q_ASSERT(active->d_func()->isActive);+ −
active->d_func()->setActive(false);+ −
resetActiveWindow();+ −
}+ −
return;+ −
}+ −
+ −
if (child->isHidden() || child == active)+ −
return;+ −
child->d_func()->setActive(true);+ −
}+ −
+ −
/*!+ −
\internal+ −
*/+ −
void QMdiAreaPrivate::activateCurrentWindow()+ −
{+ −
QMdiSubWindow *current = q_func()->currentSubWindow();+ −
if (current && !isExplicitlyDeactivated(current)) {+ −
current->d_func()->activationEnabled = true;+ −
current->d_func()->setActive(true, /*changeFocus=*/false);+ −
}+ −
}+ −
+ −
void QMdiAreaPrivate::activateHighlightedWindow()+ −
{+ −
if (indexToHighlighted < 0)+ −
return;+ −
+ −
Q_ASSERT(indexToHighlighted < childWindows.size());+ −
if (tabToPreviousTimerId != -1)+ −
activateWindow(nextVisibleSubWindow(-1, QMdiArea::ActivationHistoryOrder));+ −
else+ −
activateWindow(childWindows.at(indexToHighlighted));+ −
#ifndef QT_NO_RUBBERBAND+ −
hideRubberBand();+ −
#endif+ −
}+ −
+ −
/*!+ −
\internal+ −
*/+ −
void QMdiAreaPrivate::emitWindowActivated(QMdiSubWindow *activeWindow)+ −
{+ −
Q_Q(QMdiArea);+ −
Q_ASSERT(activeWindow);+ −
if (activeWindow == active)+ −
return;+ −
Q_ASSERT(activeWindow->d_func()->isActive);+ −
+ −
if (!aboutToBecomeActive)+ −
_q_deactivateAllWindows(activeWindow);+ −
Q_ASSERT(aboutToBecomeActive);+ −
+ −
// This is true only if 'DontMaximizeSubWindowOnActivation' is disabled+ −
// and the previous active window was maximized.+ −
if (showActiveWindowMaximized) {+ −
if (!activeWindow->isMaximized())+ −
activeWindow->showMaximized();+ −
showActiveWindowMaximized = false;+ −
}+ −
+ −
// Put in front to update activation order.+ −
const int indexToActiveWindow = childWindows.indexOf(activeWindow);+ −
Q_ASSERT(indexToActiveWindow != -1);+ −
const int index = indicesToActivatedChildren.indexOf(indexToActiveWindow);+ −
Q_ASSERT(index != -1);+ −
indicesToActivatedChildren.move(index, 0);+ −
internalRaise(activeWindow);+ −
+ −
if (updatesDisabledByUs) {+ −
q->setUpdatesEnabled(true);+ −
updatesDisabledByUs = false;+ −
}+ −
+ −
Q_ASSERT(aboutToBecomeActive == activeWindow);+ −
active = activeWindow;+ −
aboutToBecomeActive = 0;+ −
Q_ASSERT(active->d_func()->isActive);+ −
+ −
#ifndef QT_NO_TABBAR+ −
if (tabBar && tabBar->currentIndex() != indexToActiveWindow)+ −
tabBar->setCurrentIndex(indexToActiveWindow);+ −
#endif+ −
+ −
if (active->isMaximized() && scrollBarsEnabled())+ −
updateScrollBars();+ −
+ −
emit q->subWindowActivated(active);+ −
}+ −
+ −
/*!+ −
\internal+ −
*/+ −
void QMdiAreaPrivate::resetActiveWindow(QMdiSubWindow *deactivatedWindow)+ −
{+ −
Q_Q(QMdiArea);+ −
if (deactivatedWindow) {+ −
if (deactivatedWindow != active)+ −
return;+ −
active = 0;+ −
if ((aboutToBecomeActive || isActivated || lastWindowAboutToBeDestroyed())+ −
&& !isExplicitlyDeactivated(deactivatedWindow) && !q->window()->isMinimized()) {+ −
return;+ −
}+ −
emit q->subWindowActivated(0);+ −
return;+ −
}+ −
+ −
if (aboutToBecomeActive)+ −
return;+ −
+ −
active = 0;+ −
emit q->subWindowActivated(0);+ −
}+ −
+ −
/*!+ −
\internal+ −
*/+ −
void QMdiAreaPrivate::updateActiveWindow(int removedIndex, bool activeRemoved)+ −
{+ −
Q_ASSERT(indicesToActivatedChildren.size() == childWindows.size());+ −
+ −
#ifndef QT_NO_TABBAR+ −
if (tabBar && removedIndex >= 0) {+ −
tabBar->blockSignals(true);+ −
tabBar->removeTab(removedIndex);+ −
updateTabBarGeometry();+ −
tabBar->blockSignals(false);+ −
}+ −
#endif+ −
+ −
if (childWindows.isEmpty()) {+ −
showActiveWindowMaximized = false;+ −
resetActiveWindow();+ −
return;+ −
}+ −
+ −
if (indexToHighlighted >= 0) {+ −
#ifndef QT_NO_RUBBERBAND+ −
// Hide rubber band if highlighted window is removed.+ −
if (indexToHighlighted == removedIndex)+ −
hideRubberBand();+ −
else+ −
#endif+ −
// or update index if necessary.+ −
if (indexToHighlighted > removedIndex)+ −
--indexToHighlighted;+ −
}+ −
+ −
// Update indices list+ −
for (int i = 0; i < indicesToActivatedChildren.size(); ++i) {+ −
int *index = &indicesToActivatedChildren[i];+ −
if (*index > removedIndex)+ −
--*index;+ −
}+ −
+ −
if (!activeRemoved)+ −
return;+ −
+ −
// Activate next window.+ −
QMdiSubWindow *next = nextVisibleSubWindow(0, activationOrder, removedIndex);+ −
if (next)+ −
activateWindow(next);+ −
}+ −
+ −
/*!+ −
\internal+ −
*/+ −
void QMdiAreaPrivate::updateScrollBars()+ −
{+ −
if (ignoreGeometryChange || !scrollBarsEnabled())+ −
return;+ −
+ −
Q_Q(QMdiArea);+ −
QSize maxSize = q->maximumViewportSize();+ −
QSize hbarExtent = hbar->sizeHint();+ −
QSize vbarExtent = vbar->sizeHint();+ −
+ −
if (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents, 0, q)) {+ −
const int doubleFrameWidth = frameWidth * 2;+ −
if (hbarpolicy == Qt::ScrollBarAlwaysOn)+ −
maxSize.rheight() -= doubleFrameWidth;+ −
if (vbarpolicy == Qt::ScrollBarAlwaysOn)+ −
maxSize.rwidth() -= doubleFrameWidth;+ −
hbarExtent.rheight() += doubleFrameWidth;+ −
vbarExtent.rwidth() += doubleFrameWidth;+ −
}+ −
+ −
const QRect childrenRect = active && active->isMaximized()+ −
? active->geometry() : viewport->childrenRect();+ −
bool useHorizontalScrollBar = useScrollBar(childrenRect, maxSize, Qt::Horizontal);+ −
bool useVerticalScrollBar = useScrollBar(childrenRect, maxSize, Qt::Vertical);+ −
+ −
if (useHorizontalScrollBar && !useVerticalScrollBar) {+ −
const QSize max = maxSize - QSize(0, hbarExtent.height());+ −
useVerticalScrollBar = useScrollBar(childrenRect, max, Qt::Vertical);+ −
}+ −
+ −
if (useVerticalScrollBar && !useHorizontalScrollBar) {+ −
const QSize max = maxSize - QSize(vbarExtent.width(), 0);+ −
useHorizontalScrollBar = useScrollBar(childrenRect, max, Qt::Horizontal);+ −
}+ −
+ −
if (useHorizontalScrollBar && hbarpolicy != Qt::ScrollBarAlwaysOn)+ −
maxSize.rheight() -= hbarExtent.height();+ −
if (useVerticalScrollBar && vbarpolicy != Qt::ScrollBarAlwaysOn)+ −
maxSize.rwidth() -= vbarExtent.width();+ −
+ −
QRect viewportRect(QPoint(0, 0), maxSize);+ −
const int startX = q->isLeftToRight() ? childrenRect.left() : viewportRect.right()+ −
- childrenRect.right();+ −
+ −
// Horizontal scroll bar.+ −
if (isSubWindowsTiled && hbar->value() != 0)+ −
hbar->setValue(0);+ −
const int xOffset = startX + hbar->value();+ −
hbar->setRange(qMin(0, xOffset),+ −
qMax(0, xOffset + childrenRect.width() - viewportRect.width()));+ −
hbar->setPageStep(childrenRect.width());+ −
hbar->setSingleStep(childrenRect.width() / 20);+ −
+ −
// Vertical scroll bar.+ −
if (isSubWindowsTiled && vbar->value() != 0)+ −
vbar->setValue(0);+ −
const int yOffset = childrenRect.top() + vbar->value();+ −
vbar->setRange(qMin(0, yOffset),+ −
qMax(0, yOffset + childrenRect.height() - viewportRect.height()));+ −
vbar->setPageStep(childrenRect.height());+ −
vbar->setSingleStep(childrenRect.height() / 20);+ −
}+ −
+ −
/*!+ −
\internal+ −
*/+ −
void QMdiAreaPrivate::internalRaise(QMdiSubWindow *mdiChild) const+ −
{+ −
if (!sanityCheck(mdiChild, "QMdiArea::internalRaise") || childWindows.size() < 2)+ −
return;+ −
+ −
QMdiSubWindow *stackUnderChild = 0;+ −
if (!windowStaysOnTop(mdiChild)) {+ −
foreach (QObject *object, viewport->children()) {+ −
QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(object);+ −
if (!child || !childWindows.contains(child))+ −
continue;+ −
if (!child->isHidden() && windowStaysOnTop(child)) {+ −
if (stackUnderChild)+ −
child->stackUnder(stackUnderChild);+ −
else+ −
child->raise();+ −
stackUnderChild = child;+ −
}+ −
}+ −
}+ −
+ −
if (stackUnderChild)+ −
mdiChild->stackUnder(stackUnderChild);+ −
else+ −
mdiChild->raise();+ −
}+ −
+ −
QRect QMdiAreaPrivate::resizeToMinimumTileSize(const QSize &minSubWindowSize, int subWindowCount)+ −
{+ −
Q_Q(QMdiArea);+ −
if (!minSubWindowSize.isValid() || subWindowCount <= 0)+ −
return viewport->rect();+ −
+ −
// Calculate minimum size.+ −
const int columns = qMax(qCeil(qSqrt(qreal(subWindowCount))), 1);+ −
const int rows = qMax((subWindowCount % columns) ? (subWindowCount / columns + 1)+ −
: (subWindowCount / columns), 1);+ −
const int minWidth = minSubWindowSize.width() * columns;+ −
const int minHeight = minSubWindowSize.height() * rows;+ −
+ −
// Increase area size if necessary. Scroll bars are provided if we're not able+ −
// to resize to the minimum size.+ −
if (!tileCalledFromResizeEvent) {+ −
QWidget *topLevel = q;+ −
// Find the topLevel for this area, either a real top-level or a sub-window.+ −
while (topLevel && !topLevel->isWindow() && topLevel->windowType() != Qt::SubWindow)+ −
topLevel = topLevel->parentWidget();+ −
// We don't want sub-subwindows to be placed at the edge, thus add 2 pixels.+ −
int minAreaWidth = minWidth + left + right + 2;+ −
int minAreaHeight = minHeight + top + bottom + 2;+ −
if (hbar->isVisible())+ −
minAreaHeight += hbar->height();+ −
if (vbar->isVisible())+ −
minAreaWidth += vbar->width();+ −
if (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents, 0, q)) {+ −
const int frame = q->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, 0, q);+ −
minAreaWidth += 2 * frame;+ −
minAreaHeight += 2 * frame;+ −
}+ −
const QSize diff = QSize(minAreaWidth, minAreaHeight).expandedTo(q->size()) - q->size();+ −
topLevel->resize(topLevel->size() + diff);+ −
}+ −
+ −
QRect domain = viewport->rect();+ −
+ −
// Adjust domain width and provide horizontal scroll bar.+ −
if (domain.width() < minWidth) {+ −
domain.setWidth(minWidth);+ −
if (hbarpolicy == Qt::ScrollBarAlwaysOff)+ −
q->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);+ −
else+ −
hbar->setValue(0);+ −
}+ −
// Adjust domain height and provide vertical scroll bar.+ −
if (domain.height() < minHeight) {+ −
domain.setHeight(minHeight);+ −
if (vbarpolicy == Qt::ScrollBarAlwaysOff)+ −
q->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);+ −
else+ −
vbar->setValue(0);+ −
}+ −
return domain;+ −
}+ −
+ −
/*!+ −
\internal+ −
*/+ −
bool QMdiAreaPrivate::scrollBarsEnabled() const+ −
{+ −
return hbarpolicy != Qt::ScrollBarAlwaysOff || vbarpolicy != Qt::ScrollBarAlwaysOff;+ −
}+ −
+ −
/*!+ −
\internal+ −
*/+ −
bool QMdiAreaPrivate::lastWindowAboutToBeDestroyed() const+ −
{+ −
if (childWindows.count() != 1)+ −
return false;+ −
+ −
QMdiSubWindow *last = childWindows.at(0);+ −
if (!last)+ −
return true;+ −
+ −
if (!last->testAttribute(Qt::WA_DeleteOnClose))+ −
return false;+ −
+ −
return last->d_func()->data.is_closing;+ −
}+ −
+ −
/*!+ −
\internal+ −
*/+ −
void QMdiAreaPrivate::setChildActivationEnabled(bool enable, bool onlyNextActivationEvent) const+ −
{+ −
foreach (QMdiSubWindow *subWindow, childWindows) {+ −
if (!subWindow || !subWindow->isVisible())+ −
continue;+ −
if (onlyNextActivationEvent)+ −
subWindow->d_func()->ignoreNextActivationEvent = !enable;+ −
else+ −
subWindow->d_func()->activationEnabled = enable;+ −
}+ −
}+ −
+ −
/*!+ −
\internal+ −
\reimp+ −
*/+ −
void QMdiAreaPrivate::scrollBarPolicyChanged(Qt::Orientation orientation, Qt::ScrollBarPolicy policy)+ −
{+ −
if (childWindows.isEmpty())+ −
return;+ −
+ −
const QMdiSubWindow::SubWindowOption option = orientation == Qt::Horizontal ?+ −
QMdiSubWindow::AllowOutsideAreaHorizontally : QMdiSubWindow::AllowOutsideAreaVertically;+ −
const bool enable = policy != Qt::ScrollBarAlwaysOff;+ −
foreach (QMdiSubWindow *child, childWindows) {+ −
if (!sanityCheck(child, "QMdiArea::scrollBarPolicyChanged"))+ −
continue;+ −
child->setOption(option, enable);+ −
}+ −
updateScrollBars();+ −
}+ −
+ −
QList<QMdiSubWindow*>+ −
QMdiAreaPrivate::subWindowList(QMdiArea::WindowOrder order, bool reversed) const+ −
{+ −
QList<QMdiSubWindow *> list;+ −
if (childWindows.isEmpty())+ −
return list;+ −
+ −
if (order == QMdiArea::CreationOrder) {+ −
foreach (QMdiSubWindow *child, childWindows) {+ −
if (!child)+ −
continue;+ −
if (!reversed)+ −
list.append(child);+ −
else+ −
list.prepend(child);+ −
}+ −
} else if (order == QMdiArea::StackingOrder) {+ −
foreach (QObject *object, viewport->children()) {+ −
QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(object);+ −
if (!child || !childWindows.contains(child))+ −
continue;+ −
if (!reversed)+ −
list.append(child);+ −
else+ −
list.prepend(child);+ −
}+ −
} else { // ActivationHistoryOrder+ −
Q_ASSERT(indicesToActivatedChildren.size() == childWindows.size());+ −
for (int i = indicesToActivatedChildren.count() - 1; i >= 0; --i) {+ −
QMdiSubWindow *child = childWindows.at(indicesToActivatedChildren.at(i));+ −
if (!child)+ −
continue;+ −
if (!reversed)+ −
list.append(child);+ −
else+ −
list.prepend(child);+ −
}+ −
}+ −
return list;+ −
}+ −
+ −
/*!+ −
\internal+ −
*/+ −
void QMdiAreaPrivate::disconnectSubWindow(QObject *subWindow)+ −
{+ −
if (!subWindow)+ −
return;+ −
+ −
Q_Q(QMdiArea);+ −
QObject::disconnect(subWindow, 0, q, 0);+ −
subWindow->removeEventFilter(q);+ −
}+ −
+ −
/*!+ −
\internal+ −
*/+ −
QMdiSubWindow *QMdiAreaPrivate::nextVisibleSubWindow(int increaseFactor, QMdiArea::WindowOrder order,+ −
int removedIndex, int fromIndex) const+ −
{+ −
if (childWindows.isEmpty())+ −
return 0;+ −
+ −
Q_Q(const QMdiArea);+ −
const QList<QMdiSubWindow *> subWindows = q->subWindowList(order);+ −
QMdiSubWindow *current = 0;+ −
+ −
if (removedIndex < 0) {+ −
if (fromIndex >= 0 && fromIndex < subWindows.size())+ −
current = childWindows.at(fromIndex);+ −
else+ −
current = q->currentSubWindow();+ −
}+ −
+ −
// There's no current sub-window (removed or deactivated),+ −
// so we have to pick the last active or the next in creation order.+ −
if (!current) {+ −
if (removedIndex >= 0 && order == QMdiArea::CreationOrder) {+ −
int candidateIndex = -1;+ −
setIndex(&candidateIndex, removedIndex, 0, subWindows.size() - 1, true);+ −
current = childWindows.at(candidateIndex);+ −
} else {+ −
current = subWindows.back();+ −
}+ −
}+ −
Q_ASSERT(current);+ −
+ −
// Find the index for the current sub-window in the given activation order+ −
const int indexToCurrent = subWindows.indexOf(current);+ −
const bool increasing = increaseFactor > 0 ? true : false;+ −
+ −
// and use that index + increseFactor as a candidate.+ −
int index = -1;+ −
setIndex(&index, indexToCurrent + increaseFactor, 0, subWindows.size() - 1, increasing);+ −
Q_ASSERT(index != -1);+ −
+ −
// Try to find another window if the candidate is hidden.+ −
while (subWindows.at(index)->isHidden()) {+ −
setIndex(&index, index + increaseFactor, 0, subWindows.size() - 1, increasing);+ −
if (index == indexToCurrent)+ −
break;+ −
}+ −
+ −
if (!subWindows.at(index)->isHidden())+ −
return subWindows.at(index);+ −
return 0;+ −
}+ −
+ −
/*!+ −
\internal+ −
*/+ −
void QMdiAreaPrivate::highlightNextSubWindow(int increaseFactor)+ −
{+ −
if (childWindows.size() == 1)+ −
return;+ −
+ −
Q_Q(QMdiArea);+ −
// There's no highlighted sub-window atm, use current.+ −
if (indexToHighlighted < 0) {+ −
QMdiSubWindow *current = q->currentSubWindow();+ −
if (!current)+ −
return;+ −
indexToHighlighted = childWindows.indexOf(current);+ −
}+ −
+ −
Q_ASSERT(indexToHighlighted >= 0);+ −
Q_ASSERT(indexToHighlighted < childWindows.size());+ −
+ −
QMdiSubWindow *highlight = nextVisibleSubWindow(increaseFactor, activationOrder, -1, indexToHighlighted);+ −
if (!highlight)+ −
return;+ −
+ −
#ifndef QT_NO_RUBBERBAND+ −
if (!rubberBand) {+ −
rubberBand = new QRubberBand(QRubberBand::Rectangle, viewport);+ −
// For accessibility to identify this special widget.+ −
rubberBand->setObjectName(QLatin1String("qt_rubberband"));+ −
rubberBand->setWindowFlags(rubberBand->windowFlags() | Qt::WindowStaysOnTopHint);+ −
}+ −
#endif+ −
+ −
// Only highlight if we're not switching back to the previously active window (Ctrl-Tab once).+ −
#ifndef QT_NO_RUBBERBAND+ −
if (tabToPreviousTimerId == -1)+ −
showRubberBandFor(highlight);+ −
#endif+ −
+ −
indexToHighlighted = childWindows.indexOf(highlight);+ −
Q_ASSERT(indexToHighlighted >= 0);+ −
}+ −
+ −
/*!+ −
\internal+ −
\since 4.4+ −
*/+ −
void QMdiAreaPrivate::setViewMode(QMdiArea::ViewMode mode)+ −
{+ −
Q_Q(QMdiArea);+ −
if (viewMode == mode || inViewModeChange)+ −
return;+ −
+ −
// Just a guard since we cannot set viewMode = mode here.+ −
inViewModeChange = true;+ −
+ −
#ifndef QT_NO_TABBAR+ −
if (mode == QMdiArea::TabbedView) {+ −
Q_ASSERT(!tabBar);+ −
tabBar = new QMdiAreaTabBar(q);+ −
tabBar->setDocumentMode(documentMode);+ −
#ifndef QT_NO_TABWIDGET+ −
tabBar->setShape(tabBarShapeFrom(tabShape, tabPosition));+ −
#endif+ −
+ −
isSubWindowsTiled = false;+ −
+ −
foreach (QMdiSubWindow *subWindow, childWindows)+ −
tabBar->addTab(subWindow->windowIcon(), tabTextFor(subWindow));+ −
+ −
QMdiSubWindow *current = q->currentSubWindow();+ −
if (current) {+ −
tabBar->setCurrentIndex(childWindows.indexOf(current));+ −
// Restore sub-window (i.e. cleanup buttons in menu bar and window title).+ −
if (current->isMaximized())+ −
current->showNormal();+ −
+ −
viewMode = mode;+ −
+ −
// Now, maximize it.+ −
if (!q->testOption(QMdiArea::DontMaximizeSubWindowOnActivation)) {+ −
current->showMaximized();+ −
}+ −
} else {+ −
viewMode = mode;+ −
}+ −
+ −
if (q->isVisible())+ −
tabBar->show();+ −
updateTabBarGeometry();+ −
+ −
QObject::connect(tabBar, SIGNAL(currentChanged(int)), q, SLOT(_q_currentTabChanged(int)));+ −
} else+ −
#endif // QT_NO_TABBAR+ −
{ // SubWindowView+ −
#ifndef QT_NO_TABBAR+ −
delete tabBar;+ −
tabBar = 0;+ −
#endif // QT_NO_TABBAR+ −
+ −
viewMode = mode;+ −
q->setViewportMargins(0, 0, 0, 0);+ −
indexToLastActiveTab = -1;+ −
+ −
QMdiSubWindow *current = q->currentSubWindow();+ −
if (current && current->isMaximized())+ −
current->showNormal();+ −
}+ −
+ −
Q_ASSERT(viewMode == mode);+ −
inViewModeChange = false;+ −
}+ −
+ −
#ifndef QT_NO_TABBAR+ −
/*!+ −
\internal+ −
*/+ −
void QMdiAreaPrivate::updateTabBarGeometry()+ −
{+ −
if (!tabBar)+ −
return;+ −
+ −
Q_Q(QMdiArea);+ −
#ifndef QT_NO_TABWIDGET+ −
Q_ASSERT(tabBarShapeFrom(tabShape, tabPosition) == tabBar->shape());+ −
#endif+ −
const QSize tabBarSizeHint = tabBar->sizeHint();+ −
+ −
int areaHeight = q->height();+ −
if (hbar && hbar->isVisible())+ −
areaHeight -= hbar->height();+ −
+ −
int areaWidth = q->width();+ −
if (vbar && vbar->isVisible())+ −
areaWidth -= vbar->width();+ −
+ −
QRect tabBarRect;+ −
#ifndef QT_NO_TABWIDGET+ −
switch (tabPosition) {+ −
case QTabWidget::North:+ −
q->setViewportMargins(0, tabBarSizeHint.height(), 0, 0);+ −
tabBarRect = QRect(0, 0, areaWidth, tabBarSizeHint.height());+ −
break;+ −
case QTabWidget::South:+ −
q->setViewportMargins(0, 0, 0, tabBarSizeHint.height());+ −
tabBarRect = QRect(0, areaHeight - tabBarSizeHint.height(), areaWidth, tabBarSizeHint.height());+ −
break;+ −
case QTabWidget::East:+ −
if (q->layoutDirection() == Qt::LeftToRight)+ −
q->setViewportMargins(0, 0, tabBarSizeHint.width(), 0);+ −
else+ −
q->setViewportMargins(tabBarSizeHint.width(), 0, 0, 0);+ −
tabBarRect = QRect(areaWidth - tabBarSizeHint.width(), 0, tabBarSizeHint.width(), areaHeight);+ −
break;+ −
case QTabWidget::West:+ −
if (q->layoutDirection() == Qt::LeftToRight)+ −
q->setViewportMargins(tabBarSizeHint.width(), 0, 0, 0);+ −
else+ −
q->setViewportMargins(0, 0, tabBarSizeHint.width(), 0);+ −
tabBarRect = QRect(0, 0, tabBarSizeHint.width(), areaHeight);+ −
break;+ −
default:+ −
break;+ −
}+ −
#endif // QT_NO_TABWIDGET+ −
+ −
tabBar->setGeometry(QStyle::visualRect(q->layoutDirection(), q->contentsRect(), tabBarRect));+ −
}+ −
+ −
/*!+ −
\internal+ −
*/+ −
void QMdiAreaPrivate::refreshTabBar()+ −
{+ −
if (!tabBar)+ −
return;+ −
+ −
tabBar->setDocumentMode(documentMode);+ −
#ifndef QT_NO_TABWIDGET+ −
tabBar->setShape(tabBarShapeFrom(tabShape, tabPosition));+ −
#endif+ −
updateTabBarGeometry();+ −
}+ −
#endif // QT_NO_TABBAR+ −
+ −
/*!+ −
Constructs an empty mdi area. \a parent is passed to QWidget's+ −
constructor.+ −
*/+ −
QMdiArea::QMdiArea(QWidget *parent)+ −
: QAbstractScrollArea(*new QMdiAreaPrivate, parent)+ −
{+ −
setBackground(palette().brush(QPalette::Dark));+ −
setFrameStyle(QFrame::NoFrame);+ −
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);+ −
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);+ −
setViewport(0);+ −
setFocusPolicy(Qt::NoFocus);+ −
QApplication::instance()->installEventFilter(this);+ −
}+ −
+ −
/*!+ −
Destroys the MDI area.+ −
*/+ −
QMdiArea::~QMdiArea()+ −
{+ −
Q_D(QMdiArea);+ −
delete d->cascader;+ −
d->cascader = 0;+ −
+ −
delete d->regularTiler;+ −
d->regularTiler = 0;+ −
+ −
delete d->iconTiler;+ −
d->iconTiler = 0;+ −
+ −
delete d->placer;+ −
d->placer = 0;+ −
}+ −
+ −
/*!+ −
\reimp+ −
*/+ −
QSize QMdiArea::sizeHint() const+ −
{+ −
// Calculate a proper scale factor for QDesktopWidget::size().+ −
// This also takes into account that we can have nested workspaces.+ −
int nestedCount = 0;+ −
QWidget *widget = this->parentWidget();+ −
while (widget) {+ −
if (qobject_cast<QMdiArea *>(widget))+ −
++nestedCount;+ −
widget = widget->parentWidget();+ −
}+ −
const int scaleFactor = 3 * (nestedCount + 1);+ −
+ −
QSize desktopSize = QApplication::desktop()->size();+ −
QSize size(desktopSize.width() * 2 / scaleFactor, desktopSize.height() * 2 / scaleFactor);+ −
foreach (QMdiSubWindow *child, d_func()->childWindows) {+ −
if (!sanityCheck(child, "QMdiArea::sizeHint"))+ −
continue;+ −
size = size.expandedTo(child->sizeHint());+ −
}+ −
return size.expandedTo(QApplication::globalStrut());+ −
}+ −
+ −
/*!+ −
\reimp+ −
*/+ −
QSize QMdiArea::minimumSizeHint() const+ −
{+ −
Q_D(const QMdiArea);+ −
QSize size(style()->pixelMetric(QStyle::PM_MdiSubWindowMinimizedWidth, 0, this),+ −
style()->pixelMetric(QStyle::PM_TitleBarHeight, 0, this));+ −
size = size.expandedTo(QAbstractScrollArea::minimumSizeHint());+ −
if (!d->scrollBarsEnabled()) {+ −
foreach (QMdiSubWindow *child, d->childWindows) {+ −
if (!sanityCheck(child, "QMdiArea::sizeHint"))+ −
continue;+ −
size = size.expandedTo(child->minimumSizeHint());+ −
}+ −
}+ −
return size.expandedTo(QApplication::globalStrut());+ −
}+ −
+ −
/*!+ −
Returns a pointer to the current subwindow, or 0 if there is+ −
no current subwindow.+ −
+ −
This function will return the same as activeSubWindow() if+ −
the QApplication containing QMdiArea is active.+ −
+ −
\sa activeSubWindow(), QApplication::activeWindow()+ −
*/+ −
QMdiSubWindow *QMdiArea::currentSubWindow() const+ −
{+ −
Q_D(const QMdiArea);+ −
if (d->childWindows.isEmpty())+ −
return 0;+ −
+ −
if (d->active)+ −
return d->active;+ −
+ −
if (d->isActivated && !window()->isMinimized())+ −
return 0;+ −
+ −
Q_ASSERT(d->indicesToActivatedChildren.count() > 0);+ −
int index = d->indicesToActivatedChildren.at(0);+ −
Q_ASSERT(index >= 0 && index < d->childWindows.size());+ −
QMdiSubWindow *current = d->childWindows.at(index);+ −
Q_ASSERT(current);+ −
return current;+ −
}+ −
+ −
/*!+ −
Returns a pointer to the current active subwindow. If no+ −
window is currently active, 0 is returned.+ −
+ −
Subwindows are treated as top-level windows with respect to+ −
window state, i.e., if a widget outside the MDI area is the active+ −
window, no subwindow will be active. Note that if a widget in the+ −
window in which the MDI area lives gains focus, the window will be+ −
activated.+ −
+ −
\sa setActiveSubWindow(), Qt::WindowState+ −
*/+ −
QMdiSubWindow *QMdiArea::activeSubWindow() const+ −
{+ −
Q_D(const QMdiArea);+ −
return d->active;+ −
}+ −
+ −
/*!+ −
Activates the subwindow \a window. If \a window is 0, any+ −
current active window is deactivated.+ −
+ −
\sa activeSubWindow()+ −
*/+ −
void QMdiArea::setActiveSubWindow(QMdiSubWindow *window)+ −
{+ −
Q_D(QMdiArea);+ −
if (!window) {+ −
d->activateWindow(0);+ −
return;+ −
}+ −
+ −
if (d->childWindows.isEmpty()) {+ −
qWarning("QMdiArea::setActiveSubWindow: workspace is empty");+ −
return;+ −
}+ −
+ −
if (d->childWindows.indexOf(window) == -1) {+ −
qWarning("QMdiArea::setActiveSubWindow: window is not inside workspace");+ −
return;+ −
}+ −
+ −
d->activateWindow(window);+ −
}+ −
+ −
/*!+ −
Closes the active subwindow.+ −
+ −
\sa closeAllSubWindows()+ −
*/+ −
void QMdiArea::closeActiveSubWindow()+ −
{+ −
Q_D(QMdiArea);+ −
if (d->active)+ −
d->active->close();+ −
}+ −
+ −
/*!+ −
Returns a list of all subwindows in the MDI area. If \a order is+ −
CreationOrder (the default), the windows are sorted in the order+ −
in which they were inserted into the workspace. If \a order is+ −
StackingOrder, the windows are listed in their stacking order,+ −
with the topmost window as the last item in the list. If \a order+ −
is ActivationHistoryOrder, the windows are listed according to+ −
their recent activation history.+ −
+ −
\sa WindowOrder+ −
*/+ −
QList<QMdiSubWindow *> QMdiArea::subWindowList(WindowOrder order) const+ −
{+ −
Q_D(const QMdiArea);+ −
return d->subWindowList(order, false);+ −
}+ −
+ −
/*!+ −
Closes all subwindows by sending a QCloseEvent to each window.+ −
You may receive subWindowActivated() signals from subwindows+ −
before they are closed (if the MDI area activates the subwindow+ −
when another is closing).+ −
+ −
Subwindows that ignore the close event will remain open.+ −
+ −
\sa closeActiveSubWindow()+ −
*/+ −
void QMdiArea::closeAllSubWindows()+ −
{+ −
Q_D(QMdiArea);+ −
if (d->childWindows.isEmpty())+ −
return;+ −
+ −
d->isSubWindowsTiled = false;+ −
foreach (QMdiSubWindow *child, d->childWindows) {+ −
if (!sanityCheck(child, "QMdiArea::closeAllSubWindows"))+ −
continue;+ −
child->close();+ −
}+ −
+ −
d->updateScrollBars();+ −
}+ −
+ −
/*!+ −
Gives the keyboard focus to another window in the list of child+ −
windows. The window activated will be the next one determined+ −
by the current \l{QMdiArea::WindowOrder} {activation order}.+ −
+ −
\sa activatePreviousSubWindow(), QMdiArea::WindowOrder+ −
*/+ −
void QMdiArea::activateNextSubWindow()+ −
{+ −
Q_D(QMdiArea);+ −
if (d->childWindows.isEmpty())+ −
return;+ −
+ −
QMdiSubWindow *next = d->nextVisibleSubWindow(1, d->activationOrder);+ −
if (next)+ −
d->activateWindow(next);+ −
}+ −
+ −
/*!+ −
Gives the keyboard focus to another window in the list of child+ −
windows. The window activated will be the previous one determined+ −
by the current \l{QMdiArea::WindowOrder} {activation order}.+ −
+ −
\sa activateNextSubWindow(), QMdiArea::WindowOrder+ −
*/+ −
void QMdiArea::activatePreviousSubWindow()+ −
{+ −
Q_D(QMdiArea);+ −
if (d->childWindows.isEmpty())+ −
return;+ −
+ −
QMdiSubWindow *previous = d->nextVisibleSubWindow(-1, d->activationOrder);+ −
if (previous)+ −
d->activateWindow(previous);+ −
}+ −
+ −
/*!+ −
Adds \a widget as a new subwindow to the MDI area. If \a+ −
windowFlags are non-zero, they will override the flags set on the+ −
widget.+ −
+ −
The \a widget can be either a QMdiSubWindow or another QWidget+ −
(in which case the MDI area will create a subwindow and set the \a+ −
widget as the internal widget).+ −
+ −
\note Once the subwindow has been added, its parent will be the+ −
\e{viewport widget} of the QMdiArea.+ −
+ −
\snippet doc/src/snippets/mdiareasnippets.cpp 1+ −
+ −
When you create your own subwindow, you must set the+ −
Qt::WA_DeleteOnClose widget attribute if you want the window to be+ −
deleted when closed in the MDI area. If not, the window will be+ −
hidden and the MDI area will not activate the next subwindow.+ −
+ −
Returns the QMdiSubWindow that is added to the MDI area.+ −
+ −
\sa removeSubWindow()+ −
*/+ −
QMdiSubWindow *QMdiArea::addSubWindow(QWidget *widget, Qt::WindowFlags windowFlags)+ −
{+ −
if (!widget) {+ −
qWarning("QMdiArea::addSubWindow: null pointer to widget");+ −
return 0;+ −
}+ −
+ −
Q_D(QMdiArea);+ −
// QWidget::setParent clears focusWidget so store it+ −
QWidget *childFocus = widget->focusWidget();+ −
QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(widget);+ −
+ −
// Widget is already a QMdiSubWindow+ −
if (child) {+ −
if (d->childWindows.indexOf(child) != -1) {+ −
qWarning("QMdiArea::addSubWindow: window is already added");+ −
return child;+ −
}+ −
child->setParent(viewport(), windowFlags ? windowFlags : child->windowFlags());+ −
// Create a QMdiSubWindow+ −
} else {+ −
child = new QMdiSubWindow(viewport(), windowFlags);+ −
child->setAttribute(Qt::WA_DeleteOnClose);+ −
child->setWidget(widget);+ −
Q_ASSERT(child->testAttribute(Qt::WA_DeleteOnClose));+ −
}+ −
+ −
if (childFocus)+ −
childFocus->setFocus();+ −
d->appendChild(child);+ −
return child;+ −
}+ −
+ −
/*!+ −
Removes \a widget from the MDI area. The \a widget must be+ −
either a QMdiSubWindow or a widget that is the internal widget of+ −
a subwindow. Note \a widget is never actually deleted by QMdiArea.+ −
If a QMdiSubWindow is passed in its parent is set to 0 and it is+ −
removed, but if an internal widget is passed in the child widget+ −
is set to 0 but the QMdiSubWindow is not removed.+ −
+ −
\sa addSubWindow()+ −
*/+ −
void QMdiArea::removeSubWindow(QWidget *widget)+ −
{+ −
if (!widget) {+ −
qWarning("QMdiArea::removeSubWindow: null pointer to widget");+ −
return;+ −
}+ −
+ −
Q_D(QMdiArea);+ −
if (d->childWindows.isEmpty())+ −
return;+ −
+ −
if (QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(widget)) {+ −
int index = d->childWindows.indexOf(child);+ −
if (index == -1) {+ −
qWarning("QMdiArea::removeSubWindow: window is not inside workspace");+ −
return;+ −
}+ −
d->disconnectSubWindow(child);+ −
d->childWindows.removeAll(child);+ −
d->indicesToActivatedChildren.removeAll(index);+ −
d->updateActiveWindow(index, d->active == child);+ −
child->setParent(0);+ −
return;+ −
}+ −
+ −
bool found = false;+ −
foreach (QMdiSubWindow *child, d->childWindows) {+ −
if (!sanityCheck(child, "QMdiArea::removeSubWindow"))+ −
continue;+ −
if (child->widget() == widget) {+ −
child->setWidget(0);+ −
Q_ASSERT(!child->widget());+ −
found = true;+ −
break;+ −
}+ −
}+ −
+ −
if (!found)+ −
qWarning("QMdiArea::removeSubWindow: widget is not child of any window inside QMdiArea");+ −
}+ −
+ −
/*!+ −
\property QMdiArea::background+ −
\brief the background brush for the workspace+ −
+ −
This property sets the background brush for the workspace area+ −
itself. By default, it is a gray color, but can be any brush+ −
(e.g., colors, gradients or pixmaps).+ −
*/+ −
QBrush QMdiArea::background() const+ −
{+ −
return d_func()->background;+ −
}+ −
+ −
void QMdiArea::setBackground(const QBrush &brush)+ −
{+ −
Q_D(QMdiArea);+ −
if (d->background != brush) {+ −
d->background = brush;+ −
d->viewport->setAttribute(Qt::WA_OpaquePaintEvent, brush.isOpaque());+ −
update();+ −
}+ −
}+ −
+ −
+ −
/*!+ −
\property QMdiArea::activationOrder+ −
\brief the ordering criteria for subwindow lists+ −
\since 4.4+ −
+ −
This property specifies the ordering criteria for the list of+ −
subwindows returned by subWindowList(). By default, it is the window+ −
creation order.+ −
+ −
\sa subWindowList()+ −
*/+ −
QMdiArea::WindowOrder QMdiArea::activationOrder() const+ −
{+ −
Q_D(const QMdiArea);+ −
return d->activationOrder;+ −
}+ −
+ −
void QMdiArea::setActivationOrder(WindowOrder order)+ −
{+ −
Q_D(QMdiArea);+ −
if (order != d->activationOrder)+ −
d->activationOrder = order;+ −
}+ −
+ −
/*!+ −
If \a on is true, \a option is enabled on the MDI area; otherwise+ −
it is disabled. See AreaOption for the effect of each option.+ −
+ −
\sa AreaOption, testOption()+ −
*/+ −
void QMdiArea::setOption(AreaOption option, bool on)+ −
{+ −
Q_D(QMdiArea);+ −
if (on && !(d->options & option))+ −
d->options |= option;+ −
else if (!on && (d->options & option))+ −
d->options &= ~option;+ −
}+ −
+ −
/*!+ −
Returns true if \a option is enabled; otherwise returns false.+ −
+ −
\sa AreaOption, setOption()+ −
*/+ −
bool QMdiArea::testOption(AreaOption option) const+ −
{+ −
return d_func()->options & option;+ −
}+ −
+ −
/*!+ −
\property QMdiArea::viewMode+ −
\brief the way sub-windows are displayed in the QMdiArea.+ −
\since 4.4+ −
+ −
By default, the SubWindowView is used to display sub-windows.+ −
+ −
\sa ViewMode, setTabShape(), setTabPosition()+ −
*/+ −
QMdiArea::ViewMode QMdiArea::viewMode() const+ −
{+ −
Q_D(const QMdiArea);+ −
return d->viewMode;+ −
}+ −
+ −
void QMdiArea::setViewMode(ViewMode mode)+ −
{+ −
Q_D(QMdiArea);+ −
d->setViewMode(mode);+ −
}+ −
+ −
#ifndef QT_NO_TABBAR+ −
/*!+ −
\property QMdiArea::documentMode+ −
\brief whether the tab bar is set to document mode in tabbed view mode.+ −
\since 4.5+ −
+ −
Document mode is disabled by default.+ −
+ −
\sa QTabBar::documentMode, setViewMode()+ −
*/+ −
bool QMdiArea::documentMode() const+ −
{+ −
Q_D(const QMdiArea);+ −
return d->documentMode;+ −
}+ −
+ −
void QMdiArea::setDocumentMode(bool enabled)+ −
{+ −
Q_D(QMdiArea);+ −
if (d->documentMode == enabled)+ −
return;+ −
+ −
d->documentMode = enabled;+ −
d->refreshTabBar();+ −
}+ −
#endif // QT_NO_TABBAR+ −
+ −
#ifndef QT_NO_TABWIDGET+ −
/*!+ −
\property QMdiArea::tabShape+ −
\brief the shape of the tabs in tabbed view mode.+ −
\since 4.4+ −
+ −
Possible values for this property are QTabWidget::Rounded+ −
(default) or QTabWidget::Triangular.+ −
+ −
\sa QTabWidget::TabShape, setViewMode()+ −
*/+ −
QTabWidget::TabShape QMdiArea::tabShape() const+ −
{+ −
Q_D(const QMdiArea);+ −
return d->tabShape;+ −
}+ −
+ −
void QMdiArea::setTabShape(QTabWidget::TabShape shape)+ −
{+ −
Q_D(QMdiArea);+ −
if (d->tabShape == shape)+ −
return;+ −
+ −
d->tabShape = shape;+ −
d->refreshTabBar();+ −
}+ −
+ −
/*!+ −
\property QMdiArea::tabPosition+ −
\brief the position of the tabs in tabbed view mode.+ −
\since 4.4+ −
+ −
Possible values for this property are described by the+ −
QTabWidget::TabPosition enum.+ −
+ −
\sa QTabWidget::TabPosition, setViewMode()+ −
*/+ −
QTabWidget::TabPosition QMdiArea::tabPosition() const+ −
{+ −
Q_D(const QMdiArea);+ −
return d->tabPosition;+ −
}+ −
+ −
void QMdiArea::setTabPosition(QTabWidget::TabPosition position)+ −
{+ −
Q_D(QMdiArea);+ −
if (d->tabPosition == position)+ −
return;+ −
+ −
d->tabPosition = position;+ −
d->refreshTabBar();+ −
}+ −
#endif // QT_NO_TABWIDGET+ −
+ −
/*!+ −
\reimp+ −
*/+ −
void QMdiArea::childEvent(QChildEvent *childEvent)+ −
{+ −
Q_D(QMdiArea);+ −
if (childEvent->type() == QEvent::ChildPolished) {+ −
if (QMdiSubWindow *mdiChild = qobject_cast<QMdiSubWindow *>(childEvent->child())) {+ −
if (d->childWindows.indexOf(mdiChild) == -1)+ −
d->appendChild(mdiChild);+ −
}+ −
}+ −
}+ −
+ −
/*!+ −
\reimp+ −
*/+ −
void QMdiArea::resizeEvent(QResizeEvent *resizeEvent)+ −
{+ −
Q_D(QMdiArea);+ −
if (d->childWindows.isEmpty()) {+ −
resizeEvent->ignore();+ −
return;+ −
}+ −
+ −
#ifndef QT_NO_TABBAR+ −
d->updateTabBarGeometry();+ −
#endif+ −
+ −
// Re-tile the views if we're in tiled mode. Re-tile means we will change+ −
// the geometry of the children, which in turn means 'isSubWindowsTiled'+ −
// is set to false, so we have to update the state at the end.+ −
if (d->isSubWindowsTiled) {+ −
d->tileCalledFromResizeEvent = true;+ −
tileSubWindows();+ −
d->tileCalledFromResizeEvent = false;+ −
d->isSubWindowsTiled = true;+ −
d->startResizeTimer();+ −
// We don't have scroll bars or any maximized views.+ −
return;+ −
}+ −
+ −
// Resize maximized views.+ −
bool hasMaximizedSubWindow = false;+ −
foreach (QMdiSubWindow *child, d->childWindows) {+ −
if (sanityCheck(child, "QMdiArea::resizeEvent") && child->isMaximized()+ −
&& child->size() != resizeEvent->size()) {+ −
child->resize(resizeEvent->size());+ −
if (!hasMaximizedSubWindow)+ −
hasMaximizedSubWindow = true;+ −
}+ −
}+ −
+ −
d->updateScrollBars();+ −
+ −
// Minimized views are stacked under maximized views so there's+ −
// no need to re-arrange minimized views on-demand. Start a timer+ −
// just to make things faster with subsequent resize events.+ −
if (hasMaximizedSubWindow)+ −
d->startResizeTimer();+ −
else+ −
d->arrangeMinimizedSubWindows();+ −
}+ −
+ −
/*!+ −
\reimp+ −
*/+ −
void QMdiArea::timerEvent(QTimerEvent *timerEvent)+ −
{+ −
Q_D(QMdiArea);+ −
if (timerEvent->timerId() == d->resizeTimerId) {+ −
killTimer(d->resizeTimerId);+ −
d->resizeTimerId = -1;+ −
d->arrangeMinimizedSubWindows();+ −
} else if (timerEvent->timerId() == d->tabToPreviousTimerId) {+ −
killTimer(d->tabToPreviousTimerId);+ −
d->tabToPreviousTimerId = -1;+ −
if (d->indexToHighlighted < 0)+ −
return;+ −
#ifndef QT_NO_RUBBERBAND+ −
// We're not doing a "quick switch" ... show rubber band.+ −
Q_ASSERT(d->indexToHighlighted < d->childWindows.size());+ −
Q_ASSERT(d->rubberBand);+ −
d->showRubberBandFor(d->childWindows.at(d->indexToHighlighted));+ −
#endif+ −
}+ −
}+ −
+ −
/*!+ −
\reimp+ −
*/+ −
void QMdiArea::showEvent(QShowEvent *showEvent)+ −
{+ −
Q_D(QMdiArea);+ −
if (!d->pendingRearrangements.isEmpty()) {+ −
bool skipPlacement = false;+ −
foreach (Rearranger *rearranger, d->pendingRearrangements) {+ −
// If this is the case, we don't have to lay out pending child windows+ −
// since the rearranger will find a placement for them.+ −
if (rearranger->type() != Rearranger::IconTiler && !skipPlacement)+ −
skipPlacement = true;+ −
d->rearrange(rearranger);+ −
}+ −
d->pendingRearrangements.clear();+ −
+ −
if (skipPlacement && !d->pendingPlacements.isEmpty())+ −
d->pendingPlacements.clear();+ −
}+ −
+ −
if (!d->pendingPlacements.isEmpty()) {+ −
foreach (QMdiSubWindow *window, d->pendingPlacements) {+ −
if (!window)+ −
continue;+ −
if (!window->testAttribute(Qt::WA_Resized)) {+ −
QSize newSize(window->sizeHint().boundedTo(viewport()->size()));+ −
window->resize(newSize.expandedTo(qSmartMinSize(window)));+ −
}+ −
if (!window->testAttribute(Qt::WA_Moved) && !window->isMinimized()+ −
&& !window->isMaximized()) {+ −
d->place(d->placer, window);+ −
}+ −
}+ −
d->pendingPlacements.clear();+ −
}+ −
+ −
d->setChildActivationEnabled(true);+ −
d->activateCurrentWindow();+ −
+ −
QAbstractScrollArea::showEvent(showEvent);+ −
}+ −
+ −
/*!+ −
\reimp+ −
*/+ −
bool QMdiArea::viewportEvent(QEvent *event)+ −
{+ −
Q_D(QMdiArea);+ −
switch (event->type()) {+ −
case QEvent::ChildRemoved: {+ −
d->isSubWindowsTiled = false;+ −
QObject *removedChild = static_cast<QChildEvent *>(event)->child();+ −
for (int i = 0; i < d->childWindows.size(); ++i) {+ −
QObject *child = d->childWindows.at(i);+ −
if (!child || child == removedChild || !child->parent()+ −
|| child->parent() != viewport()) {+ −
if (!testOption(DontMaximizeSubWindowOnActivation)) {+ −
// In this case we can only rely on the child being a QObject+ −
// (or 0), but let's try and see if we can get more information.+ −
QWidget *mdiChild = qobject_cast<QWidget *>(removedChild);+ −
if (mdiChild && mdiChild->isMaximized())+ −
d->showActiveWindowMaximized = true;+ −
}+ −
d->disconnectSubWindow(child);+ −
const bool activeRemoved = i == d->indicesToActivatedChildren.at(0);+ −
d->childWindows.removeAt(i);+ −
d->indicesToActivatedChildren.removeAll(i);+ −
d->updateActiveWindow(i, activeRemoved);+ −
d->arrangeMinimizedSubWindows();+ −
break;+ −
}+ −
}+ −
d->updateScrollBars();+ −
break;+ −
}+ −
case QEvent::Destroy:+ −
d->isSubWindowsTiled = false;+ −
d->resetActiveWindow();+ −
d->childWindows.clear();+ −
qWarning("QMdiArea: Deleting the view port is undefined, use setViewport instead.");+ −
break;+ −
default:+ −
break;+ −
}+ −
return QAbstractScrollArea::viewportEvent(event);+ −
}+ −
+ −
/*!+ −
\reimp+ −
*/+ −
void QMdiArea::scrollContentsBy(int dx, int dy)+ −
{+ −
Q_D(QMdiArea);+ −
const bool wasSubWindowsTiled = d->isSubWindowsTiled;+ −
d->ignoreGeometryChange = true;+ −
viewport()->scroll(isLeftToRight() ? dx : -dx, dy);+ −
d->arrangeMinimizedSubWindows();+ −
d->ignoreGeometryChange = false;+ −
if (wasSubWindowsTiled)+ −
d->isSubWindowsTiled = true;+ −
}+ −
+ −
/*!+ −
Arranges all child windows in a tile pattern.+ −
+ −
\sa cascadeSubWindows()+ −
*/+ −
void QMdiArea::tileSubWindows()+ −
{+ −
Q_D(QMdiArea);+ −
if (!d->regularTiler)+ −
d->regularTiler = new RegularTiler;+ −
d->rearrange(d->regularTiler);+ −
}+ −
+ −
/*!+ −
Arranges all the child windows in a cascade pattern.+ −
+ −
\sa tileSubWindows()+ −
*/+ −
void QMdiArea::cascadeSubWindows()+ −
{+ −
Q_D(QMdiArea);+ −
if (!d->cascader)+ −
d->cascader = new SimpleCascader;+ −
d->rearrange(d->cascader);+ −
}+ −
+ −
/*!+ −
\reimp+ −
*/+ −
bool QMdiArea::event(QEvent *event)+ −
{+ −
Q_D(QMdiArea);+ −
switch (event->type()) {+ −
#ifdef Q_WS_WIN+ −
// QWidgetPrivate::hide_helper activates another sub-window when closing a+ −
// modal dialog on Windows (see activateWindow() inside the the ifdef).+ −
case QEvent::WindowUnblocked:+ −
d->activateCurrentWindow();+ −
break;+ −
#endif+ −
case QEvent::WindowActivate: {+ −
d->isActivated = true;+ −
if (d->childWindows.isEmpty())+ −
break;+ −
if (!d->active)+ −
d->activateCurrentWindow();+ −
d->setChildActivationEnabled(false, true);+ −
break;+ −
}+ −
case QEvent::WindowDeactivate:+ −
d->isActivated = false;+ −
d->setChildActivationEnabled(false, true);+ −
break;+ −
case QEvent::StyleChange:+ −
// Re-tile the views if we're in tiled mode. Re-tile means we will change+ −
// the geometry of the children, which in turn means 'isSubWindowsTiled'+ −
// is set to false, so we have to update the state at the end.+ −
if (d->isSubWindowsTiled) {+ −
tileSubWindows();+ −
d->isSubWindowsTiled = true;+ −
}+ −
break;+ −
case QEvent::WindowIconChange:+ −
foreach (QMdiSubWindow *window, d->childWindows) {+ −
if (sanityCheck(window, "QMdiArea::WindowIconChange"))+ −
QApplication::sendEvent(window, event);+ −
}+ −
break;+ −
case QEvent::Hide:+ −
d->setActive(d->active, false, false);+ −
d->setChildActivationEnabled(false);+ −
break;+ −
#ifndef QT_NO_TABBAR+ −
case QEvent::LayoutDirectionChange:+ −
d->updateTabBarGeometry();+ −
break;+ −
#endif+ −
default:+ −
break;+ −
}+ −
return QAbstractScrollArea::event(event);+ −
}+ −
+ −
/*!+ −
\reimp+ −
*/+ −
bool QMdiArea::eventFilter(QObject *object, QEvent *event)+ −
{+ −
if (!object)+ −
return QAbstractScrollArea::eventFilter(object, event);+ −
+ −
Q_D(QMdiArea);+ −
// Global key events with Ctrl modifier.+ −
if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) {+ −
+ −
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);+ −
// Ingore key events without a Ctrl modifier (except for press/release on the modifier itself).+ −
#ifdef Q_WS_MAC+ −
if (!(keyEvent->modifiers() & Qt::MetaModifier) && keyEvent->key() != Qt::Key_Meta)+ −
#else+ −
if (!(keyEvent->modifiers() & Qt::ControlModifier) && keyEvent->key() != Qt::Key_Control)+ −
#endif+ −
return QAbstractScrollArea::eventFilter(object, event);+ −
+ −
// Find closest mdi area (in case we have a nested workspace).+ −
QMdiArea *area = mdiAreaParent(static_cast<QWidget *>(object));+ −
if (!area)+ −
return QAbstractScrollArea::eventFilter(object, event);+ −
+ −
const bool keyPress = (event->type() == QEvent::KeyPress) ? true : false;+ −
+ −
// 1) Ctrl-Tab once -> activate the previously active window.+ −
// 2) Ctrl-Tab (Tab, Tab, ...) -> iterate through all windows (activateNextSubWindow()).+ −
// 3) Ctrl-Shift-Tab (Tab, Tab, ...) -> iterate through all windows in the opposite+ −
// direction (activatePreviousSubWindow())+ −
switch (keyEvent->key()) {+ −
#ifdef Q_WS_MAC+ −
case Qt::Key_Meta:+ −
#else+ −
case Qt::Key_Control:+ −
#endif+ −
if (keyPress)+ −
area->d_func()->startTabToPreviousTimer();+ −
else+ −
area->d_func()->activateHighlightedWindow();+ −
break;+ −
case Qt::Key_Tab:+ −
case Qt::Key_Backtab:+ −
if (keyPress)+ −
area->d_func()->highlightNextSubWindow(keyEvent->key() == Qt::Key_Tab ? 1 : -1);+ −
return true;+ −
#ifndef QT_NO_RUBBERBAND+ −
case Qt::Key_Escape:+ −
area->d_func()->hideRubberBand();+ −
break;+ −
#endif+ −
default:+ −
break;+ −
}+ −
return QAbstractScrollArea::eventFilter(object, event);+ −
}+ −
+ −
QMdiSubWindow *subWindow = qobject_cast<QMdiSubWindow *>(object);+ −
+ −
if (!subWindow) {+ −
// QApplication events:+ −
if (event->type() == QEvent::ApplicationActivate && !d->active+ −
&& isVisible() && !window()->isMinimized()) {+ −
d->activateCurrentWindow();+ −
} else if (event->type() == QEvent::ApplicationDeactivate && d->active) {+ −
d->setActive(d->active, false, false);+ −
}+ −
return QAbstractScrollArea::eventFilter(object, event);+ −
}+ −
+ −
// QMdiSubWindow events:+ −
switch (event->type()) {+ −
case QEvent::Move:+ −
case QEvent::Resize:+ −
if (d->tileCalledFromResizeEvent)+ −
break;+ −
d->updateScrollBars();+ −
if (!subWindow->isMinimized())+ −
d->isSubWindowsTiled = false;+ −
break;+ −
case QEvent::Show:+ −
#ifndef QT_NO_TABBAR+ −
if (d->tabBar) {+ −
const int tabIndex = d->childWindows.indexOf(subWindow);+ −
if (!d->tabBar->isTabEnabled(tabIndex))+ −
d->tabBar->setTabEnabled(tabIndex, true);+ −
}+ −
#endif // QT_NO_TABBAR+ −
// fall through+ −
case QEvent::Hide:+ −
d->isSubWindowsTiled = false;+ −
break;+ −
#ifndef QT_NO_RUBBERBAND+ −
case QEvent::Close:+ −
if (d->childWindows.indexOf(subWindow) == d->indexToHighlighted)+ −
d->hideRubberBand();+ −
break;+ −
#endif+ −
#ifndef QT_NO_TABBAR+ −
case QEvent::WindowTitleChange:+ −
case QEvent::ModifiedChange:+ −
if (d->tabBar)+ −
d->tabBar->setTabText(d->childWindows.indexOf(subWindow), tabTextFor(subWindow));+ −
break;+ −
case QEvent::WindowIconChange:+ −
if (d->tabBar)+ −
d->tabBar->setTabIcon(d->childWindows.indexOf(subWindow), subWindow->windowIcon());+ −
break;+ −
#endif // QT_NO_TABBAR+ −
default:+ −
break;+ −
}+ −
return QAbstractScrollArea::eventFilter(object, event);+ −
}+ −
+ −
/*!+ −
\reimp+ −
*/+ −
void QMdiArea::paintEvent(QPaintEvent *paintEvent)+ −
{+ −
Q_D(QMdiArea);+ −
QPainter painter(d->viewport);+ −
const QVector<QRect> &exposedRects = paintEvent->region().rects();+ −
for (int i = 0; i < exposedRects.size(); ++i)+ −
painter.fillRect(exposedRects.at(i), d->background);+ −
}+ −
+ −
/*!+ −
This slot is called by QAbstractScrollArea after setViewport() has been+ −
called. Reimplement this function in a subclass of QMdiArea to+ −
initialize the new \a viewport before it is used.+ −
+ −
\sa setViewport()+ −
*/+ −
void QMdiArea::setupViewport(QWidget *viewport)+ −
{+ −
Q_D(QMdiArea);+ −
if (viewport)+ −
viewport->setAttribute(Qt::WA_OpaquePaintEvent, d->background.isOpaque());+ −
foreach (QMdiSubWindow *child, d->childWindows) {+ −
if (!sanityCheck(child, "QMdiArea::setupViewport"))+ −
continue;+ −
child->setParent(viewport, child->windowFlags());+ −
}+ −
}+ −
+ −
QT_END_NAMESPACE+ −
+ −
#include "moc_qmdiarea.cpp"+ −
+ −
#endif // QT_NO_MDIAREA+ −