5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
64
65
66
67
68
69
70
71
74
75
76
77
78
79
80
81
82
83
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
106
107
108
109
110
111
112
113
114
115
116
120#include <QApplication>
122#include <QChildEvent>
123#include <QResizeEvent>
125#include <QtAlgorithms>
127#include <QFontMetrics>
128#include <QStyleOption>
134#include <private/qlayoutengine_p.h>
140using namespace Qt::StringLiterals;
144static bool sanityCheck(
const QMdiSubWindow *
const child,
const char *where)
146 if (Q_UNLIKELY(!child)) {
147 const char error[] =
"null pointer";
148 Q_ASSERT_X(
false, where, error);
149 qWarning(
"%s:%s", where, error);
155static bool sanityCheck(
const QList<QWidget *> &widgets,
const int index,
const char *where)
157 if (Q_UNLIKELY(index < 0 || index >= widgets.size())) {
158 const char error[] =
"index out of range";
159 Q_ASSERT_X(
false, where, error);
160 qWarning(
"%s:%s", where, error);
163 if (Q_UNLIKELY(!widgets.at(index))) {
164 const char error[] =
"null pointer";
165 Q_ASSERT_X(
false, where, error);
166 qWarning(
"%s:%s", where, error);
172static void setIndex(
int *index,
int candidate,
int min,
int max,
bool isIncreasing)
181 *index = qMax(candidate, min);
186 *index = qMin(candidate, max);
188 Q_ASSERT(*index >= min && *index <= max);
191static inline bool useScrollBar(
const QRect &childrenRect,
const QSize &maxViewportSize,
192 Qt::Orientation orientation)
194 if (orientation == Qt::Horizontal)
195 return childrenRect.width() > maxViewportSize.width()
196 || childrenRect.left() < 0
197 || childrenRect.right() >= maxViewportSize.width();
199 return childrenRect.height() > maxViewportSize.height()
200 || childrenRect.top() < 0
201 || childrenRect.bottom() >= maxViewportSize.height();
210 QWidget *parent = widget->parentWidget();
212 if (QMdiArea *area = qobject_cast<QMdiArea *>(parent))
214 parent = parent->parentWidget();
219#if QT_CONFIG(tabwidget)
220QTabBar::Shape _q_tb_tabBarShapeFrom(QTabWidget::TabShape shape, QTabWidget::TabPosition position);
228 QString title = subWindow->windowTitle();
229 if (subWindow->isWindowModified()) {
230 title.replace(
"[*]"_L1,
"*"_L1);
233 title = qt_setWindowTitle_helperHelper(title, subWindow);
236 return title.isEmpty() ? QMdiArea::tr(
"(Untitled)") : title;
240
241
244 if (widgets.isEmpty())
247 const int n = widgets.size();
248 const int ncols = qMax(qCeil(qSqrt(qreal(n))), 1);
249 const int nrows = qMax((n % ncols) ? (n / ncols + 1) : (n / ncols), 1);
250 const int nspecial = (n % ncols) ? (ncols - n % ncols) : 0;
251 const int dx = domain.width() / ncols;
252 const int dy = domain.height() / nrows;
255 for (
int row = 0; row < nrows; ++row) {
256 const int y1 =
int(row * (dy + 1));
257 for (
int col = 0; col < ncols; ++col) {
258 if (row == 1 && col < nspecial)
260 const int x1 =
int(col * (dx + 1));
261 int x2 =
int(x1 + dx);
262 int y2 =
int(y1 + dy);
263 if (row == 0 && col < nspecial) {
268 y2 = domain.bottom();
270 if (col == ncols - 1 && x2 != domain.right())
272 if (row == nrows - 1 && y2 != domain.bottom())
273 y2 = domain.bottom();
274 if (!sanityCheck(widgets, i,
"RegularTiler"))
276 QWidget *widget = widgets.at(i++);
277 QRect newGeometry = QRect(QPoint(x1, y1), QPoint(x2, y2));
278 widget->setGeometry(QStyle::visualRect(widget->layoutDirection(), domain, newGeometry));
284
285
288 if (widgets.isEmpty())
292 const int topOffset = 0;
293 const int bottomOffset = 50;
294 const int leftOffset = 0;
295 const int rightOffset = 100;
298 QStyleOptionTitleBar options;
299 options.initFrom(widgets.at(0));
300 int titleBarHeight = widgets.at(0)->style()->pixelMetric(QStyle::PM_TitleBarHeight, &options, widgets.at(0));
301 const QFontMetrics fontMetrics = QFontMetrics(QApplication::font(
"QMdiSubWindowTitleBar"));
302 const int dy = qMax(titleBarHeight - (titleBarHeight - fontMetrics.height()) / 2, 1)
303 + widgets.at(0)->style()->pixelMetric(QStyle::PM_FocusFrameVMargin,
nullptr, widgets.at(0));
305 const int n = widgets.size();
306 const int nrows = qMax((domain.height() - (topOffset + bottomOffset)) / dy, 1);
307 const int ncols = qMax(n / nrows + ((n % nrows) ? 1 : 0), 1);
308 const int dcol = (domain.width() - (leftOffset + rightOffset)) / ncols;
311 for (
int row = 0; row < nrows; ++row) {
312 for (
int col = 0; col < ncols; ++col) {
313 const int x = leftOffset + row * dx + col * dcol;
314 const int y = topOffset + row * dy;
315 if (!sanityCheck(widgets, i,
"SimpleCascader"))
317 QWidget *widget = widgets.at(i++);
318 QRect newGeometry = QRect(QPoint(x, y), widget->sizeHint());
319 widget->setGeometry(QStyle::visualRect(widget->layoutDirection(), domain, newGeometry));
327
328
331 if (widgets.isEmpty() || !sanityCheck(widgets, 0,
"IconTiler"))
334 const int n = widgets.size();
335 const int width = qMax(widgets.at(0)->width(), 1);
336 const int height = widgets.at(0)->height();
337 const int ncols = qMax(domain.width() / width, 1);
338 const int nrows = n / ncols + ((n % ncols) ? 1 : 0);
341 for (
int row = 0; row < nrows; ++row) {
342 for (
int col = 0; col < ncols; ++col) {
343 const int x = col * width;
344 const int y = domain.height() - height - row * height;
345 if (!sanityCheck(widgets, i,
"IconTiler"))
347 QWidget *widget = widgets.at(i++);
349 QRect newGeometry = QRect(newPos.x(), newPos.y(), widget->width(), widget->height());
350 widget->setGeometry(QStyle::visualRect(widget->layoutDirection(), domain, newGeometry));
358
359
360
361int MinOverlapPlacer::accumulatedOverlap(
const QRect &source,
const QList<QRect> &rects)
364 for (
const QRect &rect : rects) {
365 QRect intersection = source.intersected(rect);
366 accOverlap += intersection.width() * intersection.height();
373
374
375
376
377QRect
MinOverlapPlacer::findMinOverlapRect(
const QList<QRect> &source,
const QList<QRect> &rects)
379 int minAccOverlap = -1;
380 QRect minAccOverlapRect;
381 for (
const QRect &srcRect : source) {
382 const int accOverlap = accumulatedOverlap(srcRect, rects);
383 if (accOverlap < minAccOverlap || minAccOverlap == -1) {
384 minAccOverlap = accOverlap;
385 minAccOverlapRect = srcRect;
388 return minAccOverlapRect;
392
393
394
395QList<QRect>
MinOverlapPlacer::getCandidatePlacements(
const QSize &size,
const QList<QRect> &rects,
401 xlist.reserve(2 + rects.size());
402 xlist << domain.left() << domain.right() - size.width() + 1;
405 ylist.reserve(2 + rects.size());
406 ylist << domain.top();
407 if (domain.bottom() - size.height() + 1 >= 0)
408 ylist << domain.bottom() - size.height() + 1;
410 for (
const QRect &rect : rects) {
411 xlist << rect.right() + 1;
412 ylist << rect.bottom() + 1;
415 std::sort(xlist.begin(), xlist.end());
416 xlist.erase(
std::unique(xlist.begin(), xlist.end()), xlist.end());
418 std::sort(ylist.begin(), ylist.end());
419 ylist.erase(
std::unique(ylist.begin(), ylist.end()), ylist.end());
421 result.reserve(ylist.size() * xlist.size());
422 for (
int y : std::as_const(ylist))
423 for (
int x : std::as_const(xlist))
424 result << QRect(QPoint(x, y), size);
429
430
431
432
433QList<QRect>
MinOverlapPlacer::findNonInsiders(
const QRect &domain, QList<QRect> &source)
435 const auto containedInDomain =
436 [domain](
const QRect &srcRect) {
return domain.contains(srcRect); };
438 const auto firstOut =
std::stable_partition(source.begin(), source.end(), containedInDomain);
441 result.reserve(source.end() - firstOut);
442 std::copy(firstOut, source.end(),
std::back_inserter(result));
444 source.erase(firstOut, source.end());
450
451
452
453
454QList<QRect>
MinOverlapPlacer::findMaxOverlappers(
const QRect &domain,
const QList<QRect> &source)
457 result.reserve(source.size());
460 for (
const QRect &srcRect : source) {
461 QRect intersection = domain.intersected(srcRect);
462 const int overlap = intersection.width() * intersection.height();
463 if (overlap >= maxOverlap || maxOverlap == -1) {
464 if (overlap > maxOverlap) {
465 maxOverlap = overlap;
476
477
478
479
480
481QPoint
MinOverlapPlacer::findBestPlacement(
const QRect &domain,
const QList<QRect> &rects,
482 QList<QRect> &source)
484 const QList<QRect> nonInsiders = findNonInsiders(domain, source);
487 return findMinOverlapRect(source, rects).topLeft();
489 QList<QRect> maxOverlappers = findMaxOverlappers(domain, nonInsiders);
490 return findMinOverlapRect(maxOverlappers, rects).topLeft();
495
496
497
498
499
501 const QRect &domain)
const
503 if (size.isEmpty() || !domain.isValid())
505 for (
const QRect &rect : rects) {
510 QList<QRect> candidates = getCandidatePlacements(size, rects, domain);
511 return findBestPlacement(domain, rects, candidates);
515class QMdiAreaTabBar :
public QTabBar
518 QMdiAreaTabBar(QWidget *parent) : QTabBar(parent) {}
521 void mousePressEvent(QMouseEvent *event) override;
522#ifndef QT_NO_CONTEXTMENU
523 void contextMenuEvent(QContextMenuEvent *event) override;
527 QMdiSubWindow *subWindowFromIndex(
int index)
const;
531
532
533void QMdiAreaTabBar::mousePressEvent(QMouseEvent *event)
535 if (event->button() != Qt::MiddleButton) {
536 QTabBar::mousePressEvent(event);
540 QMdiSubWindow *subWindow = subWindowFromIndex(tabAt(event->position().toPoint()));
549#ifndef QT_NO_CONTEXTMENU
551
552
553void QMdiAreaTabBar::contextMenuEvent(QContextMenuEvent *event)
555 QPointer<QMdiSubWindow> subWindow = subWindowFromIndex(tabAt(event->pos()));
556 if (!subWindow || subWindow->isHidden()) {
562 QMdiSubWindowPrivate *subWindowPrivate = subWindow->d_func();
563 if (!subWindowPrivate->systemMenu) {
568 QMdiSubWindow *currentSubWindow = subWindowFromIndex(currentIndex());
569 Q_ASSERT(currentSubWindow);
573 if (currentSubWindow->isMaximized()) {
574 subWindowPrivate->setVisible(QMdiSubWindowPrivate::MoveAction,
false);
575 subWindowPrivate->setVisible(QMdiSubWindowPrivate::ResizeAction,
false);
576 subWindowPrivate->setVisible(QMdiSubWindowPrivate::MinimizeAction,
false);
577 subWindowPrivate->setVisible(QMdiSubWindowPrivate::MaximizeAction,
false);
578 subWindowPrivate->setVisible(QMdiSubWindowPrivate::RestoreAction,
false);
579 subWindowPrivate->setVisible(QMdiSubWindowPrivate::StayOnTopAction,
false);
583 subWindowPrivate->systemMenu->exec(event->globalPos());
588 subWindowPrivate->updateActions();
594
595
596QMdiSubWindow *QMdiAreaTabBar::subWindowFromIndex(
int index)
const
598 if (index < 0 || index >= count())
601 QMdiArea *mdiArea = qobject_cast<QMdiArea *>(parentWidget());
604 const QList<QMdiSubWindow *> subWindows = mdiArea->subWindowList();
605 Q_ASSERT(index < subWindows.size());
607 QMdiSubWindow *subWindow = mdiArea->subWindowList().at(index);
615
616
622#if QT_CONFIG(rubberband)
628 activationOrder(QMdiArea::CreationOrder),
629 viewMode(QMdiArea::SubWindowView),
635#if QT_CONFIG(tabwidget)
636 tabShape(QTabWidget::Rounded),
637 tabPosition(QTabWidget::North),
655
656
663 if (!aboutToActivate)
664 aboutToBecomeActive = qobject_cast<QMdiSubWindow *>(q->sender());
666 aboutToBecomeActive = aboutToActivate;
667 Q_ASSERT(aboutToBecomeActive);
672 const auto subWindows = childWindows;
673 for (QMdiSubWindow *child : subWindows) {
674 if (!sanityCheck(child,
"QMdiArea::deactivateAllWindows") || aboutToBecomeActive == child)
677 ignoreWindowStateChange =
true;
678 if (!(options & QMdiArea::DontMaximizeSubWindowOnActivation) && !showActiveWindowMaximized)
679 showActiveWindowMaximized = child->isMaximized() && child->isVisible();
680 if (showActiveWindowMaximized && child->isMaximized()) {
681 if (q->updatesEnabled()) {
682 updatesDisabledByUs =
true;
683 q->setUpdatesEnabled(
false);
687 if (child->isMinimized() && !child->isShaded() && !windowStaysOnTop(child))
689 ignoreWindowStateChange =
false;
690 child->d_func()->setActive(
false);
695
696
698 Qt::WindowStates newState)
704 QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(q->sender());
709 if (!(oldState & Qt::WindowActive) && (newState & Qt::WindowActive))
712 else if ((oldState & Qt::WindowActive) && !(newState & Qt::WindowActive))
716 if (!(oldState & Qt::WindowMinimized) && (newState & Qt::WindowMinimized)) {
720 }
else if (!(oldState & Qt::WindowMaximized) && (newState & Qt::WindowMaximized)) {
723 }
else if (!(newState & (Qt::WindowMaximized | Qt::WindowMinimized))) {
725 if (oldState & Qt::WindowMinimized)
732#if !QT_CONFIG(tabbar)
739 if (indexToLastActiveTab >= 0 && indexToLastActiveTab < tabBar->count()
740 && indexToLastActiveTab < childWindows.size()) {
741 QMdiSubWindow *lastActive = childWindows.at(indexToLastActiveTab);
742 if (lastActive && lastActive->isHidden())
747 Q_ASSERT(childWindows.size() > index);
748 QMdiSubWindow *subWindow = childWindows.at(index);
756#if !QT_CONFIG(tabbar)
759 QMdiSubWindow *subWindow = childWindows.at(index);
767#if !QT_CONFIG(tabbar)
771 childWindows.move(from, to);
774 const int indexToActiveWindow = childWindows.indexOf(active);
775 if (indexToActiveWindow != -1) {
776 const int index = indicesToActivatedChildren.indexOf(indexToActiveWindow);
777 Q_ASSERT(index != -1);
779 indicesToActivatedChildren.move(index, 0);
780 internalRaise(active);
787
788
792 Q_ASSERT(child && childWindows.indexOf(child) == -1);
794 if (child->parent() != viewport)
795 child->setParent(viewport, child->windowFlags());
796 childWindows.append(QPointer<QMdiSubWindow>(child));
798 if (!child->testAttribute(Qt::WA_Resized) && q->isVisible()) {
799 QSize newSize(child->sizeHint().boundedTo(viewport->size()));
800 child->resize(newSize.expandedTo(qSmartMinSize(child)));
807 if (hbarpolicy != Qt::ScrollBarAlwaysOff)
808 child->setOption(QMdiSubWindow::AllowOutsideAreaHorizontally,
true);
810 child->setOption(QMdiSubWindow::AllowOutsideAreaHorizontally,
false);
812 if (vbarpolicy != Qt::ScrollBarAlwaysOff)
813 child->setOption(QMdiSubWindow::AllowOutsideAreaVertically,
true);
815 child->setOption(QMdiSubWindow::AllowOutsideAreaVertically,
false);
818 indicesToActivatedChildren.prepend(childWindows.size() - 1);
819 Q_ASSERT(indicesToActivatedChildren.size() == childWindows.size());
823 tabBar->addTab(child->windowIcon(), tabTextFor(child));
824 updateTabBarGeometry();
825 if (childWindows.size() == 1 && !(options & QMdiArea::DontMaximizeSubWindowOnActivation))
826 showActiveWindowMaximized =
true;
830 if (!(child->windowFlags() & Qt::SubWindow))
831 child->setWindowFlags(Qt::SubWindow);
832 child->installEventFilter(q);
834 QObject::connect(child, SIGNAL(aboutToActivate()), q, SLOT(_q_deactivateAllWindows()));
835 QObject::connect(child, SIGNAL(windowStateChanged(Qt::WindowStates,Qt::WindowStates)),
836 q, SLOT(_q_processWindowStateChanged(Qt::WindowStates,Qt::WindowStates)));
840
841
844 if (!placer || !child)
848 if (!q->isVisible()) {
852 pendingPlacements.append(child);
857 rects.reserve(childWindows.size());
858 QRect parentRect = q->rect();
859 for (QMdiSubWindow *window : std::as_const(childWindows)) {
860 if (!sanityCheck(window,
"QMdiArea::place") || window == child || !window->isVisibleTo(q)
861 || !window->testAttribute(Qt::WA_Moved)) {
864 QRect occupiedGeometry;
865 if (window->isMaximized()) {
866 occupiedGeometry = QRect(window->d_func()->oldGeometry.topLeft(),
867 window->d_func()->restoreSize);
869 occupiedGeometry = window->geometry();
871 rects.append(QStyle::visualRect(child->layoutDirection(), parentRect, occupiedGeometry));
873 QPoint newPos = placer->place(child->size(), rects, parentRect);
874 QRect newGeometry = QRect(newPos.x(), newPos.y(), child->width(), child->height());
875 child->setGeometry(QStyle::visualRect(child->layoutDirection(), parentRect, newGeometry));
879
880
887 if (!q->isVisible()) {
889 int index = pendingRearrangements.indexOf(rearranger);
891 pendingRearrangements.move(index, pendingRearrangements.size() - 1);
893 pendingRearrangements.append(rearranger);
897 QList<QWidget *> widgets;
899 const QList<QMdiSubWindow *> subWindows = subWindowList(activationOrder, reverseList);
900 QSize minSubWindowSize;
901 for (QMdiSubWindow *child : subWindows) {
902 if (!sanityCheck(child,
"QMdiArea::rearrange") || !child->isVisible())
904 if (rearranger->type() == Rearranger::IconTiler) {
905 if (child->isMinimized() && !child->isShaded())
906 widgets.append(child);
908 if (child->isMinimized() && !child->isShaded())
910 if (child->isMaximized() || child->isShaded())
912 minSubWindowSize = minSubWindowSize.expandedTo(child->minimumSize())
913 .expandedTo(child->d_func()->internalMinimumSize);
914 widgets.append(child);
918 QRect domain = viewport->rect();
919 if (rearranger->type() == Rearranger::RegularTiler && !widgets.isEmpty())
920 domain = resizeToMinimumTileSize(minSubWindowSize, widgets.size());
922 rearranger->rearrange(widgets, domain);
933
934
935
936
940 iconTiler =
new IconTiler;
945
946
949 if (childWindows.isEmpty()) {
957 Q_ASSERT(active->d_func()->isActive);
958 active->d_func()->setActive(
false);
964 if (child->isHidden() || child == active)
967 if (child->d_func()->isActive && active ==
nullptr)
968 child->d_func()->isActive =
false;
970 child->d_func()->setActive(
true);
974
975
978 QMdiSubWindow *current = q_func()->currentSubWindow();
980 current->d_func()->activationEnabled =
true;
981 current->d_func()->setActive(
true,
false);
990 Q_ASSERT(indexToHighlighted < childWindows.size());
991 if (tabToPreviousTimer.isActive())
992 activateWindow(nextVisibleSubWindow(-1, QMdiArea::ActivationHistoryOrder));
994 activateWindow(childWindows.at(indexToHighlighted));
995#if QT_CONFIG(rubberband)
1001
1002
1006 Q_ASSERT(activeWindow);
1007 if (activeWindow == active)
1009 Q_ASSERT(activeWindow->d_func()->isActive);
1011 if (!aboutToBecomeActive)
1013 Q_ASSERT(aboutToBecomeActive);
1018 if (!activeWindow->isMaximized())
1019 activeWindow->showMaximized();
1024 const int indexToActiveWindow = childWindows.indexOf(activeWindow);
1025 Q_ASSERT(indexToActiveWindow != -1);
1026 const int index = indicesToActivatedChildren.indexOf(indexToActiveWindow);
1027 Q_ASSERT(index != -1);
1028 indicesToActivatedChildren.move(index, 0);
1032 q->setUpdatesEnabled(
true);
1036 Q_ASSERT(aboutToBecomeActive == activeWindow);
1037 active = activeWindow;
1038 aboutToBecomeActive =
nullptr;
1039 Q_ASSERT(active->d_func()->isActive);
1041#if QT_CONFIG(tabbar)
1042 if (tabBar && tabBar->currentIndex() != indexToActiveWindow)
1043 tabBar->setCurrentIndex(indexToActiveWindow);
1046 if (active->isMaximized() && scrollBarsEnabled())
1049 emit q->subWindowActivated(active);
1053
1054
1058 if (deactivatedWindow) {
1059 if (deactivatedWindow != active)
1062 if ((aboutToBecomeActive || isActivated || lastWindowAboutToBeDestroyed())
1063 && !isExplicitlyDeactivated(deactivatedWindow) && !q->window()->isMinimized()) {
1066 emit q->subWindowActivated(
nullptr);
1070 if (aboutToBecomeActive)
1074 emit q->subWindowActivated(
nullptr);
1078
1079
1082 Q_ASSERT(indicesToActivatedChildren.size() == childWindows.size());
1085 for (
int i = 0; i < indicesToActivatedChildren.size(); ++i) {
1086 int &index = indicesToActivatedChildren[i];
1087 if (index > removedIndex)
1091#if QT_CONFIG(tabbar)
1092 if (tabBar && removedIndex >= 0) {
1093 const QSignalBlocker blocker(tabBar);
1094 tabBar->removeTab(removedIndex);
1095 updateTabBarGeometry();
1099 if (childWindows.isEmpty()) {
1106#if QT_CONFIG(rubberband)
1108 if (indexToHighlighted == removedIndex)
1121 QMdiSubWindow *next = nextVisibleSubWindow(0, activationOrder, removedIndex);
1127
1128
1135 QSize maxSize = q->maximumViewportSize();
1136 QSize hbarExtent = hbar->sizeHint();
1137 QSize vbarExtent = vbar->sizeHint();
1139 if (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents,
nullptr, q)) {
1140 const int doubleFrameWidth = frameWidth * 2;
1141 if (hbarpolicy == Qt::ScrollBarAlwaysOn)
1142 maxSize.rheight() -= doubleFrameWidth;
1143 if (vbarpolicy == Qt::ScrollBarAlwaysOn)
1144 maxSize.rwidth() -= doubleFrameWidth;
1145 hbarExtent.rheight() += doubleFrameWidth;
1146 vbarExtent.rwidth() += doubleFrameWidth;
1149 const QRect childrenRect = active && active->isMaximized()
1150 ? active->geometry() : viewport->childrenRect();
1151 bool useHorizontalScrollBar = useScrollBar(childrenRect, maxSize, Qt::Horizontal);
1152 bool useVerticalScrollBar = useScrollBar(childrenRect, maxSize, Qt::Vertical);
1154 if (useHorizontalScrollBar && !useVerticalScrollBar) {
1155 const QSize max = maxSize - QSize(0, hbarExtent.height());
1156 useVerticalScrollBar = useScrollBar(childrenRect, max, Qt::Vertical);
1159 if (useVerticalScrollBar && !useHorizontalScrollBar) {
1160 const QSize max = maxSize - QSize(vbarExtent.width(), 0);
1161 useHorizontalScrollBar = useScrollBar(childrenRect, max, Qt::Horizontal);
1164 if (useHorizontalScrollBar && hbarpolicy != Qt::ScrollBarAlwaysOn)
1165 maxSize.rheight() -= hbarExtent.height();
1166 if (useVerticalScrollBar && vbarpolicy != Qt::ScrollBarAlwaysOn)
1167 maxSize.rwidth() -= vbarExtent.width();
1169 QRect viewportRect(QPoint(0, 0), maxSize);
1170 const int startX = q->isLeftToRight() ? childrenRect.left() : viewportRect.right()
1171 - childrenRect.right();
1174 if (isSubWindowsTiled && hbar->value() != 0)
1176 const int xOffset = startX + hbar->value();
1177 hbar->setRange(qMin(0, xOffset),
1178 qMax(0, xOffset + childrenRect.width() - viewportRect.width()));
1179 hbar->setPageStep(childrenRect.width());
1180 hbar->setSingleStep(childrenRect.width() / 20);
1183 if (isSubWindowsTiled && vbar->value() != 0)
1185 const int yOffset = childrenRect.top() + vbar->value();
1186 vbar->setRange(qMin(0, yOffset),
1187 qMax(0, yOffset + childrenRect.height() - viewportRect.height()));
1188 vbar->setPageStep(childrenRect.height());
1189 vbar->setSingleStep(childrenRect.height() / 20);
1193
1194
1197 if (!sanityCheck(mdiChild,
"QMdiArea::internalRaise") || childWindows.size() < 2)
1200 QMdiSubWindow *stackUnderChild =
nullptr;
1202 const auto children = viewport->children();
1203 for (QObject *object : children) {
1204 QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(object);
1205 if (!child || !childWindows.contains(child))
1207 if (!child->isHidden() && windowStaysOnTop(child)) {
1208 if (stackUnderChild)
1209 child->stackUnder(stackUnderChild);
1212 stackUnderChild = child;
1217 if (stackUnderChild)
1218 mdiChild->stackUnder(stackUnderChild);
1226 if (!minSubWindowSize.isValid() || subWindowCount <= 0)
1227 return viewport->rect();
1230 const int columns = qMax(qCeil(qSqrt(qreal(subWindowCount))), 1);
1231 const int rows = qMax((subWindowCount % columns) ? (subWindowCount / columns + 1)
1232 : (subWindowCount / columns), 1);
1233 const int minWidth = minSubWindowSize.width() * columns;
1234 const int minHeight = minSubWindowSize.height() * rows;
1239 QWidget *topLevel = q;
1241 while (topLevel && !topLevel->isWindow() && topLevel->windowType() != Qt::SubWindow)
1242 topLevel = topLevel->parentWidget();
1244 int minAreaWidth = minWidth + left + right + 2;
1245 int minAreaHeight = minHeight + top + bottom + 2;
1246 if (hbar->isVisible())
1247 minAreaHeight += hbar->height();
1248 if (vbar->isVisible())
1249 minAreaWidth += vbar->width();
1250 if (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents,
nullptr, q)) {
1251 const int frame = q->style()->pixelMetric(QStyle::PM_DefaultFrameWidth,
nullptr, q);
1252 minAreaWidth += 2 * frame;
1253 minAreaHeight += 2 * frame;
1255 const QSize diff = QSize(minAreaWidth, minAreaHeight).expandedTo(q->size()) - q->size();
1257 if (hbarpolicy == Qt::ScrollBarAlwaysOff)
1258 topLevel->resize(topLevel->size().width() + diff.width(), topLevel->size().height());
1259 if (vbarpolicy == Qt::ScrollBarAlwaysOff)
1260 topLevel->resize(topLevel->size().width(), topLevel->size().height() + diff.height());
1263 QRect domain = viewport->rect();
1266 if (domain.width() < minWidth) {
1267 domain.setWidth(minWidth);
1268 if (hbarpolicy == Qt::ScrollBarAlwaysOff)
1269 q->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
1274 if (domain.height() < minHeight) {
1275 domain.setHeight(minHeight);
1276 if (vbarpolicy == Qt::ScrollBarAlwaysOff)
1277 q->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
1285
1286
1289 return hbarpolicy != Qt::ScrollBarAlwaysOff || vbarpolicy != Qt::ScrollBarAlwaysOff;
1293
1294
1297 if (childWindows.size() != 1)
1300 QMdiSubWindow *last = childWindows.at(0);
1304 if (!last->testAttribute(Qt::WA_DeleteOnClose))
1307 return last->d_func()->data.is_closing;
1311
1312
1315 for (QMdiSubWindow *subWindow : childWindows) {
1316 if (!subWindow || !subWindow->isVisible())
1318 if (onlyNextActivationEvent)
1319 subWindow->d_func()->ignoreNextActivationEvent = !enable;
1321 subWindow->d_func()->activationEnabled = enable;
1326
1327
1328
1331 if (childWindows.isEmpty())
1334 const QMdiSubWindow::SubWindowOption option = orientation == Qt::Horizontal ?
1335 QMdiSubWindow::AllowOutsideAreaHorizontally : QMdiSubWindow::AllowOutsideAreaVertically;
1336 const bool enable = policy != Qt::ScrollBarAlwaysOff;
1340 const auto subWindows = childWindows;
1341 for (QMdiSubWindow *child : subWindows) {
1342 if (!sanityCheck(child,
"QMdiArea::scrollBarPolicyChanged"))
1344 child->setOption(option, enable);
1352 QList<QMdiSubWindow *> list;
1353 if (childWindows.isEmpty())
1356 if (order == QMdiArea::CreationOrder) {
1357 for (QMdiSubWindow *child : childWindows) {
1363 list.prepend(child);
1365 }
else if (order == QMdiArea::StackingOrder) {
1366 for (QObject *object : viewport->children()) {
1367 QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(object);
1368 if (!child || !childWindows.contains(child))
1373 list.prepend(child);
1376 Q_ASSERT(indicesToActivatedChildren.size() == childWindows.size());
1377 for (
int i = indicesToActivatedChildren.size() - 1; i >= 0; --i) {
1378 QMdiSubWindow *child = childWindows.at(indicesToActivatedChildren.at(i));
1384 list.prepend(child);
1391
1392
1399 QObject::disconnect(subWindow,
nullptr, q,
nullptr);
1400 subWindow->removeEventFilter(q);
1404
1405
1407 int removedIndex,
int fromIndex)
const
1409 if (childWindows.isEmpty())
1412 Q_Q(
const QMdiArea);
1413 const QList<QMdiSubWindow *> subWindows = q->subWindowList(order);
1414 QMdiSubWindow *current =
nullptr;
1416 if (removedIndex < 0) {
1417 if (fromIndex >= 0 && fromIndex < subWindows.size())
1418 current = childWindows.at(fromIndex);
1420 current = q->currentSubWindow();
1426 if (removedIndex >= 0 && order == QMdiArea::CreationOrder) {
1427 int candidateIndex = -1;
1428 setIndex(&candidateIndex, removedIndex, 0, subWindows.size() - 1,
true);
1429 current = childWindows.at(candidateIndex);
1431 current = subWindows.back();
1437 const int indexToCurrent = subWindows.indexOf(current);
1438 const bool increasing = increaseFactor > 0;
1442 setIndex(&index, indexToCurrent + increaseFactor, 0, subWindows.size() - 1, increasing);
1443 Q_ASSERT(index != -1);
1446 while (subWindows.at(index)->isHidden()) {
1447 setIndex(&index, index + increaseFactor, 0, subWindows.size() - 1, increasing);
1448 if (index == indexToCurrent)
1452 if (!subWindows.at(index)->isHidden())
1453 return subWindows.at(index);
1458
1459
1462 if (childWindows.size() == 1)
1468 QMdiSubWindow *current = q->currentSubWindow();
1471 indexToHighlighted = childWindows.indexOf(current);
1475 Q_ASSERT(indexToHighlighted < childWindows.size());
1477 QMdiSubWindow *highlight = nextVisibleSubWindow(increaseFactor, activationOrder, -1, indexToHighlighted);
1481#if QT_CONFIG(rubberband)
1483 rubberBand =
new QRubberBand(QRubberBand::Rectangle, q);
1485 rubberBand->setObjectName(
"qt_rubberband"_L1);
1486 rubberBand->setWindowFlags(rubberBand->windowFlags() | Qt::WindowStaysOnTopHint);
1491#if QT_CONFIG(rubberband)
1492 if (!tabToPreviousTimer.isActive())
1493 showRubberBandFor(highlight);
1496 indexToHighlighted = childWindows.indexOf(highlight);
1500#if QT_CONFIG(rubberband)
1501void QMdiAreaPrivate::showRubberBandFor(QMdiSubWindow *subWindow)
1503 if (!subWindow || !rubberBand)
1506#if QT_CONFIG(tabbar)
1507 if (viewMode == QMdiArea::TabbedView)
1508 rubberBand->setGeometry(tabBar->tabRect(childWindows.indexOf(subWindow)));
1511 rubberBand->setGeometry(subWindow->geometry());
1513 rubberBand->raise();
1518
1519
1520
1524 if (viewMode == mode || inViewModeChange)
1530#if QT_CONFIG(tabbar)
1531 if (mode == QMdiArea::TabbedView) {
1533 tabBar =
new QMdiAreaTabBar(q);
1534 tabBar->setDocumentMode(documentMode);
1535 tabBar->setTabsClosable(tabsClosable);
1536 tabBar->setMovable(tabsMovable);
1537#if QT_CONFIG(tabwidget)
1538 tabBar->setShape(_q_tb_tabBarShapeFrom(tabShape, tabPosition));
1541 isSubWindowsTiled =
false;
1547 const auto subWindows = childWindows;
1548 for (QMdiSubWindow *subWindow : subWindows)
1549 tabBar->addTab(subWindow->windowIcon(), tabTextFor(subWindow));
1551 QMdiSubWindow *current = q->currentSubWindow();
1553 tabBar->setCurrentIndex(childWindows.indexOf(current));
1555 if (current->isMaximized())
1556 current->showNormal();
1561 if (!q->testOption(QMdiArea::DontMaximizeSubWindowOnActivation)) {
1562 current->showMaximized();
1570 updateTabBarGeometry();
1572 QObject::connect(tabBar, SIGNAL(currentChanged(
int)), q, SLOT(_q_currentTabChanged(
int)));
1573 QObject::connect(tabBar, SIGNAL(tabCloseRequested(
int)), q, SLOT(_q_closeTab(
int)));
1574 QObject::connect(tabBar, SIGNAL(tabMoved(
int,
int)), q, SLOT(_q_moveTab(
int,
int)));
1578#if QT_CONFIG(tabbar)
1584 q->setViewportMargins(0, 0, 0, 0);
1587 QMdiSubWindow *current = q->currentSubWindow();
1588 if (current && current->isMaximized())
1589 current->showNormal();
1592 Q_ASSERT(viewMode == mode);
1596#if QT_CONFIG(tabbar)
1598
1599
1600void QMdiAreaPrivate::updateTabBarGeometry()
1606#if QT_CONFIG(tabwidget)
1607 Q_ASSERT(_q_tb_tabBarShapeFrom(tabShape, tabPosition) == tabBar->shape());
1609 const QSize tabBarSizeHint = tabBar->sizeHint();
1611 int areaHeight = q->height();
1612 if (hbar && hbar->isVisible())
1613 areaHeight -= hbar->height();
1615 int areaWidth = q->width();
1616 if (vbar && vbar->isVisible())
1617 areaWidth -= vbar->width();
1620#if QT_CONFIG(tabwidget)
1621 switch (tabPosition) {
1622 case QTabWidget::North:
1623 q->setViewportMargins(0, tabBarSizeHint.height(), 0, 0);
1624 tabBarRect = QRect(0, 0, areaWidth, tabBarSizeHint.height());
1626 case QTabWidget::South:
1627 q->setViewportMargins(0, 0, 0, tabBarSizeHint.height());
1628 tabBarRect = QRect(0, areaHeight - tabBarSizeHint.height(), areaWidth, tabBarSizeHint.height());
1630 case QTabWidget::East:
1631 if (q->layoutDirection() == Qt::LeftToRight)
1632 q->setViewportMargins(0, 0, tabBarSizeHint.width(), 0);
1634 q->setViewportMargins(tabBarSizeHint.width(), 0, 0, 0);
1635 tabBarRect = QRect(areaWidth - tabBarSizeHint.width(), 0, tabBarSizeHint.width(), areaHeight);
1637 case QTabWidget::West:
1638 if (q->layoutDirection() == Qt::LeftToRight)
1639 q->setViewportMargins(tabBarSizeHint.width(), 0, 0, 0);
1641 q->setViewportMargins(0, 0, tabBarSizeHint.width(), 0);
1642 tabBarRect = QRect(0, 0, tabBarSizeHint.width(), areaHeight);
1649 tabBar->setGeometry(QStyle::visualRect(q->layoutDirection(), q->contentsRect(), tabBarRect));
1653
1654
1655void QMdiAreaPrivate::refreshTabBar()
1660 tabBar->setDocumentMode(documentMode);
1661 tabBar->setTabsClosable(tabsClosable);
1662 tabBar->setMovable(tabsMovable);
1663#if QT_CONFIG(tabwidget)
1664 tabBar->setShape(_q_tb_tabBarShapeFrom(tabShape, tabPosition));
1666 updateTabBarGeometry();
1671
1672
1673
1674QMdiArea::QMdiArea(QWidget *parent)
1675 : QAbstractScrollArea(*
new QMdiAreaPrivate, parent)
1677 setBackground(palette().brush(QPalette::Dark));
1678 setFrameStyle(QFrame::NoFrame);
1679 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1680 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1681 setViewport(
nullptr);
1682 setFocusPolicy(Qt::NoFocus);
1683 QApplication::instance()->installEventFilter(
this);
1687
1688
1689QMdiArea::~QMdiArea()
1693 d->cascader =
nullptr;
1695 delete d->regularTiler;
1696 d->regularTiler =
nullptr;
1698 delete d->iconTiler;
1699 d->iconTiler =
nullptr;
1702 d->placer =
nullptr;
1706
1707
1708QSize QMdiArea::sizeHint()
const
1712 int nestedCount = 0;
1713 QWidget *widget =
this->parentWidget();
1715 if (qobject_cast<QMdiArea *>(widget))
1717 widget = widget->parentWidget();
1719 const int scaleFactor = 3 * (nestedCount + 1);
1721 QSize desktopSize = QGuiApplication::primaryScreen()->virtualSize();
1722 QSize size(desktopSize.width() * 2 / scaleFactor, desktopSize.height() * 2 / scaleFactor);
1723 for (QMdiSubWindow *child : d_func()->childWindows) {
1724 if (!sanityCheck(child,
"QMdiArea::sizeHint"))
1726 size = size.expandedTo(child->sizeHint());
1732
1733
1734QSize QMdiArea::minimumSizeHint()
const
1736 Q_D(
const QMdiArea);
1737 QSize size(style()->pixelMetric(QStyle::PM_MdiSubWindowMinimizedWidth,
nullptr,
this),
1738 style()->pixelMetric(QStyle::PM_TitleBarHeight,
nullptr,
this));
1739 size = size.expandedTo(QAbstractScrollArea::minimumSizeHint());
1740 if (!d->scrollBarsEnabled()) {
1741 for (QMdiSubWindow *child : d->childWindows) {
1742 if (!sanityCheck(child,
"QMdiArea::sizeHint"))
1744 size = size.expandedTo(child->minimumSizeHint());
1751
1752
1753
1754
1755
1756
1757
1758
1759QMdiSubWindow *QMdiArea::currentSubWindow()
const
1761 Q_D(
const QMdiArea);
1762 if (d->childWindows.isEmpty())
1768 if (d->isActivated && !window()->isMinimized())
1771 Q_ASSERT(d->indicesToActivatedChildren.size() > 0);
1772 int index = d->indicesToActivatedChildren.at(0);
1773 Q_ASSERT(index >= 0 && index < d->childWindows.size());
1774 QMdiSubWindow *current = d->childWindows.at(index);
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791QMdiSubWindow *QMdiArea::activeSubWindow()
const
1793 Q_D(
const QMdiArea);
1798
1799
1800
1801
1802
1803void QMdiArea::setActiveSubWindow(QMdiSubWindow *window)
1807 d->activateWindow(
nullptr);
1811 if (Q_UNLIKELY(d->childWindows.isEmpty())) {
1812 qWarning(
"QMdiArea::setActiveSubWindow: workspace is empty");
1816 if (Q_UNLIKELY(d->childWindows.indexOf(window) == -1)) {
1817 qWarning(
"QMdiArea::setActiveSubWindow: window is not inside workspace");
1821 d->activateWindow(window);
1825
1826
1827
1828
1829void QMdiArea::closeActiveSubWindow()
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847QList<QMdiSubWindow *> QMdiArea::subWindowList(WindowOrder order)
const
1849 Q_D(
const QMdiArea);
1850 return d->subWindowList(order,
false);
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863void QMdiArea::closeAllSubWindows()
1866 if (d->childWindows.isEmpty())
1869 d->isSubWindowsTiled =
false;
1873 const auto subWindows = d->childWindows;
1874 for (QMdiSubWindow *child : subWindows) {
1875 if (!sanityCheck(child,
"QMdiArea::closeAllSubWindows"))
1880 d->updateScrollBars();
1884
1885
1886
1887
1888
1889
1890void QMdiArea::activateNextSubWindow()
1893 if (d->childWindows.isEmpty())
1896 QMdiSubWindow *next = d->nextVisibleSubWindow(1, d->activationOrder);
1898 d->activateWindow(next);
1902
1903
1904
1905
1906
1907
1908void QMdiArea::activatePreviousSubWindow()
1911 if (d->childWindows.isEmpty())
1914 QMdiSubWindow *previous = d->nextVisibleSubWindow(-1, d->activationOrder);
1916 d->activateWindow(previous);
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942QMdiSubWindow *QMdiArea::addSubWindow(QWidget *widget, Qt::WindowFlags windowFlags)
1944 if (Q_UNLIKELY(!widget)) {
1945 qWarning(
"QMdiArea::addSubWindow: null pointer to widget");
1951 QWidget *childFocus = widget->focusWidget();
1952 QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(widget);
1956 if (Q_UNLIKELY(d->childWindows.indexOf(child) != -1)) {
1957 qWarning(
"QMdiArea::addSubWindow: window is already added");
1960 child->setParent(viewport(), windowFlags ? windowFlags : child->windowFlags());
1963 child =
new QMdiSubWindow(viewport(), windowFlags);
1964 child->setAttribute(Qt::WA_DeleteOnClose);
1965 child->setWidget(widget);
1966 Q_ASSERT(child->testAttribute(Qt::WA_DeleteOnClose));
1969 d->appendChild(child);
1972 childFocus->setFocus();
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987void QMdiArea::removeSubWindow(QWidget *widget)
1989 if (Q_UNLIKELY(!widget)) {
1990 qWarning(
"QMdiArea::removeSubWindow: null pointer to widget");
1995 if (d->childWindows.isEmpty())
1998 if (QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(widget)) {
1999 int index = d->childWindows.indexOf(child);
2000 if (Q_UNLIKELY(index == -1)) {
2001 qWarning(
"QMdiArea::removeSubWindow: window is not inside workspace");
2004 d->disconnectSubWindow(child);
2005 d->childWindows.removeAll(child);
2006 d->indicesToActivatedChildren.removeAll(index);
2007 d->updateActiveWindow(index, d->active == child);
2008 child->setParent(
nullptr);
2016 const auto subWindows = d->childWindows;
2017 for (QMdiSubWindow *child : subWindows) {
2018 if (!sanityCheck(child,
"QMdiArea::removeSubWindow"))
2020 if (child->widget() == widget) {
2021 child->setWidget(
nullptr);
2022 Q_ASSERT(!child->widget());
2028 if (Q_UNLIKELY(!found))
2029 qWarning(
"QMdiArea::removeSubWindow: widget is not child of any window inside QMdiArea");
2033
2034
2035
2036
2037
2038
2039
2040QBrush QMdiArea::background()
const
2042 return d_func()->background;
2045void QMdiArea::setBackground(
const QBrush &brush)
2048 if (d->background != brush) {
2049 d->background = brush;
2050 d->viewport->setAttribute(Qt::WA_OpaquePaintEvent, brush.isOpaque());
2051 d->viewport->update();
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067QMdiArea::WindowOrder QMdiArea::activationOrder()
const
2069 Q_D(
const QMdiArea);
2070 return d->activationOrder;
2073void QMdiArea::setActivationOrder(WindowOrder order)
2076 if (order != d->activationOrder)
2077 d->activationOrder = order;
2081
2082
2083
2084
2085
2086void QMdiArea::setOption(AreaOption option,
bool on)
2089 d->options.setFlag(option, on);
2093
2094
2095
2096
2097bool QMdiArea::testOption(AreaOption option)
const
2099 return d_func()->options & option;
2103
2104
2105
2106
2107
2108
2109
2110
2111QMdiArea::ViewMode QMdiArea::viewMode()
const
2113 Q_D(
const QMdiArea);
2117void QMdiArea::setViewMode(ViewMode mode)
2120 d->setViewMode(mode);
2123#if QT_CONFIG(tabbar)
2125
2126
2127
2128
2129
2130
2131
2132
2133bool QMdiArea::documentMode()
const
2135 Q_D(
const QMdiArea);
2136 return d->documentMode;
2139void QMdiArea::setDocumentMode(
bool enabled)
2142 if (d->documentMode == enabled)
2145 d->documentMode = enabled;
2150
2151
2152
2153
2154
2155
2156
2157
2158bool QMdiArea::tabsClosable()
const
2160 Q_D(
const QMdiArea);
2161 return d->tabsClosable;
2164void QMdiArea::setTabsClosable(
bool closable)
2167 if (d->tabsClosable == closable)
2170 d->tabsClosable = closable;
2175
2176
2177
2178
2179
2180
2181
2182
2183bool QMdiArea::tabsMovable()
const
2185 Q_D(
const QMdiArea);
2186 return d->tabsMovable;
2189void QMdiArea::setTabsMovable(
bool movable)
2192 if (d->tabsMovable == movable)
2195 d->tabsMovable = movable;
2200#if QT_CONFIG(tabwidget)
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211QTabWidget::TabShape QMdiArea::tabShape()
const
2213 Q_D(
const QMdiArea);
2217void QMdiArea::setTabShape(QTabWidget::TabShape shape)
2220 if (d->tabShape == shape)
2223 d->tabShape = shape;
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237QTabWidget::TabPosition QMdiArea::tabPosition()
const
2239 Q_D(
const QMdiArea);
2240 return d->tabPosition;
2243void QMdiArea::setTabPosition(QTabWidget::TabPosition position)
2246 if (d->tabPosition == position)
2249 d->tabPosition = position;
2255
2256
2257void QMdiArea::childEvent(QChildEvent *childEvent)
2260 if (childEvent->type() == QEvent::ChildPolished) {
2261 if (QMdiSubWindow *mdiChild = qobject_cast<QMdiSubWindow *>(childEvent->child())) {
2262 if (d->childWindows.indexOf(mdiChild) == -1)
2263 d->appendChild(mdiChild);
2269
2270
2271void QMdiArea::resizeEvent(QResizeEvent *resizeEvent)
2274 if (d->childWindows.isEmpty()) {
2275 resizeEvent->ignore();
2279#if QT_CONFIG(tabbar)
2280 d->updateTabBarGeometry();
2286 if (d->isSubWindowsTiled) {
2287 d->tileCalledFromResizeEvent =
true;
2289 d->tileCalledFromResizeEvent =
false;
2290 d->isSubWindowsTiled =
true;
2291 d->startResizeTimer();
2297 bool hasMaximizedSubWindow =
false;
2301 const auto subWindows = d->childWindows;
2302 for (QMdiSubWindow *child : subWindows) {
2303 if (sanityCheck(child,
"QMdiArea::resizeEvent") && child->isMaximized()
2304 && child->size() != resizeEvent->size()) {
2305 auto realSize = resizeEvent->size();
2306 const auto minSizeHint = child->minimumSizeHint();
2310 if (minSizeHint.isValid())
2311 realSize = realSize.expandedTo(minSizeHint);
2312 child->resize(realSize);
2313 if (!hasMaximizedSubWindow)
2314 hasMaximizedSubWindow =
true;
2318 d->updateScrollBars();
2323 if (hasMaximizedSubWindow)
2324 d->startResizeTimer();
2326 d->arrangeMinimizedSubWindows();
2330
2331
2332void QMdiArea::timerEvent(QTimerEvent *timerEvent)
2335 if (timerEvent->id() == d->resizeTimer.id()) {
2336 d->resizeTimer.stop();
2337 d->arrangeMinimizedSubWindows();
2338 }
else if (timerEvent->id() == d->tabToPreviousTimer.id()) {
2339 d->tabToPreviousTimer.stop();
2340 if (d->indexToHighlighted < 0)
2342#if QT_CONFIG(rubberband)
2344 Q_ASSERT(d->indexToHighlighted < d->childWindows.size());
2345 Q_ASSERT(d->rubberBand);
2346 d->showRubberBandFor(d->childWindows.at(d->indexToHighlighted));
2352
2353
2354void QMdiArea::showEvent(QShowEvent *showEvent)
2357 if (!d->pendingRearrangements.isEmpty()) {
2358 bool skipPlacement =
false;
2360 const auto pendingRearrange = d->pendingRearrangements;
2361 for (Rearranger *rearranger : pendingRearrange) {
2364 if (rearranger->type() != Rearranger::IconTiler && !skipPlacement)
2365 skipPlacement =
true;
2366 d->rearrange(rearranger);
2368 d->pendingRearrangements.clear();
2370 if (skipPlacement && !d->pendingPlacements.isEmpty())
2371 d->pendingPlacements.clear();
2374 if (!d->pendingPlacements.isEmpty()) {
2379 const auto copy = d->pendingPlacements;
2380 for (QMdiSubWindow *window : copy) {
2383 if (d->viewMode == TabbedView && window->d_func()->isActive && !d->active) {
2384 d->showActiveWindowMaximized =
true;
2385 d->emitWindowActivated(window);
2388 if (!window->testAttribute(Qt::WA_Resized)) {
2389 QSize newSize(window->sizeHint().boundedTo(viewport()->size()));
2390 window->resize(newSize.expandedTo(qSmartMinSize(window)));
2392 if (!window->testAttribute(Qt::WA_Moved) && !window->isMinimized()
2393 && !window->isMaximized()) {
2394 d->place(d->placer, window);
2397 d->pendingPlacements.clear();
2400 d->setChildActivationEnabled(
true);
2401 d->activateCurrentWindow();
2403 QAbstractScrollArea::showEvent(showEvent);
2407
2408
2409bool QMdiArea::viewportEvent(QEvent *event)
2412 switch (event->type()) {
2413 case QEvent::ChildRemoved: {
2414 d->isSubWindowsTiled =
false;
2415 QObject *removedChild =
static_cast<QChildEvent *>(event)->child();
2416 for (
int i = 0; i < d->childWindows.size(); ++i) {
2417 QObject *child = d->childWindows.at(i);
2418 if (!child || child == removedChild || !child->parent()
2419 || child->parent() != viewport()) {
2420 if (!testOption(DontMaximizeSubWindowOnActivation)) {
2423 QWidget *mdiChild = qobject_cast<QWidget *>(removedChild);
2424 if (mdiChild && mdiChild->isMaximized())
2425 d->showActiveWindowMaximized =
true;
2427 d->disconnectSubWindow(child);
2428 const bool activeRemoved = i == d->indicesToActivatedChildren.at(0);
2429 d->childWindows.removeAt(i);
2430 d->indicesToActivatedChildren.removeAll(i);
2431 d->updateActiveWindow(i, activeRemoved);
2432 d->arrangeMinimizedSubWindows();
2436 d->updateScrollBars();
2439 case QEvent::Destroy:
2440 d->isSubWindowsTiled =
false;
2441 d->resetActiveWindow();
2442 d->childWindows.clear();
2443 qWarning(
"QMdiArea: Deleting the view port is undefined, use setViewport instead.");
2448 return QAbstractScrollArea::viewportEvent(event);
2452
2453
2454void QMdiArea::scrollContentsBy(
int dx,
int dy)
2457 const bool wasSubWindowsTiled = d->isSubWindowsTiled;
2458 d->ignoreGeometryChange =
true;
2459 viewport()->scroll(isLeftToRight() ? dx : -dx, dy);
2460 d->arrangeMinimizedSubWindows();
2461 d->ignoreGeometryChange =
false;
2462 if (wasSubWindowsTiled)
2463 d->isSubWindowsTiled =
true;
2467
2468
2469
2470
2471void QMdiArea::tileSubWindows()
2474 if (!d->regularTiler)
2475 d->regularTiler =
new RegularTiler;
2476 d->rearrange(d->regularTiler);
2480
2481
2482
2483
2484void QMdiArea::cascadeSubWindows()
2488 d->cascader =
new SimpleCascader;
2489 d->rearrange(d->cascader);
2493
2494
2495bool QMdiArea::event(QEvent *event)
2498 switch (event->type()) {
2499 case QEvent::WindowActivate: {
2500 d->isActivated =
true;
2501 if (d->childWindows.isEmpty())
2504 d->activateCurrentWindow();
2505 d->setChildActivationEnabled(
false,
true);
2508 case QEvent::WindowDeactivate:
2509 d->isActivated =
false;
2510 d->setChildActivationEnabled(
false,
true);
2512 case QEvent::StyleChange:
2516 if (d->isSubWindowsTiled) {
2518 d->isSubWindowsTiled =
true;
2521 case QEvent::WindowIconChange: {
2524 const auto subWindows = d->childWindows;
2525 for (QMdiSubWindow *window : subWindows) {
2526 if (sanityCheck(window,
"QMdiArea::WindowIconChange"))
2527 QCoreApplication::sendEvent(window, event);
2532 d->setActive(d->active,
false,
false);
2533 d->setChildActivationEnabled(
false);
2535#if QT_CONFIG(tabbar)
2536 case QEvent::LayoutDirectionChange:
2537 d->updateTabBarGeometry();
2543 return QAbstractScrollArea::event(event);
2547
2548
2549bool QMdiArea::eventFilter(QObject *object, QEvent *event)
2552 return QAbstractScrollArea::eventFilter(object, event);
2556 if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) {
2558 QKeyEvent *keyEvent =
static_cast<QKeyEvent *>(event);
2560 if (!(keyEvent->modifiers() & Qt::ControlModifier) && keyEvent->key() != Qt::Key_Control)
2561 return QAbstractScrollArea::eventFilter(object, event);
2564 QMdiArea *area = mdiAreaParent(
static_cast<QWidget *>(object));
2566 return QAbstractScrollArea::eventFilter(object, event);
2568 const bool keyPress = (event->type() == QEvent::KeyPress);
2574 switch (keyEvent->key()) {
2575 case Qt::Key_Control:
2577 area->d_func()->startTabToPreviousTimer();
2579 area->d_func()->activateHighlightedWindow();
2582 case Qt::Key_Backtab:
2584 area->d_func()->highlightNextSubWindow(keyEvent->key() == Qt::Key_Tab ? 1 : -1);
2586#if QT_CONFIG(rubberband)
2587 case Qt::Key_Escape:
2588 area->d_func()->hideRubberBand();
2594 return QAbstractScrollArea::eventFilter(object, event);
2597 QMdiSubWindow *subWindow = qobject_cast<QMdiSubWindow *>(object);
2601 if (event->type() == QEvent::ApplicationActivate && !d->active
2602 && isVisible() && !window()->isMinimized()) {
2603 d->activateCurrentWindow();
2604 }
else if (event->type() == QEvent::ApplicationDeactivate && d->active) {
2605 d->setActive(d->active,
false,
false);
2607 return QAbstractScrollArea::eventFilter(object, event);
2610 if (subWindow->mdiArea() !=
this)
2611 return QAbstractScrollArea::eventFilter(object, event);
2614 switch (event->type()) {
2616 case QEvent::Resize:
2617 if (d->tileCalledFromResizeEvent)
2619 d->updateScrollBars();
2620 if (!subWindow->isMinimized())
2621 d->isSubWindowsTiled =
false;
2624#if QT_CONFIG(tabbar)
2626 const int tabIndex = d->childWindows.indexOf(subWindow);
2627 if (!d->tabBar->isTabEnabled(tabIndex))
2628 d->tabBar->setTabEnabled(tabIndex,
true);
2636 if (!event->spontaneous())
2637 d->isSubWindowsTiled =
false;
2639#if QT_CONFIG(rubberband)
2641 if (d->childWindows.indexOf(subWindow) == d->indexToHighlighted)
2642 d->hideRubberBand();
2645#if QT_CONFIG(tabbar)
2646 case QEvent::WindowTitleChange:
2647 case QEvent::ModifiedChange:
2649 d->tabBar->setTabText(d->childWindows.indexOf(subWindow), tabTextFor(subWindow));
2651 case QEvent::WindowIconChange:
2653 d->tabBar->setTabIcon(d->childWindows.indexOf(subWindow), subWindow->windowIcon());
2659 return QAbstractScrollArea::eventFilter(object, event);
2663
2664
2665void QMdiArea::paintEvent(QPaintEvent *paintEvent)
2668 QPainter painter(d->viewport);
2669 for (
const QRect &exposedRect : paintEvent->region())
2670 painter.fillRect(exposedRect, d->background);
2674
2675
2676
2677
2678
2679
2680void QMdiArea::setupViewport(QWidget *viewport)
2684 viewport->setAttribute(Qt::WA_OpaquePaintEvent, d->background.isOpaque());
2687 const auto subWindows = d->childWindows;
2688 for (QMdiSubWindow *child : subWindows) {
2689 if (!sanityCheck(child,
"QMdiArea::setupViewport"))
2691 child->setParent(viewport, child->windowFlags());
2697#include "moc_qmdiarea.cpp"
void internalRaise(QMdiSubWindow *child) const
void place(QMdi::Placer *placer, QMdiSubWindow *child)
void resetActiveWindow(QMdiSubWindow *child=nullptr)
QMdi::Rearranger * cascader
QMdi::Rearranger * regularTiler
void activateCurrentWindow()
bool scrollBarsEnabled() const
void appendChild(QMdiSubWindow *child)
void activateHighlightedWindow()
void emitWindowActivated(QMdiSubWindow *child)
QMdi::Rearranger * iconTiler
QList< QMdiSubWindow * > subWindowList(QMdiArea::WindowOrder, bool reversed=false) const
QRect resizeToMinimumTileSize(const QSize &minSubWindowSize, int subWindowCount)
bool isExplicitlyDeactivated(QMdiSubWindow *subWindow) const
void arrangeMinimizedSubWindows()
bool lastWindowAboutToBeDestroyed() const
bool ignoreGeometryChange
void activateWindow(QMdiSubWindow *child)
void highlightNextSubWindow(int increaseFactor)
bool tileCalledFromResizeEvent
void disconnectSubWindow(QObject *subWindow)
void _q_moveTab(int from, int to)
bool windowStaysOnTop(QMdiSubWindow *subWindow) const
bool ignoreWindowStateChange
void _q_currentTabChanged(int index)
void _q_deactivateAllWindows(QMdiSubWindow *aboutToActivate=nullptr)
void scrollBarPolicyChanged(Qt::Orientation, Qt::ScrollBarPolicy) override
bool showActiveWindowMaximized
int indexToPreviousWindow
void setViewMode(QMdiArea::ViewMode mode)
void updateActiveWindow(int removedIndex, bool activeRemoved)
void rearrange(QMdi::Rearranger *rearranger)
void setChildActivationEnabled(bool enable=true, bool onlyNextActivationEvent=false) const
void _q_closeTab(int index)
void _q_processWindowStateChanged(Qt::WindowStates oldState, Qt::WindowStates newState)
QMdiSubWindow * nextVisibleSubWindow(int increaseFactor, QMdiArea::WindowOrder, int removed=-1, int fromIndex=-1) const
void rearrange(QList< QWidget * > &widgets, const QRect &domain) const override
QPoint place(const QSize &size, const QList< QRect > &rects, const QRect &domain) const override
virtual Type type() const =0
void rearrange(QList< QWidget * > &widgets, const QRect &domain) const override
void rearrange(QList< QWidget * > &widgets, const QRect &domain) const override
static bool sanityCheck(const QList< QWidget * > &widgets, const int index, const char *where)
static QString tabTextFor(QMdiSubWindow *subWindow)
static bool sanityCheck(const QMdiSubWindow *const child, const char *where)
static QMdiArea * mdiAreaParent(QWidget *widget)
static bool useScrollBar(const QRect &childrenRect, const QSize &maxViewportSize, Qt::Orientation orientation)
static void setIndex(int *index, int candidate, int min, int max, bool isIncreasing)
QString qt_setWindowTitle_helperHelper(const QString &, const QWidget *)
Returns a modified window title with the [*] place holder replaced according to the rules described i...