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 void mouseReleaseEvent(QMouseEvent *event) override;
526#ifndef QT_NO_CONTEXTMENU
527 void contextMenuEvent(QContextMenuEvent *event) override;
531 QMdiSubWindow *subWindowFromIndex(
int index)
const;
535
536
537void QMdiAreaTabBar::mousePressEvent(QMouseEvent *event)
539 if (event->button() != Qt::MiddleButton) {
540 QTabBar::mousePressEvent(event);
544 QMdiSubWindow *subWindow = subWindowFromIndex(tabAt(event->position().toPoint()));
554
555
556void QMdiAreaTabBar::mouseReleaseEvent(QMouseEvent *event)
558 if (event->button() != Qt::MiddleButton) {
559 QTabBar::mouseReleaseEvent(event);
563#ifndef QT_NO_CONTEXTMENU
565
566
567void QMdiAreaTabBar::contextMenuEvent(QContextMenuEvent *event)
569 QPointer<QMdiSubWindow> subWindow = subWindowFromIndex(tabAt(event->pos()));
570 if (!subWindow || subWindow->isHidden()) {
576 QMdiSubWindowPrivate *subWindowPrivate = subWindow->d_func();
577 if (!subWindowPrivate->systemMenu) {
582 QMdiSubWindow *currentSubWindow = subWindowFromIndex(currentIndex());
583 Q_ASSERT(currentSubWindow);
587 if (currentSubWindow->isMaximized()) {
588 subWindowPrivate->setVisible(QMdiSubWindowPrivate::MoveAction,
false);
589 subWindowPrivate->setVisible(QMdiSubWindowPrivate::ResizeAction,
false);
590 subWindowPrivate->setVisible(QMdiSubWindowPrivate::MinimizeAction,
false);
591 subWindowPrivate->setVisible(QMdiSubWindowPrivate::MaximizeAction,
false);
592 subWindowPrivate->setVisible(QMdiSubWindowPrivate::RestoreAction,
false);
593 subWindowPrivate->setVisible(QMdiSubWindowPrivate::StayOnTopAction,
false);
597 subWindowPrivate->systemMenu->exec(event->globalPos());
602 subWindowPrivate->updateActions();
608
609
610QMdiSubWindow *QMdiAreaTabBar::subWindowFromIndex(
int index)
const
612 if (index < 0 || index >= count())
615 QMdiArea *mdiArea = qobject_cast<QMdiArea *>(parentWidget());
618 const QList<QMdiSubWindow *> subWindows = mdiArea->subWindowList();
619 Q_ASSERT(index < subWindows.size());
621 QMdiSubWindow *subWindow = mdiArea->subWindowList().at(index);
629
630
636#if QT_CONFIG(rubberband)
642 activationOrder(QMdiArea::CreationOrder),
643 viewMode(QMdiArea::SubWindowView),
649#if QT_CONFIG(tabwidget)
650 tabShape(QTabWidget::Rounded),
651 tabPosition(QTabWidget::North),
669
670
677 if (!aboutToActivate)
678 aboutToBecomeActive = qobject_cast<QMdiSubWindow *>(q->sender());
680 aboutToBecomeActive = aboutToActivate;
681 Q_ASSERT(aboutToBecomeActive);
686 const auto subWindows = childWindows;
687 for (QMdiSubWindow *child : subWindows) {
688 if (!sanityCheck(child,
"QMdiArea::deactivateAllWindows") || aboutToBecomeActive == child)
691 ignoreWindowStateChange =
true;
692 if (!(options & QMdiArea::DontMaximizeSubWindowOnActivation) && !showActiveWindowMaximized)
693 showActiveWindowMaximized = child->isMaximized() && child->isVisible();
694 if (showActiveWindowMaximized && child->isMaximized()) {
695 if (q->updatesEnabled()) {
696 updatesDisabledByUs =
true;
697 q->setUpdatesEnabled(
false);
701 if (child->isMinimized() && !child->isShaded() && !windowStaysOnTop(child))
703 ignoreWindowStateChange =
false;
704 child->d_func()->setActive(
false);
709
710
712 Qt::WindowStates newState)
718 QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(q->sender());
723 if (!(oldState & Qt::WindowActive) && (newState & Qt::WindowActive))
726 else if ((oldState & Qt::WindowActive) && !(newState & Qt::WindowActive))
730 if (!(oldState & Qt::WindowMinimized) && (newState & Qt::WindowMinimized)) {
734 }
else if (!(oldState & Qt::WindowMaximized) && (newState & Qt::WindowMaximized)) {
737 }
else if (!(newState & (Qt::WindowMaximized | Qt::WindowMinimized))) {
739 if (oldState & Qt::WindowMinimized)
746#if !QT_CONFIG(tabbar)
753 if (indexToLastActiveTab >= 0 && indexToLastActiveTab < tabBar->count()
754 && indexToLastActiveTab < childWindows.size()) {
755 QMdiSubWindow *lastActive = childWindows.at(indexToLastActiveTab);
756 if (lastActive && lastActive->isHidden())
761 Q_ASSERT(childWindows.size() > index);
762 QMdiSubWindow *subWindow = childWindows.at(index);
770#if !QT_CONFIG(tabbar)
773 QMdiSubWindow *subWindow = childWindows.at(index);
781#if !QT_CONFIG(tabbar)
785 childWindows.move(from, to);
788 const int indexToActiveWindow = childWindows.indexOf(active);
789 if (indexToActiveWindow != -1) {
790 const int index = indicesToActivatedChildren.indexOf(indexToActiveWindow);
791 Q_ASSERT(index != -1);
793 indicesToActivatedChildren.move(index, 0);
801
802
806 Q_ASSERT(child && childWindows.indexOf(child) == -1);
808 if (child->parent() != viewport)
809 child->setParent(viewport, child->windowFlags());
810 childWindows.append(QPointer<QMdiSubWindow>(child));
812 if (!child->testAttribute(Qt::WA_Resized) && q->isVisible()) {
813 QSize newSize(child->sizeHint().boundedTo(viewport->size()));
814 child->resize(newSize.expandedTo(qSmartMinSize(child)));
821 if (hbarpolicy != Qt::ScrollBarAlwaysOff)
822 child->setOption(QMdiSubWindow::AllowOutsideAreaHorizontally,
true);
824 child->setOption(QMdiSubWindow::AllowOutsideAreaHorizontally,
false);
826 if (vbarpolicy != Qt::ScrollBarAlwaysOff)
827 child->setOption(QMdiSubWindow::AllowOutsideAreaVertically,
true);
829 child->setOption(QMdiSubWindow::AllowOutsideAreaVertically,
false);
832 indicesToActivatedChildren.prepend(childWindows.size() - 1);
833 Q_ASSERT(indicesToActivatedChildren.size() == childWindows.size());
837 tabBar->addTab(child->windowIcon(), tabTextFor(child));
838 updateTabBarGeometry();
839 if (childWindows.size() == 1 && !(options & QMdiArea::DontMaximizeSubWindowOnActivation))
840 showActiveWindowMaximized =
true;
844 if (!(child->windowFlags() & Qt::SubWindow))
845 child->setWindowFlags(Qt::SubWindow);
846 child->installEventFilter(q);
848 QObject::connect(child, SIGNAL(aboutToActivate()), q, SLOT(_q_deactivateAllWindows()));
849 QObject::connect(child, SIGNAL(windowStateChanged(Qt::WindowStates,Qt::WindowStates)),
850 q, SLOT(_q_processWindowStateChanged(Qt::WindowStates,Qt::WindowStates)));
854
855
858 if (!placer || !child)
862 if (!q->isVisible()) {
866 pendingPlacements.append(child);
871 rects.reserve(childWindows.size());
872 QRect parentRect = q->rect();
873 for (QMdiSubWindow *window : std::as_const(childWindows)) {
874 if (!sanityCheck(window,
"QMdiArea::place") || window == child || !window->isVisibleTo(q)
875 || !window->testAttribute(Qt::WA_Moved)) {
878 QRect occupiedGeometry;
879 if (window->isMaximized()) {
880 occupiedGeometry = QRect(window->d_func()->oldGeometry.topLeft(),
881 window->d_func()->restoreSize);
883 occupiedGeometry = window->geometry();
885 rects.append(QStyle::visualRect(child->layoutDirection(), parentRect, occupiedGeometry));
887 QPoint newPos = placer->place(child->size(), rects, parentRect);
888 QRect newGeometry = QRect(newPos.x(), newPos.y(), child->width(), child->height());
889 child->setGeometry(QStyle::visualRect(child->layoutDirection(), parentRect, newGeometry));
893
894
901 if (!q->isVisible()) {
903 int index = pendingRearrangements.indexOf(rearranger);
905 pendingRearrangements.move(index, pendingRearrangements.size() - 1);
907 pendingRearrangements.append(rearranger);
911 QList<QWidget *> widgets;
913 const QList<QMdiSubWindow *> subWindows = subWindowList(activationOrder, reverseList);
914 QSize minSubWindowSize;
915 for (QMdiSubWindow *child : subWindows) {
916 if (!sanityCheck(child,
"QMdiArea::rearrange") || !child->isVisible())
918 if (rearranger->type() == Rearranger::IconTiler) {
919 if (child->isMinimized() && !child->isShaded())
920 widgets.append(child);
922 if (child->isMinimized() && !child->isShaded())
924 if (child->isMaximized() || child->isShaded())
926 minSubWindowSize = minSubWindowSize.expandedTo(child->minimumSize())
927 .expandedTo(child->d_func()->internalMinimumSize);
928 widgets.append(child);
932 QRect domain = viewport->rect();
933 if (rearranger->type() == Rearranger::RegularTiler && !widgets.isEmpty())
934 domain = resizeToMinimumTileSize(minSubWindowSize, widgets.size());
936 rearranger->rearrange(widgets, domain);
947
948
949
950
954 iconTiler =
new IconTiler;
959
960
963 if (childWindows.isEmpty()) {
971 Q_ASSERT(active->d_func()->isActive);
972 active->d_func()->setActive(
false);
978 if (child->isHidden() || child == active)
981 if (child->d_func()->isActive && active ==
nullptr)
982 child->d_func()->isActive =
false;
984 child->d_func()->setActive(
true);
988
989
992 QMdiSubWindow *current = q_func()->currentSubWindow();
994 current->d_func()->activationEnabled =
true;
995 current->d_func()->setActive(
true,
false);
1004 Q_ASSERT(indexToHighlighted < childWindows.size());
1005 if (tabToPreviousTimer.isActive())
1006 activateWindow(nextVisibleSubWindow(-1, QMdiArea::ActivationHistoryOrder));
1009#if QT_CONFIG(rubberband)
1015
1016
1020 Q_ASSERT(activeWindow);
1021 if (activeWindow == active)
1023 Q_ASSERT(activeWindow->d_func()->isActive);
1025 if (!aboutToBecomeActive)
1027 Q_ASSERT(aboutToBecomeActive);
1032 if (!activeWindow->isMaximized())
1033 activeWindow->showMaximized();
1038 const int indexToActiveWindow = childWindows.indexOf(activeWindow);
1039 Q_ASSERT(indexToActiveWindow != -1);
1040 const int index = indicesToActivatedChildren.indexOf(indexToActiveWindow);
1041 Q_ASSERT(index != -1);
1042 indicesToActivatedChildren.move(index, 0);
1046 q->setUpdatesEnabled(
true);
1050 Q_ASSERT(aboutToBecomeActive == activeWindow);
1051 active = activeWindow;
1052 aboutToBecomeActive =
nullptr;
1053 Q_ASSERT(active->d_func()->isActive);
1055#if QT_CONFIG(tabbar)
1056 if (tabBar && tabBar->currentIndex() != indexToActiveWindow)
1057 tabBar->setCurrentIndex(indexToActiveWindow);
1060 if (active->isMaximized() && scrollBarsEnabled())
1063 emit q->subWindowActivated(active);
1067
1068
1072 if (deactivatedWindow) {
1073 if (deactivatedWindow != active)
1076 if ((aboutToBecomeActive || isActivated || lastWindowAboutToBeDestroyed())
1077 && !isExplicitlyDeactivated(deactivatedWindow) && !q->window()->isMinimized()) {
1080 emit q->subWindowActivated(
nullptr);
1084 if (aboutToBecomeActive)
1088 emit q->subWindowActivated(
nullptr);
1092
1093
1096 Q_ASSERT(indicesToActivatedChildren.size() == childWindows.size());
1099 for (
int i = 0; i < indicesToActivatedChildren.size(); ++i) {
1100 int &index = indicesToActivatedChildren[i];
1101 if (index > removedIndex)
1105#if QT_CONFIG(tabbar)
1106 if (tabBar && removedIndex >= 0) {
1107 const QSignalBlocker blocker(tabBar);
1108 tabBar->removeTab(removedIndex);
1109 updateTabBarGeometry();
1113 if (childWindows.isEmpty()) {
1120#if QT_CONFIG(rubberband)
1122 if (indexToHighlighted == removedIndex)
1135 QMdiSubWindow *next = nextVisibleSubWindow(0, activationOrder, removedIndex);
1141
1142
1149 QSize maxSize = q->maximumViewportSize();
1150 QSize hbarExtent = hbar->sizeHint();
1151 QSize vbarExtent = vbar->sizeHint();
1153 if (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents,
nullptr, q)) {
1154 const int doubleFrameWidth = frameWidth * 2;
1155 if (hbarpolicy == Qt::ScrollBarAlwaysOn)
1156 maxSize.rheight() -= doubleFrameWidth;
1157 if (vbarpolicy == Qt::ScrollBarAlwaysOn)
1158 maxSize.rwidth() -= doubleFrameWidth;
1159 hbarExtent.rheight() += doubleFrameWidth;
1160 vbarExtent.rwidth() += doubleFrameWidth;
1163 const QRect childrenRect = active && active->isMaximized()
1164 ? active->geometry() : viewport->childrenRect();
1165 bool useHorizontalScrollBar = useScrollBar(childrenRect, maxSize, Qt::Horizontal);
1166 bool useVerticalScrollBar = useScrollBar(childrenRect, maxSize, Qt::Vertical);
1168 if (useHorizontalScrollBar && !useVerticalScrollBar) {
1169 const QSize max = maxSize - QSize(0, hbarExtent.height());
1170 useVerticalScrollBar = useScrollBar(childrenRect, max, Qt::Vertical);
1173 if (useVerticalScrollBar && !useHorizontalScrollBar) {
1174 const QSize max = maxSize - QSize(vbarExtent.width(), 0);
1175 useHorizontalScrollBar = useScrollBar(childrenRect, max, Qt::Horizontal);
1178 if (useHorizontalScrollBar && hbarpolicy != Qt::ScrollBarAlwaysOn)
1179 maxSize.rheight() -= hbarExtent.height();
1180 if (useVerticalScrollBar && vbarpolicy != Qt::ScrollBarAlwaysOn)
1181 maxSize.rwidth() -= vbarExtent.width();
1183 QRect viewportRect(QPoint(0, 0), maxSize);
1184 const int startX = q->isLeftToRight() ? childrenRect.left() : viewportRect.right()
1185 - childrenRect.right();
1187 const auto singleStep = defaultSingleStep();
1190 if (isSubWindowsTiled && hbar->value() != 0)
1192 const int xOffset = startX + hbar->value();
1193 hbar->setRange(qMin(0, xOffset),
1194 qMax(0, xOffset + childrenRect.width() - viewportRect.width()));
1195 hbar->setPageStep(childrenRect.width());
1196 hbar->setSingleStep(childrenRect.width() / singleStep);
1199 if (isSubWindowsTiled && vbar->value() != 0)
1201 const int yOffset = childrenRect.top() + vbar->value();
1202 vbar->setRange(qMin(0, yOffset),
1203 qMax(0, yOffset + childrenRect.height() - viewportRect.height()));
1204 vbar->setPageStep(childrenRect.height());
1205 vbar->setSingleStep(childrenRect.height() / singleStep);
1209
1210
1213 if (!sanityCheck(mdiChild,
"QMdiArea::internalRaise") || childWindows.size() < 2)
1216 QMdiSubWindow *stackUnderChild =
nullptr;
1218 const auto children = viewport->children();
1219 for (QObject *object : children) {
1220 QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(object);
1221 if (!child || !childWindows.contains(child))
1223 if (!child->isHidden() && windowStaysOnTop(child)) {
1224 if (stackUnderChild)
1225 child->stackUnder(stackUnderChild);
1228 stackUnderChild = child;
1233 if (stackUnderChild)
1234 mdiChild->stackUnder(stackUnderChild);
1242 if (!minSubWindowSize.isValid() || subWindowCount <= 0)
1243 return viewport->rect();
1246 const int columns = qMax(qCeil(qSqrt(qreal(subWindowCount))), 1);
1247 const int rows = qMax((subWindowCount % columns) ? (subWindowCount / columns + 1)
1248 : (subWindowCount / columns), 1);
1249 const int minWidth = minSubWindowSize.width() * columns;
1250 const int minHeight = minSubWindowSize.height() * rows;
1255 QWidget *topLevel = q;
1257 while (topLevel && !topLevel->isWindow() && topLevel->windowType() != Qt::SubWindow)
1258 topLevel = topLevel->parentWidget();
1260 int minAreaWidth = minWidth + left + right + 2;
1261 int minAreaHeight = minHeight + top + bottom + 2;
1262 if (hbar->isVisible())
1263 minAreaHeight += hbar->height();
1264 if (vbar->isVisible())
1265 minAreaWidth += vbar->width();
1266 if (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents,
nullptr, q)) {
1267 const int frame = q->style()->pixelMetric(QStyle::PM_DefaultFrameWidth,
nullptr, q);
1268 minAreaWidth += 2 * frame;
1269 minAreaHeight += 2 * frame;
1271 const QSize diff = QSize(minAreaWidth, minAreaHeight).expandedTo(q->size()) - q->size();
1273 if (hbarpolicy == Qt::ScrollBarAlwaysOff)
1274 topLevel->resize(topLevel->size().width() + diff.width(), topLevel->size().height());
1275 if (vbarpolicy == Qt::ScrollBarAlwaysOff)
1276 topLevel->resize(topLevel->size().width(), topLevel->size().height() + diff.height());
1279 QRect domain = viewport->rect();
1282 if (domain.width() < minWidth) {
1283 domain.setWidth(minWidth);
1284 if (hbarpolicy == Qt::ScrollBarAlwaysOff)
1285 q->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
1290 if (domain.height() < minHeight) {
1291 domain.setHeight(minHeight);
1292 if (vbarpolicy == Qt::ScrollBarAlwaysOff)
1293 q->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
1301
1302
1305 return hbarpolicy != Qt::ScrollBarAlwaysOff || vbarpolicy != Qt::ScrollBarAlwaysOff;
1309
1310
1313 if (childWindows.size() != 1)
1316 QMdiSubWindow *last = childWindows.at(0);
1320 if (!last->testAttribute(Qt::WA_DeleteOnClose))
1323 return last->d_func()->data.is_closing;
1327
1328
1331 for (QMdiSubWindow *subWindow : childWindows) {
1332 if (!subWindow || !subWindow->isVisible())
1334 if (onlyNextActivationEvent)
1335 subWindow->d_func()->ignoreNextActivationEvent = !enable;
1337 subWindow->d_func()->activationEnabled = enable;
1342
1343
1344
1347 if (childWindows.isEmpty())
1350 const QMdiSubWindow::SubWindowOption option = orientation == Qt::Horizontal ?
1351 QMdiSubWindow::AllowOutsideAreaHorizontally : QMdiSubWindow::AllowOutsideAreaVertically;
1352 const bool enable = policy != Qt::ScrollBarAlwaysOff;
1356 const auto subWindows = childWindows;
1357 for (QMdiSubWindow *child : subWindows) {
1358 if (!sanityCheck(child,
"QMdiArea::scrollBarPolicyChanged"))
1360 child->setOption(option, enable);
1368 QList<QMdiSubWindow *> list;
1369 if (childWindows.isEmpty())
1372 if (order == QMdiArea::CreationOrder) {
1373 for (QMdiSubWindow *child : childWindows) {
1379 list.prepend(child);
1381 }
else if (order == QMdiArea::StackingOrder) {
1382 for (QObject *object : viewport->children()) {
1383 QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(object);
1384 if (!child || !childWindows.contains(child))
1389 list.prepend(child);
1392 Q_ASSERT(indicesToActivatedChildren.size() == childWindows.size());
1393 for (
int i = indicesToActivatedChildren.size() - 1; i >= 0; --i) {
1394 QMdiSubWindow *child = childWindows.at(indicesToActivatedChildren.at(i));
1400 list.prepend(child);
1407
1408
1415 QObject::disconnect(subWindow,
nullptr, q,
nullptr);
1416 subWindow->removeEventFilter(q);
1420
1421
1423 int removedIndex,
int fromIndex)
const
1425 if (childWindows.isEmpty())
1428 Q_Q(
const QMdiArea);
1429 const QList<QMdiSubWindow *> subWindows = q->subWindowList(order);
1430 QMdiSubWindow *current =
nullptr;
1432 if (removedIndex < 0) {
1433 if (fromIndex >= 0 && fromIndex < subWindows.size())
1434 current = childWindows.at(fromIndex);
1436 current = q->currentSubWindow();
1442 if (removedIndex >= 0 && order == QMdiArea::CreationOrder) {
1443 int candidateIndex = -1;
1444 setIndex(&candidateIndex, removedIndex, 0, subWindows.size() - 1,
true);
1445 current = childWindows.at(candidateIndex);
1447 current = subWindows.back();
1453 const int indexToCurrent = subWindows.indexOf(current);
1454 const bool increasing = increaseFactor > 0;
1458 setIndex(&index, indexToCurrent + increaseFactor, 0, subWindows.size() - 1, increasing);
1459 Q_ASSERT(index != -1);
1462 while (subWindows.at(index)->isHidden()) {
1463 setIndex(&index, index + increaseFactor, 0, subWindows.size() - 1, increasing);
1464 if (index == indexToCurrent)
1468 if (!subWindows.at(index)->isHidden())
1469 return subWindows.at(index);
1474
1475
1478 if (childWindows.size() == 1)
1484 QMdiSubWindow *current = q->currentSubWindow();
1487 indexToHighlighted = childWindows.indexOf(current);
1491 Q_ASSERT(indexToHighlighted < childWindows.size());
1493 QMdiSubWindow *highlight = nextVisibleSubWindow(increaseFactor, activationOrder, -1, indexToHighlighted);
1497#if QT_CONFIG(rubberband)
1499 rubberBand =
new QRubberBand(QRubberBand::Rectangle, q);
1501 rubberBand->setObjectName(
"qt_rubberband"_L1);
1502 rubberBand->setWindowFlags(rubberBand->windowFlags() | Qt::WindowStaysOnTopHint);
1507#if QT_CONFIG(rubberband)
1508 if (!tabToPreviousTimer.isActive())
1509 showRubberBandFor(highlight);
1512 indexToHighlighted = childWindows.indexOf(highlight);
1516#if QT_CONFIG(rubberband)
1517void QMdiAreaPrivate::showRubberBandFor(QMdiSubWindow *subWindow)
1519 if (!subWindow || !rubberBand)
1522#if QT_CONFIG(tabbar)
1523 if (viewMode == QMdiArea::TabbedView)
1524 rubberBand->setGeometry(tabBar->tabRect(childWindows.indexOf(subWindow)));
1527 rubberBand->setGeometry(subWindow->geometry());
1529 rubberBand->raise();
1534
1535
1536
1540 if (viewMode == mode || inViewModeChange)
1546#if QT_CONFIG(tabbar)
1547 if (mode == QMdiArea::TabbedView) {
1549 tabBar =
new QMdiAreaTabBar(q);
1550 tabBar->setDocumentMode(documentMode);
1551 tabBar->setTabsClosable(tabsClosable);
1552 tabBar->setMovable(tabsMovable);
1553#if QT_CONFIG(tabwidget)
1554 tabBar->setShape(_q_tb_tabBarShapeFrom(tabShape, tabPosition));
1557 isSubWindowsTiled =
false;
1563 const auto subWindows = childWindows;
1564 for (QMdiSubWindow *subWindow : subWindows)
1565 tabBar->addTab(subWindow->windowIcon(), tabTextFor(subWindow));
1567 QMdiSubWindow *current = q->currentSubWindow();
1569 tabBar->setCurrentIndex(childWindows.indexOf(current));
1571 if (current->isMaximized())
1572 current->showNormal();
1577 if (!q->testOption(QMdiArea::DontMaximizeSubWindowOnActivation)) {
1578 current->showMaximized();
1586 updateTabBarGeometry();
1588 QObject::connect(tabBar, SIGNAL(currentChanged(
int)), q, SLOT(_q_currentTabChanged(
int)));
1589 QObject::connect(tabBar, SIGNAL(tabCloseRequested(
int)), q, SLOT(_q_closeTab(
int)));
1590 QObject::connect(tabBar, SIGNAL(tabMoved(
int,
int)), q, SLOT(_q_moveTab(
int,
int)));
1594#if QT_CONFIG(tabbar)
1600 q->setViewportMargins(0, 0, 0, 0);
1603 QMdiSubWindow *current = q->currentSubWindow();
1604 if (current && current->isMaximized())
1605 current->showNormal();
1608 Q_ASSERT(viewMode == mode);
1612#if QT_CONFIG(tabbar)
1614
1615
1616void QMdiAreaPrivate::updateTabBarGeometry()
1622#if QT_CONFIG(tabwidget)
1623 Q_ASSERT(_q_tb_tabBarShapeFrom(tabShape, tabPosition) == tabBar->shape());
1625 const QSize tabBarSizeHint = tabBar->sizeHint();
1627 int areaHeight = q->height();
1628 if (hbar && hbar->isVisible())
1629 areaHeight -= hbar->height();
1631 int areaWidth = q->width();
1632 if (vbar && vbar->isVisible())
1633 areaWidth -= vbar->width();
1636#if QT_CONFIG(tabwidget)
1637 switch (tabPosition) {
1638 case QTabWidget::North:
1639 q->setViewportMargins(0, tabBarSizeHint.height(), 0, 0);
1640 tabBarRect = QRect(0, 0, areaWidth, tabBarSizeHint.height());
1642 case QTabWidget::South:
1643 q->setViewportMargins(0, 0, 0, tabBarSizeHint.height());
1644 tabBarRect = QRect(0, areaHeight - tabBarSizeHint.height(), areaWidth, tabBarSizeHint.height());
1646 case QTabWidget::East:
1647 if (q->layoutDirection() == Qt::LeftToRight)
1648 q->setViewportMargins(0, 0, tabBarSizeHint.width(), 0);
1650 q->setViewportMargins(tabBarSizeHint.width(), 0, 0, 0);
1651 tabBarRect = QRect(areaWidth - tabBarSizeHint.width(), 0, tabBarSizeHint.width(), areaHeight);
1653 case QTabWidget::West:
1654 if (q->layoutDirection() == Qt::LeftToRight)
1655 q->setViewportMargins(tabBarSizeHint.width(), 0, 0, 0);
1657 q->setViewportMargins(0, 0, tabBarSizeHint.width(), 0);
1658 tabBarRect = QRect(0, 0, tabBarSizeHint.width(), areaHeight);
1665 tabBar->setGeometry(QStyle::visualRect(q->layoutDirection(), q->contentsRect(), tabBarRect));
1669
1670
1671void QMdiAreaPrivate::refreshTabBar()
1676 tabBar->setDocumentMode(documentMode);
1677 tabBar->setTabsClosable(tabsClosable);
1678 tabBar->setMovable(tabsMovable);
1679#if QT_CONFIG(tabwidget)
1680 tabBar->setShape(_q_tb_tabBarShapeFrom(tabShape, tabPosition));
1682 updateTabBarGeometry();
1687
1688
1689
1690QMdiArea::QMdiArea(QWidget *parent)
1691 : QAbstractScrollArea(*
new QMdiAreaPrivate, parent)
1693 setBackground(palette().brush(QPalette::Dark));
1694 setFrameStyle(QFrame::NoFrame);
1695 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1696 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1697 setViewport(
nullptr);
1698 setFocusPolicy(Qt::NoFocus);
1699 QApplication::instance()->installEventFilter(
this);
1703
1704
1705QMdiArea::~QMdiArea()
1709 d->cascader =
nullptr;
1711 delete d->regularTiler;
1712 d->regularTiler =
nullptr;
1714 delete d->iconTiler;
1715 d->iconTiler =
nullptr;
1718 d->placer =
nullptr;
1722
1723
1724QSize QMdiArea::sizeHint()
const
1728 int nestedCount = 0;
1729 QWidget *widget =
this->parentWidget();
1731 if (qobject_cast<QMdiArea *>(widget))
1733 widget = widget->parentWidget();
1735 const int scaleFactor = 3 * (nestedCount + 1);
1737 QSize desktopSize = QGuiApplication::primaryScreen()->virtualSize();
1738 QSize size(desktopSize.width() * 2 / scaleFactor, desktopSize.height() * 2 / scaleFactor);
1739 for (QMdiSubWindow *child : d_func()->childWindows) {
1740 if (!sanityCheck(child,
"QMdiArea::sizeHint"))
1742 size = size.expandedTo(child->sizeHint());
1748
1749
1750QSize QMdiArea::minimumSizeHint()
const
1752 Q_D(
const QMdiArea);
1753 QSize size(style()->pixelMetric(QStyle::PM_MdiSubWindowMinimizedWidth,
nullptr,
this),
1754 style()->pixelMetric(QStyle::PM_TitleBarHeight,
nullptr,
this));
1755 size = size.expandedTo(QAbstractScrollArea::minimumSizeHint());
1756 if (!d->scrollBarsEnabled()) {
1757 for (QMdiSubWindow *child : d->childWindows) {
1758 if (!sanityCheck(child,
"QMdiArea::sizeHint"))
1760 size = size.expandedTo(child->minimumSizeHint());
1767
1768
1769
1770
1771
1772
1773
1774
1775QMdiSubWindow *QMdiArea::currentSubWindow()
const
1777 Q_D(
const QMdiArea);
1778 if (d->childWindows.isEmpty())
1784 if (d->isActivated && !window()->isMinimized())
1787 Q_ASSERT(d->indicesToActivatedChildren.size() > 0);
1788 int index = d->indicesToActivatedChildren.at(0);
1789 Q_ASSERT(index >= 0 && index < d->childWindows.size());
1790 QMdiSubWindow *current = d->childWindows.at(index);
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807QMdiSubWindow *QMdiArea::activeSubWindow()
const
1809 Q_D(
const QMdiArea);
1814
1815
1816
1817
1818
1819void QMdiArea::setActiveSubWindow(QMdiSubWindow *window)
1823 d->activateWindow(
nullptr);
1827 if (Q_UNLIKELY(d->childWindows.isEmpty())) {
1828 qWarning(
"QMdiArea::setActiveSubWindow: workspace is empty");
1832 if (Q_UNLIKELY(d->childWindows.indexOf(window) == -1)) {
1833 qWarning(
"QMdiArea::setActiveSubWindow: window is not inside workspace");
1837 d->activateWindow(window);
1841
1842
1843
1844
1845void QMdiArea::closeActiveSubWindow()
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863QList<QMdiSubWindow *> QMdiArea::subWindowList(WindowOrder order)
const
1865 Q_D(
const QMdiArea);
1866 return d->subWindowList(order,
false);
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879void QMdiArea::closeAllSubWindows()
1882 if (d->childWindows.isEmpty())
1885 d->isSubWindowsTiled =
false;
1889 const auto subWindows = d->childWindows;
1890 for (QMdiSubWindow *child : subWindows) {
1891 if (!sanityCheck(child,
"QMdiArea::closeAllSubWindows"))
1896 d->updateScrollBars();
1900
1901
1902
1903
1904
1905
1906void QMdiArea::activateNextSubWindow()
1909 if (d->childWindows.isEmpty())
1912 QMdiSubWindow *next = d->nextVisibleSubWindow(1, d->activationOrder);
1914 d->activateWindow(next);
1918
1919
1920
1921
1922
1923
1924void QMdiArea::activatePreviousSubWindow()
1927 if (d->childWindows.isEmpty())
1930 QMdiSubWindow *previous = d->nextVisibleSubWindow(-1, d->activationOrder);
1932 d->activateWindow(previous);
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958QMdiSubWindow *QMdiArea::addSubWindow(QWidget *widget, Qt::WindowFlags windowFlags)
1960 if (Q_UNLIKELY(!widget)) {
1961 qWarning(
"QMdiArea::addSubWindow: null pointer to widget");
1967 QWidget *childFocus = widget->focusWidget();
1968 QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(widget);
1972 if (Q_UNLIKELY(d->childWindows.indexOf(child) != -1)) {
1973 qWarning(
"QMdiArea::addSubWindow: window is already added");
1976 child->setParent(viewport(), windowFlags ? windowFlags : child->windowFlags());
1979 child =
new QMdiSubWindow(viewport(), windowFlags);
1980 child->setAttribute(Qt::WA_DeleteOnClose);
1981 child->setWidget(widget);
1982 Q_ASSERT(child->testAttribute(Qt::WA_DeleteOnClose));
1985 d->appendChild(child);
1988 childFocus->setFocus();
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003void QMdiArea::removeSubWindow(QWidget *widget)
2005 if (Q_UNLIKELY(!widget)) {
2006 qWarning(
"QMdiArea::removeSubWindow: null pointer to widget");
2011 if (d->childWindows.isEmpty())
2014 if (QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(widget)) {
2015 int index = d->childWindows.indexOf(child);
2016 if (Q_UNLIKELY(index == -1)) {
2017 qWarning(
"QMdiArea::removeSubWindow: window is not inside workspace");
2020 d->disconnectSubWindow(child);
2021 d->childWindows.removeAll(child);
2022 d->indicesToActivatedChildren.removeAll(index);
2023 d->updateActiveWindow(index, d->active == child);
2024 child->setParent(
nullptr);
2032 const auto subWindows = d->childWindows;
2033 for (QMdiSubWindow *child : subWindows) {
2034 if (!sanityCheck(child,
"QMdiArea::removeSubWindow"))
2036 if (child->widget() == widget) {
2037 child->setWidget(
nullptr);
2038 Q_ASSERT(!child->widget());
2044 if (Q_UNLIKELY(!found))
2045 qWarning(
"QMdiArea::removeSubWindow: widget is not child of any window inside QMdiArea");
2049
2050
2051
2052
2053
2054
2055
2056QBrush QMdiArea::background()
const
2058 return d_func()->background;
2061void QMdiArea::setBackground(
const QBrush &brush)
2064 if (d->background != brush) {
2065 d->background = brush;
2066 d->viewport->setAttribute(Qt::WA_OpaquePaintEvent, brush.isOpaque());
2067 d->viewport->update();
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083QMdiArea::WindowOrder QMdiArea::activationOrder()
const
2085 Q_D(
const QMdiArea);
2086 return d->activationOrder;
2089void QMdiArea::setActivationOrder(WindowOrder order)
2092 if (order != d->activationOrder)
2093 d->activationOrder = order;
2097
2098
2099
2100
2101
2102void QMdiArea::setOption(AreaOption option,
bool on)
2105 d->options.setFlag(option, on);
2109
2110
2111
2112
2113bool QMdiArea::testOption(AreaOption option)
const
2115 return d_func()->options & option;
2119
2120
2121
2122
2123
2124
2125
2126
2127QMdiArea::ViewMode QMdiArea::viewMode()
const
2129 Q_D(
const QMdiArea);
2133void QMdiArea::setViewMode(ViewMode mode)
2136 d->setViewMode(mode);
2139#if QT_CONFIG(tabbar)
2141
2142
2143
2144
2145
2146
2147
2148
2149bool QMdiArea::documentMode()
const
2151 Q_D(
const QMdiArea);
2152 return d->documentMode;
2155void QMdiArea::setDocumentMode(
bool enabled)
2158 if (d->documentMode == enabled)
2161 d->documentMode = enabled;
2166
2167
2168
2169
2170
2171
2172
2173
2174bool QMdiArea::tabsClosable()
const
2176 Q_D(
const QMdiArea);
2177 return d->tabsClosable;
2180void QMdiArea::setTabsClosable(
bool closable)
2183 if (d->tabsClosable == closable)
2186 d->tabsClosable = closable;
2191
2192
2193
2194
2195
2196
2197
2198
2199bool QMdiArea::tabsMovable()
const
2201 Q_D(
const QMdiArea);
2202 return d->tabsMovable;
2205void QMdiArea::setTabsMovable(
bool movable)
2208 if (d->tabsMovable == movable)
2211 d->tabsMovable = movable;
2216#if QT_CONFIG(tabwidget)
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227QTabWidget::TabShape QMdiArea::tabShape()
const
2229 Q_D(
const QMdiArea);
2233void QMdiArea::setTabShape(QTabWidget::TabShape shape)
2236 if (d->tabShape == shape)
2239 d->tabShape = shape;
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253QTabWidget::TabPosition QMdiArea::tabPosition()
const
2255 Q_D(
const QMdiArea);
2256 return d->tabPosition;
2259void QMdiArea::setTabPosition(QTabWidget::TabPosition position)
2262 if (d->tabPosition == position)
2265 d->tabPosition = position;
2271
2272
2273void QMdiArea::childEvent(QChildEvent *childEvent)
2276 if (childEvent->type() == QEvent::ChildPolished) {
2277 if (QMdiSubWindow *mdiChild = qobject_cast<QMdiSubWindow *>(childEvent->child())) {
2278 if (d->childWindows.indexOf(mdiChild) == -1)
2279 d->appendChild(mdiChild);
2285
2286
2287void QMdiArea::resizeEvent(QResizeEvent *resizeEvent)
2290 if (d->childWindows.isEmpty()) {
2291 resizeEvent->ignore();
2295#if QT_CONFIG(tabbar)
2296 d->updateTabBarGeometry();
2302 if (d->isSubWindowsTiled) {
2303 d->tileCalledFromResizeEvent =
true;
2305 d->tileCalledFromResizeEvent =
false;
2306 d->isSubWindowsTiled =
true;
2307 d->startResizeTimer();
2313 bool hasMaximizedSubWindow =
false;
2317 const auto subWindows = d->childWindows;
2318 for (QMdiSubWindow *child : subWindows) {
2319 if (sanityCheck(child,
"QMdiArea::resizeEvent") && child->isMaximized()
2320 && child->size() != resizeEvent->size()) {
2321 auto realSize = resizeEvent->size();
2322 const auto minSizeHint = child->minimumSizeHint();
2326 if (minSizeHint.isValid())
2327 realSize = realSize.expandedTo(minSizeHint);
2328 child->resize(realSize);
2329 if (!hasMaximizedSubWindow)
2330 hasMaximizedSubWindow =
true;
2334 d->updateScrollBars();
2339 if (hasMaximizedSubWindow)
2340 d->startResizeTimer();
2342 d->arrangeMinimizedSubWindows();
2346
2347
2348void QMdiArea::timerEvent(QTimerEvent *timerEvent)
2351 if (timerEvent->id() == d->resizeTimer.id()) {
2352 d->resizeTimer.stop();
2353 d->arrangeMinimizedSubWindows();
2354 }
else if (timerEvent->id() == d->tabToPreviousTimer.id()) {
2355 d->tabToPreviousTimer.stop();
2356 if (d->indexToHighlighted < 0)
2358#if QT_CONFIG(rubberband)
2360 Q_ASSERT(d->indexToHighlighted < d->childWindows.size());
2361 Q_ASSERT(d->rubberBand);
2362 d->showRubberBandFor(d->childWindows.at(d->indexToHighlighted));
2368
2369
2370void QMdiArea::showEvent(QShowEvent *showEvent)
2373 if (!d->pendingRearrangements.isEmpty()) {
2374 bool skipPlacement =
false;
2376 const auto pendingRearrange = d->pendingRearrangements;
2377 for (Rearranger *rearranger : pendingRearrange) {
2380 if (rearranger->type() != Rearranger::IconTiler && !skipPlacement)
2381 skipPlacement =
true;
2382 d->rearrange(rearranger);
2384 d->pendingRearrangements.clear();
2386 if (skipPlacement && !d->pendingPlacements.isEmpty())
2387 d->pendingPlacements.clear();
2390 if (!d->pendingPlacements.isEmpty()) {
2395 const auto copy = d->pendingPlacements;
2396 for (QMdiSubWindow *window : copy) {
2399 if (d->viewMode == TabbedView && window->d_func()->isActive && !d->active) {
2400 d->showActiveWindowMaximized =
true;
2401 d->emitWindowActivated(window);
2404 if (!window->testAttribute(Qt::WA_Resized)) {
2405 QSize newSize(window->sizeHint().boundedTo(viewport()->size()));
2406 window->resize(newSize.expandedTo(qSmartMinSize(window)));
2408 if (!window->testAttribute(Qt::WA_Moved) && !window->isMinimized()
2409 && !window->isMaximized()) {
2410 d->place(d->placer, window);
2413 d->pendingPlacements.clear();
2416 d->setChildActivationEnabled(
true);
2417 d->activateCurrentWindow();
2419 QAbstractScrollArea::showEvent(showEvent);
2423
2424
2425bool QMdiArea::viewportEvent(QEvent *event)
2428 switch (event->type()) {
2429 case QEvent::ChildRemoved: {
2430 d->isSubWindowsTiled =
false;
2431 QObject *removedChild =
static_cast<QChildEvent *>(event)->child();
2432 for (
int i = 0; i < d->childWindows.size(); ++i) {
2433 QObject *child = d->childWindows.at(i);
2434 if (!child || child == removedChild || !child->parent()
2435 || child->parent() != viewport()) {
2436 if (!testOption(DontMaximizeSubWindowOnActivation)) {
2439 QWidget *mdiChild = qobject_cast<QWidget *>(removedChild);
2440 if (mdiChild && mdiChild->isMaximized())
2441 d->showActiveWindowMaximized =
true;
2443 d->disconnectSubWindow(child);
2444 const bool activeRemoved = i == d->indicesToActivatedChildren.at(0);
2445 d->childWindows.removeAt(i);
2446 d->indicesToActivatedChildren.removeAll(i);
2447 d->updateActiveWindow(i, activeRemoved);
2448 d->arrangeMinimizedSubWindows();
2452 d->updateScrollBars();
2455 case QEvent::Destroy:
2456 d->isSubWindowsTiled =
false;
2457 d->resetActiveWindow();
2458 d->childWindows.clear();
2459 qWarning(
"QMdiArea: Deleting the view port is undefined, use setViewport instead.");
2464 return QAbstractScrollArea::viewportEvent(event);
2468
2469
2470void QMdiArea::scrollContentsBy(
int dx,
int dy)
2473 const bool wasSubWindowsTiled = d->isSubWindowsTiled;
2474 d->ignoreGeometryChange =
true;
2475 viewport()->scroll(isLeftToRight() ? dx : -dx, dy);
2476 d->arrangeMinimizedSubWindows();
2477 d->ignoreGeometryChange =
false;
2478 if (wasSubWindowsTiled)
2479 d->isSubWindowsTiled =
true;
2483
2484
2485
2486
2487void QMdiArea::tileSubWindows()
2490 if (!d->regularTiler)
2491 d->regularTiler =
new RegularTiler;
2492 d->rearrange(d->regularTiler);
2496
2497
2498
2499
2500void QMdiArea::cascadeSubWindows()
2504 d->cascader =
new SimpleCascader;
2505 d->rearrange(d->cascader);
2509
2510
2511bool QMdiArea::event(QEvent *event)
2514 switch (event->type()) {
2515 case QEvent::WindowActivate: {
2516 d->isActivated =
true;
2517 if (d->childWindows.isEmpty())
2520 d->activateCurrentWindow();
2521 d->setChildActivationEnabled(
false,
true);
2524 case QEvent::WindowDeactivate:
2525 d->isActivated =
false;
2526 d->setChildActivationEnabled(
false,
true);
2528 case QEvent::StyleChange:
2532 if (d->isSubWindowsTiled) {
2534 d->isSubWindowsTiled =
true;
2537 case QEvent::WindowIconChange: {
2540 const auto subWindows = d->childWindows;
2541 for (QMdiSubWindow *window : subWindows) {
2542 if (sanityCheck(window,
"QMdiArea::WindowIconChange"))
2543 QCoreApplication::sendEvent(window, event);
2548 d->setActive(d->active,
false,
false);
2549 d->setChildActivationEnabled(
false);
2551#if QT_CONFIG(tabbar)
2552 case QEvent::LayoutDirectionChange:
2553 d->updateTabBarGeometry();
2559 return QAbstractScrollArea::event(event);
2563
2564
2565bool QMdiArea::eventFilter(QObject *object, QEvent *event)
2568 return QAbstractScrollArea::eventFilter(object, event);
2572 if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) {
2574 QKeyEvent *keyEvent =
static_cast<QKeyEvent *>(event);
2576 if (!(keyEvent->modifiers() & Qt::ControlModifier) && keyEvent->key() != Qt::Key_Control)
2577 return QAbstractScrollArea::eventFilter(object, event);
2580 QMdiArea *area = mdiAreaParent(
static_cast<QWidget *>(object));
2582 return QAbstractScrollArea::eventFilter(object, event);
2584 const bool keyPress = (event->type() == QEvent::KeyPress);
2590 switch (keyEvent->key()) {
2591 case Qt::Key_Control:
2593 area->d_func()->startTabToPreviousTimer();
2595 area->d_func()->activateHighlightedWindow();
2598 case Qt::Key_Backtab:
2600 area->d_func()->highlightNextSubWindow(keyEvent->key() == Qt::Key_Tab ? 1 : -1);
2602#if QT_CONFIG(rubberband)
2603 case Qt::Key_Escape:
2604 area->d_func()->hideRubberBand();
2610 return QAbstractScrollArea::eventFilter(object, event);
2613 QMdiSubWindow *subWindow = qobject_cast<QMdiSubWindow *>(object);
2617 if (event->type() == QEvent::ApplicationActivate && !d->active
2618 && isVisible() && !window()->isMinimized()) {
2619 d->activateCurrentWindow();
2620 }
else if (event->type() == QEvent::ApplicationDeactivate && d->active) {
2621 d->setActive(d->active,
false,
false);
2623 return QAbstractScrollArea::eventFilter(object, event);
2626 if (subWindow->mdiArea() !=
this)
2627 return QAbstractScrollArea::eventFilter(object, event);
2630 switch (event->type()) {
2632 case QEvent::Resize:
2633 if (d->tileCalledFromResizeEvent)
2635 d->updateScrollBars();
2636 if (!subWindow->isMinimized())
2637 d->isSubWindowsTiled =
false;
2640#if QT_CONFIG(tabbar)
2642 const int tabIndex = d->childWindows.indexOf(subWindow);
2643 if (!d->tabBar->isTabEnabled(tabIndex))
2644 d->tabBar->setTabEnabled(tabIndex,
true);
2652 if (!event->spontaneous())
2653 d->isSubWindowsTiled =
false;
2655#if QT_CONFIG(rubberband)
2657 if (d->childWindows.indexOf(subWindow) == d->indexToHighlighted)
2658 d->hideRubberBand();
2661#if QT_CONFIG(tabbar)
2662 case QEvent::WindowTitleChange:
2663 case QEvent::ModifiedChange:
2665 d->tabBar->setTabText(d->childWindows.indexOf(subWindow), tabTextFor(subWindow));
2667 case QEvent::WindowIconChange:
2669 d->tabBar->setTabIcon(d->childWindows.indexOf(subWindow), subWindow->windowIcon());
2675 return QAbstractScrollArea::eventFilter(object, event);
2679
2680
2681void QMdiArea::paintEvent(QPaintEvent *paintEvent)
2684 QPainter painter(d->viewport);
2685 for (
const QRect &exposedRect : paintEvent->region())
2686 painter.fillRect(exposedRect, d->background);
2690
2691
2692
2693
2694
2695
2696void QMdiArea::setupViewport(QWidget *viewport)
2700 viewport->setAttribute(Qt::WA_OpaquePaintEvent, d->background.isOpaque());
2703 const auto subWindows = d->childWindows;
2704 for (QMdiSubWindow *child : subWindows) {
2705 if (!sanityCheck(child,
"QMdiArea::setupViewport"))
2707 child->setParent(viewport, child->windowFlags());
2713#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...