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
62
63
64
67
68
69
70
71
72
73
74
77
78
79
80
81
82
83
84
85
86
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
109
110
111
112
113
114
115
116
117
118
119
123#include <QApplication>
125#include <QChildEvent>
126#include <QResizeEvent>
128#include <QtAlgorithms>
130#include <QFontMetrics>
131#include <QStyleOption>
137#include <private/qlayoutengine_p.h>
143using namespace Qt::StringLiterals;
147static bool sanityCheck(
const QMdiSubWindow *
const child,
const char *where)
149 if (Q_UNLIKELY(!child)) {
150 const char error[] =
"null pointer";
151 Q_ASSERT_X(
false, where, error);
152 qWarning(
"%s:%s", where, error);
158static bool sanityCheck(
const QList<QWidget *> &widgets,
const int index,
const char *where)
160 if (Q_UNLIKELY(index < 0 || index >= widgets.size())) {
161 const char error[] =
"index out of range";
162 Q_ASSERT_X(
false, where, error);
163 qWarning(
"%s:%s", where, error);
166 if (Q_UNLIKELY(!widgets.at(index))) {
167 const char error[] =
"null pointer";
168 Q_ASSERT_X(
false, where, error);
169 qWarning(
"%s:%s", where, error);
175static void setIndex(
int *index,
int candidate,
int min,
int max,
bool isIncreasing)
184 *index = qMax(candidate, min);
189 *index = qMin(candidate, max);
191 Q_ASSERT(*index >= min && *index <= max);
194static inline bool useScrollBar(
const QRect &childrenRect,
const QSize &maxViewportSize,
195 Qt::Orientation orientation)
197 if (orientation == Qt::Horizontal)
198 return childrenRect.width() > maxViewportSize.width()
199 || childrenRect.left() < 0
200 || childrenRect.right() >= maxViewportSize.width();
202 return childrenRect.height() > maxViewportSize.height()
203 || childrenRect.top() < 0
204 || childrenRect.bottom() >= maxViewportSize.height();
213 QWidget *parent = widget->parentWidget();
215 if (QMdiArea *area = qobject_cast<QMdiArea *>(parent))
217 parent = parent->parentWidget();
222#if QT_CONFIG(tabwidget)
223QTabBar::Shape _q_tb_tabBarShapeFrom(QTabWidget::TabShape shape, QTabWidget::TabPosition position);
231 QString title = subWindow->windowTitle();
232 if (subWindow->isWindowModified()) {
233 title.replace(
"[*]"_L1,
"*"_L1);
236 title = qt_setWindowTitle_helperHelper(title, subWindow);
239 return title.isEmpty() ? QMdiArea::tr(
"(Untitled)") : title;
243
244
247 if (widgets.isEmpty())
250 const int n = widgets.size();
251 const int ncols = qMax(qCeil(qSqrt(qreal(n))), 1);
252 const int nrows = qMax((n % ncols) ? (n / ncols + 1) : (n / ncols), 1);
253 const int nspecial = (n % ncols) ? (ncols - n % ncols) : 0;
254 const int dx = domain.width() / ncols;
255 const int dy = domain.height() / nrows;
258 for (
int row = 0; row < nrows; ++row) {
259 const int y1 =
int(row * (dy + 1));
260 for (
int col = 0; col < ncols; ++col) {
261 if (row == 1 && col < nspecial)
263 const int x1 =
int(col * (dx + 1));
264 int x2 =
int(x1 + dx);
265 int y2 =
int(y1 + dy);
266 if (row == 0 && col < nspecial) {
271 y2 = domain.bottom();
273 if (col == ncols - 1 && x2 != domain.right())
275 if (row == nrows - 1 && y2 != domain.bottom())
276 y2 = domain.bottom();
277 if (!sanityCheck(widgets, i,
"RegularTiler"))
279 QWidget *widget = widgets.at(i++);
280 QRect newGeometry = QRect(QPoint(x1, y1), QPoint(x2, y2));
281 widget->setGeometry(QStyle::visualRect(widget->layoutDirection(), domain, newGeometry));
287
288
291 if (widgets.isEmpty())
295 const int topOffset = 0;
296 const int bottomOffset = 50;
297 const int leftOffset = 0;
298 const int rightOffset = 100;
301 QStyleOptionTitleBar options;
302 options.initFrom(widgets.at(0));
303 int titleBarHeight = widgets.at(0)->style()->pixelMetric(QStyle::PM_TitleBarHeight, &options, widgets.at(0));
304 const QFontMetrics fontMetrics = QFontMetrics(QApplication::font(
"QMdiSubWindowTitleBar"));
305 const int dy = qMax(titleBarHeight - (titleBarHeight - fontMetrics.height()) / 2, 1)
306 + widgets.at(0)->style()->pixelMetric(QStyle::PM_FocusFrameVMargin,
nullptr, widgets.at(0));
308 const int n = widgets.size();
309 const int nrows = qMax((domain.height() - (topOffset + bottomOffset)) / dy, 1);
310 const int ncols = qMax(n / nrows + ((n % nrows) ? 1 : 0), 1);
311 const int dcol = (domain.width() - (leftOffset + rightOffset)) / ncols;
314 for (
int row = 0; row < nrows; ++row) {
315 for (
int col = 0; col < ncols; ++col) {
316 const int x = leftOffset + row * dx + col * dcol;
317 const int y = topOffset + row * dy;
318 if (!sanityCheck(widgets, i,
"SimpleCascader"))
320 QWidget *widget = widgets.at(i++);
321 QRect newGeometry = QRect(QPoint(x, y), widget->sizeHint());
322 widget->setGeometry(QStyle::visualRect(widget->layoutDirection(), domain, newGeometry));
330
331
334 if (widgets.isEmpty() || !sanityCheck(widgets, 0,
"IconTiler"))
337 const int n = widgets.size();
338 const int width = qMax(widgets.at(0)->width(), 1);
339 const int height = widgets.at(0)->height();
340 const int ncols = qMax(domain.width() / width, 1);
341 const int nrows = n / ncols + ((n % ncols) ? 1 : 0);
344 for (
int row = 0; row < nrows; ++row) {
345 for (
int col = 0; col < ncols; ++col) {
346 const int x = col * width;
347 const int y = domain.height() - height - row * height;
348 if (!sanityCheck(widgets, i,
"IconTiler"))
350 QWidget *widget = widgets.at(i++);
352 QRect newGeometry = QRect(newPos.x(), newPos.y(), widget->width(), widget->height());
353 widget->setGeometry(QStyle::visualRect(widget->layoutDirection(), domain, newGeometry));
361
362
363
364int MinOverlapPlacer::accumulatedOverlap(
const QRect &source,
const QList<QRect> &rects)
367 for (
const QRect &rect : rects) {
368 QRect intersection = source.intersected(rect);
369 accOverlap += intersection.width() * intersection.height();
376
377
378
379
380QRect
MinOverlapPlacer::findMinOverlapRect(
const QList<QRect> &source,
const QList<QRect> &rects)
382 int minAccOverlap = -1;
383 QRect minAccOverlapRect;
384 for (
const QRect &srcRect : source) {
385 const int accOverlap = accumulatedOverlap(srcRect, rects);
386 if (accOverlap < minAccOverlap || minAccOverlap == -1) {
387 minAccOverlap = accOverlap;
388 minAccOverlapRect = srcRect;
391 return minAccOverlapRect;
395
396
397
398QList<QRect>
MinOverlapPlacer::getCandidatePlacements(
const QSize &size,
const QList<QRect> &rects,
404 xlist.reserve(2 + rects.size());
405 xlist << domain.left() << domain.right() - size.width() + 1;
408 ylist.reserve(2 + rects.size());
409 ylist << domain.top();
410 if (domain.bottom() - size.height() + 1 >= 0)
411 ylist << domain.bottom() - size.height() + 1;
413 for (
const QRect &rect : rects) {
414 xlist << rect.right() + 1;
415 ylist << rect.bottom() + 1;
418 std::sort(xlist.begin(), xlist.end());
419 xlist.erase(
std::unique(xlist.begin(), xlist.end()), xlist.end());
421 std::sort(ylist.begin(), ylist.end());
422 ylist.erase(
std::unique(ylist.begin(), ylist.end()), ylist.end());
424 result.reserve(ylist.size() * xlist.size());
425 for (
int y : std::as_const(ylist))
426 for (
int x : std::as_const(xlist))
427 result << QRect(QPoint(x, y), size);
432
433
434
435
436QList<QRect>
MinOverlapPlacer::findNonInsiders(
const QRect &domain, QList<QRect> &source)
438 const auto containedInDomain =
439 [domain](
const QRect &srcRect) {
return domain.contains(srcRect); };
441 const auto firstOut =
std::stable_partition(source.begin(), source.end(), containedInDomain);
444 result.reserve(source.end() - firstOut);
445 std::copy(firstOut, source.end(),
std::back_inserter(result));
447 source.erase(firstOut, source.end());
453
454
455
456
457QList<QRect>
MinOverlapPlacer::findMaxOverlappers(
const QRect &domain,
const QList<QRect> &source)
460 result.reserve(source.size());
463 for (
const QRect &srcRect : source) {
464 QRect intersection = domain.intersected(srcRect);
465 const int overlap = intersection.width() * intersection.height();
466 if (overlap >= maxOverlap || maxOverlap == -1) {
467 if (overlap > maxOverlap) {
468 maxOverlap = overlap;
479
480
481
482
483
484QPoint
MinOverlapPlacer::findBestPlacement(
const QRect &domain,
const QList<QRect> &rects,
485 QList<QRect> &source)
487 const QList<QRect> nonInsiders = findNonInsiders(domain, source);
490 return findMinOverlapRect(source, rects).topLeft();
492 QList<QRect> maxOverlappers = findMaxOverlappers(domain, nonInsiders);
493 return findMinOverlapRect(maxOverlappers, rects).topLeft();
498
499
500
501
502
504 const QRect &domain)
const
506 if (size.isEmpty() || !domain.isValid())
508 for (
const QRect &rect : rects) {
513 QList<QRect> candidates = getCandidatePlacements(size, rects, domain);
514 return findBestPlacement(domain, rects, candidates);
518class QMdiAreaTabBar :
public QTabBar
521 QMdiAreaTabBar(QWidget *parent) : QTabBar(parent) {}
524 void mousePressEvent(QMouseEvent *event) override;
525#ifndef QT_NO_CONTEXTMENU
526 void contextMenuEvent(QContextMenuEvent *event) override;
530 QMdiSubWindow *subWindowFromIndex(
int index)
const;
534
535
536void QMdiAreaTabBar::mousePressEvent(QMouseEvent *event)
538 if (event->button() != Qt::MiddleButton) {
539 QTabBar::mousePressEvent(event);
543 QMdiSubWindow *subWindow = subWindowFromIndex(tabAt(event->position().toPoint()));
552#ifndef QT_NO_CONTEXTMENU
554
555
556void QMdiAreaTabBar::contextMenuEvent(QContextMenuEvent *event)
558 QPointer<QMdiSubWindow> subWindow = subWindowFromIndex(tabAt(event->pos()));
559 if (!subWindow || subWindow->isHidden()) {
565 QMdiSubWindowPrivate *subWindowPrivate = subWindow->d_func();
566 if (!subWindowPrivate->systemMenu) {
571 QMdiSubWindow *currentSubWindow = subWindowFromIndex(currentIndex());
572 Q_ASSERT(currentSubWindow);
576 if (currentSubWindow->isMaximized()) {
577 subWindowPrivate->setVisible(QMdiSubWindowPrivate::MoveAction,
false);
578 subWindowPrivate->setVisible(QMdiSubWindowPrivate::ResizeAction,
false);
579 subWindowPrivate->setVisible(QMdiSubWindowPrivate::MinimizeAction,
false);
580 subWindowPrivate->setVisible(QMdiSubWindowPrivate::MaximizeAction,
false);
581 subWindowPrivate->setVisible(QMdiSubWindowPrivate::RestoreAction,
false);
582 subWindowPrivate->setVisible(QMdiSubWindowPrivate::StayOnTopAction,
false);
586 subWindowPrivate->systemMenu->exec(event->globalPos());
591 subWindowPrivate->updateActions();
597
598
599QMdiSubWindow *QMdiAreaTabBar::subWindowFromIndex(
int index)
const
601 if (index < 0 || index >= count())
604 QMdiArea *mdiArea = qobject_cast<QMdiArea *>(parentWidget());
607 const QList<QMdiSubWindow *> subWindows = mdiArea->subWindowList();
608 Q_ASSERT(index < subWindows.size());
610 QMdiSubWindow *subWindow = mdiArea->subWindowList().at(index);
618
619
625#if QT_CONFIG(rubberband)
631 activationOrder(QMdiArea::CreationOrder),
632 viewMode(QMdiArea::SubWindowView),
638#if QT_CONFIG(tabwidget)
639 tabShape(QTabWidget::Rounded),
640 tabPosition(QTabWidget::North),
658
659
666 if (!aboutToActivate)
667 aboutToBecomeActive = qobject_cast<QMdiSubWindow *>(q->sender());
669 aboutToBecomeActive = aboutToActivate;
670 Q_ASSERT(aboutToBecomeActive);
675 const auto subWindows = childWindows;
676 for (QMdiSubWindow *child : subWindows) {
677 if (!sanityCheck(child,
"QMdiArea::deactivateAllWindows") || aboutToBecomeActive == child)
680 ignoreWindowStateChange =
true;
681 if (!(options & QMdiArea::DontMaximizeSubWindowOnActivation) && !showActiveWindowMaximized)
682 showActiveWindowMaximized = child->isMaximized() && child->isVisible();
683 if (showActiveWindowMaximized && child->isMaximized()) {
684 if (q->updatesEnabled()) {
685 updatesDisabledByUs =
true;
686 q->setUpdatesEnabled(
false);
690 if (child->isMinimized() && !child->isShaded() && !windowStaysOnTop(child))
692 ignoreWindowStateChange =
false;
693 child->d_func()->setActive(
false);
698
699
701 Qt::WindowStates newState)
707 QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(q->sender());
712 if (!(oldState & Qt::WindowActive) && (newState & Qt::WindowActive))
715 else if ((oldState & Qt::WindowActive) && !(newState & Qt::WindowActive))
719 if (!(oldState & Qt::WindowMinimized) && (newState & Qt::WindowMinimized)) {
723 }
else if (!(oldState & Qt::WindowMaximized) && (newState & Qt::WindowMaximized)) {
726 }
else if (!(newState & (Qt::WindowMaximized | Qt::WindowMinimized))) {
728 if (oldState & Qt::WindowMinimized)
735#if !QT_CONFIG(tabbar)
742 if (indexToLastActiveTab >= 0 && indexToLastActiveTab < tabBar->count()
743 && indexToLastActiveTab < childWindows.size()) {
744 QMdiSubWindow *lastActive = childWindows.at(indexToLastActiveTab);
745 if (lastActive && lastActive->isHidden())
750 Q_ASSERT(childWindows.size() > index);
751 QMdiSubWindow *subWindow = childWindows.at(index);
759#if !QT_CONFIG(tabbar)
762 QMdiSubWindow *subWindow = childWindows.at(index);
770#if !QT_CONFIG(tabbar)
774 childWindows.move(from, to);
777 const int indexToActiveWindow = childWindows.indexOf(active);
778 if (indexToActiveWindow != -1) {
779 const int index = indicesToActivatedChildren.indexOf(indexToActiveWindow);
780 Q_ASSERT(index != -1);
782 indicesToActivatedChildren.move(index, 0);
783 internalRaise(active);
790
791
795 Q_ASSERT(child && childWindows.indexOf(child) == -1);
797 if (child->parent() != viewport)
798 child->setParent(viewport, child->windowFlags());
799 childWindows.append(QPointer<QMdiSubWindow>(child));
801 if (!child->testAttribute(Qt::WA_Resized) && q->isVisible()) {
802 QSize newSize(child->sizeHint().boundedTo(viewport->size()));
803 child->resize(newSize.expandedTo(qSmartMinSize(child)));
810 if (hbarpolicy != Qt::ScrollBarAlwaysOff)
811 child->setOption(QMdiSubWindow::AllowOutsideAreaHorizontally,
true);
813 child->setOption(QMdiSubWindow::AllowOutsideAreaHorizontally,
false);
815 if (vbarpolicy != Qt::ScrollBarAlwaysOff)
816 child->setOption(QMdiSubWindow::AllowOutsideAreaVertically,
true);
818 child->setOption(QMdiSubWindow::AllowOutsideAreaVertically,
false);
821 indicesToActivatedChildren.prepend(childWindows.size() - 1);
822 Q_ASSERT(indicesToActivatedChildren.size() == childWindows.size());
826 tabBar->addTab(child->windowIcon(), tabTextFor(child));
827 updateTabBarGeometry();
828 if (childWindows.size() == 1 && !(options & QMdiArea::DontMaximizeSubWindowOnActivation))
829 showActiveWindowMaximized =
true;
833 if (!(child->windowFlags() & Qt::SubWindow))
834 child->setWindowFlags(Qt::SubWindow);
835 child->installEventFilter(q);
837 QObject::connect(child, SIGNAL(aboutToActivate()), q, SLOT(_q_deactivateAllWindows()));
838 QObject::connect(child, SIGNAL(windowStateChanged(Qt::WindowStates,Qt::WindowStates)),
839 q, SLOT(_q_processWindowStateChanged(Qt::WindowStates,Qt::WindowStates)));
843
844
847 if (!placer || !child)
851 if (!q->isVisible()) {
855 pendingPlacements.append(child);
860 rects.reserve(childWindows.size());
861 QRect parentRect = q->rect();
862 for (QMdiSubWindow *window : std::as_const(childWindows)) {
863 if (!sanityCheck(window,
"QMdiArea::place") || window == child || !window->isVisibleTo(q)
864 || !window->testAttribute(Qt::WA_Moved)) {
867 QRect occupiedGeometry;
868 if (window->isMaximized()) {
869 occupiedGeometry = QRect(window->d_func()->oldGeometry.topLeft(),
870 window->d_func()->restoreSize);
872 occupiedGeometry = window->geometry();
874 rects.append(QStyle::visualRect(child->layoutDirection(), parentRect, occupiedGeometry));
876 QPoint newPos = placer->place(child->size(), rects, parentRect);
877 QRect newGeometry = QRect(newPos.x(), newPos.y(), child->width(), child->height());
878 child->setGeometry(QStyle::visualRect(child->layoutDirection(), parentRect, newGeometry));
882
883
890 if (!q->isVisible()) {
892 int index = pendingRearrangements.indexOf(rearranger);
894 pendingRearrangements.move(index, pendingRearrangements.size() - 1);
896 pendingRearrangements.append(rearranger);
900 QList<QWidget *> widgets;
902 const QList<QMdiSubWindow *> subWindows = subWindowList(activationOrder, reverseList);
903 QSize minSubWindowSize;
904 for (QMdiSubWindow *child : subWindows) {
905 if (!sanityCheck(child,
"QMdiArea::rearrange") || !child->isVisible())
907 if (rearranger->type() == Rearranger::IconTiler) {
908 if (child->isMinimized() && !child->isShaded())
909 widgets.append(child);
911 if (child->isMinimized() && !child->isShaded())
913 if (child->isMaximized() || child->isShaded())
915 minSubWindowSize = minSubWindowSize.expandedTo(child->minimumSize())
916 .expandedTo(child->d_func()->internalMinimumSize);
917 widgets.append(child);
921 QRect domain = viewport->rect();
922 if (rearranger->type() == Rearranger::RegularTiler && !widgets.isEmpty())
923 domain = resizeToMinimumTileSize(minSubWindowSize, widgets.size());
925 rearranger->rearrange(widgets, domain);
936
937
938
939
943 iconTiler =
new IconTiler;
948
949
952 if (childWindows.isEmpty()) {
960 Q_ASSERT(active->d_func()->isActive);
961 active->d_func()->setActive(
false);
967 if (child->isHidden() || child == active)
970 if (child->d_func()->isActive && active ==
nullptr)
971 child->d_func()->isActive =
false;
973 child->d_func()->setActive(
true);
977
978
981 QMdiSubWindow *current = q_func()->currentSubWindow();
983 current->d_func()->activationEnabled =
true;
984 current->d_func()->setActive(
true,
false);
993 Q_ASSERT(indexToHighlighted < childWindows.size());
994 if (tabToPreviousTimer.isActive())
995 activateWindow(nextVisibleSubWindow(-1, QMdiArea::ActivationHistoryOrder));
997 activateWindow(childWindows.at(indexToHighlighted));
998#if QT_CONFIG(rubberband)
1004
1005
1009 Q_ASSERT(activeWindow);
1010 if (activeWindow == active)
1012 Q_ASSERT(activeWindow->d_func()->isActive);
1014 if (!aboutToBecomeActive)
1016 Q_ASSERT(aboutToBecomeActive);
1021 if (!activeWindow->isMaximized())
1022 activeWindow->showMaximized();
1027 const int indexToActiveWindow = childWindows.indexOf(activeWindow);
1028 Q_ASSERT(indexToActiveWindow != -1);
1029 const int index = indicesToActivatedChildren.indexOf(indexToActiveWindow);
1030 Q_ASSERT(index != -1);
1031 indicesToActivatedChildren.move(index, 0);
1035 q->setUpdatesEnabled(
true);
1039 Q_ASSERT(aboutToBecomeActive == activeWindow);
1040 active = activeWindow;
1041 aboutToBecomeActive =
nullptr;
1042 Q_ASSERT(active->d_func()->isActive);
1044#if QT_CONFIG(tabbar)
1045 if (tabBar && tabBar->currentIndex() != indexToActiveWindow)
1046 tabBar->setCurrentIndex(indexToActiveWindow);
1049 if (active->isMaximized() && scrollBarsEnabled())
1052 emit q->subWindowActivated(active);
1056
1057
1061 if (deactivatedWindow) {
1062 if (deactivatedWindow != active)
1065 if ((aboutToBecomeActive || isActivated || lastWindowAboutToBeDestroyed())
1066 && !isExplicitlyDeactivated(deactivatedWindow) && !q->window()->isMinimized()) {
1069 emit q->subWindowActivated(
nullptr);
1073 if (aboutToBecomeActive)
1077 emit q->subWindowActivated(
nullptr);
1081
1082
1085 Q_ASSERT(indicesToActivatedChildren.size() == childWindows.size());
1088 for (
int i = 0; i < indicesToActivatedChildren.size(); ++i) {
1089 int &index = indicesToActivatedChildren[i];
1090 if (index > removedIndex)
1094#if QT_CONFIG(tabbar)
1095 if (tabBar && removedIndex >= 0) {
1096 const QSignalBlocker blocker(tabBar);
1097 tabBar->removeTab(removedIndex);
1098 updateTabBarGeometry();
1102 if (childWindows.isEmpty()) {
1109#if QT_CONFIG(rubberband)
1111 if (indexToHighlighted == removedIndex)
1124 QMdiSubWindow *next = nextVisibleSubWindow(0, activationOrder, removedIndex);
1130
1131
1138 QSize maxSize = q->maximumViewportSize();
1139 QSize hbarExtent = hbar->sizeHint();
1140 QSize vbarExtent = vbar->sizeHint();
1142 if (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents,
nullptr, q)) {
1143 const int doubleFrameWidth = frameWidth * 2;
1144 if (hbarpolicy == Qt::ScrollBarAlwaysOn)
1145 maxSize.rheight() -= doubleFrameWidth;
1146 if (vbarpolicy == Qt::ScrollBarAlwaysOn)
1147 maxSize.rwidth() -= doubleFrameWidth;
1148 hbarExtent.rheight() += doubleFrameWidth;
1149 vbarExtent.rwidth() += doubleFrameWidth;
1152 const QRect childrenRect = active && active->isMaximized()
1153 ? active->geometry() : viewport->childrenRect();
1154 bool useHorizontalScrollBar = useScrollBar(childrenRect, maxSize, Qt::Horizontal);
1155 bool useVerticalScrollBar = useScrollBar(childrenRect, maxSize, Qt::Vertical);
1157 if (useHorizontalScrollBar && !useVerticalScrollBar) {
1158 const QSize max = maxSize - QSize(0, hbarExtent.height());
1159 useVerticalScrollBar = useScrollBar(childrenRect, max, Qt::Vertical);
1162 if (useVerticalScrollBar && !useHorizontalScrollBar) {
1163 const QSize max = maxSize - QSize(vbarExtent.width(), 0);
1164 useHorizontalScrollBar = useScrollBar(childrenRect, max, Qt::Horizontal);
1167 if (useHorizontalScrollBar && hbarpolicy != Qt::ScrollBarAlwaysOn)
1168 maxSize.rheight() -= hbarExtent.height();
1169 if (useVerticalScrollBar && vbarpolicy != Qt::ScrollBarAlwaysOn)
1170 maxSize.rwidth() -= vbarExtent.width();
1172 QRect viewportRect(QPoint(0, 0), maxSize);
1173 const int startX = q->isLeftToRight() ? childrenRect.left() : viewportRect.right()
1174 - childrenRect.right();
1176 const auto singleStep = defaultSingleStep();
1179 if (isSubWindowsTiled && hbar->value() != 0)
1181 const int xOffset = startX + hbar->value();
1182 hbar->setRange(qMin(0, xOffset),
1183 qMax(0, xOffset + childrenRect.width() - viewportRect.width()));
1184 hbar->setPageStep(childrenRect.width());
1185 hbar->setSingleStep(childrenRect.width() / singleStep);
1188 if (isSubWindowsTiled && vbar->value() != 0)
1190 const int yOffset = childrenRect.top() + vbar->value();
1191 vbar->setRange(qMin(0, yOffset),
1192 qMax(0, yOffset + childrenRect.height() - viewportRect.height()));
1193 vbar->setPageStep(childrenRect.height());
1194 vbar->setSingleStep(childrenRect.height() / singleStep);
1198
1199
1202 if (!sanityCheck(mdiChild,
"QMdiArea::internalRaise") || childWindows.size() < 2)
1205 QMdiSubWindow *stackUnderChild =
nullptr;
1207 const auto children = viewport->children();
1208 for (QObject *object : children) {
1209 QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(object);
1210 if (!child || !childWindows.contains(child))
1212 if (!child->isHidden() && windowStaysOnTop(child)) {
1213 if (stackUnderChild)
1214 child->stackUnder(stackUnderChild);
1217 stackUnderChild = child;
1222 if (stackUnderChild)
1223 mdiChild->stackUnder(stackUnderChild);
1231 if (!minSubWindowSize.isValid() || subWindowCount <= 0)
1232 return viewport->rect();
1235 const int columns = qMax(qCeil(qSqrt(qreal(subWindowCount))), 1);
1236 const int rows = qMax((subWindowCount % columns) ? (subWindowCount / columns + 1)
1237 : (subWindowCount / columns), 1);
1238 const int minWidth = minSubWindowSize.width() * columns;
1239 const int minHeight = minSubWindowSize.height() * rows;
1244 QWidget *topLevel = q;
1246 while (topLevel && !topLevel->isWindow() && topLevel->windowType() != Qt::SubWindow)
1247 topLevel = topLevel->parentWidget();
1249 int minAreaWidth = minWidth + left + right + 2;
1250 int minAreaHeight = minHeight + top + bottom + 2;
1251 if (hbar->isVisible())
1252 minAreaHeight += hbar->height();
1253 if (vbar->isVisible())
1254 minAreaWidth += vbar->width();
1255 if (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents,
nullptr, q)) {
1256 const int frame = q->style()->pixelMetric(QStyle::PM_DefaultFrameWidth,
nullptr, q);
1257 minAreaWidth += 2 * frame;
1258 minAreaHeight += 2 * frame;
1260 const QSize diff = QSize(minAreaWidth, minAreaHeight).expandedTo(q->size()) - q->size();
1262 if (hbarpolicy == Qt::ScrollBarAlwaysOff)
1263 topLevel->resize(topLevel->size().width() + diff.width(), topLevel->size().height());
1264 if (vbarpolicy == Qt::ScrollBarAlwaysOff)
1265 topLevel->resize(topLevel->size().width(), topLevel->size().height() + diff.height());
1268 QRect domain = viewport->rect();
1271 if (domain.width() < minWidth) {
1272 domain.setWidth(minWidth);
1273 if (hbarpolicy == Qt::ScrollBarAlwaysOff)
1274 q->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
1279 if (domain.height() < minHeight) {
1280 domain.setHeight(minHeight);
1281 if (vbarpolicy == Qt::ScrollBarAlwaysOff)
1282 q->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
1290
1291
1294 return hbarpolicy != Qt::ScrollBarAlwaysOff || vbarpolicy != Qt::ScrollBarAlwaysOff;
1298
1299
1302 if (childWindows.size() != 1)
1305 QMdiSubWindow *last = childWindows.at(0);
1309 if (!last->testAttribute(Qt::WA_DeleteOnClose))
1312 return last->d_func()->data.is_closing;
1316
1317
1320 for (QMdiSubWindow *subWindow : childWindows) {
1321 if (!subWindow || !subWindow->isVisible())
1323 if (onlyNextActivationEvent)
1324 subWindow->d_func()->ignoreNextActivationEvent = !enable;
1326 subWindow->d_func()->activationEnabled = enable;
1331
1332
1333
1336 if (childWindows.isEmpty())
1339 const QMdiSubWindow::SubWindowOption option = orientation == Qt::Horizontal ?
1340 QMdiSubWindow::AllowOutsideAreaHorizontally : QMdiSubWindow::AllowOutsideAreaVertically;
1341 const bool enable = policy != Qt::ScrollBarAlwaysOff;
1345 const auto subWindows = childWindows;
1346 for (QMdiSubWindow *child : subWindows) {
1347 if (!sanityCheck(child,
"QMdiArea::scrollBarPolicyChanged"))
1349 child->setOption(option, enable);
1357 QList<QMdiSubWindow *> list;
1358 if (childWindows.isEmpty())
1361 if (order == QMdiArea::CreationOrder) {
1362 for (QMdiSubWindow *child : childWindows) {
1368 list.prepend(child);
1370 }
else if (order == QMdiArea::StackingOrder) {
1371 for (QObject *object : viewport->children()) {
1372 QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(object);
1373 if (!child || !childWindows.contains(child))
1378 list.prepend(child);
1381 Q_ASSERT(indicesToActivatedChildren.size() == childWindows.size());
1382 for (
int i = indicesToActivatedChildren.size() - 1; i >= 0; --i) {
1383 QMdiSubWindow *child = childWindows.at(indicesToActivatedChildren.at(i));
1389 list.prepend(child);
1396
1397
1404 QObject::disconnect(subWindow,
nullptr, q,
nullptr);
1405 subWindow->removeEventFilter(q);
1409
1410
1412 int removedIndex,
int fromIndex)
const
1414 if (childWindows.isEmpty())
1417 Q_Q(
const QMdiArea);
1418 const QList<QMdiSubWindow *> subWindows = q->subWindowList(order);
1419 QMdiSubWindow *current =
nullptr;
1421 if (removedIndex < 0) {
1422 if (fromIndex >= 0 && fromIndex < subWindows.size())
1423 current = childWindows.at(fromIndex);
1425 current = q->currentSubWindow();
1431 if (removedIndex >= 0 && order == QMdiArea::CreationOrder) {
1432 int candidateIndex = -1;
1433 setIndex(&candidateIndex, removedIndex, 0, subWindows.size() - 1,
true);
1434 current = childWindows.at(candidateIndex);
1436 current = subWindows.back();
1442 const int indexToCurrent = subWindows.indexOf(current);
1443 const bool increasing = increaseFactor > 0;
1447 setIndex(&index, indexToCurrent + increaseFactor, 0, subWindows.size() - 1, increasing);
1448 Q_ASSERT(index != -1);
1451 while (subWindows.at(index)->isHidden()) {
1452 setIndex(&index, index + increaseFactor, 0, subWindows.size() - 1, increasing);
1453 if (index == indexToCurrent)
1457 if (!subWindows.at(index)->isHidden())
1458 return subWindows.at(index);
1463
1464
1467 if (childWindows.size() == 1)
1473 QMdiSubWindow *current = q->currentSubWindow();
1476 indexToHighlighted = childWindows.indexOf(current);
1480 Q_ASSERT(indexToHighlighted < childWindows.size());
1482 QMdiSubWindow *highlight = nextVisibleSubWindow(increaseFactor, activationOrder, -1, indexToHighlighted);
1486#if QT_CONFIG(rubberband)
1488 rubberBand =
new QRubberBand(QRubberBand::Rectangle, q);
1490 rubberBand->setObjectName(
"qt_rubberband"_L1);
1491 rubberBand->setWindowFlags(rubberBand->windowFlags() | Qt::WindowStaysOnTopHint);
1496#if QT_CONFIG(rubberband)
1497 if (!tabToPreviousTimer.isActive())
1498 showRubberBandFor(highlight);
1501 indexToHighlighted = childWindows.indexOf(highlight);
1505#if QT_CONFIG(rubberband)
1506void QMdiAreaPrivate::showRubberBandFor(QMdiSubWindow *subWindow)
1508 if (!subWindow || !rubberBand)
1511#if QT_CONFIG(tabbar)
1512 if (viewMode == QMdiArea::TabbedView)
1513 rubberBand->setGeometry(tabBar->tabRect(childWindows.indexOf(subWindow)));
1516 rubberBand->setGeometry(subWindow->geometry());
1518 rubberBand->raise();
1523
1524
1525
1529 if (viewMode == mode || inViewModeChange)
1535#if QT_CONFIG(tabbar)
1536 if (mode == QMdiArea::TabbedView) {
1538 tabBar =
new QMdiAreaTabBar(q);
1539 tabBar->setDocumentMode(documentMode);
1540 tabBar->setTabsClosable(tabsClosable);
1541 tabBar->setMovable(tabsMovable);
1542#if QT_CONFIG(tabwidget)
1543 tabBar->setShape(_q_tb_tabBarShapeFrom(tabShape, tabPosition));
1546 isSubWindowsTiled =
false;
1552 const auto subWindows = childWindows;
1553 for (QMdiSubWindow *subWindow : subWindows)
1554 tabBar->addTab(subWindow->windowIcon(), tabTextFor(subWindow));
1556 QMdiSubWindow *current = q->currentSubWindow();
1558 tabBar->setCurrentIndex(childWindows.indexOf(current));
1560 if (current->isMaximized())
1561 current->showNormal();
1566 if (!q->testOption(QMdiArea::DontMaximizeSubWindowOnActivation)) {
1567 current->showMaximized();
1575 updateTabBarGeometry();
1577 QObject::connect(tabBar, SIGNAL(currentChanged(
int)), q, SLOT(_q_currentTabChanged(
int)));
1578 QObject::connect(tabBar, SIGNAL(tabCloseRequested(
int)), q, SLOT(_q_closeTab(
int)));
1579 QObject::connect(tabBar, SIGNAL(tabMoved(
int,
int)), q, SLOT(_q_moveTab(
int,
int)));
1583#if QT_CONFIG(tabbar)
1589 q->setViewportMargins(0, 0, 0, 0);
1592 QMdiSubWindow *current = q->currentSubWindow();
1593 if (current && current->isMaximized())
1594 current->showNormal();
1597 Q_ASSERT(viewMode == mode);
1601#if QT_CONFIG(tabbar)
1603
1604
1605void QMdiAreaPrivate::updateTabBarGeometry()
1611#if QT_CONFIG(tabwidget)
1612 Q_ASSERT(_q_tb_tabBarShapeFrom(tabShape, tabPosition) == tabBar->shape());
1614 const QSize tabBarSizeHint = tabBar->sizeHint();
1616 int areaHeight = q->height();
1617 if (hbar && hbar->isVisible())
1618 areaHeight -= hbar->height();
1620 int areaWidth = q->width();
1621 if (vbar && vbar->isVisible())
1622 areaWidth -= vbar->width();
1625#if QT_CONFIG(tabwidget)
1626 switch (tabPosition) {
1627 case QTabWidget::North:
1628 q->setViewportMargins(0, tabBarSizeHint.height(), 0, 0);
1629 tabBarRect = QRect(0, 0, areaWidth, tabBarSizeHint.height());
1631 case QTabWidget::South:
1632 q->setViewportMargins(0, 0, 0, tabBarSizeHint.height());
1633 tabBarRect = QRect(0, areaHeight - tabBarSizeHint.height(), areaWidth, tabBarSizeHint.height());
1635 case QTabWidget::East:
1636 if (q->layoutDirection() == Qt::LeftToRight)
1637 q->setViewportMargins(0, 0, tabBarSizeHint.width(), 0);
1639 q->setViewportMargins(tabBarSizeHint.width(), 0, 0, 0);
1640 tabBarRect = QRect(areaWidth - tabBarSizeHint.width(), 0, tabBarSizeHint.width(), areaHeight);
1642 case QTabWidget::West:
1643 if (q->layoutDirection() == Qt::LeftToRight)
1644 q->setViewportMargins(tabBarSizeHint.width(), 0, 0, 0);
1646 q->setViewportMargins(0, 0, tabBarSizeHint.width(), 0);
1647 tabBarRect = QRect(0, 0, tabBarSizeHint.width(), areaHeight);
1654 tabBar->setGeometry(QStyle::visualRect(q->layoutDirection(), q->contentsRect(), tabBarRect));
1658
1659
1660void QMdiAreaPrivate::refreshTabBar()
1665 tabBar->setDocumentMode(documentMode);
1666 tabBar->setTabsClosable(tabsClosable);
1667 tabBar->setMovable(tabsMovable);
1668#if QT_CONFIG(tabwidget)
1669 tabBar->setShape(_q_tb_tabBarShapeFrom(tabShape, tabPosition));
1671 updateTabBarGeometry();
1676
1677
1678
1679QMdiArea::QMdiArea(QWidget *parent)
1680 : QAbstractScrollArea(*
new QMdiAreaPrivate, parent)
1682 setBackground(palette().brush(QPalette::Dark));
1683 setFrameStyle(QFrame::NoFrame);
1684 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1685 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1686 setViewport(
nullptr);
1687 setFocusPolicy(Qt::NoFocus);
1688 QApplication::instance()->installEventFilter(
this);
1692
1693
1694QMdiArea::~QMdiArea()
1698 d->cascader =
nullptr;
1700 delete d->regularTiler;
1701 d->regularTiler =
nullptr;
1703 delete d->iconTiler;
1704 d->iconTiler =
nullptr;
1707 d->placer =
nullptr;
1711
1712
1713QSize QMdiArea::sizeHint()
const
1717 int nestedCount = 0;
1718 QWidget *widget =
this->parentWidget();
1720 if (qobject_cast<QMdiArea *>(widget))
1722 widget = widget->parentWidget();
1724 const int scaleFactor = 3 * (nestedCount + 1);
1726 QSize desktopSize = QGuiApplication::primaryScreen()->virtualSize();
1727 QSize size(desktopSize.width() * 2 / scaleFactor, desktopSize.height() * 2 / scaleFactor);
1728 for (QMdiSubWindow *child : d_func()->childWindows) {
1729 if (!sanityCheck(child,
"QMdiArea::sizeHint"))
1731 size = size.expandedTo(child->sizeHint());
1737
1738
1739QSize QMdiArea::minimumSizeHint()
const
1741 Q_D(
const QMdiArea);
1742 QSize size(style()->pixelMetric(QStyle::PM_MdiSubWindowMinimizedWidth,
nullptr,
this),
1743 style()->pixelMetric(QStyle::PM_TitleBarHeight,
nullptr,
this));
1744 size = size.expandedTo(QAbstractScrollArea::minimumSizeHint());
1745 if (!d->scrollBarsEnabled()) {
1746 for (QMdiSubWindow *child : d->childWindows) {
1747 if (!sanityCheck(child,
"QMdiArea::sizeHint"))
1749 size = size.expandedTo(child->minimumSizeHint());
1756
1757
1758
1759
1760
1761
1762
1763
1764QMdiSubWindow *QMdiArea::currentSubWindow()
const
1766 Q_D(
const QMdiArea);
1767 if (d->childWindows.isEmpty())
1773 if (d->isActivated && !window()->isMinimized())
1776 Q_ASSERT(d->indicesToActivatedChildren.size() > 0);
1777 int index = d->indicesToActivatedChildren.at(0);
1778 Q_ASSERT(index >= 0 && index < d->childWindows.size());
1779 QMdiSubWindow *current = d->childWindows.at(index);
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796QMdiSubWindow *QMdiArea::activeSubWindow()
const
1798 Q_D(
const QMdiArea);
1803
1804
1805
1806
1807
1808void QMdiArea::setActiveSubWindow(QMdiSubWindow *window)
1812 d->activateWindow(
nullptr);
1816 if (Q_UNLIKELY(d->childWindows.isEmpty())) {
1817 qWarning(
"QMdiArea::setActiveSubWindow: workspace is empty");
1821 if (Q_UNLIKELY(d->childWindows.indexOf(window) == -1)) {
1822 qWarning(
"QMdiArea::setActiveSubWindow: window is not inside workspace");
1826 d->activateWindow(window);
1830
1831
1832
1833
1834void QMdiArea::closeActiveSubWindow()
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852QList<QMdiSubWindow *> QMdiArea::subWindowList(WindowOrder order)
const
1854 Q_D(
const QMdiArea);
1855 return d->subWindowList(order,
false);
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868void QMdiArea::closeAllSubWindows()
1871 if (d->childWindows.isEmpty())
1874 d->isSubWindowsTiled =
false;
1878 const auto subWindows = d->childWindows;
1879 for (QMdiSubWindow *child : subWindows) {
1880 if (!sanityCheck(child,
"QMdiArea::closeAllSubWindows"))
1885 d->updateScrollBars();
1889
1890
1891
1892
1893
1894
1895void QMdiArea::activateNextSubWindow()
1898 if (d->childWindows.isEmpty())
1901 QMdiSubWindow *next = d->nextVisibleSubWindow(1, d->activationOrder);
1903 d->activateWindow(next);
1907
1908
1909
1910
1911
1912
1913void QMdiArea::activatePreviousSubWindow()
1916 if (d->childWindows.isEmpty())
1919 QMdiSubWindow *previous = d->nextVisibleSubWindow(-1, d->activationOrder);
1921 d->activateWindow(previous);
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947QMdiSubWindow *QMdiArea::addSubWindow(QWidget *widget, Qt::WindowFlags windowFlags)
1949 if (Q_UNLIKELY(!widget)) {
1950 qWarning(
"QMdiArea::addSubWindow: null pointer to widget");
1956 QWidget *childFocus = widget->focusWidget();
1957 QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(widget);
1961 if (Q_UNLIKELY(d->childWindows.indexOf(child) != -1)) {
1962 qWarning(
"QMdiArea::addSubWindow: window is already added");
1965 child->setParent(viewport(), windowFlags ? windowFlags : child->windowFlags());
1968 child =
new QMdiSubWindow(viewport(), windowFlags);
1969 child->setAttribute(Qt::WA_DeleteOnClose);
1970 child->setWidget(widget);
1971 Q_ASSERT(child->testAttribute(Qt::WA_DeleteOnClose));
1974 d->appendChild(child);
1977 childFocus->setFocus();
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992void QMdiArea::removeSubWindow(QWidget *widget)
1994 if (Q_UNLIKELY(!widget)) {
1995 qWarning(
"QMdiArea::removeSubWindow: null pointer to widget");
2000 if (d->childWindows.isEmpty())
2003 if (QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(widget)) {
2004 int index = d->childWindows.indexOf(child);
2005 if (Q_UNLIKELY(index == -1)) {
2006 qWarning(
"QMdiArea::removeSubWindow: window is not inside workspace");
2009 d->disconnectSubWindow(child);
2010 d->childWindows.removeAll(child);
2011 d->indicesToActivatedChildren.removeAll(index);
2012 d->updateActiveWindow(index, d->active == child);
2013 child->setParent(
nullptr);
2021 const auto subWindows = d->childWindows;
2022 for (QMdiSubWindow *child : subWindows) {
2023 if (!sanityCheck(child,
"QMdiArea::removeSubWindow"))
2025 if (child->widget() == widget) {
2026 child->setWidget(
nullptr);
2027 Q_ASSERT(!child->widget());
2033 if (Q_UNLIKELY(!found))
2034 qWarning(
"QMdiArea::removeSubWindow: widget is not child of any window inside QMdiArea");
2038
2039
2040
2041
2042
2043
2044
2045QBrush QMdiArea::background()
const
2047 return d_func()->background;
2050void QMdiArea::setBackground(
const QBrush &brush)
2053 if (d->background != brush) {
2054 d->background = brush;
2055 d->viewport->setAttribute(Qt::WA_OpaquePaintEvent, brush.isOpaque());
2056 d->viewport->update();
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072QMdiArea::WindowOrder QMdiArea::activationOrder()
const
2074 Q_D(
const QMdiArea);
2075 return d->activationOrder;
2078void QMdiArea::setActivationOrder(WindowOrder order)
2081 if (order != d->activationOrder)
2082 d->activationOrder = order;
2086
2087
2088
2089
2090
2091void QMdiArea::setOption(AreaOption option,
bool on)
2094 d->options.setFlag(option, on);
2098
2099
2100
2101
2102bool QMdiArea::testOption(AreaOption option)
const
2104 return d_func()->options & option;
2108
2109
2110
2111
2112
2113
2114
2115
2116QMdiArea::ViewMode QMdiArea::viewMode()
const
2118 Q_D(
const QMdiArea);
2122void QMdiArea::setViewMode(ViewMode mode)
2125 d->setViewMode(mode);
2128#if QT_CONFIG(tabbar)
2130
2131
2132
2133
2134
2135
2136
2137
2138bool QMdiArea::documentMode()
const
2140 Q_D(
const QMdiArea);
2141 return d->documentMode;
2144void QMdiArea::setDocumentMode(
bool enabled)
2147 if (d->documentMode == enabled)
2150 d->documentMode = enabled;
2155
2156
2157
2158
2159
2160
2161
2162
2163bool QMdiArea::tabsClosable()
const
2165 Q_D(
const QMdiArea);
2166 return d->tabsClosable;
2169void QMdiArea::setTabsClosable(
bool closable)
2172 if (d->tabsClosable == closable)
2175 d->tabsClosable = closable;
2180
2181
2182
2183
2184
2185
2186
2187
2188bool QMdiArea::tabsMovable()
const
2190 Q_D(
const QMdiArea);
2191 return d->tabsMovable;
2194void QMdiArea::setTabsMovable(
bool movable)
2197 if (d->tabsMovable == movable)
2200 d->tabsMovable = movable;
2205#if QT_CONFIG(tabwidget)
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216QTabWidget::TabShape QMdiArea::tabShape()
const
2218 Q_D(
const QMdiArea);
2222void QMdiArea::setTabShape(QTabWidget::TabShape shape)
2225 if (d->tabShape == shape)
2228 d->tabShape = shape;
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242QTabWidget::TabPosition QMdiArea::tabPosition()
const
2244 Q_D(
const QMdiArea);
2245 return d->tabPosition;
2248void QMdiArea::setTabPosition(QTabWidget::TabPosition position)
2251 if (d->tabPosition == position)
2254 d->tabPosition = position;
2260
2261
2262void QMdiArea::childEvent(QChildEvent *childEvent)
2265 if (childEvent->type() == QEvent::ChildPolished) {
2266 if (QMdiSubWindow *mdiChild = qobject_cast<QMdiSubWindow *>(childEvent->child())) {
2267 if (d->childWindows.indexOf(mdiChild) == -1)
2268 d->appendChild(mdiChild);
2274
2275
2276void QMdiArea::resizeEvent(QResizeEvent *resizeEvent)
2279 if (d->childWindows.isEmpty()) {
2280 resizeEvent->ignore();
2284#if QT_CONFIG(tabbar)
2285 d->updateTabBarGeometry();
2291 if (d->isSubWindowsTiled) {
2292 d->tileCalledFromResizeEvent =
true;
2294 d->tileCalledFromResizeEvent =
false;
2295 d->isSubWindowsTiled =
true;
2296 d->startResizeTimer();
2302 bool hasMaximizedSubWindow =
false;
2306 const auto subWindows = d->childWindows;
2307 for (QMdiSubWindow *child : subWindows) {
2308 if (sanityCheck(child,
"QMdiArea::resizeEvent") && child->isMaximized()
2309 && child->size() != resizeEvent->size()) {
2310 auto realSize = resizeEvent->size();
2311 const auto minSizeHint = child->minimumSizeHint();
2315 if (minSizeHint.isValid())
2316 realSize = realSize.expandedTo(minSizeHint);
2317 child->resize(realSize);
2318 if (!hasMaximizedSubWindow)
2319 hasMaximizedSubWindow =
true;
2323 d->updateScrollBars();
2328 if (hasMaximizedSubWindow)
2329 d->startResizeTimer();
2331 d->arrangeMinimizedSubWindows();
2335
2336
2337void QMdiArea::timerEvent(QTimerEvent *timerEvent)
2340 if (timerEvent->id() == d->resizeTimer.id()) {
2341 d->resizeTimer.stop();
2342 d->arrangeMinimizedSubWindows();
2343 }
else if (timerEvent->id() == d->tabToPreviousTimer.id()) {
2344 d->tabToPreviousTimer.stop();
2345 if (d->indexToHighlighted < 0)
2347#if QT_CONFIG(rubberband)
2349 Q_ASSERT(d->indexToHighlighted < d->childWindows.size());
2350 Q_ASSERT(d->rubberBand);
2351 d->showRubberBandFor(d->childWindows.at(d->indexToHighlighted));
2357
2358
2359void QMdiArea::showEvent(QShowEvent *showEvent)
2362 if (!d->pendingRearrangements.isEmpty()) {
2363 bool skipPlacement =
false;
2365 const auto pendingRearrange = d->pendingRearrangements;
2366 for (Rearranger *rearranger : pendingRearrange) {
2369 if (rearranger->type() != Rearranger::IconTiler && !skipPlacement)
2370 skipPlacement =
true;
2371 d->rearrange(rearranger);
2373 d->pendingRearrangements.clear();
2375 if (skipPlacement && !d->pendingPlacements.isEmpty())
2376 d->pendingPlacements.clear();
2379 if (!d->pendingPlacements.isEmpty()) {
2384 const auto copy = d->pendingPlacements;
2385 for (QMdiSubWindow *window : copy) {
2388 if (d->viewMode == TabbedView && window->d_func()->isActive && !d->active) {
2389 d->showActiveWindowMaximized =
true;
2390 d->emitWindowActivated(window);
2393 if (!window->testAttribute(Qt::WA_Resized)) {
2394 QSize newSize(window->sizeHint().boundedTo(viewport()->size()));
2395 window->resize(newSize.expandedTo(qSmartMinSize(window)));
2397 if (!window->testAttribute(Qt::WA_Moved) && !window->isMinimized()
2398 && !window->isMaximized()) {
2399 d->place(d->placer, window);
2402 d->pendingPlacements.clear();
2405 d->setChildActivationEnabled(
true);
2406 d->activateCurrentWindow();
2408 QAbstractScrollArea::showEvent(showEvent);
2412
2413
2414bool QMdiArea::viewportEvent(QEvent *event)
2417 switch (event->type()) {
2418 case QEvent::ChildRemoved: {
2419 d->isSubWindowsTiled =
false;
2420 QObject *removedChild =
static_cast<QChildEvent *>(event)->child();
2421 for (
int i = 0; i < d->childWindows.size(); ++i) {
2422 QObject *child = d->childWindows.at(i);
2423 if (!child || child == removedChild || !child->parent()
2424 || child->parent() != viewport()) {
2425 if (!testOption(DontMaximizeSubWindowOnActivation)) {
2428 QWidget *mdiChild = qobject_cast<QWidget *>(removedChild);
2429 if (mdiChild && mdiChild->isMaximized())
2430 d->showActiveWindowMaximized =
true;
2432 d->disconnectSubWindow(child);
2433 const bool activeRemoved = i == d->indicesToActivatedChildren.at(0);
2434 d->childWindows.removeAt(i);
2435 d->indicesToActivatedChildren.removeAll(i);
2436 d->updateActiveWindow(i, activeRemoved);
2437 d->arrangeMinimizedSubWindows();
2441 d->updateScrollBars();
2444 case QEvent::Destroy:
2445 d->isSubWindowsTiled =
false;
2446 d->resetActiveWindow();
2447 d->childWindows.clear();
2448 qWarning(
"QMdiArea: Deleting the view port is undefined, use setViewport instead.");
2453 return QAbstractScrollArea::viewportEvent(event);
2457
2458
2459void QMdiArea::scrollContentsBy(
int dx,
int dy)
2462 const bool wasSubWindowsTiled = d->isSubWindowsTiled;
2463 d->ignoreGeometryChange =
true;
2464 viewport()->scroll(isLeftToRight() ? dx : -dx, dy);
2465 d->arrangeMinimizedSubWindows();
2466 d->ignoreGeometryChange =
false;
2467 if (wasSubWindowsTiled)
2468 d->isSubWindowsTiled =
true;
2472
2473
2474
2475
2476void QMdiArea::tileSubWindows()
2479 if (!d->regularTiler)
2480 d->regularTiler =
new RegularTiler;
2481 d->rearrange(d->regularTiler);
2485
2486
2487
2488
2489void QMdiArea::cascadeSubWindows()
2493 d->cascader =
new SimpleCascader;
2494 d->rearrange(d->cascader);
2498
2499
2500bool QMdiArea::event(QEvent *event)
2503 switch (event->type()) {
2504 case QEvent::WindowActivate: {
2505 d->isActivated =
true;
2506 if (d->childWindows.isEmpty())
2509 d->activateCurrentWindow();
2510 d->setChildActivationEnabled(
false,
true);
2513 case QEvent::WindowDeactivate:
2514 d->isActivated =
false;
2515 d->setChildActivationEnabled(
false,
true);
2517 case QEvent::StyleChange:
2521 if (d->isSubWindowsTiled) {
2523 d->isSubWindowsTiled =
true;
2526 case QEvent::WindowIconChange: {
2529 const auto subWindows = d->childWindows;
2530 for (QMdiSubWindow *window : subWindows) {
2531 if (sanityCheck(window,
"QMdiArea::WindowIconChange"))
2532 QCoreApplication::sendEvent(window, event);
2537 d->setActive(d->active,
false,
false);
2538 d->setChildActivationEnabled(
false);
2540#if QT_CONFIG(tabbar)
2541 case QEvent::LayoutDirectionChange:
2542 d->updateTabBarGeometry();
2548 return QAbstractScrollArea::event(event);
2552
2553
2554bool QMdiArea::eventFilter(QObject *object, QEvent *event)
2557 return QAbstractScrollArea::eventFilter(object, event);
2561 if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) {
2563 QKeyEvent *keyEvent =
static_cast<QKeyEvent *>(event);
2565 if (!(keyEvent->modifiers() & Qt::ControlModifier) && keyEvent->key() != Qt::Key_Control)
2566 return QAbstractScrollArea::eventFilter(object, event);
2569 QMdiArea *area = mdiAreaParent(
static_cast<QWidget *>(object));
2571 return QAbstractScrollArea::eventFilter(object, event);
2573 const bool keyPress = (event->type() == QEvent::KeyPress);
2579 switch (keyEvent->key()) {
2580 case Qt::Key_Control:
2582 area->d_func()->startTabToPreviousTimer();
2584 area->d_func()->activateHighlightedWindow();
2587 case Qt::Key_Backtab:
2589 area->d_func()->highlightNextSubWindow(keyEvent->key() == Qt::Key_Tab ? 1 : -1);
2591#if QT_CONFIG(rubberband)
2592 case Qt::Key_Escape:
2593 area->d_func()->hideRubberBand();
2599 return QAbstractScrollArea::eventFilter(object, event);
2602 QMdiSubWindow *subWindow = qobject_cast<QMdiSubWindow *>(object);
2606 if (event->type() == QEvent::ApplicationActivate && !d->active
2607 && isVisible() && !window()->isMinimized()) {
2608 d->activateCurrentWindow();
2609 }
else if (event->type() == QEvent::ApplicationDeactivate && d->active) {
2610 d->setActive(d->active,
false,
false);
2612 return QAbstractScrollArea::eventFilter(object, event);
2615 if (subWindow->mdiArea() !=
this)
2616 return QAbstractScrollArea::eventFilter(object, event);
2619 switch (event->type()) {
2621 case QEvent::Resize:
2622 if (d->tileCalledFromResizeEvent)
2624 d->updateScrollBars();
2625 if (!subWindow->isMinimized())
2626 d->isSubWindowsTiled =
false;
2629#if QT_CONFIG(tabbar)
2631 const int tabIndex = d->childWindows.indexOf(subWindow);
2632 if (!d->tabBar->isTabEnabled(tabIndex))
2633 d->tabBar->setTabEnabled(tabIndex,
true);
2641 if (!event->spontaneous())
2642 d->isSubWindowsTiled =
false;
2644#if QT_CONFIG(rubberband)
2646 if (d->childWindows.indexOf(subWindow) == d->indexToHighlighted)
2647 d->hideRubberBand();
2650#if QT_CONFIG(tabbar)
2651 case QEvent::WindowTitleChange:
2652 case QEvent::ModifiedChange:
2654 d->tabBar->setTabText(d->childWindows.indexOf(subWindow), tabTextFor(subWindow));
2656 case QEvent::WindowIconChange:
2658 d->tabBar->setTabIcon(d->childWindows.indexOf(subWindow), subWindow->windowIcon());
2664 return QAbstractScrollArea::eventFilter(object, event);
2668
2669
2670void QMdiArea::paintEvent(QPaintEvent *paintEvent)
2673 QPainter painter(d->viewport);
2674 for (
const QRect &exposedRect : paintEvent->region())
2675 painter.fillRect(exposedRect, d->background);
2679
2680
2681
2682
2683
2684
2685void QMdiArea::setupViewport(QWidget *viewport)
2689 viewport->setAttribute(Qt::WA_OpaquePaintEvent, d->background.isOpaque());
2692 const auto subWindows = d->childWindows;
2693 for (QMdiSubWindow *child : subWindows) {
2694 if (!sanityCheck(child,
"QMdiArea::setupViewport"))
2696 child->setParent(viewport, child->windowFlags());
2702#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...