summaryrefslogtreecommitdiffstats
path: root/src/widgets/widgets/qmdiarea.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/widgets/widgets/qmdiarea.cpp')
-rw-r--r--src/widgets/widgets/qmdiarea.cpp359
1 files changed, 176 insertions, 183 deletions
diff --git a/src/widgets/widgets/qmdiarea.cpp b/src/widgets/widgets/qmdiarea.cpp
index f32cd26478..79b83453ac 100644
--- a/src/widgets/widgets/qmdiarea.cpp
+++ b/src/widgets/widgets/qmdiarea.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWidgets module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/*!
\class QMdiArea
@@ -51,7 +15,7 @@
applications, but can also be placed in any layout. The following
code adds an area to a main window:
- \snippet mdiareasnippets.cpp 0
+ \snippet mdiarea/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
@@ -63,7 +27,7 @@
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
+ 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
@@ -103,8 +67,8 @@
\fn void 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.
+ window is \nullptr, QMdiArea has just deactivated its last active window,
+ and there are no active windows on the workspace.
\sa QMdiArea::activeSubWindow()
*/
@@ -165,8 +129,6 @@
#include <QPainter>
#include <QFontMetrics>
#include <QStyleOption>
-#include <QDesktopWidget>
-#include <private/qdesktopwidget_p.h>
#include <QDebug>
#include <qmath.h>
#if QT_CONFIG(menu)
@@ -178,6 +140,7 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
using namespace QMdi;
// Asserts in debug mode, gives warning otherwise.
@@ -245,7 +208,7 @@ static inline bool useScrollBar(const QRect &childrenRect, const QSize &maxViewp
static inline QMdiArea *mdiAreaParent(QWidget *widget)
{
if (!widget)
- return 0;
+ return nullptr;
QWidget *parent = widget->parentWidget();
while (parent) {
@@ -253,23 +216,11 @@ static inline QMdiArea *mdiAreaParent(QWidget *widget)
return area;
parent = parent->parentWidget();
}
- return 0;
+ return nullptr;
}
#if QT_CONFIG(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;
-}
+QTabBar::Shape _q_tb_tabBarShapeFrom(QTabWidget::TabShape shape, QTabWidget::TabPosition position);
#endif // QT_CONFIG(tabwidget)
static inline QString tabTextFor(QMdiSubWindow *subWindow)
@@ -279,7 +230,7 @@ static inline QString tabTextFor(QMdiSubWindow *subWindow)
QString title = subWindow->windowTitle();
if (subWindow->isWindowModified()) {
- title.replace(QLatin1String("[*]"), QLatin1String("*"));
+ title.replace("[*]"_L1, "*"_L1);
} else {
extern QString qt_setWindowTitle_helperHelper(const QString&, const QWidget*);
title = qt_setWindowTitle_helperHelper(title, subWindow);
@@ -352,7 +303,7 @@ void SimpleCascader::rearrange(QList<QWidget *> &widgets, const QRect &domain) c
int titleBarHeight = widgets.at(0)->style()->pixelMetric(QStyle::PM_TitleBarHeight, &options, widgets.at(0));
const QFontMetrics fontMetrics = QFontMetrics(QApplication::font("QMdiSubWindowTitleBar"));
const int dy = qMax(titleBarHeight - (titleBarHeight - fontMetrics.height()) / 2, 1)
- + widgets.at(0)->style()->pixelMetric(QStyle::PM_FocusFrameVMargin, 0, widgets.at(0));
+ + widgets.at(0)->style()->pixelMetric(QStyle::PM_FocusFrameVMargin, nullptr, widgets.at(0));
const int n = widgets.size();
const int nrows = qMax((domain.height() - (topOffset + bottomOffset)) / dy, 1);
@@ -410,7 +361,7 @@ void IconTiler::rearrange(QList<QWidget *> &widgets, const QRect &domain) const
\internal
Calculates the accumulated overlap (intersection area) between 'source' and 'rects'.
*/
-int MinOverlapPlacer::accumulatedOverlap(const QRect &source, const QVector<QRect> &rects)
+int MinOverlapPlacer::accumulatedOverlap(const QRect &source, const QList<QRect> &rects)
{
int accOverlap = 0;
for (const QRect &rect : rects) {
@@ -426,7 +377,7 @@ int MinOverlapPlacer::accumulatedOverlap(const QRect &source, const QVector<QRec
Finds among 'source' the rectangle with the minimum accumulated overlap with the
rectangles in 'rects'.
*/
-QRect MinOverlapPlacer::findMinOverlapRect(const QVector<QRect> &source, const QVector<QRect> &rects)
+QRect MinOverlapPlacer::findMinOverlapRect(const QList<QRect> &source, const QList<QRect> &rects)
{
int minAccOverlap = -1;
QRect minAccOverlapRect;
@@ -444,16 +395,16 @@ QRect MinOverlapPlacer::findMinOverlapRect(const QVector<QRect> &source, const Q
\internal
Gets candidates for the final placement.
*/
-QVector<QRect> MinOverlapPlacer::getCandidatePlacements(const QSize &size, const QVector<QRect> &rects,
- const QRect &domain)
+QList<QRect> MinOverlapPlacer::getCandidatePlacements(const QSize &size, const QList<QRect> &rects,
+ const QRect &domain)
{
- QVector<QRect> result;
+ QList<QRect> result;
- QVector<int> xlist;
+ QList<int> xlist;
xlist.reserve(2 + rects.size());
xlist << domain.left() << domain.right() - size.width() + 1;
- QVector<int> ylist;
+ QList<int> ylist;
ylist.reserve(2 + rects.size());
ylist << domain.top();
if (domain.bottom() - size.height() + 1 >= 0)
@@ -471,8 +422,8 @@ QVector<QRect> MinOverlapPlacer::getCandidatePlacements(const QSize &size, const
ylist.erase(std::unique(ylist.begin(), ylist.end()), ylist.end());
result.reserve(ylist.size() * xlist.size());
- for (int y : qAsConst(ylist))
- for (int x : qAsConst(xlist))
+ for (int y : std::as_const(ylist))
+ for (int x : std::as_const(xlist))
result << QRect(QPoint(x, y), size);
return result;
}
@@ -482,14 +433,14 @@ QVector<QRect> MinOverlapPlacer::getCandidatePlacements(const QSize &size, const
Finds all rectangles in 'source' not completely inside 'domain'. The result is stored
in 'result' and also removed from 'source'.
*/
-QVector<QRect> MinOverlapPlacer::findNonInsiders(const QRect &domain, QVector<QRect> &source)
+QList<QRect> MinOverlapPlacer::findNonInsiders(const QRect &domain, QList<QRect> &source)
{
const auto containedInDomain =
[domain](const QRect &srcRect) { return domain.contains(srcRect); };
const auto firstOut = std::stable_partition(source.begin(), source.end(), containedInDomain);
- QVector<QRect> result;
+ QList<QRect> result;
result.reserve(source.end() - firstOut);
std::copy(firstOut, source.end(), std::back_inserter(result));
@@ -503,9 +454,9 @@ QVector<QRect> MinOverlapPlacer::findNonInsiders(const QRect &domain, QVector<QR
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'.
*/
-QVector<QRect> MinOverlapPlacer::findMaxOverlappers(const QRect &domain, const QVector<QRect> &source)
+QList<QRect> MinOverlapPlacer::findMaxOverlappers(const QRect &domain, const QList<QRect> &source)
{
- QVector<QRect> result;
+ QList<QRect> result;
result.reserve(source.size());
int maxOverlap = -1;
@@ -530,15 +481,15 @@ QVector<QRect> MinOverlapPlacer::findMaxOverlappers(const QRect &domain, const Q
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 QVector<QRect> &rects,
- QVector<QRect> &source)
+QPoint MinOverlapPlacer::findBestPlacement(const QRect &domain, const QList<QRect> &rects,
+ QList<QRect> &source)
{
- const QVector<QRect> nonInsiders = findNonInsiders(domain, source);
+ const QList<QRect> nonInsiders = findNonInsiders(domain, source);
if (!source.empty())
return findMinOverlapRect(source, rects).topLeft();
- QVector<QRect> maxOverlappers = findMaxOverlappers(domain, nonInsiders);
+ QList<QRect> maxOverlappers = findMaxOverlappers(domain, nonInsiders);
return findMinOverlapRect(maxOverlappers, rects).topLeft();
}
@@ -549,7 +500,7 @@ QPoint MinOverlapPlacer::findBestPlacement(const QRect &domain, const QVector<QR
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 QVector<QRect> &rects,
+QPoint MinOverlapPlacer::place(const QSize &size, const QList<QRect> &rects,
const QRect &domain) const
{
if (size.isEmpty() || !domain.isValid())
@@ -559,7 +510,7 @@ QPoint MinOverlapPlacer::place(const QSize &size, const QVector<QRect> &rects,
return QPoint();
}
- QVector<QRect> candidates = getCandidatePlacements(size, rects, domain);
+ QList<QRect> candidates = getCandidatePlacements(size, rects, domain);
return findBestPlacement(domain, rects, candidates);
}
@@ -584,12 +535,12 @@ private:
*/
void QMdiAreaTabBar::mousePressEvent(QMouseEvent *event)
{
- if (event->button() != Qt::MidButton) {
+ if (event->button() != Qt::MiddleButton) {
QTabBar::mousePressEvent(event);
return;
}
- QMdiSubWindow *subWindow = subWindowFromIndex(tabAt(event->pos()));
+ QMdiSubWindow *subWindow = subWindowFromIndex(tabAt(event->position().toPoint()));
if (!subWindow) {
event->ignore();
return;
@@ -648,7 +599,7 @@ void QMdiAreaTabBar::contextMenuEvent(QContextMenuEvent *event)
QMdiSubWindow *QMdiAreaTabBar::subWindowFromIndex(int index) const
{
if (index < 0 || index >= count())
- return 0;
+ return nullptr;
QMdiArea *mdiArea = qobject_cast<QMdiArea *>(parentWidget());
Q_ASSERT(mdiArea);
@@ -667,15 +618,15 @@ QMdiSubWindow *QMdiAreaTabBar::subWindowFromIndex(int index) const
\internal
*/
QMdiAreaPrivate::QMdiAreaPrivate()
- : cascader(0),
- regularTiler(0),
- iconTiler(0),
- placer(0),
+ : cascader(nullptr),
+ regularTiler(nullptr),
+ iconTiler(nullptr),
+ placer(nullptr),
#if QT_CONFIG(rubberband)
- rubberBand(0),
+ rubberBand(nullptr),
#endif
#if QT_CONFIG(tabbar)
- tabBar(0),
+ tabBar(nullptr),
#endif
activationOrder(QMdiArea::CreationOrder),
viewMode(QMdiArea::SubWindowView),
@@ -720,12 +671,16 @@ void QMdiAreaPrivate::_q_deactivateAllWindows(QMdiSubWindow *aboutToActivate)
aboutToBecomeActive = aboutToActivate;
Q_ASSERT(aboutToBecomeActive);
- foreach (QMdiSubWindow *child, childWindows) {
+ // Take a copy because child->showNormal() could indirectly call
+ // QCoreApplication::sendEvent(), which could call unknown code that e.g.
+ // recurses into the class modifying childWindows.
+ const auto subWindows = childWindows;
+ for (QMdiSubWindow *child : subWindows) {
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)
+ if (!(options & QMdiArea::DontMaximizeSubWindowOnActivation) && !showActiveWindowMaximized)
showActiveWindowMaximized = child->isMaximized() && child->isVisible();
if (showActiveWindowMaximized && child->isMaximized()) {
if (q->updatesEnabled()) {
@@ -787,7 +742,7 @@ void QMdiAreaPrivate::_q_currentTabChanged(int index)
// If the previous active sub-window was hidden, disable the tab.
if (indexToLastActiveTab >= 0 && indexToLastActiveTab < tabBar->count()
- && indexToLastActiveTab < childWindows.count()) {
+ && indexToLastActiveTab < childWindows.size()) {
QMdiSubWindow *lastActive = childWindows.at(indexToLastActiveTab);
if (lastActive && lastActive->isHidden())
tabBar->setTabEnabled(indexToLastActiveTab, false);
@@ -861,7 +816,7 @@ void QMdiAreaPrivate::appendChild(QMdiSubWindow *child)
if (tabBar) {
tabBar->addTab(child->windowIcon(), tabTextFor(child));
updateTabBarGeometry();
- if (childWindows.count() == 1 && !(options & QMdiArea::DontMaximizeSubWindowOnActivation))
+ if (childWindows.size() == 1 && !(options & QMdiArea::DontMaximizeSubWindowOnActivation))
showActiveWindowMaximized = true;
}
#endif
@@ -892,10 +847,10 @@ void QMdiAreaPrivate::place(Placer *placer, QMdiSubWindow *child)
return;
}
- QVector<QRect> rects;
+ QList<QRect> rects;
rects.reserve(childWindows.size());
QRect parentRect = q->rect();
- foreach (QMdiSubWindow *window, childWindows) {
+ for (QMdiSubWindow *window : std::as_const(childWindows)) {
if (!sanityCheck(window, "QMdiArea::place") || window == child || !window->isVisibleTo(q)
|| !window->testAttribute(Qt::WA_Moved)) {
continue;
@@ -937,7 +892,7 @@ void QMdiAreaPrivate::rearrange(Rearranger *rearranger)
const bool reverseList = rearranger->type() == Rearranger::RegularTiler;
const QList<QMdiSubWindow *> subWindows = subWindowList(activationOrder, reverseList);
QSize minSubWindowSize;
- foreach (QMdiSubWindow *child, subWindows) {
+ for (QMdiSubWindow *child : subWindows) {
if (!sanityCheck(child, "QMdiArea::rearrange") || !child->isVisible())
continue;
if (rearranger->type() == Rearranger::IconTiler) {
@@ -954,17 +909,9 @@ void QMdiAreaPrivate::rearrange(Rearranger *rearranger)
}
}
- if (active && rearranger->type() == Rearranger::RegularTiler && !tileCalledFromResizeEvent) {
- // 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());
+ domain = resizeToMinimumTileSize(minSubWindowSize, widgets.size());
rearranger->rearrange(widgets, domain);
@@ -1010,6 +957,10 @@ void QMdiAreaPrivate::activateWindow(QMdiSubWindow *child)
if (child->isHidden() || child == active)
return;
+
+ if (child->d_func()->isActive && active == nullptr)
+ child->d_func()->isActive = false;
+
child->d_func()->setActive(true);
}
@@ -1078,7 +1029,7 @@ void QMdiAreaPrivate::emitWindowActivated(QMdiSubWindow *activeWindow)
Q_ASSERT(aboutToBecomeActive == activeWindow);
active = activeWindow;
- aboutToBecomeActive = 0;
+ aboutToBecomeActive = nullptr;
Q_ASSERT(active->d_func()->isActive);
#if QT_CONFIG(tabbar)
@@ -1101,20 +1052,20 @@ void QMdiAreaPrivate::resetActiveWindow(QMdiSubWindow *deactivatedWindow)
if (deactivatedWindow) {
if (deactivatedWindow != active)
return;
- active = 0;
+ active = nullptr;
if ((aboutToBecomeActive || isActivated || lastWindowAboutToBeDestroyed())
&& !isExplicitlyDeactivated(deactivatedWindow) && !q->window()->isMinimized()) {
return;
}
- emit q->subWindowActivated(0);
+ emit q->subWindowActivated(nullptr);
return;
}
if (aboutToBecomeActive)
return;
- active = 0;
- emit q->subWindowActivated(0);
+ active = nullptr;
+ emit q->subWindowActivated(nullptr);
}
/*!
@@ -1179,7 +1130,7 @@ void QMdiAreaPrivate::updateScrollBars()
QSize hbarExtent = hbar->sizeHint();
QSize vbarExtent = vbar->sizeHint();
- if (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents, 0, q)) {
+ if (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents, nullptr, q)) {
const int doubleFrameWidth = frameWidth * 2;
if (hbarpolicy == Qt::ScrollBarAlwaysOn)
maxSize.rheight() -= doubleFrameWidth;
@@ -1240,7 +1191,7 @@ void QMdiAreaPrivate::internalRaise(QMdiSubWindow *mdiChild) const
if (!sanityCheck(mdiChild, "QMdiArea::internalRaise") || childWindows.size() < 2)
return;
- QMdiSubWindow *stackUnderChild = 0;
+ QMdiSubWindow *stackUnderChild = nullptr;
if (!windowStaysOnTop(mdiChild)) {
const auto children = viewport->children(); // take a copy, as raising/stacking under changes the order
for (QObject *object : children) {
@@ -1290,13 +1241,17 @@ QRect QMdiAreaPrivate::resizeToMinimumTileSize(const QSize &minSubWindowSize, in
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);
+ if (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents, nullptr, q)) {
+ const int frame = q->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, nullptr, q);
minAreaWidth += 2 * frame;
minAreaHeight += 2 * frame;
}
const QSize diff = QSize(minAreaWidth, minAreaHeight).expandedTo(q->size()) - q->size();
- topLevel->resize(topLevel->size() + diff);
+ // Only resize topLevel widget if scroll bars are disabled.
+ if (hbarpolicy == Qt::ScrollBarAlwaysOff)
+ topLevel->resize(topLevel->size().width() + diff.width(), topLevel->size().height());
+ if (vbarpolicy == Qt::ScrollBarAlwaysOff)
+ topLevel->resize(topLevel->size().width(), topLevel->size().height() + diff.height());
}
QRect domain = viewport->rect();
@@ -1333,7 +1288,7 @@ bool QMdiAreaPrivate::scrollBarsEnabled() const
*/
bool QMdiAreaPrivate::lastWindowAboutToBeDestroyed() const
{
- if (childWindows.count() != 1)
+ if (childWindows.size() != 1)
return false;
QMdiSubWindow *last = childWindows.at(0);
@@ -1351,7 +1306,7 @@ bool QMdiAreaPrivate::lastWindowAboutToBeDestroyed() const
*/
void QMdiAreaPrivate::setChildActivationEnabled(bool enable, bool onlyNextActivationEvent) const
{
- foreach (QMdiSubWindow *subWindow, childWindows) {
+ for (QMdiSubWindow *subWindow : childWindows) {
if (!subWindow || !subWindow->isVisible())
continue;
if (onlyNextActivationEvent)
@@ -1373,7 +1328,11 @@ void QMdiAreaPrivate::scrollBarPolicyChanged(Qt::Orientation orientation, Qt::Sc
const QMdiSubWindow::SubWindowOption option = orientation == Qt::Horizontal ?
QMdiSubWindow::AllowOutsideAreaHorizontally : QMdiSubWindow::AllowOutsideAreaVertically;
const bool enable = policy != Qt::ScrollBarAlwaysOff;
- foreach (QMdiSubWindow *child, childWindows) {
+ // Take a copy because child->setOption() may indirectly call QCoreApplication::sendEvent(),
+ // the latter could call unknown code that could e.g. recurse into the class
+ // modifying childWindows.
+ const auto subWindows = childWindows;
+ for (QMdiSubWindow *child : subWindows) {
if (!sanityCheck(child, "QMdiArea::scrollBarPolicyChanged"))
continue;
child->setOption(option, enable);
@@ -1389,7 +1348,7 @@ QMdiAreaPrivate::subWindowList(QMdiArea::WindowOrder order, bool reversed) const
return list;
if (order == QMdiArea::CreationOrder) {
- foreach (QMdiSubWindow *child, childWindows) {
+ for (QMdiSubWindow *child : childWindows) {
if (!child)
continue;
if (!reversed)
@@ -1409,7 +1368,7 @@ QMdiAreaPrivate::subWindowList(QMdiArea::WindowOrder order, bool reversed) const
}
} else { // ActivationHistoryOrder
Q_ASSERT(indicesToActivatedChildren.size() == childWindows.size());
- for (int i = indicesToActivatedChildren.count() - 1; i >= 0; --i) {
+ for (int i = indicesToActivatedChildren.size() - 1; i >= 0; --i) {
QMdiSubWindow *child = childWindows.at(indicesToActivatedChildren.at(i));
if (!child)
continue;
@@ -1431,7 +1390,7 @@ void QMdiAreaPrivate::disconnectSubWindow(QObject *subWindow)
return;
Q_Q(QMdiArea);
- QObject::disconnect(subWindow, 0, q, 0);
+ QObject::disconnect(subWindow, nullptr, q, nullptr);
subWindow->removeEventFilter(q);
}
@@ -1442,11 +1401,11 @@ QMdiSubWindow *QMdiAreaPrivate::nextVisibleSubWindow(int increaseFactor, QMdiAre
int removedIndex, int fromIndex) const
{
if (childWindows.isEmpty())
- return 0;
+ return nullptr;
Q_Q(const QMdiArea);
const QList<QMdiSubWindow *> subWindows = q->subWindowList(order);
- QMdiSubWindow *current = 0;
+ QMdiSubWindow *current = nullptr;
if (removedIndex < 0) {
if (fromIndex >= 0 && fromIndex < subWindows.size())
@@ -1486,7 +1445,7 @@ QMdiSubWindow *QMdiAreaPrivate::nextVisibleSubWindow(int increaseFactor, QMdiAre
if (!subWindows.at(index)->isHidden())
return subWindows.at(index);
- return 0;
+ return nullptr;
}
/*!
@@ -1517,7 +1476,7 @@ void QMdiAreaPrivate::highlightNextSubWindow(int increaseFactor)
if (!rubberBand) {
rubberBand = new QRubberBand(QRubberBand::Rectangle, q);
// For accessibility to identify this special widget.
- rubberBand->setObjectName(QLatin1String("qt_rubberband"));
+ rubberBand->setObjectName("qt_rubberband"_L1);
rubberBand->setWindowFlags(rubberBand->windowFlags() | Qt::WindowStaysOnTopHint);
}
#endif
@@ -1570,12 +1529,17 @@ void QMdiAreaPrivate::setViewMode(QMdiArea::ViewMode mode)
tabBar->setTabsClosable(tabsClosable);
tabBar->setMovable(tabsMovable);
#if QT_CONFIG(tabwidget)
- tabBar->setShape(tabBarShapeFrom(tabShape, tabPosition));
+ tabBar->setShape(_q_tb_tabBarShapeFrom(tabShape, tabPosition));
#endif
isSubWindowsTiled = false;
- foreach (QMdiSubWindow *subWindow, childWindows)
+ // Take a copy as tabBar->addTab() will (indirectly) create a connection between
+ // the tab close button clicked() signal and the _q_closeTab() slot, which may
+ // indirectly call QCoreApplication::sendEvent(), the latter could result in
+ // invoking unknown code that could e.g. recurse into the class modifying childWindows.
+ const auto subWindows = childWindows;
+ for (QMdiSubWindow *subWindow : subWindows)
tabBar->addTab(subWindow->windowIcon(), tabTextFor(subWindow));
QMdiSubWindow *current = q->currentSubWindow();
@@ -1607,7 +1571,7 @@ void QMdiAreaPrivate::setViewMode(QMdiArea::ViewMode mode)
{ // SubWindowView
#if QT_CONFIG(tabbar)
delete tabBar;
- tabBar = 0;
+ tabBar = nullptr;
#endif // QT_CONFIG(tabbar)
viewMode = mode;
@@ -1634,7 +1598,7 @@ void QMdiAreaPrivate::updateTabBarGeometry()
Q_Q(QMdiArea);
#if QT_CONFIG(tabwidget)
- Q_ASSERT(tabBarShapeFrom(tabShape, tabPosition) == tabBar->shape());
+ Q_ASSERT(_q_tb_tabBarShapeFrom(tabShape, tabPosition) == tabBar->shape());
#endif
const QSize tabBarSizeHint = tabBar->sizeHint();
@@ -1691,7 +1655,7 @@ void QMdiAreaPrivate::refreshTabBar()
tabBar->setTabsClosable(tabsClosable);
tabBar->setMovable(tabsMovable);
#if QT_CONFIG(tabwidget)
- tabBar->setShape(tabBarShapeFrom(tabShape, tabPosition));
+ tabBar->setShape(_q_tb_tabBarShapeFrom(tabShape, tabPosition));
#endif
updateTabBarGeometry();
}
@@ -1708,7 +1672,7 @@ QMdiArea::QMdiArea(QWidget *parent)
setFrameStyle(QFrame::NoFrame);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
- setViewport(0);
+ setViewport(nullptr);
setFocusPolicy(Qt::NoFocus);
QApplication::instance()->installEventFilter(this);
}
@@ -1720,16 +1684,16 @@ QMdiArea::~QMdiArea()
{
Q_D(QMdiArea);
delete d->cascader;
- d->cascader = 0;
+ d->cascader = nullptr;
delete d->regularTiler;
- d->regularTiler = 0;
+ d->regularTiler = nullptr;
delete d->iconTiler;
- d->iconTiler = 0;
+ d->iconTiler = nullptr;
delete d->placer;
- d->placer = 0;
+ d->placer = nullptr;
}
/*!
@@ -1737,7 +1701,7 @@ QMdiArea::~QMdiArea()
*/
QSize QMdiArea::sizeHint() const
{
- // Calculate a proper scale factor for QDesktopWidget::size().
+ // Calculate a proper scale factor for the desktop's size.
// This also takes into account that we can have nested workspaces.
int nestedCount = 0;
QWidget *widget = this->parentWidget();
@@ -1748,14 +1712,14 @@ QSize QMdiArea::sizeHint() const
}
const int scaleFactor = 3 * (nestedCount + 1);
- QSize desktopSize = QDesktopWidgetPrivate::size();
+ QSize desktopSize = QGuiApplication::primaryScreen()->virtualSize();
QSize size(desktopSize.width() * 2 / scaleFactor, desktopSize.height() * 2 / scaleFactor);
for (QMdiSubWindow *child : d_func()->childWindows) {
if (!sanityCheck(child, "QMdiArea::sizeHint"))
continue;
size = size.expandedTo(child->sizeHint());
}
- return size.expandedTo(QApplication::globalStrut());
+ return size;
}
/*!
@@ -1764,8 +1728,8 @@ QSize QMdiArea::sizeHint() const
QSize QMdiArea::minimumSizeHint() const
{
Q_D(const QMdiArea);
- QSize size(style()->pixelMetric(QStyle::PM_MdiSubWindowMinimizedWidth, 0, this),
- style()->pixelMetric(QStyle::PM_TitleBarHeight, 0, this));
+ QSize size(style()->pixelMetric(QStyle::PM_MdiSubWindowMinimizedWidth, nullptr, this),
+ style()->pixelMetric(QStyle::PM_TitleBarHeight, nullptr, this));
size = size.expandedTo(QAbstractScrollArea::minimumSizeHint());
if (!d->scrollBarsEnabled()) {
for (QMdiSubWindow *child : d->childWindows) {
@@ -1774,11 +1738,11 @@ QSize QMdiArea::minimumSizeHint() const
size = size.expandedTo(child->minimumSizeHint());
}
}
- return size.expandedTo(QApplication::globalStrut());
+ return size;
}
/*!
- Returns a pointer to the current subwindow, or 0 if there is
+ Returns a pointer to the current subwindow, or \nullptr if there is
no current subwindow.
This function will return the same as activeSubWindow() if
@@ -1790,15 +1754,15 @@ QMdiSubWindow *QMdiArea::currentSubWindow() const
{
Q_D(const QMdiArea);
if (d->childWindows.isEmpty())
- return 0;
+ return nullptr;
if (d->active)
return d->active;
if (d->isActivated && !window()->isMinimized())
- return 0;
+ return nullptr;
- Q_ASSERT(d->indicesToActivatedChildren.count() > 0);
+ Q_ASSERT(d->indicesToActivatedChildren.size() > 0);
int index = d->indicesToActivatedChildren.at(0);
Q_ASSERT(index >= 0 && index < d->childWindows.size());
QMdiSubWindow *current = d->childWindows.at(index);
@@ -1808,7 +1772,7 @@ QMdiSubWindow *QMdiArea::currentSubWindow() const
/*!
Returns a pointer to the current active subwindow. If no
- window is currently active, 0 is returned.
+ window is currently active, \nullptr 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
@@ -1825,7 +1789,7 @@ QMdiSubWindow *QMdiArea::activeSubWindow() const
}
/*!
- Activates the subwindow \a window. If \a window is 0, any
+ Activates the subwindow \a window. If \a window is \nullptr, any
current active window is deactivated.
\sa activeSubWindow()
@@ -1834,7 +1798,7 @@ void QMdiArea::setActiveSubWindow(QMdiSubWindow *window)
{
Q_D(QMdiArea);
if (!window) {
- d->activateWindow(0);
+ d->activateWindow(nullptr);
return;
}
@@ -1897,7 +1861,11 @@ void QMdiArea::closeAllSubWindows()
return;
d->isSubWindowsTiled = false;
- foreach (QMdiSubWindow *child, d->childWindows) {
+ // Take a copy because the child->close() call below may end up indirectly calling
+ // QCoreApplication::send{Spontaneous}Event(), which may call unknown code that
+ // could e.g. recurse into the class modifying d->childWindows.
+ const auto subWindows = d->childWindows;
+ for (QMdiSubWindow *child : subWindows) {
if (!sanityCheck(child, "QMdiArea::closeAllSubWindows"))
continue;
child->close();
@@ -1954,7 +1922,7 @@ void QMdiArea::activatePreviousSubWindow()
\note Once the subwindow has been added, its parent will be the
\e{viewport widget} of the QMdiArea.
- \snippet mdiareasnippets.cpp 1
+ \snippet mdiarea/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
@@ -1969,7 +1937,7 @@ QMdiSubWindow *QMdiArea::addSubWindow(QWidget *widget, Qt::WindowFlags windowFla
{
if (Q_UNLIKELY(!widget)) {
qWarning("QMdiArea::addSubWindow: null pointer to widget");
- return 0;
+ return nullptr;
}
Q_D(QMdiArea);
@@ -1992,9 +1960,11 @@ QMdiSubWindow *QMdiArea::addSubWindow(QWidget *widget, Qt::WindowFlags windowFla
Q_ASSERT(child->testAttribute(Qt::WA_DeleteOnClose));
}
+ d->appendChild(child);
+
if (childFocus)
childFocus->setFocus();
- d->appendChild(child);
+
return child;
}
@@ -2002,9 +1972,9 @@ QMdiSubWindow *QMdiArea::addSubWindow(QWidget *widget, Qt::WindowFlags windowFla
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.
+ If a QMdiSubWindow is passed in, its parent is set to \nullptr and it is
+ removed; but if an internal widget is passed in, the child widget
+ is set to \nullptr and the QMdiSubWindow is \e not removed.
\sa addSubWindow()
*/
@@ -2029,16 +1999,20 @@ void QMdiArea::removeSubWindow(QWidget *widget)
d->childWindows.removeAll(child);
d->indicesToActivatedChildren.removeAll(index);
d->updateActiveWindow(index, d->active == child);
- child->setParent(0);
+ child->setParent(nullptr);
return;
}
bool found = false;
- foreach (QMdiSubWindow *child, d->childWindows) {
+ // Take a copy because child->setWidget(nullptr) will indirectly
+ // QCoreApplication::sendEvent(); the latter could call unknown code that could
+ // e.g. recurse into the class modifying d->childWindows.
+ const auto subWindows = d->childWindows;
+ for (QMdiSubWindow *child : subWindows) {
if (!sanityCheck(child, "QMdiArea::removeSubWindow"))
continue;
if (child->widget() == widget) {
- child->setWidget(0);
+ child->setWidget(nullptr);
Q_ASSERT(!child->widget());
found = true;
break;
@@ -2315,10 +2289,21 @@ void QMdiArea::resizeEvent(QResizeEvent *resizeEvent)
// Resize maximized views.
bool hasMaximizedSubWindow = false;
- foreach (QMdiSubWindow *child, d->childWindows) {
+ // Take a copy because child->resize() may call QCoreApplication::sendEvent()
+ // which may invoke unknown code, that could e.g. recurse into the class
+ // modifying d->childWindows.
+ const auto subWindows = d->childWindows;
+ for (QMdiSubWindow *child : subWindows) {
if (sanityCheck(child, "QMdiArea::resizeEvent") && child->isMaximized()
&& child->size() != resizeEvent->size()) {
- child->resize(resizeEvent->size());
+ auto realSize = resizeEvent->size();
+ const auto minSizeHint = child->minimumSizeHint();
+ // QMdiSubWindow is no tlw so minimumSize() is not set by the layout manager
+ // and therefore we have to take care by ourself that we're not getting smaller
+ // than allowed
+ if (minSizeHint.isValid())
+ realSize = realSize.expandedTo(minSizeHint);
+ child->resize(realSize);
if (!hasMaximizedSubWindow)
hasMaximizedSubWindow = true;
}
@@ -2367,7 +2352,9 @@ void QMdiArea::showEvent(QShowEvent *showEvent)
Q_D(QMdiArea);
if (!d->pendingRearrangements.isEmpty()) {
bool skipPlacement = false;
- foreach (Rearranger *rearranger, d->pendingRearrangements) {
+ // Take a copy because d->rearrange() may modify d->pendingRearrangements
+ const auto pendingRearrange = d->pendingRearrangements;
+ for (Rearranger *rearranger : pendingRearrange) {
// 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)
@@ -2381,9 +2368,19 @@ void QMdiArea::showEvent(QShowEvent *showEvent)
}
if (!d->pendingPlacements.isEmpty()) {
- foreach (QMdiSubWindow *window, d->pendingPlacements) {
+ // Nothing obvious in the loop body changes the container (in this code path)
+ // during iteration, this is calling into a non-const method that does change
+ // the container when called from other places. So take a copy anyway for good
+ // measure.
+ const auto copy = d->pendingPlacements;
+ for (QMdiSubWindow *window : copy) {
if (!window)
continue;
+ if (d->viewMode == TabbedView && window->d_func()->isActive && !d->active) {
+ d->showActiveWindowMaximized = true;
+ d->emitWindowActivated(window); // Also maximizes the window
+ continue;
+ }
if (!window->testAttribute(Qt::WA_Resized)) {
QSize newSize(window->sizeHint().boundedTo(viewport()->size()));
window->resize(newSize.expandedTo(qSmartMinSize(window)));
@@ -2495,13 +2492,6 @@ bool QMdiArea::event(QEvent *event)
{
Q_D(QMdiArea);
switch (event->type()) {
-#if 0 // Used to be included in Qt4 for Q_WS_WIN
- // QWidgetPrivate::hide_helper activates another sub-window when closing a
- // modal dialog on Windows (see activateWindow() inside the ifdef).
- case QEvent::WindowUnblocked:
- d->activateCurrentWindow();
- break;
-#endif
case QEvent::WindowActivate: {
d->isActivated = true;
if (d->childWindows.isEmpty())
@@ -2524,12 +2514,16 @@ bool QMdiArea::event(QEvent *event)
d->isSubWindowsTiled = true;
}
break;
- case QEvent::WindowIconChange:
- foreach (QMdiSubWindow *window, d->childWindows) {
+ case QEvent::WindowIconChange: {
+ // Take a copy because QCoreApplication::sendEvent() may call unknown code,
+ // that may cause recursing into the class
+ const auto subWindows = d->childWindows;
+ for (QMdiSubWindow *window : subWindows) {
if (sanityCheck(window, "QMdiArea::WindowIconChange"))
- QApplication::sendEvent(window, event);
+ QCoreApplication::sendEvent(window, event);
}
break;
+ }
case QEvent::Hide:
d->setActive(d->active, false, false);
d->setChildActivationEnabled(false);
@@ -2558,12 +2552,8 @@ bool QMdiArea::eventFilter(QObject *object, QEvent *event)
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).
-#if 0 // Used to be included in Qt4 for Q_WS_MAC
- if (!(keyEvent->modifiers() & Qt::MetaModifier) && keyEvent->key() != Qt::Key_Meta)
-#else
+ // Ignore key events without a Ctrl modifier (except for press/release on the modifier itself).
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).
@@ -2578,11 +2568,7 @@ bool QMdiArea::eventFilter(QObject *object, QEvent *event)
// 3) Ctrl-Shift-Tab (Tab, Tab, ...) -> iterate through all windows in the opposite
// direction (activatePreviousSubWindow())
switch (keyEvent->key()) {
-#if 0 // Used to be included in Qt4 for Q_WS_MAC
- case Qt::Key_Meta:
-#else
case Qt::Key_Control:
-#endif
if (keyPress)
area->d_func()->startTabToPreviousTimer();
else
@@ -2640,7 +2626,11 @@ bool QMdiArea::eventFilter(QObject *object, QEvent *event)
#endif // QT_CONFIG(tabbar)
Q_FALLTHROUGH();
case QEvent::Hide:
- d->isSubWindowsTiled = false;
+ // Do not reset the isSubWindowsTiled flag if the event is a spontaneous system window event.
+ // This ensures that tiling will be performed during the resizeEvent after an application
+ // window minimize (hide) and then restore (show).
+ if (!event->spontaneous())
+ d->isSubWindowsTiled = false;
break;
#if QT_CONFIG(rubberband)
case QEvent::Close:
@@ -2688,7 +2678,10 @@ void QMdiArea::setupViewport(QWidget *viewport)
Q_D(QMdiArea);
if (viewport)
viewport->setAttribute(Qt::WA_OpaquePaintEvent, d->background.isOpaque());
- foreach (QMdiSubWindow *child, d->childWindows) {
+ // Take a copy because the child->setParent() call below may call QCoreApplication::sendEvent()
+ // which may call unknown code that could e.g. recurse into the class modifying d->childWindows.
+ const auto subWindows = d->childWindows;
+ for (QMdiSubWindow *child : subWindows) {
if (!sanityCheck(child, "QMdiArea::setupViewport"))
continue;
child->setParent(viewport, child->windowFlags());