diff options
Diffstat (limited to 'src/gui/widgets/qmdiarea.cpp')
-rw-r--r-- | src/gui/widgets/qmdiarea.cpp | 2678 |
1 files changed, 0 insertions, 2678 deletions
diff --git a/src/gui/widgets/qmdiarea.cpp b/src/gui/widgets/qmdiarea.cpp deleted file mode 100644 index 2a486bba18..0000000000 --- a/src/gui/widgets/qmdiarea.cpp +++ /dev/null @@ -1,2678 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 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), - tabsClosable(false), - tabsMovable(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 -} - -void QMdiAreaPrivate::_q_closeTab(int index) -{ -#ifdef QT_NO_TABBAR - Q_UNUSED(index); -#else - QMdiSubWindow *subWindow = childWindows.at(index); - Q_ASSERT(subWindow); - subWindow->close(); -#endif // QT_NO_TABBAR -} - -void QMdiAreaPrivate::_q_moveTab(int from, int to) -{ -#ifdef QT_NO_TABBAR - Q_UNUSED(from); - Q_UNUSED(to); -#else - childWindows.move(from, to); -#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); - tabBar->setTabsClosable(tabsClosable); - tabBar->setMovable(tabsMovable); -#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))); - QObject::connect(tabBar, SIGNAL(tabCloseRequested(int)), q, SLOT(_q_closeTab(int))); - QObject::connect(tabBar, SIGNAL(tabMoved(int,int)), q, SLOT(_q_moveTab(int,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); - tabBar->setTabsClosable(tabsClosable); - tabBar->setMovable(tabsMovable); -#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(); -} - -/*! - \property QMdiArea::tabsClosable - \brief whether the tab bar should place close buttons on each tab in tabbed view mode. - \since 4.8 - - Tabs are not closable by default. - - \sa QTabBar::tabsClosable, setViewMode() -*/ -bool QMdiArea::tabsClosable() const -{ - Q_D(const QMdiArea); - return d->tabsClosable; -} - -void QMdiArea::setTabsClosable(bool closable) -{ - Q_D(QMdiArea); - if (d->tabsClosable == closable) - return; - - d->tabsClosable = closable; - d->refreshTabBar(); -} - -/*! - \property QMdiArea::tabsMovable - \brief whether the user can move the tabs within the tabbar area in tabbed view mode. - \since 4.8 - - Tabs are not movable by default. - - \sa QTabBar::tabsMovable, setViewMode() -*/ -bool QMdiArea::tabsMovable() const -{ - Q_D(const QMdiArea); - return d->tabsMovable; -} - -void QMdiArea::setTabsMovable(bool movable) -{ - Q_D(QMdiArea); - if (d->tabsMovable == movable) - return; - - d->tabsMovable = movable; - 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 |