Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qmdiarea.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
121#include "qmdiarea_p.h"
122
123#include <QApplication>
124#include <QStyle>
125#include <QChildEvent>
126#include <QResizeEvent>
127#include <QScrollBar>
128#include <QtAlgorithms>
129#include <QPainter>
130#include <QFontMetrics>
131#include <QStyleOption>
132#include <QDebug>
133#include <qmath.h>
134#if QT_CONFIG(menu)
135#include <qmenu.h>
136#endif
137#include <private/qlayoutengine_p.h>
138
139#include <algorithm>
140
142
143using namespace Qt::StringLiterals;
144using namespace QMdi;
145
146// Asserts in debug mode, gives warning otherwise.
147static bool sanityCheck(const QMdiSubWindow * const child, const char *where)
148{
149 if (Q_UNLIKELY(!child)) {
150 const char error[] = "null pointer";
151 Q_ASSERT_X(false, where, error);
152 qWarning("%s:%s", where, error);
153 return false;
154 }
155 return true;
156}
157
158static bool sanityCheck(const QList<QWidget *> &widgets, const int index, const char *where)
159{
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);
164 return false;
165 }
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);
170 return false;
171 }
172 return true;
173}
174
175static void setIndex(int *index, int candidate, int min, int max, bool isIncreasing)
176{
177 if (!index)
178 return;
179
180 if (isIncreasing) {
181 if (candidate > max)
182 *index = min;
183 else
184 *index = qMax(candidate, min);
185 } else {
186 if (candidate < min)
187 *index = max;
188 else
189 *index = qMin(candidate, max);
190 }
191 Q_ASSERT(*index >= min && *index <= max);
192}
193
194static inline bool useScrollBar(const QRect &childrenRect, const QSize &maxViewportSize,
195 Qt::Orientation orientation)
196{
197 if (orientation == Qt::Horizontal)
198 return childrenRect.width() > maxViewportSize.width()
199 || childrenRect.left() < 0
200 || childrenRect.right() >= maxViewportSize.width();
201 else
202 return childrenRect.height() > maxViewportSize.height()
203 || childrenRect.top() < 0
204 || childrenRect.bottom() >= maxViewportSize.height();
205}
206
207// Returns the closest mdi area containing the widget (if any).
209{
210 if (!widget)
211 return nullptr;
212
214 while (parent) {
215 if (QMdiArea *area = qobject_cast<QMdiArea *>(parent))
216 return area;
217 parent = parent->parentWidget();
218 }
219 return nullptr;
220}
221
222#if QT_CONFIG(tabwidget)
224#endif // QT_CONFIG(tabwidget)
225
226static inline QString tabTextFor(QMdiSubWindow *subWindow)
227{
228 if (!subWindow)
229 return QString();
230
231 QString title = subWindow->windowTitle();
232 if (subWindow->isWindowModified()) {
233 title.replace("[*]"_L1, "*"_L1);
234 } else {
237 }
238
239 return title.isEmpty() ? QMdiArea::tr("(Untitled)") : title;
240}
241
246{
247 if (widgets.isEmpty())
248 return;
249
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;
256
257 int i = 0;
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)
262 continue;
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) {
267 y2 *= 2;
268 if (nrows != 2)
269 y2 += 1;
270 else
271 y2 = domain.bottom();
272 }
273 if (col == ncols - 1 && x2 != domain.right())
274 x2 = domain.right();
275 if (row == nrows - 1 && y2 != domain.bottom())
276 y2 = domain.bottom();
277 if (!sanityCheck(widgets, i, "RegularTiler"))
278 continue;
279 QWidget *widget = widgets.at(i++);
280 QRect newGeometry = QRect(QPoint(x1, y1), QPoint(x2, y2));
282 }
283 }
284}
285
290{
291 if (widgets.isEmpty())
292 return;
293
294 // Tunables:
295 const int topOffset = 0;
296 const int bottomOffset = 50;
297 const int leftOffset = 0;
298 const int rightOffset = 100;
299 const int dx = 10;
300
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)
307
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;
312
313 int i = 0;
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"))
319 continue;
320 QWidget *widget = widgets.at(i++);
321 QRect newGeometry = QRect(QPoint(x, y), widget->sizeHint());
323 if (i == n)
324 return;
325 }
326 }
327}
328
333{
334 if (widgets.isEmpty() || !sanityCheck(widgets, 0, "IconTiler"))
335 return;
336
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);
342
343 int i = 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"))
349 continue;
350 QWidget *widget = widgets.at(i++);
351 QPoint newPos(x, y);
352 QRect newGeometry = QRect(newPos.x(), newPos.y(), widget->width(), widget->height());
354 if (i == n)
355 return;
356 }
357 }
358}
359
364int MinOverlapPlacer::accumulatedOverlap(const QRect &source, const QList<QRect> &rects)
365{
366 int accOverlap = 0;
367 for (const QRect &rect : rects) {
368 QRect intersection = source.intersected(rect);
369 accOverlap += intersection.width() * intersection.height();
370 }
371 return accOverlap;
372}
373
374
380QRect MinOverlapPlacer::findMinOverlapRect(const QList<QRect> &source, const QList<QRect> &rects)
381{
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;
389 }
390 }
391 return minAccOverlapRect;
392}
393
398QList<QRect> MinOverlapPlacer::getCandidatePlacements(const QSize &size, const QList<QRect> &rects,
399 const QRect &domain)
400{
402
403 QList<int> xlist;
404 xlist.reserve(2 + rects.size());
405 xlist << domain.left() << domain.right() - size.width() + 1;
406
407 QList<int> ylist;
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;
412
413 for (const QRect &rect : rects) {
414 xlist << rect.right() + 1;
415 ylist << rect.bottom() + 1;
416 }
417
418 std::sort(xlist.begin(), xlist.end());
419 xlist.erase(std::unique(xlist.begin(), xlist.end()), xlist.end());
420
421 std::sort(ylist.begin(), ylist.end());
422 ylist.erase(std::unique(ylist.begin(), ylist.end()), ylist.end());
423
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);
428 return result;
429}
430
436QList<QRect> MinOverlapPlacer::findNonInsiders(const QRect &domain, QList<QRect> &source)
437{
438 const auto containedInDomain =
439 [domain](const QRect &srcRect) { return domain.contains(srcRect); };
440
441 const auto firstOut = std::stable_partition(source.begin(), source.end(), containedInDomain);
442
444 result.reserve(source.end() - firstOut);
445 std::copy(firstOut, source.end(), std::back_inserter(result));
446
447 source.erase(firstOut, source.end());
448
449 return result;
450}
451
457QList<QRect> MinOverlapPlacer::findMaxOverlappers(const QRect &domain, const QList<QRect> &source)
458{
460 result.reserve(source.size());
461
462 int maxOverlap = -1;
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;
469 result.clear();
470 }
471 result << srcRect;
472 }
473 }
474
475 return result;
476}
477
484QPoint MinOverlapPlacer::findBestPlacement(const QRect &domain, const QList<QRect> &rects,
486{
487 const QList<QRect> nonInsiders = findNonInsiders(domain, source);
488
489 if (!source.empty())
490 return findMinOverlapRect(source, rects).topLeft();
491
492 QList<QRect> maxOverlappers = findMaxOverlappers(domain, nonInsiders);
493 return findMinOverlapRect(maxOverlappers, rects).topLeft();
494}
495
496
504 const QRect &domain) const
505{
506 if (size.isEmpty() || !domain.isValid())
507 return QPoint();
508 for (const QRect &rect : rects) {
509 if (!rect.isValid())
510 return QPoint();
511 }
512
513 QList<QRect> candidates = getCandidatePlacements(size, rects, domain);
514 return findBestPlacement(domain, rects, candidates);
515}
516
517#if QT_CONFIG(tabbar)
518class QMdiAreaTabBar : public QTabBar
519{
520public:
521 QMdiAreaTabBar(QWidget *parent) : QTabBar(parent) {}
522
523protected:
524 void mousePressEvent(QMouseEvent *event) override;
525#ifndef QT_NO_CONTEXTMENU
526 void contextMenuEvent(QContextMenuEvent *event) override;
527#endif
528
529private:
530 QMdiSubWindow *subWindowFromIndex(int index) const;
531};
532
536void QMdiAreaTabBar::mousePressEvent(QMouseEvent *event)
537{
538 if (event->button() != Qt::MiddleButton) {
540 return;
541 }
542
543 QMdiSubWindow *subWindow = subWindowFromIndex(tabAt(event->position().toPoint()));
544 if (!subWindow) {
545 event->ignore();
546 return;
547 }
548
549 subWindow->close();
550}
551
552#ifndef QT_NO_CONTEXTMENU
556void QMdiAreaTabBar::contextMenuEvent(QContextMenuEvent *event)
557{
558 QPointer<QMdiSubWindow> subWindow = subWindowFromIndex(tabAt(event->pos()));
559 if (!subWindow || subWindow->isHidden()) {
560 event->ignore();
561 return;
562 }
563
564#if QT_CONFIG(menu)
565 QMdiSubWindowPrivate *subWindowPrivate = subWindow->d_func();
566 if (!subWindowPrivate->systemMenu) {
567 event->ignore();
568 return;
569 }
570
571 QMdiSubWindow *currentSubWindow = subWindowFromIndex(currentIndex());
572 Q_ASSERT(currentSubWindow);
573
574 // We don't want these actions to show up in the system menu when the
575 // current sub-window is maximized, i.e. covers the entire viewport.
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);
583 }
584
585 // Show system menu.
586 subWindowPrivate->systemMenu->exec(event->globalPos());
587 if (!subWindow)
588 return;
589
590 // Restore action visibility.
591 subWindowPrivate->updateActions();
592#endif // QT_CONFIG(menu)
593}
594#endif // QT_NO_CONTEXTMENU
595
599QMdiSubWindow *QMdiAreaTabBar::subWindowFromIndex(int index) const
600{
601 if (index < 0 || index >= count())
602 return nullptr;
603
604 QMdiArea *mdiArea = qobject_cast<QMdiArea *>(parentWidget());
605 Q_ASSERT(mdiArea);
606
607 const QList<QMdiSubWindow *> subWindows = mdiArea->subWindowList();
608 Q_ASSERT(index < subWindows.size());
609
610 QMdiSubWindow *subWindow = mdiArea->subWindowList().at(index);
611 Q_ASSERT(subWindow);
612
613 return subWindow;
614}
615#endif // QT_CONFIG(tabbar)
616
621 : cascader(nullptr),
622 regularTiler(nullptr),
623 iconTiler(nullptr),
624 placer(nullptr),
625#if QT_CONFIG(rubberband)
626 rubberBand(nullptr),
627#endif
628#if QT_CONFIG(tabbar)
629 tabBar(nullptr),
630#endif
631 activationOrder(QMdiArea::CreationOrder),
632 viewMode(QMdiArea::SubWindowView),
633#if QT_CONFIG(tabbar)
634 documentMode(false),
635 tabsClosable(false),
636 tabsMovable(false),
637#endif
638#if QT_CONFIG(tabwidget)
639 tabShape(QTabWidget::Rounded),
640 tabPosition(QTabWidget::North),
641#endif
642 ignoreGeometryChange(false),
643 ignoreWindowStateChange(false),
644 isActivated(false),
645 isSubWindowsTiled(false),
646 showActiveWindowMaximized(false),
647 tileCalledFromResizeEvent(false),
648 updatesDisabledByUs(false),
649 inViewModeChange(false),
650 indexToNextWindow(-1),
651 indexToPreviousWindow(-1),
652 indexToHighlighted(-1),
653 indexToLastActiveTab(-1),
654 resizeTimerId(-1),
655 tabToPreviousTimerId(-1)
656{
657}
658
663{
665 return;
666
667 Q_Q(QMdiArea);
668 if (!aboutToActivate)
669 aboutToBecomeActive = qobject_cast<QMdiSubWindow *>(q->sender());
670 else
671 aboutToBecomeActive = aboutToActivate;
673
674 foreach (QMdiSubWindow *child, childWindows) {
675 if (!sanityCheck(child, "QMdiArea::deactivateAllWindows") || aboutToBecomeActive == child)
676 continue;
677 // We don't want to handle signals caused by child->showNormal().
680 showActiveWindowMaximized = child->isMaximized() && child->isVisible();
681 if (showActiveWindowMaximized && child->isMaximized()) {
682 if (q->updatesEnabled()) {
683 updatesDisabledByUs = true;
684 q->setUpdatesEnabled(false);
685 }
686 child->showNormal();
687 }
688 if (child->isMinimized() && !child->isShaded() && !windowStaysOnTop(child))
689 child->lower();
691 child->d_func()->setActive(false);
692 }
693}
694
699 Qt::WindowStates newState)
700{
702 return;
703
704 Q_Q(QMdiArea);
705 QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(q->sender());
706 if (!child)
707 return;
708
709 // windowActivated
710 if (!(oldState & Qt::WindowActive) && (newState & Qt::WindowActive))
712 // windowDeactivated
713 else if ((oldState & Qt::WindowActive) && !(newState & Qt::WindowActive))
715
716 // windowMinimized
717 if (!(oldState & Qt::WindowMinimized) && (newState & Qt::WindowMinimized)) {
718 isSubWindowsTiled = false;
720 // windowMaximized
721 } else if (!(oldState & Qt::WindowMaximized) && (newState & Qt::WindowMaximized)) {
723 // windowRestored
726 if (oldState & Qt::WindowMinimized)
728 }
729}
730
732{
733#if !QT_CONFIG(tabbar)
735#else
736 if (!tabBar || index < 0)
737 return;
738
739 // If the previous active sub-window was hidden, disable the tab.
740 if (indexToLastActiveTab >= 0 && indexToLastActiveTab < tabBar->count()
743 if (lastActive && lastActive->isHidden())
744 tabBar->setTabEnabled(indexToLastActiveTab, false);
745 }
746
749 QMdiSubWindow *subWindow = childWindows.at(index);
750 Q_ASSERT(subWindow);
751 activateWindow(subWindow);
752#endif // QT_CONFIG(tabbar)
753}
754
756{
757#if !QT_CONFIG(tabbar)
759#else
760 QMdiSubWindow *subWindow = childWindows.at(index);
761 Q_ASSERT(subWindow);
762 subWindow->close();
763#endif // QT_CONFIG(tabbar)
764}
765
766void QMdiAreaPrivate::_q_moveTab(int from, int to)
767{
768#if !QT_CONFIG(tabbar)
769 Q_UNUSED(from);
770 Q_UNUSED(to);
771#else
772 childWindows.move(from, to);
773#endif // QT_CONFIG(tabbar)
774}
775
780{
781 Q_Q(QMdiArea);
783
784 if (child->parent() != viewport)
785 child->setParent(viewport, child->windowFlags());
787
788 if (!child->testAttribute(Qt::WA_Resized) && q->isVisible()) {
789 QSize newSize(child->sizeHint().boundedTo(viewport->size()));
790 child->resize(newSize.expandedTo(qSmartMinSize(child)));
791 }
792
793 if (!placer)
796
797 if (hbarpolicy != Qt::ScrollBarAlwaysOff)
799 else
801
802 if (vbarpolicy != Qt::ScrollBarAlwaysOff)
804 else
806
810
811#if QT_CONFIG(tabbar)
812 if (tabBar) {
813 tabBar->addTab(child->windowIcon(), tabTextFor(child));
814 updateTabBarGeometry();
817 }
818#endif
819
820 if (!(child->windowFlags() & Qt::SubWindow))
821 child->setWindowFlags(Qt::SubWindow);
822 child->installEventFilter(q);
823
824 QObject::connect(child, SIGNAL(aboutToActivate()), q, SLOT(_q_deactivateAllWindows()));
825 QObject::connect(child, SIGNAL(windowStateChanged(Qt::WindowStates,Qt::WindowStates)),
826 q, SLOT(_q_processWindowStateChanged(Qt::WindowStates,Qt::WindowStates)));
827}
828
833{
834 if (!placer || !child)
835 return;
836
837 Q_Q(QMdiArea);
838 if (!q->isVisible()) {
839 // The window is only laid out when it's added to QMdiArea,
840 // so there's no need to check that we don't have it in the
841 // list already. appendChild() ensures that.
843 return;
844 }
845
846 QList<QRect> rects;
847 rects.reserve(childWindows.size());
848 QRect parentRect = q->rect();
849 foreach (QMdiSubWindow *window, childWindows) {
850 if (!sanityCheck(window, "QMdiArea::place") || window == child || !window->isVisibleTo(q)
851 || !window->testAttribute(Qt::WA_Moved)) {
852 continue;
853 }
854 QRect occupiedGeometry;
855 if (window->isMaximized()) {
856 occupiedGeometry = QRect(window->d_func()->oldGeometry.topLeft(),
857 window->d_func()->restoreSize);
858 } else {
859 occupiedGeometry = window->geometry();
860 }
861 rects.append(QStyle::visualRect(child->layoutDirection(), parentRect, occupiedGeometry));
862 }
863 QPoint newPos = placer->place(child->size(), rects, parentRect);
864 QRect newGeometry = QRect(newPos.x(), newPos.y(), child->width(), child->height());
865 child->setGeometry(QStyle::visualRect(child->layoutDirection(), parentRect, newGeometry));
866}
867
872{
873 if (!rearranger)
874 return;
875
876 Q_Q(QMdiArea);
877 if (!q->isVisible()) {
878 // Compress if we already have the rearranger in the list.
879 int index = pendingRearrangements.indexOf(rearranger);
880 if (index != -1)
882 else
883 pendingRearrangements.append(rearranger);
884 return;
885 }
886
888 const bool reverseList = rearranger->type() == Rearranger::RegularTiler;
889 const QList<QMdiSubWindow *> subWindows = subWindowList(activationOrder, reverseList);
890 QSize minSubWindowSize;
891 foreach (QMdiSubWindow *child, subWindows) {
892 if (!sanityCheck(child, "QMdiArea::rearrange") || !child->isVisible())
893 continue;
894 if (rearranger->type() == Rearranger::IconTiler) {
895 if (child->isMinimized() && !child->isShaded())
897 } else {
898 if (child->isMinimized() && !child->isShaded())
899 continue;
900 if (child->isMaximized() || child->isShaded())
901 child->showNormal();
902 minSubWindowSize = minSubWindowSize.expandedTo(child->minimumSize())
903 .expandedTo(child->d_func()->internalMinimumSize);
905 }
906 }
907
908 QRect domain = viewport->rect();
909 if (rearranger->type() == Rearranger::RegularTiler && !widgets.isEmpty())
910 domain = resizeToMinimumTileSize(minSubWindowSize, widgets.size());
911
912 rearranger->rearrange(widgets, domain);
913
914 if (rearranger->type() == Rearranger::RegularTiler && !widgets.isEmpty()) {
915 isSubWindowsTiled = true;
917 } else if (rearranger->type() == Rearranger::SimpleCascader) {
918 isSubWindowsTiled = false;
919 }
920}
921
928{
929 if (!iconTiler)
930 iconTiler = new IconTiler;
932}
933
938{
939 if (childWindows.isEmpty()) {
940 Q_ASSERT(!child);
942 return;
943 }
944
945 if (!child) {
946 if (active) {
947 Q_ASSERT(active->d_func()->isActive);
948 active->d_func()->setActive(false);
950 }
951 return;
952 }
953
954 if (child->isHidden() || child == active)
955 return;
956
957 if (child->d_func()->isActive && active == nullptr)
958 child->d_func()->isActive = false;
959
960 child->d_func()->setActive(true);
961}
962
967{
968 QMdiSubWindow *current = q_func()->currentSubWindow();
969 if (current && !isExplicitlyDeactivated(current)) {
970 current->d_func()->activationEnabled = true;
971 current->d_func()->setActive(true, /*changeFocus=*/false);
972 }
973}
974
976{
977 if (indexToHighlighted < 0)
978 return;
979
981 if (tabToPreviousTimerId != -1)
983 else
985#if QT_CONFIG(rubberband)
986 hideRubberBand();
987#endif
988}
989
994{
995 Q_Q(QMdiArea);
996 Q_ASSERT(activeWindow);
997 if (activeWindow == active)
998 return;
999 Q_ASSERT(activeWindow->d_func()->isActive);
1000
1002 _q_deactivateAllWindows(activeWindow);
1004
1005 // This is true only if 'DontMaximizeSubWindowOnActivation' is disabled
1006 // and the previous active window was maximized.
1008 if (!activeWindow->isMaximized())
1009 activeWindow->showMaximized();
1011 }
1012
1013 // Put in front to update activation order.
1014 const int indexToActiveWindow = childWindows.indexOf(activeWindow);
1015 Q_ASSERT(indexToActiveWindow != -1);
1016 const int index = indicesToActivatedChildren.indexOf(indexToActiveWindow);
1017 Q_ASSERT(index != -1);
1019 internalRaise(activeWindow);
1020
1021 if (updatesDisabledByUs) {
1022 q->setUpdatesEnabled(true);
1023 updatesDisabledByUs = false;
1024 }
1025
1026 Q_ASSERT(aboutToBecomeActive == activeWindow);
1027 active = activeWindow;
1028 aboutToBecomeActive = nullptr;
1029 Q_ASSERT(active->d_func()->isActive);
1030
1031#if QT_CONFIG(tabbar)
1032 if (tabBar && tabBar->currentIndex() != indexToActiveWindow)
1033 tabBar->setCurrentIndex(indexToActiveWindow);
1034#endif
1035
1038
1039 emit q->subWindowActivated(active);
1040}
1041
1046{
1047 Q_Q(QMdiArea);
1048 if (deactivatedWindow) {
1049 if (deactivatedWindow != active)
1050 return;
1051 active = nullptr;
1053 && !isExplicitlyDeactivated(deactivatedWindow) && !q->window()->isMinimized()) {
1054 return;
1055 }
1056 emit q->subWindowActivated(nullptr);
1057 return;
1058 }
1059
1061 return;
1062
1063 active = nullptr;
1064 emit q->subWindowActivated(nullptr);
1065}
1066
1070void QMdiAreaPrivate::updateActiveWindow(int removedIndex, bool activeRemoved)
1071{
1073
1074#if QT_CONFIG(tabbar)
1075 if (tabBar && removedIndex >= 0) {
1076 const QSignalBlocker blocker(tabBar);
1077 tabBar->removeTab(removedIndex);
1078 updateTabBarGeometry();
1079 }
1080#endif
1081
1082 if (childWindows.isEmpty()) {
1085 return;
1086 }
1087
1088 if (indexToHighlighted >= 0) {
1089#if QT_CONFIG(rubberband)
1090 // Hide rubber band if highlighted window is removed.
1091 if (indexToHighlighted == removedIndex)
1092 hideRubberBand();
1093 else
1094#endif
1095 // or update index if necessary.
1096 if (indexToHighlighted > removedIndex)
1098 }
1099
1100 // Update indices list
1101 for (int i = 0; i < indicesToActivatedChildren.size(); ++i) {
1103 if (*index > removedIndex)
1104 --*index;
1105 }
1106
1107 if (!activeRemoved)
1108 return;
1109
1110 // Activate next window.
1112 if (next)
1114}
1115
1120{
1122 return;
1123
1124 Q_Q(QMdiArea);
1125 QSize maxSize = q->maximumViewportSize();
1126 QSize hbarExtent = hbar->sizeHint();
1127 QSize vbarExtent = vbar->sizeHint();
1128
1129 if (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents, nullptr, q)) {
1130 const int doubleFrameWidth = frameWidth * 2;
1131 if (hbarpolicy == Qt::ScrollBarAlwaysOn)
1132 maxSize.rheight() -= doubleFrameWidth;
1133 if (vbarpolicy == Qt::ScrollBarAlwaysOn)
1134 maxSize.rwidth() -= doubleFrameWidth;
1135 hbarExtent.rheight() += doubleFrameWidth;
1136 vbarExtent.rwidth() += doubleFrameWidth;
1137 }
1138
1139 const QRect childrenRect = active && active->isMaximized()
1140 ? active->geometry() : viewport->childrenRect();
1141 bool useHorizontalScrollBar = useScrollBar(childrenRect, maxSize, Qt::Horizontal);
1142 bool useVerticalScrollBar = useScrollBar(childrenRect, maxSize, Qt::Vertical);
1143
1144 if (useHorizontalScrollBar && !useVerticalScrollBar) {
1145 const QSize max = maxSize - QSize(0, hbarExtent.height());
1146 useVerticalScrollBar = useScrollBar(childrenRect, max, Qt::Vertical);
1147 }
1148
1149 if (useVerticalScrollBar && !useHorizontalScrollBar) {
1150 const QSize max = maxSize - QSize(vbarExtent.width(), 0);
1151 useHorizontalScrollBar = useScrollBar(childrenRect, max, Qt::Horizontal);
1152 }
1153
1154 if (useHorizontalScrollBar && hbarpolicy != Qt::ScrollBarAlwaysOn)
1155 maxSize.rheight() -= hbarExtent.height();
1156 if (useVerticalScrollBar && vbarpolicy != Qt::ScrollBarAlwaysOn)
1157 maxSize.rwidth() -= vbarExtent.width();
1158
1159 QRect viewportRect(QPoint(0, 0), maxSize);
1160 const int startX = q->isLeftToRight() ? childrenRect.left() : viewportRect.right()
1161 - childrenRect.right();
1162
1163 // Horizontal scroll bar.
1164 if (isSubWindowsTiled && hbar->value() != 0)
1165 hbar->setValue(0);
1166 const int xOffset = startX + hbar->value();
1167 hbar->setRange(qMin(0, xOffset),
1168 qMax(0, xOffset + childrenRect.width() - viewportRect.width()));
1169 hbar->setPageStep(childrenRect.width());
1170 hbar->setSingleStep(childrenRect.width() / 20);
1171
1172 // Vertical scroll bar.
1173 if (isSubWindowsTiled && vbar->value() != 0)
1174 vbar->setValue(0);
1175 const int yOffset = childrenRect.top() + vbar->value();
1176 vbar->setRange(qMin(0, yOffset),
1177 qMax(0, yOffset + childrenRect.height() - viewportRect.height()));
1178 vbar->setPageStep(childrenRect.height());
1179 vbar->setSingleStep(childrenRect.height() / 20);
1180}
1181
1186{
1187 if (!sanityCheck(mdiChild, "QMdiArea::internalRaise") || childWindows.size() < 2)
1188 return;
1189
1190 QMdiSubWindow *stackUnderChild = nullptr;
1191 if (!windowStaysOnTop(mdiChild)) {
1192 const auto children = viewport->children(); // take a copy, as raising/stacking under changes the order
1193 for (QObject *object : children) {
1194 QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(object);
1195 if (!child || !childWindows.contains(child))
1196 continue;
1197 if (!child->isHidden() && windowStaysOnTop(child)) {
1198 if (stackUnderChild)
1199 child->stackUnder(stackUnderChild);
1200 else
1201 child->raise();
1202 stackUnderChild = child;
1203 }
1204 }
1205 }
1206
1207 if (stackUnderChild)
1208 mdiChild->stackUnder(stackUnderChild);
1209 else
1210 mdiChild->raise();
1211}
1212
1213QRect QMdiAreaPrivate::resizeToMinimumTileSize(const QSize &minSubWindowSize, int subWindowCount)
1214{
1215 Q_Q(QMdiArea);
1216 if (!minSubWindowSize.isValid() || subWindowCount <= 0)
1217 return viewport->rect();
1218
1219 // Calculate minimum size.
1220 const int columns = qMax(qCeil(qSqrt(qreal(subWindowCount))), 1);
1221 const int rows = qMax((subWindowCount % columns) ? (subWindowCount / columns + 1)
1222 : (subWindowCount / columns), 1);
1223 const int minWidth = minSubWindowSize.width() * columns;
1224 const int minHeight = minSubWindowSize.height() * rows;
1225
1226 // Increase area size if necessary. Scroll bars are provided if we're not able
1227 // to resize to the minimum size.
1229 QWidget *topLevel = q;
1230 // Find the topLevel for this area, either a real top-level or a sub-window.
1231 while (topLevel && !topLevel->isWindow() && topLevel->windowType() != Qt::SubWindow)
1232 topLevel = topLevel->parentWidget();
1233 // We don't want sub-subwindows to be placed at the edge, thus add 2 pixels.
1234 int minAreaWidth = minWidth + left + right + 2;
1235 int minAreaHeight = minHeight + top + bottom + 2;
1236 if (hbar->isVisible())
1237 minAreaHeight += hbar->height();
1238 if (vbar->isVisible())
1239 minAreaWidth += vbar->width();
1240 if (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents, nullptr, q)) {
1241 const int frame = q->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, nullptr, q);
1242 minAreaWidth += 2 * frame;
1243 minAreaHeight += 2 * frame;
1244 }
1245 const QSize diff = QSize(minAreaWidth, minAreaHeight).expandedTo(q->size()) - q->size();
1246 // Only resize topLevel widget if scroll bars are disabled.
1247 if (hbarpolicy == Qt::ScrollBarAlwaysOff)
1248 topLevel->resize(topLevel->size().width() + diff.width(), topLevel->size().height());
1249 if (vbarpolicy == Qt::ScrollBarAlwaysOff)
1250 topLevel->resize(topLevel->size().width(), topLevel->size().height() + diff.height());
1251 }
1252
1253 QRect domain = viewport->rect();
1254
1255 // Adjust domain width and provide horizontal scroll bar.
1256 if (domain.width() < minWidth) {
1257 domain.setWidth(minWidth);
1258 if (hbarpolicy == Qt::ScrollBarAlwaysOff)
1259 q->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
1260 else
1261 hbar->setValue(0);
1262 }
1263 // Adjust domain height and provide vertical scroll bar.
1264 if (domain.height() < minHeight) {
1265 domain.setHeight(minHeight);
1266 if (vbarpolicy == Qt::ScrollBarAlwaysOff)
1267 q->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
1268 else
1269 vbar->setValue(0);
1270 }
1271 return domain;
1272}
1273
1278{
1279 return hbarpolicy != Qt::ScrollBarAlwaysOff || vbarpolicy != Qt::ScrollBarAlwaysOff;
1280}
1281
1286{
1287 if (childWindows.size() != 1)
1288 return false;
1289
1290 QMdiSubWindow *last = childWindows.at(0);
1291 if (!last)
1292 return true;
1293
1295 return false;
1296
1297 return last->d_func()->data.is_closing;
1298}
1299
1303void QMdiAreaPrivate::setChildActivationEnabled(bool enable, bool onlyNextActivationEvent) const
1304{
1305 foreach (QMdiSubWindow *subWindow, childWindows) {
1306 if (!subWindow || !subWindow->isVisible())
1307 continue;
1308 if (onlyNextActivationEvent)
1309 subWindow->d_func()->ignoreNextActivationEvent = !enable;
1310 else
1311 subWindow->d_func()->activationEnabled = enable;
1312 }
1313}
1314
1320{
1321 if (childWindows.isEmpty())
1322 return;
1323
1326 const bool enable = policy != Qt::ScrollBarAlwaysOff;
1327 foreach (QMdiSubWindow *child, childWindows) {
1328 if (!sanityCheck(child, "QMdiArea::scrollBarPolicyChanged"))
1329 continue;
1330 child->setOption(option, enable);
1331 }
1333}
1334
1337{
1339 if (childWindows.isEmpty())
1340 return list;
1341
1343 foreach (QMdiSubWindow *child, childWindows) {
1344 if (!child)
1345 continue;
1346 if (!reversed)
1347 list.append(child);
1348 else
1350 }
1351 } else if (order == QMdiArea::StackingOrder) {
1352 for (QObject *object : viewport->children()) {
1353 QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(object);
1354 if (!child || !childWindows.contains(child))
1355 continue;
1356 if (!reversed)
1357 list.append(child);
1358 else
1360 }
1361 } else { // ActivationHistoryOrder
1363 for (int i = indicesToActivatedChildren.size() - 1; i >= 0; --i) {
1365 if (!child)
1366 continue;
1367 if (!reversed)
1368 list.append(child);
1369 else
1371 }
1372 }
1373 return list;
1374}
1375
1380{
1381 if (!subWindow)
1382 return;
1383
1384 Q_Q(QMdiArea);
1385 QObject::disconnect(subWindow, nullptr, q, nullptr);
1386 subWindow->removeEventFilter(q);
1387}
1388
1393 int removedIndex, int fromIndex) const
1394{
1395 if (childWindows.isEmpty())
1396 return nullptr;
1397
1398 Q_Q(const QMdiArea);
1399 const QList<QMdiSubWindow *> subWindows = q->subWindowList(order);
1400 QMdiSubWindow *current = nullptr;
1401
1402 if (removedIndex < 0) {
1403 if (fromIndex >= 0 && fromIndex < subWindows.size())
1404 current = childWindows.at(fromIndex);
1405 else
1406 current = q->currentSubWindow();
1407 }
1408
1409 // There's no current sub-window (removed or deactivated),
1410 // so we have to pick the last active or the next in creation order.
1411 if (!current) {
1412 if (removedIndex >= 0 && order == QMdiArea::CreationOrder) {
1413 int candidateIndex = -1;
1414 setIndex(&candidateIndex, removedIndex, 0, subWindows.size() - 1, true);
1415 current = childWindows.at(candidateIndex);
1416 } else {
1417 current = subWindows.back();
1418 }
1419 }
1420 Q_ASSERT(current);
1421
1422 // Find the index for the current sub-window in the given activation order
1423 const int indexToCurrent = subWindows.indexOf(current);
1424 const bool increasing = increaseFactor > 0;
1425
1426 // and use that index + increseFactor as a candidate.
1427 int index = -1;
1428 setIndex(&index, indexToCurrent + increaseFactor, 0, subWindows.size() - 1, increasing);
1429 Q_ASSERT(index != -1);
1430
1431 // Try to find another window if the candidate is hidden.
1432 while (subWindows.at(index)->isHidden()) {
1433 setIndex(&index, index + increaseFactor, 0, subWindows.size() - 1, increasing);
1434 if (index == indexToCurrent)
1435 break;
1436 }
1437
1438 if (!subWindows.at(index)->isHidden())
1439 return subWindows.at(index);
1440 return nullptr;
1441}
1442
1447{
1448 if (childWindows.size() == 1)
1449 return;
1450
1451 Q_Q(QMdiArea);
1452 // There's no highlighted sub-window atm, use current.
1453 if (indexToHighlighted < 0) {
1454 QMdiSubWindow *current = q->currentSubWindow();
1455 if (!current)
1456 return;
1458 }
1459
1462
1463 QMdiSubWindow *highlight = nextVisibleSubWindow(increaseFactor, activationOrder, -1, indexToHighlighted);
1464 if (!highlight)
1465 return;
1466
1467#if QT_CONFIG(rubberband)
1468 if (!rubberBand) {
1469 rubberBand = new QRubberBand(QRubberBand::Rectangle, q);
1470 // For accessibility to identify this special widget.
1471 rubberBand->setObjectName("qt_rubberband"_L1);
1472 rubberBand->setWindowFlags(rubberBand->windowFlags() | Qt::WindowStaysOnTopHint);
1473 }
1474#endif
1475
1476 // Only highlight if we're not switching back to the previously active window (Ctrl-Tab once).
1477#if QT_CONFIG(rubberband)
1478 if (tabToPreviousTimerId == -1)
1479 showRubberBandFor(highlight);
1480#endif
1481
1484}
1485
1486#if QT_CONFIG(rubberband)
1487void QMdiAreaPrivate::showRubberBandFor(QMdiSubWindow *subWindow)
1488{
1489 if (!subWindow || !rubberBand)
1490 return;
1491
1492#if QT_CONFIG(tabbar)
1494 rubberBand->setGeometry(tabBar->tabRect(childWindows.indexOf(subWindow)));
1495 else
1496#endif
1497 rubberBand->setGeometry(subWindow->geometry());
1498
1499 rubberBand->raise();
1500 rubberBand->show();
1501}
1502#endif // QT_CONFIG(rubberBand)
1507void QMdiAreaPrivate::setViewMode(QMdiArea::ViewMode mode)
1508{
1509 Q_Q(QMdiArea);
1510 if (viewMode == mode || inViewModeChange)
1511 return;
1512
1513 // Just a guard since we cannot set viewMode = mode here.
1514 inViewModeChange = true;
1515
1516#if QT_CONFIG(tabbar)
1517 if (mode == QMdiArea::TabbedView) {
1518 Q_ASSERT(!tabBar);
1519 tabBar = new QMdiAreaTabBar(q);
1520 tabBar->setDocumentMode(documentMode);
1521 tabBar->setTabsClosable(tabsClosable);
1522 tabBar->setMovable(tabsMovable);
1523#if QT_CONFIG(tabwidget)
1524 tabBar->setShape(_q_tb_tabBarShapeFrom(tabShape, tabPosition));
1525#endif
1526
1527 isSubWindowsTiled = false;
1528
1529 foreach (QMdiSubWindow *subWindow, childWindows)
1530 tabBar->addTab(subWindow->windowIcon(), tabTextFor(subWindow));
1531
1532 QMdiSubWindow *current = q->currentSubWindow();
1533 if (current) {
1534 tabBar->setCurrentIndex(childWindows.indexOf(current));
1535 // Restore sub-window (i.e. cleanup buttons in menu bar and window title).
1536 if (current->isMaximized())
1537 current->showNormal();
1538
1539 viewMode = mode;
1540
1541 // Now, maximize it.
1543 current->showMaximized();
1544 }
1545 } else {
1546 viewMode = mode;
1547 }
1548
1549 if (q->isVisible())
1550 tabBar->show();
1551 updateTabBarGeometry();
1552
1553 QObject::connect(tabBar, SIGNAL(currentChanged(int)), q, SLOT(_q_currentTabChanged(int)));
1554 QObject::connect(tabBar, SIGNAL(tabCloseRequested(int)), q, SLOT(_q_closeTab(int)));
1555 QObject::connect(tabBar, SIGNAL(tabMoved(int,int)), q, SLOT(_q_moveTab(int,int)));
1556 } else
1557#endif // QT_CONFIG(tabbar)
1558 { // SubWindowView
1559#if QT_CONFIG(tabbar)
1560 delete tabBar;
1561 tabBar = nullptr;
1562#endif // QT_CONFIG(tabbar)
1563
1564 viewMode = mode;
1565 q->setViewportMargins(0, 0, 0, 0);
1566 indexToLastActiveTab = -1;
1567
1568 QMdiSubWindow *current = q->currentSubWindow();
1569 if (current && current->isMaximized())
1570 current->showNormal();
1571 }
1572
1573 Q_ASSERT(viewMode == mode);
1574 inViewModeChange = false;
1575}
1576
1577#if QT_CONFIG(tabbar)
1581void QMdiAreaPrivate::updateTabBarGeometry()
1582{
1583 if (!tabBar)
1584 return;
1585
1586 Q_Q(QMdiArea);
1587#if QT_CONFIG(tabwidget)
1588 Q_ASSERT(_q_tb_tabBarShapeFrom(tabShape, tabPosition) == tabBar->shape());
1589#endif
1590 const QSize tabBarSizeHint = tabBar->sizeHint();
1591
1592 int areaHeight = q->height();
1593 if (hbar && hbar->isVisible())
1594 areaHeight -= hbar->height();
1595
1596 int areaWidth = q->width();
1597 if (vbar && vbar->isVisible())
1598 areaWidth -= vbar->width();
1599
1600 QRect tabBarRect;
1601#if QT_CONFIG(tabwidget)
1602 switch (tabPosition) {
1603 case QTabWidget::North:
1604 q->setViewportMargins(0, tabBarSizeHint.height(), 0, 0);
1605 tabBarRect = QRect(0, 0, areaWidth, tabBarSizeHint.height());
1606 break;
1607 case QTabWidget::South:
1608 q->setViewportMargins(0, 0, 0, tabBarSizeHint.height());
1609 tabBarRect = QRect(0, areaHeight - tabBarSizeHint.height(), areaWidth, tabBarSizeHint.height());
1610 break;
1611 case QTabWidget::East:
1612 if (q->layoutDirection() == Qt::LeftToRight)
1613 q->setViewportMargins(0, 0, tabBarSizeHint.width(), 0);
1614 else
1615 q->setViewportMargins(tabBarSizeHint.width(), 0, 0, 0);
1616 tabBarRect = QRect(areaWidth - tabBarSizeHint.width(), 0, tabBarSizeHint.width(), areaHeight);
1617 break;
1618 case QTabWidget::West:
1619 if (q->layoutDirection() == Qt::LeftToRight)
1620 q->setViewportMargins(tabBarSizeHint.width(), 0, 0, 0);
1621 else
1622 q->setViewportMargins(0, 0, tabBarSizeHint.width(), 0);
1623 tabBarRect = QRect(0, 0, tabBarSizeHint.width(), areaHeight);
1624 break;
1625 default:
1626 break;
1627 }
1628#endif // QT_CONFIG(tabwidget)
1629
1630 tabBar->setGeometry(QStyle::visualRect(q->layoutDirection(), q->contentsRect(), tabBarRect));
1631}
1632
1636void QMdiAreaPrivate::refreshTabBar()
1637{
1638 if (!tabBar)
1639 return;
1640
1641 tabBar->setDocumentMode(documentMode);
1642 tabBar->setTabsClosable(tabsClosable);
1643 tabBar->setMovable(tabsMovable);
1644#if QT_CONFIG(tabwidget)
1645 tabBar->setShape(_q_tb_tabBarShapeFrom(tabShape, tabPosition));
1646#endif
1647 updateTabBarGeometry();
1648}
1649#endif // QT_CONFIG(tabbar)
1650
1656 : QAbstractScrollArea(*new QMdiAreaPrivate, parent)
1657{
1660 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1661 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1662 setViewport(nullptr);
1663 setFocusPolicy(Qt::NoFocus);
1665}
1666
1671{
1672 Q_D(QMdiArea);
1673 delete d->cascader;
1674 d->cascader = nullptr;
1675
1676 delete d->regularTiler;
1677 d->regularTiler = nullptr;
1678
1679 delete d->iconTiler;
1680 d->iconTiler = nullptr;
1681
1682 delete d->placer;
1683 d->placer = nullptr;
1684}
1685
1690{
1691 // Calculate a proper scale factor for the desktop's size.
1692 // This also takes into account that we can have nested workspaces.
1693 int nestedCount = 0;
1694 QWidget *widget = this->parentWidget();
1695 while (widget) {
1696 if (qobject_cast<QMdiArea *>(widget))
1697 ++nestedCount;
1699 }
1700 const int scaleFactor = 3 * (nestedCount + 1);
1701
1703 QSize size(desktopSize.width() * 2 / scaleFactor, desktopSize.height() * 2 / scaleFactor);
1704 for (QMdiSubWindow *child : d_func()->childWindows) {
1705 if (!sanityCheck(child, "QMdiArea::sizeHint"))
1706 continue;
1707 size = size.expandedTo(child->sizeHint());
1708 }
1709 return size;
1710}
1711
1716{
1717 Q_D(const QMdiArea);
1718 QSize size(style()->pixelMetric(QStyle::PM_MdiSubWindowMinimizedWidth, nullptr, this),
1719 style()->pixelMetric(QStyle::PM_TitleBarHeight, nullptr, this));
1720 size = size.expandedTo(QAbstractScrollArea::minimumSizeHint());
1721 if (!d->scrollBarsEnabled()) {
1722 for (QMdiSubWindow *child : d->childWindows) {
1723 if (!sanityCheck(child, "QMdiArea::sizeHint"))
1724 continue;
1725 size = size.expandedTo(child->minimumSizeHint());
1726 }
1727 }
1728 return size;
1729}
1730
1741{
1742 Q_D(const QMdiArea);
1743 if (d->childWindows.isEmpty())
1744 return nullptr;
1745
1746 if (d->active)
1747 return d->active;
1748
1749 if (d->isActivated && !window()->isMinimized())
1750 return nullptr;
1751
1752 Q_ASSERT(d->indicesToActivatedChildren.size() > 0);
1753 int index = d->indicesToActivatedChildren.at(0);
1754 Q_ASSERT(index >= 0 && index < d->childWindows.size());
1755 QMdiSubWindow *current = d->childWindows.at(index);
1756 Q_ASSERT(current);
1757 return current;
1758}
1759
1773{
1774 Q_D(const QMdiArea);
1775 return d->active;
1776}
1777
1785{
1786 Q_D(QMdiArea);
1787 if (!window) {
1788 d->activateWindow(nullptr);
1789 return;
1790 }
1791
1792 if (Q_UNLIKELY(d->childWindows.isEmpty())) {
1793 qWarning("QMdiArea::setActiveSubWindow: workspace is empty");
1794 return;
1795 }
1796
1797 if (Q_UNLIKELY(d->childWindows.indexOf(window) == -1)) {
1798 qWarning("QMdiArea::setActiveSubWindow: window is not inside workspace");
1799 return;
1800 }
1801
1802 d->activateWindow(window);
1803}
1804
1811{
1812 Q_D(QMdiArea);
1813 if (d->active)
1814 d->active->close();
1815}
1816
1829{
1830 Q_D(const QMdiArea);
1831 return d->subWindowList(order, false);
1832}
1833
1845{
1846 Q_D(QMdiArea);
1847 if (d->childWindows.isEmpty())
1848 return;
1849
1850 d->isSubWindowsTiled = false;
1851 foreach (QMdiSubWindow *child, d->childWindows) {
1852 if (!sanityCheck(child, "QMdiArea::closeAllSubWindows"))
1853 continue;
1854 child->close();
1855 }
1856
1857 d->updateScrollBars();
1858}
1859
1868{
1869 Q_D(QMdiArea);
1870 if (d->childWindows.isEmpty())
1871 return;
1872
1873 QMdiSubWindow *next = d->nextVisibleSubWindow(1, d->activationOrder);
1874 if (next)
1875 d->activateWindow(next);
1876}
1877
1886{
1887 Q_D(QMdiArea);
1888 if (d->childWindows.isEmpty())
1889 return;
1890
1891 QMdiSubWindow *previous = d->nextVisibleSubWindow(-1, d->activationOrder);
1892 if (previous)
1893 d->activateWindow(previous);
1894}
1895
1920{
1921 if (Q_UNLIKELY(!widget)) {
1922 qWarning("QMdiArea::addSubWindow: null pointer to widget");
1923 return nullptr;
1924 }
1925
1926 Q_D(QMdiArea);
1927 // QWidget::setParent clears focusWidget so store it
1928 QWidget *childFocus = widget->focusWidget();
1929 QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(widget);
1930
1931 // Widget is already a QMdiSubWindow
1932 if (child) {
1933 if (Q_UNLIKELY(d->childWindows.indexOf(child) != -1)) {
1934 qWarning("QMdiArea::addSubWindow: window is already added");
1935 return child;
1936 }
1937 child->setParent(viewport(), windowFlags ? windowFlags : child->windowFlags());
1938 // Create a QMdiSubWindow
1939 } else {
1940 child = new QMdiSubWindow(viewport(), windowFlags);
1941 child->setAttribute(Qt::WA_DeleteOnClose);
1942 child->setWidget(widget);
1943 Q_ASSERT(child->testAttribute(Qt::WA_DeleteOnClose));
1944 }
1945
1946 d->appendChild(child);
1947
1948 if (childFocus)
1949 childFocus->setFocus();
1950
1951 return child;
1952}
1953
1965{
1966 if (Q_UNLIKELY(!widget)) {
1967 qWarning("QMdiArea::removeSubWindow: null pointer to widget");
1968 return;
1969 }
1970
1971 Q_D(QMdiArea);
1972 if (d->childWindows.isEmpty())
1973 return;
1974
1975 if (QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(widget)) {
1976 int index = d->childWindows.indexOf(child);
1977 if (Q_UNLIKELY(index == -1)) {
1978 qWarning("QMdiArea::removeSubWindow: window is not inside workspace");
1979 return;
1980 }
1981 d->disconnectSubWindow(child);
1982 d->childWindows.removeAll(child);
1983 d->indicesToActivatedChildren.removeAll(index);
1984 d->updateActiveWindow(index, d->active == child);
1985 child->setParent(nullptr);
1986 return;
1987 }
1988
1989 bool found = false;
1990 foreach (QMdiSubWindow *child, d->childWindows) {
1991 if (!sanityCheck(child, "QMdiArea::removeSubWindow"))
1992 continue;
1993 if (child->widget() == widget) {
1994 child->setWidget(nullptr);
1995 Q_ASSERT(!child->widget());
1996 found = true;
1997 break;
1998 }
1999 }
2000
2001 if (Q_UNLIKELY(!found))
2002 qWarning("QMdiArea::removeSubWindow: widget is not child of any window inside QMdiArea");
2003}
2004
2014{
2015 return d_func()->background;
2016}
2017
2019{
2020 Q_D(QMdiArea);
2021 if (d->background != brush) {
2022 d->background = brush;
2023 d->viewport->setAttribute(Qt::WA_OpaquePaintEvent, brush.isOpaque());
2024 d->viewport->update();
2025 }
2026}
2027
2028
2041{
2042 Q_D(const QMdiArea);
2043 return d->activationOrder;
2044}
2045
2047{
2048 Q_D(QMdiArea);
2049 if (order != d->activationOrder)
2050 d->activationOrder = order;
2051}
2052
2060{
2061 Q_D(QMdiArea);
2062 d->options.setFlag(option, on);
2063}
2064
2071{
2072 return d_func()->options & option;
2073}
2074
2085{
2086 Q_D(const QMdiArea);
2087 return d->viewMode;
2088}
2089
2091{
2092 Q_D(QMdiArea);
2093 d->setViewMode(mode);
2094}
2095
2096#if QT_CONFIG(tabbar)
2106bool QMdiArea::documentMode() const
2107{
2108 Q_D(const QMdiArea);
2109 return d->documentMode;
2110}
2111
2112void QMdiArea::setDocumentMode(bool enabled)
2113{
2114 Q_D(QMdiArea);
2115 if (d->documentMode == enabled)
2116 return;
2117
2118 d->documentMode = enabled;
2119 d->refreshTabBar();
2120}
2121
2131bool QMdiArea::tabsClosable() const
2132{
2133 Q_D(const QMdiArea);
2134 return d->tabsClosable;
2135}
2136
2137void QMdiArea::setTabsClosable(bool closable)
2138{
2139 Q_D(QMdiArea);
2140 if (d->tabsClosable == closable)
2141 return;
2142
2143 d->tabsClosable = closable;
2144 d->refreshTabBar();
2145}
2146
2156bool QMdiArea::tabsMovable() const
2157{
2158 Q_D(const QMdiArea);
2159 return d->tabsMovable;
2160}
2161
2162void QMdiArea::setTabsMovable(bool movable)
2163{
2164 Q_D(QMdiArea);
2165 if (d->tabsMovable == movable)
2166 return;
2167
2168 d->tabsMovable = movable;
2169 d->refreshTabBar();
2170}
2171#endif // QT_CONFIG(tabbar)
2172
2173#if QT_CONFIG(tabwidget)
2184QTabWidget::TabShape QMdiArea::tabShape() const
2185{
2186 Q_D(const QMdiArea);
2187 return d->tabShape;
2188}
2189
2190void QMdiArea::setTabShape(QTabWidget::TabShape shape)
2191{
2192 Q_D(QMdiArea);
2193 if (d->tabShape == shape)
2194 return;
2195
2196 d->tabShape = shape;
2197 d->refreshTabBar();
2198}
2199
2210QTabWidget::TabPosition QMdiArea::tabPosition() const
2211{
2212 Q_D(const QMdiArea);
2213 return d->tabPosition;
2214}
2215
2216void QMdiArea::setTabPosition(QTabWidget::TabPosition position)
2217{
2218 Q_D(QMdiArea);
2219 if (d->tabPosition == position)
2220 return;
2221
2222 d->tabPosition = position;
2223 d->refreshTabBar();
2224}
2225#endif // QT_CONFIG(tabwidget)
2226
2231{
2232 Q_D(QMdiArea);
2233 if (childEvent->type() == QEvent::ChildPolished) {
2234 if (QMdiSubWindow *mdiChild = qobject_cast<QMdiSubWindow *>(childEvent->child())) {
2235 if (d->childWindows.indexOf(mdiChild) == -1)
2236 d->appendChild(mdiChild);
2237 }
2238 }
2239}
2240
2245{
2246 Q_D(QMdiArea);
2247 if (d->childWindows.isEmpty()) {
2248 resizeEvent->ignore();
2249 return;
2250 }
2251
2252#if QT_CONFIG(tabbar)
2253 d->updateTabBarGeometry();
2254#endif
2255
2256 // Re-tile the views if we're in tiled mode. Re-tile means we will change
2257 // the geometry of the children, which in turn means 'isSubWindowsTiled'
2258 // is set to false, so we have to update the state at the end.
2259 if (d->isSubWindowsTiled) {
2260 d->tileCalledFromResizeEvent = true;
2262 d->tileCalledFromResizeEvent = false;
2263 d->isSubWindowsTiled = true;
2264 d->startResizeTimer();
2265 // We don't have scroll bars or any maximized views.
2266 return;
2267 }
2268
2269 // Resize maximized views.
2270 bool hasMaximizedSubWindow = false;
2271 foreach (QMdiSubWindow *child, d->childWindows) {
2272 if (sanityCheck(child, "QMdiArea::resizeEvent") && child->isMaximized()
2273 && child->size() != resizeEvent->size()) {
2274 auto realSize = resizeEvent->size();
2275 const auto minSizeHint = child->minimumSizeHint();
2276 // QMdiSubWindow is no tlw so minimumSize() is not set by the layout manager
2277 // and therefore we have to take care by ourself that we're not getting smaller
2278 // than allowed
2279 if (minSizeHint.isValid())
2280 realSize = realSize.expandedTo(minSizeHint);
2281 child->resize(realSize);
2282 if (!hasMaximizedSubWindow)
2283 hasMaximizedSubWindow = true;
2284 }
2285 }
2286
2287 d->updateScrollBars();
2288
2289 // Minimized views are stacked under maximized views so there's
2290 // no need to re-arrange minimized views on-demand. Start a timer
2291 // just to make things faster with subsequent resize events.
2292 if (hasMaximizedSubWindow)
2293 d->startResizeTimer();
2294 else
2295 d->arrangeMinimizedSubWindows();
2296}
2297
2302{
2303 Q_D(QMdiArea);
2304 if (timerEvent->timerId() == d->resizeTimerId) {
2305 killTimer(d->resizeTimerId);
2306 d->resizeTimerId = -1;
2307 d->arrangeMinimizedSubWindows();
2308 } else if (timerEvent->timerId() == d->tabToPreviousTimerId) {
2309 killTimer(d->tabToPreviousTimerId);
2310 d->tabToPreviousTimerId = -1;
2311 if (d->indexToHighlighted < 0)
2312 return;
2313#if QT_CONFIG(rubberband)
2314 // We're not doing a "quick switch" ... show rubber band.
2315 Q_ASSERT(d->indexToHighlighted < d->childWindows.size());
2316 Q_ASSERT(d->rubberBand);
2317 d->showRubberBandFor(d->childWindows.at(d->indexToHighlighted));
2318#endif
2319 }
2320}
2321
2326{
2327 Q_D(QMdiArea);
2328 if (!d->pendingRearrangements.isEmpty()) {
2329 bool skipPlacement = false;
2330 foreach (Rearranger *rearranger, d->pendingRearrangements) {
2331 // If this is the case, we don't have to lay out pending child windows
2332 // since the rearranger will find a placement for them.
2333 if (rearranger->type() != Rearranger::IconTiler && !skipPlacement)
2334 skipPlacement = true;
2335 d->rearrange(rearranger);
2336 }
2337 d->pendingRearrangements.clear();
2338
2339 if (skipPlacement && !d->pendingPlacements.isEmpty())
2340 d->pendingPlacements.clear();
2341 }
2342
2343 if (!d->pendingPlacements.isEmpty()) {
2344 foreach (QMdiSubWindow *window, d->pendingPlacements) {
2345 if (!window)
2346 continue;
2347 if (!window->testAttribute(Qt::WA_Resized)) {
2348 QSize newSize(window->sizeHint().boundedTo(viewport()->size()));
2349 window->resize(newSize.expandedTo(qSmartMinSize(window)));
2350 }
2351 if (!window->testAttribute(Qt::WA_Moved) && !window->isMinimized()
2352 && !window->isMaximized()) {
2353 d->place(d->placer, window);
2354 }
2355 }
2356 d->pendingPlacements.clear();
2357 }
2358
2359 d->setChildActivationEnabled(true);
2360 d->activateCurrentWindow();
2361
2362 QAbstractScrollArea::showEvent(showEvent);
2363}
2364
2369{
2370 Q_D(QMdiArea);
2371 switch (event->type()) {
2372 case QEvent::ChildRemoved: {
2373 d->isSubWindowsTiled = false;
2374 QObject *removedChild = static_cast<QChildEvent *>(event)->child();
2375 for (int i = 0; i < d->childWindows.size(); ++i) {
2376 QObject *child = d->childWindows.at(i);
2377 if (!child || child == removedChild || !child->parent()
2378 || child->parent() != viewport()) {
2380 // In this case we can only rely on the child being a QObject
2381 // (or 0), but let's try and see if we can get more information.
2382 QWidget *mdiChild = qobject_cast<QWidget *>(removedChild);
2383 if (mdiChild && mdiChild->isMaximized())
2384 d->showActiveWindowMaximized = true;
2385 }
2386 d->disconnectSubWindow(child);
2387 const bool activeRemoved = i == d->indicesToActivatedChildren.at(0);
2388 d->childWindows.removeAt(i);
2389 d->indicesToActivatedChildren.removeAll(i);
2390 d->updateActiveWindow(i, activeRemoved);
2391 d->arrangeMinimizedSubWindows();
2392 break;
2393 }
2394 }
2395 d->updateScrollBars();
2396 break;
2397 }
2398 case QEvent::Destroy:
2399 d->isSubWindowsTiled = false;
2400 d->resetActiveWindow();
2401 d->childWindows.clear();
2402 qWarning("QMdiArea: Deleting the view port is undefined, use setViewport instead.");
2403 break;
2404 default:
2405 break;
2406 }
2407 return QAbstractScrollArea::viewportEvent(event);
2408}
2409
2413void QMdiArea::scrollContentsBy(int dx, int dy)
2414{
2415 Q_D(QMdiArea);
2416 const bool wasSubWindowsTiled = d->isSubWindowsTiled;
2417 d->ignoreGeometryChange = true;
2418 viewport()->scroll(isLeftToRight() ? dx : -dx, dy);
2419 d->arrangeMinimizedSubWindows();
2420 d->ignoreGeometryChange = false;
2421 if (wasSubWindowsTiled)
2422 d->isSubWindowsTiled = true;
2423}
2424
2431{
2432 Q_D(QMdiArea);
2433 if (!d->regularTiler)
2434 d->regularTiler = new RegularTiler;
2435 d->rearrange(d->regularTiler);
2436}
2437
2444{
2445 Q_D(QMdiArea);
2446 if (!d->cascader)
2447 d->cascader = new SimpleCascader;
2448 d->rearrange(d->cascader);
2449}
2450
2455{
2456 Q_D(QMdiArea);
2457 switch (event->type()) {
2459 d->isActivated = true;
2460 if (d->childWindows.isEmpty())
2461 break;
2462 if (!d->active)
2463 d->activateCurrentWindow();
2464 d->setChildActivationEnabled(false, true);
2465 break;
2466 }
2468 d->isActivated = false;
2469 d->setChildActivationEnabled(false, true);
2470 break;
2472 // Re-tile the views if we're in tiled mode. Re-tile means we will change
2473 // the geometry of the children, which in turn means 'isSubWindowsTiled'
2474 // is set to false, so we have to update the state at the end.
2475 if (d->isSubWindowsTiled) {
2477 d->isSubWindowsTiled = true;
2478 }
2479 break;
2481 foreach (QMdiSubWindow *window, d->childWindows) {
2482 if (sanityCheck(window, "QMdiArea::WindowIconChange"))
2484 }
2485 break;
2486 case QEvent::Hide:
2487 d->setActive(d->active, false, false);
2488 d->setChildActivationEnabled(false);
2489 break;
2490#if QT_CONFIG(tabbar)
2492 d->updateTabBarGeometry();
2493 break;
2494#endif
2495 default:
2496 break;
2497 }
2498 return QAbstractScrollArea::event(event);
2499}
2500
2505{
2506 if (!object)
2507 return QAbstractScrollArea::eventFilter(object, event);
2508
2509 Q_D(QMdiArea);
2510 // Global key events with Ctrl modifier.
2511 if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) {
2512
2513 QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
2514 // Ignore key events without a Ctrl modifier (except for press/release on the modifier itself).
2515 if (!(keyEvent->modifiers() & Qt::ControlModifier) && keyEvent->key() != Qt::Key_Control)
2516 return QAbstractScrollArea::eventFilter(object, event);
2517
2518 // Find closest mdi area (in case we have a nested workspace).
2519 QMdiArea *area = mdiAreaParent(static_cast<QWidget *>(object));
2520 if (!area)
2521 return QAbstractScrollArea::eventFilter(object, event);
2522
2523 const bool keyPress = (event->type() == QEvent::KeyPress);
2524
2525 // 1) Ctrl-Tab once -> activate the previously active window.
2526 // 2) Ctrl-Tab (Tab, Tab, ...) -> iterate through all windows (activateNextSubWindow()).
2527 // 3) Ctrl-Shift-Tab (Tab, Tab, ...) -> iterate through all windows in the opposite
2528 // direction (activatePreviousSubWindow())
2529 switch (keyEvent->key()) {
2530 case Qt::Key_Control:
2531 if (keyPress)
2532 area->d_func()->startTabToPreviousTimer();
2533 else
2534 area->d_func()->activateHighlightedWindow();
2535 break;
2536 case Qt::Key_Tab:
2537 case Qt::Key_Backtab:
2538 if (keyPress)
2539 area->d_func()->highlightNextSubWindow(keyEvent->key() == Qt::Key_Tab ? 1 : -1);
2540 return true;
2541#if QT_CONFIG(rubberband)
2542 case Qt::Key_Escape:
2543 area->d_func()->hideRubberBand();
2544 break;
2545#endif
2546 default:
2547 break;
2548 }
2549 return QAbstractScrollArea::eventFilter(object, event);
2550 }
2551
2552 QMdiSubWindow *subWindow = qobject_cast<QMdiSubWindow *>(object);
2553
2554 if (!subWindow) {
2555 // QApplication events:
2556 if (event->type() == QEvent::ApplicationActivate && !d->active
2557 && isVisible() && !window()->isMinimized()) {
2558 d->activateCurrentWindow();
2559 } else if (event->type() == QEvent::ApplicationDeactivate && d->active) {
2560 d->setActive(d->active, false, false);
2561 }
2562 return QAbstractScrollArea::eventFilter(object, event);
2563 }
2564
2565 if (subWindow->mdiArea() != this)
2566 return QAbstractScrollArea::eventFilter(object, event);
2567
2568 // QMdiSubWindow events:
2569 switch (event->type()) {
2570 case QEvent::Move:
2571 case QEvent::Resize:
2572 if (d->tileCalledFromResizeEvent)
2573 break;
2574 d->updateScrollBars();
2575 if (!subWindow->isMinimized())
2576 d->isSubWindowsTiled = false;
2577 break;
2578 case QEvent::Show:
2579#if QT_CONFIG(tabbar)
2580 if (d->tabBar) {
2581 const int tabIndex = d->childWindows.indexOf(subWindow);
2582 if (!d->tabBar->isTabEnabled(tabIndex))
2583 d->tabBar->setTabEnabled(tabIndex, true);
2584 }
2585#endif // QT_CONFIG(tabbar)
2586 Q_FALLTHROUGH();
2587 case QEvent::Hide:
2588 // Do not reset the isSubWindowsTiled flag if the event is a spontaneous system window event.
2589 // This ensures that tiling will be performed during the resizeEvent after an application
2590 // window minimize (hide) and then restore (show).
2591 if (!event->spontaneous())
2592 d->isSubWindowsTiled = false;
2593 break;
2594#if QT_CONFIG(rubberband)
2595 case QEvent::Close:
2596 if (d->childWindows.indexOf(subWindow) == d->indexToHighlighted)
2597 d->hideRubberBand();
2598 break;
2599#endif
2600#if QT_CONFIG(tabbar)
2603 if (d->tabBar)
2604 d->tabBar->setTabText(d->childWindows.indexOf(subWindow), tabTextFor(subWindow));
2605 break;
2607 if (d->tabBar)
2608 d->tabBar->setTabIcon(d->childWindows.indexOf(subWindow), subWindow->windowIcon());
2609 break;
2610#endif // QT_CONFIG(tabbar)
2611 default:
2612 break;
2613 }
2614 return QAbstractScrollArea::eventFilter(object, event);
2615}
2616
2621{
2622 Q_D(QMdiArea);
2623 QPainter painter(d->viewport);
2624 for (const QRect &exposedRect : paintEvent->region())
2625 painter.fillRect(exposedRect, d->background);
2626}
2627
2636{
2637 Q_D(QMdiArea);
2638 if (viewport)
2639 viewport->setAttribute(Qt::WA_OpaquePaintEvent, d->background.isOpaque());
2640 foreach (QMdiSubWindow *child, d->childWindows) {
2641 if (!sanityCheck(child, "QMdiArea::setupViewport"))
2642 continue;
2643 child->setParent(viewport, child->windowFlags());
2644 }
2645}
2646
2648
2649#include "moc_qmdiarea.cpp"
static QFont font()
Returns the default application font.
\inmodule QtGui
Definition qbrush.h:30
\inmodule QtCore
Definition qcoreevent.h:372
The QContextMenuEvent class contains parameters that describe a context menu event.
Definition qevent.h:593
static bool sendEvent(QObject *receiver, QEvent *event)
Sends event event directly to receiver receiver, using the notify() function.
static QCoreApplication * instance() noexcept
Returns a pointer to the application's QCoreApplication (or QGuiApplication/QApplication) instance.
\inmodule QtCore
Definition qcoreevent.h:45
@ ApplicationDeactivate
Definition qcoreevent.h:166
@ ModifiedChange
Definition qcoreevent.h:138
@ LayoutDirectionChange
Definition qcoreevent.h:124
@ ChildPolished
Definition qcoreevent.h:107
@ ApplicationActivate
Definition qcoreevent.h:164
@ ChildRemoved
Definition qcoreevent.h:108
@ StyleChange
Definition qcoreevent.h:136
@ KeyRelease
Definition qcoreevent.h:65
@ KeyPress
Definition qcoreevent.h:64
@ WindowActivate
Definition qcoreevent.h:83
@ WindowIconChange
Definition qcoreevent.h:89
@ Destroy
Definition qcoreevent.h:75
@ WindowTitleChange
Definition qcoreevent.h:88
@ WindowDeactivate
Definition qcoreevent.h:84
\reentrant \inmodule QtGui
@ NoFrame
Definition qframe.h:39
QScreen * primaryScreen
the primary (or default) screen of the application.
The QKeyEvent class describes a key event.
Definition qevent.h:423
Qt::KeyboardModifiers modifiers() const
Returns the keyboard modifier flags that existed immediately after the event occurred.
Definition qevent.cpp:1465
int key() const
Returns the code of the key that was pressed or released.
Definition qevent.h:433
virtual QSize minimumSize() const =0
Implemented in subclasses to return the minimum size of this item.
virtual void setGeometry(const QRect &)=0
Implemented in subclasses to set this item's geometry to r.
virtual QWidget * widget() const
If this item manages a QWidget, returns that widget.
virtual QSize sizeHint() const =0
Implemented in subclasses to return the preferred size of this item.
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
bool isEmpty() const noexcept
Definition qlist.h:390
reference back()
Definition qlist.h:686
iterator erase(const_iterator begin, const_iterator end)
Definition qlist.h:882
iterator end()
Definition qlist.h:609
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
void move(qsizetype from, qsizetype to)
Definition qlist.h:593
void prepend(rvalue_ref t)
Definition qlist.h:456
iterator begin()
Definition qlist.h:608
void reserve(qsizetype size)
Definition qlist.h:746
void append(parameter_type t)
Definition qlist.h:441
void internalRaise(QMdiSubWindow *child) const
void place(QMdi::Placer *placer, QMdiSubWindow *child)
Definition qmdiarea.cpp:832
void resetActiveWindow(QMdiSubWindow *child=nullptr)
QMdi::Placer * placer
Definition qmdiarea_p.h:112
QPointer< QMdiSubWindow > aboutToBecomeActive
Definition qmdiarea_p.h:122
void activateCurrentWindow()
Definition qmdiarea.cpp:966
QList< int > indicesToActivatedChildren
Definition qmdiarea_p.h:120
bool scrollBarsEnabled() const
void appendChild(QMdiSubWindow *child)
Definition qmdiarea.cpp:779
void activateHighlightedWindow()
Definition qmdiarea.cpp:975
void emitWindowActivated(QMdiSubWindow *child)
Definition qmdiarea.cpp:993
QMdi::Rearranger * iconTiler
Definition qmdiarea_p.h:111
QPointer< QMdiSubWindow > active
Definition qmdiarea_p.h:121
QList< QMdiSubWindow * > subWindowList(QMdiArea::WindowOrder, bool reversed=false) const
void updateScrollBars()
QRect resizeToMinimumTileSize(const QSize &minSubWindowSize, int subWindowCount)
QMdiArea::WindowOrder activationOrder
Definition qmdiarea_p.h:124
bool isExplicitlyDeactivated(QMdiSubWindow *subWindow) const
Definition qmdiarea_p.h:210
void arrangeMinimizedSubWindows()
Definition qmdiarea.cpp:927
QMdiAreaTabBar * tabBar
Definition qmdiarea_p.h:116
bool lastWindowAboutToBeDestroyed() const
bool ignoreGeometryChange
Definition qmdiarea_p.h:136
void activateWindow(QMdiSubWindow *child)
Definition qmdiarea.cpp:937
void highlightNextSubWindow(int increaseFactor)
QList< QMdi::Rearranger * > pendingRearrangements
Definition qmdiarea_p.h:117
QMdiArea::AreaOptions options
Definition qmdiarea_p.h:125
bool tileCalledFromResizeEvent
Definition qmdiarea_p.h:141
void disconnectSubWindow(QObject *subWindow)
void _q_moveTab(int from, int to)
Definition qmdiarea.cpp:766
bool windowStaysOnTop(QMdiSubWindow *subWindow) const
Definition qmdiarea_p.h:203
QList< QPointer< QMdiSubWindow > > pendingPlacements
Definition qmdiarea_p.h:118
bool ignoreWindowStateChange
Definition qmdiarea_p.h:137
void _q_currentTabChanged(int index)
Definition qmdiarea.cpp:731
bool updatesDisabledByUs
Definition qmdiarea_p.h:142
QList< QPointer< QMdiSubWindow > > childWindows
Definition qmdiarea_p.h:119
void _q_deactivateAllWindows(QMdiSubWindow *aboutToActivate=nullptr)
Definition qmdiarea.cpp:662
void scrollBarPolicyChanged(Qt::Orientation, Qt::ScrollBarPolicy) override
bool showActiveWindowMaximized
Definition qmdiarea_p.h:140
QMdiArea::ViewMode viewMode
Definition qmdiarea_p.h:126
void updateActiveWindow(int removedIndex, bool activeRemoved)
void rearrange(QMdi::Rearranger *rearranger)
Definition qmdiarea.cpp:871
void setChildActivationEnabled(bool enable=true, bool onlyNextActivationEvent=false) const
void _q_closeTab(int index)
Definition qmdiarea.cpp:755
void _q_processWindowStateChanged(Qt::WindowStates oldState, Qt::WindowStates newState)
Definition qmdiarea.cpp:698
QMdiSubWindow * nextVisibleSubWindow(int increaseFactor, QMdiArea::WindowOrder, int removed=-1, int fromIndex=-1) const
The QMdiArea widget provides an area in which MDI windows are displayed.
Definition qmdiarea.h:21
bool eventFilter(QObject *object, QEvent *event) override
\reimp
WindowOrder activationOrder
the ordering criteria for subwindow lists
Definition qmdiarea.h:24
bool testOption(AreaOption opton) const
Returns true if option is enabled; otherwise returns false.
void setActivationOrder(WindowOrder order)
QBrush background
the background brush for the workspace
Definition qmdiarea.h:23
void childEvent(QChildEvent *childEvent) override
\reimp
QMdiSubWindow * addSubWindow(QWidget *widget, Qt::WindowFlags flags=Qt::WindowFlags())
Adds widget as a new subwindow to the MDI area.
void setViewMode(ViewMode mode)
bool viewportEvent(QEvent *event) override
\reimp
void setBackground(const QBrush &background)
void closeActiveSubWindow()
Closes the active subwindow.
ViewMode viewMode
the way sub-windows are displayed in the QMdiArea.
Definition qmdiarea.h:25
void activateNextSubWindow()
Gives the keyboard focus to another window in the list of child windows.
QMdiArea(QWidget *parent=nullptr)
Constructs an empty mdi area.
WindowOrder
Specifies the criteria to use for ordering the list of child windows returned by subWindowList().
Definition qmdiarea.h:41
@ StackingOrder
Definition qmdiarea.h:43
@ CreationOrder
Definition qmdiarea.h:42
@ ActivationHistoryOrder
Definition qmdiarea.h:44
QMdiSubWindow * activeSubWindow() const
Returns a pointer to the current active subwindow.
void cascadeSubWindows()
Arranges all the child windows in a cascade pattern.
void showEvent(QShowEvent *showEvent) override
\reimp
void setOption(AreaOption option, bool on=true)
If on is true, option is enabled on the MDI area; otherwise it is disabled.
void closeAllSubWindows()
Closes all subwindows by sending a QCloseEvent to each window.
bool event(QEvent *event) override
\reimp
void tileSubWindows()
Arranges all child windows in a tile pattern.
void activatePreviousSubWindow()
Gives the keyboard focus to another window in the list of child windows.
~QMdiArea()
Destroys the MDI area.
QSize sizeHint() const override
\reimp
QSize minimumSizeHint() const override
\reimp
QMdiSubWindow * currentSubWindow() const
Returns a pointer to the current subwindow, or \nullptr if there is no current subwindow.
void setupViewport(QWidget *viewport) override
This slot is called by QAbstractScrollArea after setViewport() has been called.
void timerEvent(QTimerEvent *timerEvent) override
\reimp
void scrollContentsBy(int dx, int dy) override
\reimp
void paintEvent(QPaintEvent *paintEvent) override
\reimp
void removeSubWindow(QWidget *widget)
Removes widget from the MDI area.
@ TabbedView
Definition qmdiarea.h:50
QList< QMdiSubWindow * > subWindowList(WindowOrder order=CreationOrder) const
Returns a list of all subwindows in the MDI area.
AreaOption
This enum describes options that customize the behavior of the QMdiArea.
Definition qmdiarea.h:36
@ DontMaximizeSubWindowOnActivation
Definition qmdiarea.h:37
void resizeEvent(QResizeEvent *resizeEvent) override
\reimp
void setActiveSubWindow(QMdiSubWindow *window)
Activates the subwindow window.
void setVisible(WindowStateAction, bool visible=true)
QPointer< QMenu > systemMenu
The QMdiSubWindow class provides a subwindow class for QMdiArea.
SubWindowOption
This enum describes options that customize the behavior of QMdiSubWindow.
@ AllowOutsideAreaHorizontally
QMdiArea * mdiArea() const
void rearrange(QList< QWidget * > &widgets, const QRect &domain) const override
Definition qmdiarea.cpp:332
QPoint place(const QSize &size, const QList< QRect > &rects, const QRect &domain) const override
Definition qmdiarea.cpp:503
virtual QPoint place(const QSize &size, const QList< QRect > &rects, const QRect &domain) const =0
virtual void rearrange(QList< QWidget * > &widgets, const QRect &domain) const =0
virtual Type type() const =0
void rearrange(QList< QWidget * > &widgets, const QRect &domain) const override
Definition qmdiarea.cpp:245
void rearrange(QList< QWidget * > &widgets, const QRect &domain) const override
Definition qmdiarea.cpp:289
QAction * exec()
Executes this menu synchronously.
Definition qmenu.cpp:2586
\inmodule QtGui
Definition qevent.h:195
\inmodule QtCore
Definition qobject.h:90
void installEventFilter(QObject *filterObj)
Installs an event filter filterObj on this object.
Definition qobject.cpp:2269
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2823
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
Definition qobject.cpp:3099
void removeEventFilter(QObject *obj)
Removes an event filter object obj from this object.
Definition qobject.cpp:2300
The QPaintEvent class contains event parameters for paint events.
Definition qevent.h:485
The QPainter class performs low-level painting on widgets and other paint devices.
Definition qpainter.h:46
void fillRect(const QRectF &, const QBrush &)
Fills the given rectangle with the brush specified.
\inmodule QtCore\reentrant
Definition qpoint.h:23
constexpr int x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:127
constexpr int y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:132
\inmodule QtCore
Definition qpointer.h:18
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr int height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:238
constexpr bool isValid() const noexcept
Returns true if the rectangle is valid, otherwise returns false.
Definition qrect.h:169
QRect intersected(const QRect &other) const noexcept
Definition qrect.h:414
constexpr int bottom() const noexcept
Returns the y-coordinate of the rectangle's bottom edge.
Definition qrect.h:181
constexpr QPoint topLeft() const noexcept
Returns the position of the rectangle's top-left corner.
Definition qrect.h:220
constexpr int top() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:175
bool contains(const QRect &r, bool proper=false) const noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qrect.cpp:851
constexpr int left() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:172
constexpr void setWidth(int w) noexcept
Sets the width of the rectangle to the given width.
Definition qrect.h:380
constexpr int width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:235
constexpr void setHeight(int h) noexcept
Sets the height of the rectangle to the given height.
Definition qrect.h:383
constexpr int right() const noexcept
Returns the x-coordinate of the rectangle's right edge.
Definition qrect.h:178
The QResizeEvent class contains event parameters for resize events.
Definition qevent.h:547
The QRubberBand class provides a rectangle or line that can indicate a selection or a boundary.
Definition qrubberband.h:18
QSize virtualSize
the pixel size of the virtual desktop to which this screen belongs
Definition qscreen.h:43
The QShowEvent class provides an event that is sent when a widget is shown.
Definition qevent.h:577
Exception-safe wrapper around QObject::blockSignals().
Definition qobject.h:443
\inmodule QtCore
Definition qsize.h:25
constexpr QSize boundedTo(const QSize &) const noexcept
Returns a size holding the minimum width and height of this size and the given otherSize.
Definition qsize.h:196
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:132
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:129
constexpr int & rheight() noexcept
Returns a reference to the height.
Definition qsize.h:156
constexpr QSize expandedTo(const QSize &) const noexcept
Returns a size holding the maximum width and height of this size and the given otherSize.
Definition qsize.h:191
constexpr int & rwidth() noexcept
Returns a reference to the width.
Definition qsize.h:153
constexpr bool isValid() const noexcept
Returns true if both the width and height is equal to or greater than 0; otherwise returns false.
Definition qsize.h:126
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
QString & replace(qsizetype i, qsizetype len, QChar after)
Definition qstring.cpp:3794
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
\variable QStyleOptionToolBox::selectedPosition
void initFrom(const QWidget *w)
@ SH_ScrollView_FrameOnlyAroundContents
Definition qstyle.h:600
static QRect visualRect(Qt::LayoutDirection direction, const QRect &boundingRect, const QRect &logicalRect)
Returns the given logicalRectangle converted to screen coordinates based on the specified direction.
Definition qstyle.cpp:2144
@ PM_FocusFrameVMargin
Definition qstyle.h:496
@ PM_TitleBarHeight
Definition qstyle.h:448
@ PM_DefaultFrameWidth
Definition qstyle.h:420
@ PM_MdiSubWindowMinimizedWidth
Definition qstyle.h:472
virtual int pixelMetric(PixelMetric metric, const QStyleOption *option=nullptr, const QWidget *widget=nullptr) const =0
Returns the value of the given pixel metric.
The QTabBar class provides a tab bar, e.g.
Definition qtabbar.h:19
void mousePressEvent(QMouseEvent *) override
\reimp
Definition qtabbar.cpp:2116
Shape
This enum type lists the built-in shapes supported by QTabBar.
Definition qtabbar.h:42
The QTabWidget class provides a stack of tabbed widgets.
Definition qtabwidget.h:20
TabPosition
This enum type defines where QTabWidget draws the tab row:
Definition qtabwidget.h:74
TabShape
This enum type defines the shape of the tabs: \value Rounded The tabs are drawn with a rounded look.
Definition qtabwidget.h:85
\inmodule QtCore
Definition qcoreevent.h:359
The QWidget class is the base class of all user interface objects.
Definition qwidget.h:99
void setGeometry(int x, int y, int w, int h)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qwidget.h:886
void raise()
Raises this widget to the top of the parent widget's stack.
Qt::LayoutDirection layoutDirection
the layout direction for this widget.
Definition qwidget.h:170
bool isMinimized() const
Definition qwidget.cpp:2843
bool isHidden() const
Returns true if the widget is hidden, otherwise returns false.
Definition qwidget.h:877
QSize size
the size of the widget excluding any window frame
Definition qwidget.h:113
QRect geometry
the geometry of the widget relative to its parent and excluding the window frame
Definition qwidget.h:106
int width
the width of the widget excluding any window frame
Definition qwidget.h:114
bool isMaximized() const
Definition qwidget.cpp:2883
bool close()
Closes this widget.
Definition qwidget.cpp:8608
QWidget * focusWidget() const
Returns the last child of this widget that setFocus had been called on.
Definition qwidget.cpp:6851
int height
the height of the widget excluding any window frame
Definition qwidget.h:115
void setFocus()
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qwidget.h:423
void stackUnder(QWidget *)
Places the widget under w in the parent widget's stack.
QIcon windowIcon
the widget's icon
Definition qwidget.h:152
QSize sizeHint
the recommended size for the widget
Definition qwidget.h:148
void showMaximized()
Shows the widget maximized.
Definition qwidget.cpp:3051
bool isWindowModified() const
QStyle * style() const
Definition qwidget.cpp:2607
void resize(int w, int h)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qwidget.h:883
QString windowTitle
the window title (caption)
Definition qwidget.h:151
QWidget * parentWidget() const
Returns the parent of this widget, or \nullptr if it does not have any parent widget.
Definition qwidget.h:904
bool isWindow() const
Returns true if the widget is an independent window, otherwise returns false.
Definition qwidget.h:811
void showNormal()
Restores the widget after it has been maximized or minimized.
Definition qwidget.cpp:3067
bool isVisible() const
Definition qwidget.h:874
Qt::WindowType windowType() const
Returns the window type of this widget.
Definition qwidget.h:801
bool testAttribute(Qt::WidgetAttribute) const
Returns true if attribute attribute is set on this widget; otherwise returns false.
Definition qwidget.h:910
QOpenGLWidget * widget
[1]
for(qsizetype i=0;i< list.size();++i)
rect
[4]
fontMetrics
void newState(QList< State > &states, const char *token, const char *lexem, bool pre)
short next
Definition keywords.cpp:445
Combined button and popup list for selecting options.
@ WindowMinimized
Definition qnamespace.h:252
@ WindowMaximized
Definition qnamespace.h:253
@ WindowActive
Definition qnamespace.h:255
@ MiddleButton
Definition qnamespace.h:59
@ WA_Resized
Definition qnamespace.h:307
@ WA_Moved
Definition qnamespace.h:308
@ WA_OpaquePaintEvent
Definition qnamespace.h:286
@ WA_DeleteOnClose
Definition qnamespace.h:320
@ LeftToRight
@ NoFocus
Definition qnamespace.h:106
Orientation
Definition qnamespace.h:97
@ Horizontal
Definition qnamespace.h:98
@ Vertical
Definition qnamespace.h:99
@ Key_Escape
Definition qnamespace.h:658
@ Key_Tab
Definition qnamespace.h:659
@ Key_Backtab
Definition qnamespace.h:660
@ Key_Control
Definition qnamespace.h:679
ScrollBarPolicy
@ ScrollBarAlwaysOff
@ ScrollBarAlwaysOn
@ ScrollBarAsNeeded
@ ControlModifier
@ WindowStaysOnTopHint
Definition qnamespace.h:232
@ SubWindow
Definition qnamespace.h:215
Definition brush.cpp:5
#define Q_FALLTHROUGH()
#define Q_UNLIKELY(x)
DBusConnection const char DBusError * error
qfloat16 qSqrt(qfloat16 f)
Definition qfloat16.h:243
static int area(const QSize &s)
Definition qicon.cpp:152
Q_WIDGETS_EXPORT QSize qSmartMinSize(const QSize &sizeHint, const QSize &minSizeHint, const QSize &minSize, const QSize &maxSize, const QSizePolicy &sizePolicy)
static const double leftOffset
static const double rightOffset
#define qWarning
Definition qlogging.h:162
int qCeil(T v)
Definition qmath.h:36
static QString tabTextFor(QMdiSubWindow *subWindow)
Definition qmdiarea.cpp:226
static bool sanityCheck(const QMdiSubWindow *const child, const char *where)
Definition qmdiarea.cpp:147
static QMdiArea * mdiAreaParent(QWidget *widget)
Definition qmdiarea.cpp:208
static bool useScrollBar(const QRect &childrenRect, const QSize &maxViewportSize, Qt::Orientation orientation)
Definition qmdiarea.cpp:194
static void setIndex(int *index, int candidate, int min, int max, bool isIncreasing)
Definition qmdiarea.cpp:175
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
#define SLOT(a)
Definition qobjectdefs.h:51
#define SIGNAL(a)
Definition qobjectdefs.h:52
GLint GLint GLint GLint GLint x
[0]
GLenum mode
GLint GLsizei GLsizei height
GLuint GLfloat GLfloat GLfloat GLfloat y1
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLuint GLfloat GLfloat GLfloat x1
GLdouble GLdouble GLdouble GLdouble top
GLenum GLenum GLsizei count
GLdouble GLdouble right
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLint GLsizei width
GLint left
GLint GLint bottom
GLboolean enable
GLfloat n
GLint y
GLsizei GLsizei GLchar * source
struct _cl_event * event
GLfixed GLfixed GLfixed y2
GLfixed GLfixed x2
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLenum GLenum GLsizei void * row
GLuint64EXT * result
[6]
GLuint GLenum option
GLfixed GLfixed GLint GLint order
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
QTabBar::Shape _q_tb_tabBarShapeFrom(QTabWidget::TabShape shape, QTabWidget::TabPosition position)
#define QT_CONFIG(feature)
#define emit
#define Q_UNUSED(x)
double qreal
Definition qtypes.h:92
QString qt_setWindowTitle_helperHelper(const QString &title, const QWidget *widget)
Returns a modified window title with the [*] place holder replaced according to the rules described i...
Definition qwidget.cpp:5996
QWidget * qobject_cast< QWidget * >(QObject *o)
Definition qwidget.h:786
#define enabled
QList< int > list
[14]
if(qFloatDistance(a, b)<(1<< 7))
[0]
QList< QWidget * > widgets
[11]
QObject::connect nullptr
QString title
[35]
view viewport() -> scroll(dx, dy, deviceRect)
edit isVisible()
QLayoutItem * child
[0]
QPainter painter(this)
[7]
aWidget window() -> setWindowTitle("New Window Title")
[2]
QFrame frame
[0]
label setFrameStyle(QFrame::Panel|QFrame::Raised)
QSizePolicy policy
qsizetype indexOf(const AT &t, qsizetype from=0) const noexcept
Definition qlist.h:955
bool contains(const AT &t) const noexcept
Definition qlist.h:44
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent