Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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
213 QWidget *parent = widget->parentWidget();
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
245void RegularTiler::rearrange(QList<QWidget *> &widgets, const QRect &domain) const
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
289void SimpleCascader::rearrange(QList<QWidget *> &widgets, const QRect &domain) const
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
332void IconTiler::rearrange(QList<QWidget *> &widgets, const QRect &domain) const
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{
401 QList<QRect> result;
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
443 QList<QRect> result;
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{
459 QList<QRect> result;
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,
485 QList<QRect> &source)
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
503QPoint MinOverlapPlacer::place(const QSize &size, const QList<QRect> &rects,
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 // Take a copy because child->showNormal() could indirectly call
675 // QCoreApplication::sendEvent(), which could call unknown code that e.g.
676 // recurses into the class modifying childWindows.
677 const auto subWindows = childWindows;
678 for (QMdiSubWindow *child : subWindows) {
679 if (!sanityCheck(child, "QMdiArea::deactivateAllWindows") || aboutToBecomeActive == child)
680 continue;
681 // We don't want to handle signals caused by child->showNormal().
684 showActiveWindowMaximized = child->isMaximized() && child->isVisible();
685 if (showActiveWindowMaximized && child->isMaximized()) {
686 if (q->updatesEnabled()) {
687 updatesDisabledByUs = true;
688 q->setUpdatesEnabled(false);
689 }
690 child->showNormal();
691 }
692 if (child->isMinimized() && !child->isShaded() && !windowStaysOnTop(child))
693 child->lower();
695 child->d_func()->setActive(false);
696 }
697}
698
703 Qt::WindowStates newState)
704{
706 return;
707
708 Q_Q(QMdiArea);
709 QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(q->sender());
710 if (!child)
711 return;
712
713 // windowActivated
714 if (!(oldState & Qt::WindowActive) && (newState & Qt::WindowActive))
716 // windowDeactivated
717 else if ((oldState & Qt::WindowActive) && !(newState & Qt::WindowActive))
719
720 // windowMinimized
721 if (!(oldState & Qt::WindowMinimized) && (newState & Qt::WindowMinimized)) {
722 isSubWindowsTiled = false;
724 // windowMaximized
725 } else if (!(oldState & Qt::WindowMaximized) && (newState & Qt::WindowMaximized)) {
727 // windowRestored
730 if (oldState & Qt::WindowMinimized)
732 }
733}
734
736{
737#if !QT_CONFIG(tabbar)
739#else
740 if (!tabBar || index < 0)
741 return;
742
743 // If the previous active sub-window was hidden, disable the tab.
744 if (indexToLastActiveTab >= 0 && indexToLastActiveTab < tabBar->count()
747 if (lastActive && lastActive->isHidden())
748 tabBar->setTabEnabled(indexToLastActiveTab, false);
749 }
750
753 QMdiSubWindow *subWindow = childWindows.at(index);
754 Q_ASSERT(subWindow);
755 activateWindow(subWindow);
756#endif // QT_CONFIG(tabbar)
757}
758
760{
761#if !QT_CONFIG(tabbar)
763#else
764 QMdiSubWindow *subWindow = childWindows.at(index);
765 Q_ASSERT(subWindow);
766 subWindow->close();
767#endif // QT_CONFIG(tabbar)
768}
769
770void QMdiAreaPrivate::_q_moveTab(int from, int to)
771{
772#if !QT_CONFIG(tabbar)
773 Q_UNUSED(from);
774 Q_UNUSED(to);
775#else
776 childWindows.move(from, to);
777#endif // QT_CONFIG(tabbar)
778}
779
784{
785 Q_Q(QMdiArea);
787
788 if (child->parent() != viewport)
789 child->setParent(viewport, child->windowFlags());
790 childWindows.append(QPointer<QMdiSubWindow>(child));
791
792 if (!child->testAttribute(Qt::WA_Resized) && q->isVisible()) {
793 QSize newSize(child->sizeHint().boundedTo(viewport->size()));
794 child->resize(newSize.expandedTo(qSmartMinSize(child)));
795 }
796
797 if (!placer)
800
801 if (hbarpolicy != Qt::ScrollBarAlwaysOff)
803 else
805
806 if (vbarpolicy != Qt::ScrollBarAlwaysOff)
808 else
810
814
815#if QT_CONFIG(tabbar)
816 if (tabBar) {
817 tabBar->addTab(child->windowIcon(), tabTextFor(child));
818 updateTabBarGeometry();
821 }
822#endif
823
824 if (!(child->windowFlags() & Qt::SubWindow))
825 child->setWindowFlags(Qt::SubWindow);
826 child->installEventFilter(q);
827
828 QObject::connect(child, SIGNAL(aboutToActivate()), q, SLOT(_q_deactivateAllWindows()));
829 QObject::connect(child, SIGNAL(windowStateChanged(Qt::WindowStates,Qt::WindowStates)),
830 q, SLOT(_q_processWindowStateChanged(Qt::WindowStates,Qt::WindowStates)));
831}
832
837{
838 if (!placer || !child)
839 return;
840
841 Q_Q(QMdiArea);
842 if (!q->isVisible()) {
843 // The window is only laid out when it's added to QMdiArea,
844 // so there's no need to check that we don't have it in the
845 // list already. appendChild() ensures that.
847 return;
848 }
849
850 QList<QRect> rects;
851 rects.reserve(childWindows.size());
852 QRect parentRect = q->rect();
853 for (QMdiSubWindow *window : std::as_const(childWindows)) {
854 if (!sanityCheck(window, "QMdiArea::place") || window == child || !window->isVisibleTo(q)
855 || !window->testAttribute(Qt::WA_Moved)) {
856 continue;
857 }
858 QRect occupiedGeometry;
859 if (window->isMaximized()) {
860 occupiedGeometry = QRect(window->d_func()->oldGeometry.topLeft(),
861 window->d_func()->restoreSize);
862 } else {
863 occupiedGeometry = window->geometry();
864 }
865 rects.append(QStyle::visualRect(child->layoutDirection(), parentRect, occupiedGeometry));
866 }
867 QPoint newPos = placer->place(child->size(), rects, parentRect);
868 QRect newGeometry = QRect(newPos.x(), newPos.y(), child->width(), child->height());
869 child->setGeometry(QStyle::visualRect(child->layoutDirection(), parentRect, newGeometry));
870}
871
876{
877 if (!rearranger)
878 return;
879
880 Q_Q(QMdiArea);
881 if (!q->isVisible()) {
882 // Compress if we already have the rearranger in the list.
883 int index = pendingRearrangements.indexOf(rearranger);
884 if (index != -1)
886 else
887 pendingRearrangements.append(rearranger);
888 return;
889 }
890
891 QList<QWidget *> widgets;
892 const bool reverseList = rearranger->type() == Rearranger::RegularTiler;
893 const QList<QMdiSubWindow *> subWindows = subWindowList(activationOrder, reverseList);
894 QSize minSubWindowSize;
895 for (QMdiSubWindow *child : subWindows) {
896 if (!sanityCheck(child, "QMdiArea::rearrange") || !child->isVisible())
897 continue;
898 if (rearranger->type() == Rearranger::IconTiler) {
899 if (child->isMinimized() && !child->isShaded())
901 } else {
902 if (child->isMinimized() && !child->isShaded())
903 continue;
904 if (child->isMaximized() || child->isShaded())
905 child->showNormal();
906 minSubWindowSize = minSubWindowSize.expandedTo(child->minimumSize())
907 .expandedTo(child->d_func()->internalMinimumSize);
909 }
910 }
911
912 QRect domain = viewport->rect();
913 if (rearranger->type() == Rearranger::RegularTiler && !widgets.isEmpty())
914 domain = resizeToMinimumTileSize(minSubWindowSize, widgets.size());
915
916 rearranger->rearrange(widgets, domain);
917
918 if (rearranger->type() == Rearranger::RegularTiler && !widgets.isEmpty()) {
919 isSubWindowsTiled = true;
921 } else if (rearranger->type() == Rearranger::SimpleCascader) {
922 isSubWindowsTiled = false;
923 }
924}
925
937
942{
943 if (childWindows.isEmpty()) {
944 Q_ASSERT(!child);
946 return;
947 }
948
949 if (!child) {
950 if (active) {
951 Q_ASSERT(active->d_func()->isActive);
952 active->d_func()->setActive(false);
954 }
955 return;
956 }
957
958 if (child->isHidden() || child == active)
959 return;
960
961 if (child->d_func()->isActive && active == nullptr)
962 child->d_func()->isActive = false;
963
964 child->d_func()->setActive(true);
965}
966
971{
972 QMdiSubWindow *current = q_func()->currentSubWindow();
973 if (current && !isExplicitlyDeactivated(current)) {
974 current->d_func()->activationEnabled = true;
975 current->d_func()->setActive(true, /*changeFocus=*/false);
976 }
977}
978
980{
981 if (indexToHighlighted < 0)
982 return;
983
985 if (tabToPreviousTimerId != -1)
987 else
989#if QT_CONFIG(rubberband)
990 hideRubberBand();
991#endif
992}
993
998{
999 Q_Q(QMdiArea);
1000 Q_ASSERT(activeWindow);
1001 if (activeWindow == active)
1002 return;
1003 Q_ASSERT(activeWindow->d_func()->isActive);
1004
1006 _q_deactivateAllWindows(activeWindow);
1008
1009 // This is true only if 'DontMaximizeSubWindowOnActivation' is disabled
1010 // and the previous active window was maximized.
1012 if (!activeWindow->isMaximized())
1013 activeWindow->showMaximized();
1015 }
1016
1017 // Put in front to update activation order.
1018 const int indexToActiveWindow = childWindows.indexOf(activeWindow);
1019 Q_ASSERT(indexToActiveWindow != -1);
1020 const int index = indicesToActivatedChildren.indexOf(indexToActiveWindow);
1021 Q_ASSERT(index != -1);
1023 internalRaise(activeWindow);
1024
1025 if (updatesDisabledByUs) {
1026 q->setUpdatesEnabled(true);
1027 updatesDisabledByUs = false;
1028 }
1029
1030 Q_ASSERT(aboutToBecomeActive == activeWindow);
1031 active = activeWindow;
1032 aboutToBecomeActive = nullptr;
1033 Q_ASSERT(active->d_func()->isActive);
1034
1035#if QT_CONFIG(tabbar)
1036 if (tabBar && tabBar->currentIndex() != indexToActiveWindow)
1037 tabBar->setCurrentIndex(indexToActiveWindow);
1038#endif
1039
1042
1043 emit q->subWindowActivated(active);
1044}
1045
1050{
1051 Q_Q(QMdiArea);
1052 if (deactivatedWindow) {
1053 if (deactivatedWindow != active)
1054 return;
1055 active = nullptr;
1057 && !isExplicitlyDeactivated(deactivatedWindow) && !q->window()->isMinimized()) {
1058 return;
1059 }
1060 emit q->subWindowActivated(nullptr);
1061 return;
1062 }
1063
1065 return;
1066
1067 active = nullptr;
1068 emit q->subWindowActivated(nullptr);
1069}
1070
1074void QMdiAreaPrivate::updateActiveWindow(int removedIndex, bool activeRemoved)
1075{
1077
1078#if QT_CONFIG(tabbar)
1079 if (tabBar && removedIndex >= 0) {
1080 const QSignalBlocker blocker(tabBar);
1081 tabBar->removeTab(removedIndex);
1082 updateTabBarGeometry();
1083 }
1084#endif
1085
1086 if (childWindows.isEmpty()) {
1089 return;
1090 }
1091
1092 if (indexToHighlighted >= 0) {
1093#if QT_CONFIG(rubberband)
1094 // Hide rubber band if highlighted window is removed.
1095 if (indexToHighlighted == removedIndex)
1096 hideRubberBand();
1097 else
1098#endif
1099 // or update index if necessary.
1100 if (indexToHighlighted > removedIndex)
1102 }
1103
1104 // Update indices list
1105 for (int i = 0; i < indicesToActivatedChildren.size(); ++i) {
1107 if (*index > removedIndex)
1108 --*index;
1109 }
1110
1111 if (!activeRemoved)
1112 return;
1113
1114 // Activate next window.
1116 if (next)
1118}
1119
1124{
1126 return;
1127
1128 Q_Q(QMdiArea);
1129 QSize maxSize = q->maximumViewportSize();
1130 QSize hbarExtent = hbar->sizeHint();
1131 QSize vbarExtent = vbar->sizeHint();
1132
1133 if (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents, nullptr, q)) {
1134 const int doubleFrameWidth = frameWidth * 2;
1135 if (hbarpolicy == Qt::ScrollBarAlwaysOn)
1136 maxSize.rheight() -= doubleFrameWidth;
1137 if (vbarpolicy == Qt::ScrollBarAlwaysOn)
1138 maxSize.rwidth() -= doubleFrameWidth;
1139 hbarExtent.rheight() += doubleFrameWidth;
1140 vbarExtent.rwidth() += doubleFrameWidth;
1141 }
1142
1143 const QRect childrenRect = active && active->isMaximized()
1144 ? active->geometry() : viewport->childrenRect();
1145 bool useHorizontalScrollBar = useScrollBar(childrenRect, maxSize, Qt::Horizontal);
1146 bool useVerticalScrollBar = useScrollBar(childrenRect, maxSize, Qt::Vertical);
1147
1148 if (useHorizontalScrollBar && !useVerticalScrollBar) {
1149 const QSize max = maxSize - QSize(0, hbarExtent.height());
1150 useVerticalScrollBar = useScrollBar(childrenRect, max, Qt::Vertical);
1151 }
1152
1153 if (useVerticalScrollBar && !useHorizontalScrollBar) {
1154 const QSize max = maxSize - QSize(vbarExtent.width(), 0);
1155 useHorizontalScrollBar = useScrollBar(childrenRect, max, Qt::Horizontal);
1156 }
1157
1158 if (useHorizontalScrollBar && hbarpolicy != Qt::ScrollBarAlwaysOn)
1159 maxSize.rheight() -= hbarExtent.height();
1160 if (useVerticalScrollBar && vbarpolicy != Qt::ScrollBarAlwaysOn)
1161 maxSize.rwidth() -= vbarExtent.width();
1162
1163 QRect viewportRect(QPoint(0, 0), maxSize);
1164 const int startX = q->isLeftToRight() ? childrenRect.left() : viewportRect.right()
1165 - childrenRect.right();
1166
1167 // Horizontal scroll bar.
1168 if (isSubWindowsTiled && hbar->value() != 0)
1169 hbar->setValue(0);
1170 const int xOffset = startX + hbar->value();
1171 hbar->setRange(qMin(0, xOffset),
1172 qMax(0, xOffset + childrenRect.width() - viewportRect.width()));
1173 hbar->setPageStep(childrenRect.width());
1174 hbar->setSingleStep(childrenRect.width() / 20);
1175
1176 // Vertical scroll bar.
1177 if (isSubWindowsTiled && vbar->value() != 0)
1178 vbar->setValue(0);
1179 const int yOffset = childrenRect.top() + vbar->value();
1180 vbar->setRange(qMin(0, yOffset),
1181 qMax(0, yOffset + childrenRect.height() - viewportRect.height()));
1182 vbar->setPageStep(childrenRect.height());
1183 vbar->setSingleStep(childrenRect.height() / 20);
1184}
1185
1190{
1191 if (!sanityCheck(mdiChild, "QMdiArea::internalRaise") || childWindows.size() < 2)
1192 return;
1193
1194 QMdiSubWindow *stackUnderChild = nullptr;
1195 if (!windowStaysOnTop(mdiChild)) {
1196 const auto children = viewport->children(); // take a copy, as raising/stacking under changes the order
1197 for (QObject *object : children) {
1198 QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(object);
1199 if (!child || !childWindows.contains(child))
1200 continue;
1201 if (!child->isHidden() && windowStaysOnTop(child)) {
1202 if (stackUnderChild)
1203 child->stackUnder(stackUnderChild);
1204 else
1205 child->raise();
1206 stackUnderChild = child;
1207 }
1208 }
1209 }
1210
1211 if (stackUnderChild)
1212 mdiChild->stackUnder(stackUnderChild);
1213 else
1214 mdiChild->raise();
1215}
1216
1217QRect QMdiAreaPrivate::resizeToMinimumTileSize(const QSize &minSubWindowSize, int subWindowCount)
1218{
1219 Q_Q(QMdiArea);
1220 if (!minSubWindowSize.isValid() || subWindowCount <= 0)
1221 return viewport->rect();
1222
1223 // Calculate minimum size.
1224 const int columns = qMax(qCeil(qSqrt(qreal(subWindowCount))), 1);
1225 const int rows = qMax((subWindowCount % columns) ? (subWindowCount / columns + 1)
1226 : (subWindowCount / columns), 1);
1227 const int minWidth = minSubWindowSize.width() * columns;
1228 const int minHeight = minSubWindowSize.height() * rows;
1229
1230 // Increase area size if necessary. Scroll bars are provided if we're not able
1231 // to resize to the minimum size.
1233 QWidget *topLevel = q;
1234 // Find the topLevel for this area, either a real top-level or a sub-window.
1235 while (topLevel && !topLevel->isWindow() && topLevel->windowType() != Qt::SubWindow)
1236 topLevel = topLevel->parentWidget();
1237 // We don't want sub-subwindows to be placed at the edge, thus add 2 pixels.
1238 int minAreaWidth = minWidth + left + right + 2;
1239 int minAreaHeight = minHeight + top + bottom + 2;
1240 if (hbar->isVisible())
1241 minAreaHeight += hbar->height();
1242 if (vbar->isVisible())
1243 minAreaWidth += vbar->width();
1244 if (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents, nullptr, q)) {
1245 const int frame = q->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, nullptr, q);
1246 minAreaWidth += 2 * frame;
1247 minAreaHeight += 2 * frame;
1248 }
1249 const QSize diff = QSize(minAreaWidth, minAreaHeight).expandedTo(q->size()) - q->size();
1250 // Only resize topLevel widget if scroll bars are disabled.
1251 if (hbarpolicy == Qt::ScrollBarAlwaysOff)
1252 topLevel->resize(topLevel->size().width() + diff.width(), topLevel->size().height());
1253 if (vbarpolicy == Qt::ScrollBarAlwaysOff)
1254 topLevel->resize(topLevel->size().width(), topLevel->size().height() + diff.height());
1255 }
1256
1257 QRect domain = viewport->rect();
1258
1259 // Adjust domain width and provide horizontal scroll bar.
1260 if (domain.width() < minWidth) {
1261 domain.setWidth(minWidth);
1262 if (hbarpolicy == Qt::ScrollBarAlwaysOff)
1263 q->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
1264 else
1265 hbar->setValue(0);
1266 }
1267 // Adjust domain height and provide vertical scroll bar.
1268 if (domain.height() < minHeight) {
1269 domain.setHeight(minHeight);
1270 if (vbarpolicy == Qt::ScrollBarAlwaysOff)
1271 q->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
1272 else
1273 vbar->setValue(0);
1274 }
1275 return domain;
1276}
1277
1282{
1283 return hbarpolicy != Qt::ScrollBarAlwaysOff || vbarpolicy != Qt::ScrollBarAlwaysOff;
1284}
1285
1290{
1291 if (childWindows.size() != 1)
1292 return false;
1293
1294 QMdiSubWindow *last = childWindows.at(0);
1295 if (!last)
1296 return true;
1297
1299 return false;
1300
1301 return last->d_func()->data.is_closing;
1302}
1303
1307void QMdiAreaPrivate::setChildActivationEnabled(bool enable, bool onlyNextActivationEvent) const
1308{
1309 for (QMdiSubWindow *subWindow : childWindows) {
1310 if (!subWindow || !subWindow->isVisible())
1311 continue;
1312 if (onlyNextActivationEvent)
1313 subWindow->d_func()->ignoreNextActivationEvent = !enable;
1314 else
1315 subWindow->d_func()->activationEnabled = enable;
1316 }
1317}
1318
1324{
1325 if (childWindows.isEmpty())
1326 return;
1327
1330 const bool enable = policy != Qt::ScrollBarAlwaysOff;
1331 // Take a copy because child->setOption() may indirectly call QCoreApplication::sendEvent(),
1332 // the latter could call unknown code that could e.g. recurse into the class
1333 // modifying childWindows.
1334 const auto subWindows = childWindows;
1335 for (QMdiSubWindow *child : subWindows) {
1336 if (!sanityCheck(child, "QMdiArea::scrollBarPolicyChanged"))
1337 continue;
1338 child->setOption(option, enable);
1339 }
1341}
1342
1343QList<QMdiSubWindow*>
1345{
1346 QList<QMdiSubWindow *> list;
1347 if (childWindows.isEmpty())
1348 return list;
1349
1352 if (!child)
1353 continue;
1354 if (!reversed)
1355 list.append(child);
1356 else
1358 }
1359 } else if (order == QMdiArea::StackingOrder) {
1360 for (QObject *object : viewport->children()) {
1361 QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(object);
1362 if (!child || !childWindows.contains(child))
1363 continue;
1364 if (!reversed)
1365 list.append(child);
1366 else
1368 }
1369 } else { // ActivationHistoryOrder
1371 for (int i = indicesToActivatedChildren.size() - 1; i >= 0; --i) {
1373 if (!child)
1374 continue;
1375 if (!reversed)
1376 list.append(child);
1377 else
1379 }
1380 }
1381 return list;
1382}
1383
1388{
1389 if (!subWindow)
1390 return;
1391
1392 Q_Q(QMdiArea);
1393 QObject::disconnect(subWindow, nullptr, q, nullptr);
1394 subWindow->removeEventFilter(q);
1395}
1396
1401 int removedIndex, int fromIndex) const
1402{
1403 if (childWindows.isEmpty())
1404 return nullptr;
1405
1406 Q_Q(const QMdiArea);
1407 const QList<QMdiSubWindow *> subWindows = q->subWindowList(order);
1408 QMdiSubWindow *current = nullptr;
1409
1410 if (removedIndex < 0) {
1411 if (fromIndex >= 0 && fromIndex < subWindows.size())
1412 current = childWindows.at(fromIndex);
1413 else
1414 current = q->currentSubWindow();
1415 }
1416
1417 // There's no current sub-window (removed or deactivated),
1418 // so we have to pick the last active or the next in creation order.
1419 if (!current) {
1420 if (removedIndex >= 0 && order == QMdiArea::CreationOrder) {
1421 int candidateIndex = -1;
1422 setIndex(&candidateIndex, removedIndex, 0, subWindows.size() - 1, true);
1423 current = childWindows.at(candidateIndex);
1424 } else {
1425 current = subWindows.back();
1426 }
1427 }
1428 Q_ASSERT(current);
1429
1430 // Find the index for the current sub-window in the given activation order
1431 const int indexToCurrent = subWindows.indexOf(current);
1432 const bool increasing = increaseFactor > 0;
1433
1434 // and use that index + increseFactor as a candidate.
1435 int index = -1;
1436 setIndex(&index, indexToCurrent + increaseFactor, 0, subWindows.size() - 1, increasing);
1437 Q_ASSERT(index != -1);
1438
1439 // Try to find another window if the candidate is hidden.
1440 while (subWindows.at(index)->isHidden()) {
1441 setIndex(&index, index + increaseFactor, 0, subWindows.size() - 1, increasing);
1442 if (index == indexToCurrent)
1443 break;
1444 }
1445
1446 if (!subWindows.at(index)->isHidden())
1447 return subWindows.at(index);
1448 return nullptr;
1449}
1450
1455{
1456 if (childWindows.size() == 1)
1457 return;
1458
1459 Q_Q(QMdiArea);
1460 // There's no highlighted sub-window atm, use current.
1461 if (indexToHighlighted < 0) {
1462 QMdiSubWindow *current = q->currentSubWindow();
1463 if (!current)
1464 return;
1466 }
1467
1470
1471 QMdiSubWindow *highlight = nextVisibleSubWindow(increaseFactor, activationOrder, -1, indexToHighlighted);
1472 if (!highlight)
1473 return;
1474
1475#if QT_CONFIG(rubberband)
1476 if (!rubberBand) {
1477 rubberBand = new QRubberBand(QRubberBand::Rectangle, q);
1478 // For accessibility to identify this special widget.
1479 rubberBand->setObjectName("qt_rubberband"_L1);
1480 rubberBand->setWindowFlags(rubberBand->windowFlags() | Qt::WindowStaysOnTopHint);
1481 }
1482#endif
1483
1484 // Only highlight if we're not switching back to the previously active window (Ctrl-Tab once).
1485#if QT_CONFIG(rubberband)
1486 if (tabToPreviousTimerId == -1)
1487 showRubberBandFor(highlight);
1488#endif
1489
1492}
1493
1494#if QT_CONFIG(rubberband)
1495void QMdiAreaPrivate::showRubberBandFor(QMdiSubWindow *subWindow)
1496{
1497 if (!subWindow || !rubberBand)
1498 return;
1499
1500#if QT_CONFIG(tabbar)
1502 rubberBand->setGeometry(tabBar->tabRect(childWindows.indexOf(subWindow)));
1503 else
1504#endif
1505 rubberBand->setGeometry(subWindow->geometry());
1506
1507 rubberBand->raise();
1508 rubberBand->show();
1509}
1510#endif // QT_CONFIG(rubberBand)
1515void QMdiAreaPrivate::setViewMode(QMdiArea::ViewMode mode)
1516{
1517 Q_Q(QMdiArea);
1518 if (viewMode == mode || inViewModeChange)
1519 return;
1520
1521 // Just a guard since we cannot set viewMode = mode here.
1522 inViewModeChange = true;
1523
1524#if QT_CONFIG(tabbar)
1525 if (mode == QMdiArea::TabbedView) {
1526 Q_ASSERT(!tabBar);
1527 tabBar = new QMdiAreaTabBar(q);
1528 tabBar->setDocumentMode(documentMode);
1529 tabBar->setTabsClosable(tabsClosable);
1530 tabBar->setMovable(tabsMovable);
1531#if QT_CONFIG(tabwidget)
1532 tabBar->setShape(_q_tb_tabBarShapeFrom(tabShape, tabPosition));
1533#endif
1534
1535 isSubWindowsTiled = false;
1536
1537 // Take a copy as tabBar->addTab() will (indirectly) create a connection between
1538 // the tab close button clicked() signal and the _q_closeTab() slot, which may
1539 // indirectly call QCoreApplication::sendEvent(), the latter could result in
1540 // invoking unknown code that could e.g. recurse into the class modifying childWindows.
1541 const auto subWindows = childWindows;
1542 for (QMdiSubWindow *subWindow : subWindows)
1543 tabBar->addTab(subWindow->windowIcon(), tabTextFor(subWindow));
1544
1545 QMdiSubWindow *current = q->currentSubWindow();
1546 if (current) {
1547 tabBar->setCurrentIndex(childWindows.indexOf(current));
1548 // Restore sub-window (i.e. cleanup buttons in menu bar and window title).
1549 if (current->isMaximized())
1550 current->showNormal();
1551
1552 viewMode = mode;
1553
1554 // Now, maximize it.
1556 current->showMaximized();
1557 }
1558 } else {
1559 viewMode = mode;
1560 }
1561
1562 if (q->isVisible())
1563 tabBar->show();
1564 updateTabBarGeometry();
1565
1566 QObject::connect(tabBar, SIGNAL(currentChanged(int)), q, SLOT(_q_currentTabChanged(int)));
1567 QObject::connect(tabBar, SIGNAL(tabCloseRequested(int)), q, SLOT(_q_closeTab(int)));
1568 QObject::connect(tabBar, SIGNAL(tabMoved(int,int)), q, SLOT(_q_moveTab(int,int)));
1569 } else
1570#endif // QT_CONFIG(tabbar)
1571 { // SubWindowView
1572#if QT_CONFIG(tabbar)
1573 delete tabBar;
1574 tabBar = nullptr;
1575#endif // QT_CONFIG(tabbar)
1576
1577 viewMode = mode;
1578 q->setViewportMargins(0, 0, 0, 0);
1579 indexToLastActiveTab = -1;
1580
1581 QMdiSubWindow *current = q->currentSubWindow();
1582 if (current && current->isMaximized())
1583 current->showNormal();
1584 }
1585
1586 Q_ASSERT(viewMode == mode);
1587 inViewModeChange = false;
1588}
1589
1590#if QT_CONFIG(tabbar)
1594void QMdiAreaPrivate::updateTabBarGeometry()
1595{
1596 if (!tabBar)
1597 return;
1598
1599 Q_Q(QMdiArea);
1600#if QT_CONFIG(tabwidget)
1601 Q_ASSERT(_q_tb_tabBarShapeFrom(tabShape, tabPosition) == tabBar->shape());
1602#endif
1603 const QSize tabBarSizeHint = tabBar->sizeHint();
1604
1605 int areaHeight = q->height();
1606 if (hbar && hbar->isVisible())
1607 areaHeight -= hbar->height();
1608
1609 int areaWidth = q->width();
1610 if (vbar && vbar->isVisible())
1611 areaWidth -= vbar->width();
1612
1613 QRect tabBarRect;
1614#if QT_CONFIG(tabwidget)
1615 switch (tabPosition) {
1616 case QTabWidget::North:
1617 q->setViewportMargins(0, tabBarSizeHint.height(), 0, 0);
1618 tabBarRect = QRect(0, 0, areaWidth, tabBarSizeHint.height());
1619 break;
1620 case QTabWidget::South:
1621 q->setViewportMargins(0, 0, 0, tabBarSizeHint.height());
1622 tabBarRect = QRect(0, areaHeight - tabBarSizeHint.height(), areaWidth, tabBarSizeHint.height());
1623 break;
1624 case QTabWidget::East:
1625 if (q->layoutDirection() == Qt::LeftToRight)
1626 q->setViewportMargins(0, 0, tabBarSizeHint.width(), 0);
1627 else
1628 q->setViewportMargins(tabBarSizeHint.width(), 0, 0, 0);
1629 tabBarRect = QRect(areaWidth - tabBarSizeHint.width(), 0, tabBarSizeHint.width(), areaHeight);
1630 break;
1631 case QTabWidget::West:
1632 if (q->layoutDirection() == Qt::LeftToRight)
1633 q->setViewportMargins(tabBarSizeHint.width(), 0, 0, 0);
1634 else
1635 q->setViewportMargins(0, 0, tabBarSizeHint.width(), 0);
1636 tabBarRect = QRect(0, 0, tabBarSizeHint.width(), areaHeight);
1637 break;
1638 default:
1639 break;
1640 }
1641#endif // QT_CONFIG(tabwidget)
1642
1643 tabBar->setGeometry(QStyle::visualRect(q->layoutDirection(), q->contentsRect(), tabBarRect));
1644}
1645
1649void QMdiAreaPrivate::refreshTabBar()
1650{
1651 if (!tabBar)
1652 return;
1653
1654 tabBar->setDocumentMode(documentMode);
1655 tabBar->setTabsClosable(tabsClosable);
1656 tabBar->setMovable(tabsMovable);
1657#if QT_CONFIG(tabwidget)
1658 tabBar->setShape(_q_tb_tabBarShapeFrom(tabShape, tabPosition));
1659#endif
1660 updateTabBarGeometry();
1661}
1662#endif // QT_CONFIG(tabbar)
1663
1669 : QAbstractScrollArea(*new QMdiAreaPrivate, parent)
1670{
1673 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1674 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1675 setViewport(nullptr);
1676 setFocusPolicy(Qt::NoFocus);
1677 QApplication::instance()->installEventFilter(this);
1678}
1679
1684{
1685 Q_D(QMdiArea);
1686 delete d->cascader;
1687 d->cascader = nullptr;
1688
1689 delete d->regularTiler;
1690 d->regularTiler = nullptr;
1691
1692 delete d->iconTiler;
1693 d->iconTiler = nullptr;
1694
1695 delete d->placer;
1696 d->placer = nullptr;
1697}
1698
1703{
1704 // Calculate a proper scale factor for the desktop's size.
1705 // This also takes into account that we can have nested workspaces.
1706 int nestedCount = 0;
1707 QWidget *widget = this->parentWidget();
1708 while (widget) {
1709 if (qobject_cast<QMdiArea *>(widget))
1710 ++nestedCount;
1712 }
1713 const int scaleFactor = 3 * (nestedCount + 1);
1714
1716 QSize size(desktopSize.width() * 2 / scaleFactor, desktopSize.height() * 2 / scaleFactor);
1717 for (QMdiSubWindow *child : d_func()->childWindows) {
1718 if (!sanityCheck(child, "QMdiArea::sizeHint"))
1719 continue;
1720 size = size.expandedTo(child->sizeHint());
1721 }
1722 return size;
1723}
1724
1729{
1730 Q_D(const QMdiArea);
1731 QSize size(style()->pixelMetric(QStyle::PM_MdiSubWindowMinimizedWidth, nullptr, this),
1732 style()->pixelMetric(QStyle::PM_TitleBarHeight, nullptr, this));
1733 size = size.expandedTo(QAbstractScrollArea::minimumSizeHint());
1734 if (!d->scrollBarsEnabled()) {
1735 for (QMdiSubWindow *child : d->childWindows) {
1736 if (!sanityCheck(child, "QMdiArea::sizeHint"))
1737 continue;
1738 size = size.expandedTo(child->minimumSizeHint());
1739 }
1740 }
1741 return size;
1742}
1743
1754{
1755 Q_D(const QMdiArea);
1756 if (d->childWindows.isEmpty())
1757 return nullptr;
1758
1759 if (d->active)
1760 return d->active;
1761
1762 if (d->isActivated && !window()->isMinimized())
1763 return nullptr;
1764
1765 Q_ASSERT(d->indicesToActivatedChildren.size() > 0);
1766 int index = d->indicesToActivatedChildren.at(0);
1767 Q_ASSERT(index >= 0 && index < d->childWindows.size());
1768 QMdiSubWindow *current = d->childWindows.at(index);
1769 Q_ASSERT(current);
1770 return current;
1771}
1772
1786{
1787 Q_D(const QMdiArea);
1788 return d->active;
1789}
1790
1798{
1799 Q_D(QMdiArea);
1800 if (!window) {
1801 d->activateWindow(nullptr);
1802 return;
1803 }
1804
1805 if (Q_UNLIKELY(d->childWindows.isEmpty())) {
1806 qWarning("QMdiArea::setActiveSubWindow: workspace is empty");
1807 return;
1808 }
1809
1810 if (Q_UNLIKELY(d->childWindows.indexOf(window) == -1)) {
1811 qWarning("QMdiArea::setActiveSubWindow: window is not inside workspace");
1812 return;
1813 }
1814
1815 d->activateWindow(window);
1816}
1817
1824{
1825 Q_D(QMdiArea);
1826 if (d->active)
1827 d->active->close();
1828}
1829
1841QList<QMdiSubWindow *> QMdiArea::subWindowList(WindowOrder order) const
1842{
1843 Q_D(const QMdiArea);
1844 return d->subWindowList(order, false);
1845}
1846
1858{
1859 Q_D(QMdiArea);
1860 if (d->childWindows.isEmpty())
1861 return;
1862
1863 d->isSubWindowsTiled = false;
1864 // Take a copy because the child->close() call below may end up indirectly calling
1865 // QCoreApplication::send{Spontaneous}Event(), which may call unknown code that
1866 // could e.g. recurse into the class modifying d->childWindows.
1867 const auto subWindows = d->childWindows;
1868 for (QMdiSubWindow *child : subWindows) {
1869 if (!sanityCheck(child, "QMdiArea::closeAllSubWindows"))
1870 continue;
1871 child->close();
1872 }
1873
1874 d->updateScrollBars();
1875}
1876
1885{
1886 Q_D(QMdiArea);
1887 if (d->childWindows.isEmpty())
1888 return;
1889
1890 QMdiSubWindow *next = d->nextVisibleSubWindow(1, d->activationOrder);
1891 if (next)
1892 d->activateWindow(next);
1893}
1894
1903{
1904 Q_D(QMdiArea);
1905 if (d->childWindows.isEmpty())
1906 return;
1907
1908 QMdiSubWindow *previous = d->nextVisibleSubWindow(-1, d->activationOrder);
1909 if (previous)
1910 d->activateWindow(previous);
1911}
1912
1937{
1938 if (Q_UNLIKELY(!widget)) {
1939 qWarning("QMdiArea::addSubWindow: null pointer to widget");
1940 return nullptr;
1941 }
1942
1943 Q_D(QMdiArea);
1944 // QWidget::setParent clears focusWidget so store it
1945 QWidget *childFocus = widget->focusWidget();
1946 QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(widget);
1947
1948 // Widget is already a QMdiSubWindow
1949 if (child) {
1950 if (Q_UNLIKELY(d->childWindows.indexOf(child) != -1)) {
1951 qWarning("QMdiArea::addSubWindow: window is already added");
1952 return child;
1953 }
1954 child->setParent(viewport(), windowFlags ? windowFlags : child->windowFlags());
1955 // Create a QMdiSubWindow
1956 } else {
1957 child = new QMdiSubWindow(viewport(), windowFlags);
1958 child->setAttribute(Qt::WA_DeleteOnClose);
1959 child->setWidget(widget);
1960 Q_ASSERT(child->testAttribute(Qt::WA_DeleteOnClose));
1961 }
1962
1963 d->appendChild(child);
1964
1965 if (childFocus)
1966 childFocus->setFocus();
1967
1968 return child;
1969}
1970
1982{
1983 if (Q_UNLIKELY(!widget)) {
1984 qWarning("QMdiArea::removeSubWindow: null pointer to widget");
1985 return;
1986 }
1987
1988 Q_D(QMdiArea);
1989 if (d->childWindows.isEmpty())
1990 return;
1991
1992 if (QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(widget)) {
1993 int index = d->childWindows.indexOf(child);
1994 if (Q_UNLIKELY(index == -1)) {
1995 qWarning("QMdiArea::removeSubWindow: window is not inside workspace");
1996 return;
1997 }
1998 d->disconnectSubWindow(child);
1999 d->childWindows.removeAll(child);
2000 d->indicesToActivatedChildren.removeAll(index);
2001 d->updateActiveWindow(index, d->active == child);
2002 child->setParent(nullptr);
2003 return;
2004 }
2005
2006 bool found = false;
2007 // Take a copy because child->setWidget(nullptr) will indirectly
2008 // QCoreApplication::sendEvent(); the latter could call unknown code that could
2009 // e.g. recurse into the class modifying d->childWindows.
2010 const auto subWindows = d->childWindows;
2011 for (QMdiSubWindow *child : subWindows) {
2012 if (!sanityCheck(child, "QMdiArea::removeSubWindow"))
2013 continue;
2014 if (child->widget() == widget) {
2015 child->setWidget(nullptr);
2016 Q_ASSERT(!child->widget());
2017 found = true;
2018 break;
2019 }
2020 }
2021
2022 if (Q_UNLIKELY(!found))
2023 qWarning("QMdiArea::removeSubWindow: widget is not child of any window inside QMdiArea");
2024}
2025
2035{
2036 return d_func()->background;
2037}
2038
2040{
2041 Q_D(QMdiArea);
2042 if (d->background != brush) {
2043 d->background = brush;
2044 d->viewport->setAttribute(Qt::WA_OpaquePaintEvent, brush.isOpaque());
2045 d->viewport->update();
2046 }
2047}
2048
2049
2062{
2063 Q_D(const QMdiArea);
2064 return d->activationOrder;
2065}
2066
2068{
2069 Q_D(QMdiArea);
2070 if (order != d->activationOrder)
2071 d->activationOrder = order;
2072}
2073
2081{
2082 Q_D(QMdiArea);
2083 d->options.setFlag(option, on);
2084}
2085
2092{
2093 return d_func()->options & option;
2094}
2095
2106{
2107 Q_D(const QMdiArea);
2108 return d->viewMode;
2109}
2110
2112{
2113 Q_D(QMdiArea);
2114 d->setViewMode(mode);
2115}
2116
2117#if QT_CONFIG(tabbar)
2127bool QMdiArea::documentMode() const
2128{
2129 Q_D(const QMdiArea);
2130 return d->documentMode;
2131}
2132
2133void QMdiArea::setDocumentMode(bool enabled)
2134{
2135 Q_D(QMdiArea);
2136 if (d->documentMode == enabled)
2137 return;
2138
2139 d->documentMode = enabled;
2140 d->refreshTabBar();
2141}
2142
2152bool QMdiArea::tabsClosable() const
2153{
2154 Q_D(const QMdiArea);
2155 return d->tabsClosable;
2156}
2157
2158void QMdiArea::setTabsClosable(bool closable)
2159{
2160 Q_D(QMdiArea);
2161 if (d->tabsClosable == closable)
2162 return;
2163
2164 d->tabsClosable = closable;
2165 d->refreshTabBar();
2166}
2167
2177bool QMdiArea::tabsMovable() const
2178{
2179 Q_D(const QMdiArea);
2180 return d->tabsMovable;
2181}
2182
2183void QMdiArea::setTabsMovable(bool movable)
2184{
2185 Q_D(QMdiArea);
2186 if (d->tabsMovable == movable)
2187 return;
2188
2189 d->tabsMovable = movable;
2190 d->refreshTabBar();
2191}
2192#endif // QT_CONFIG(tabbar)
2193
2194#if QT_CONFIG(tabwidget)
2205QTabWidget::TabShape QMdiArea::tabShape() const
2206{
2207 Q_D(const QMdiArea);
2208 return d->tabShape;
2209}
2210
2211void QMdiArea::setTabShape(QTabWidget::TabShape shape)
2212{
2213 Q_D(QMdiArea);
2214 if (d->tabShape == shape)
2215 return;
2216
2217 d->tabShape = shape;
2218 d->refreshTabBar();
2219}
2220
2231QTabWidget::TabPosition QMdiArea::tabPosition() const
2232{
2233 Q_D(const QMdiArea);
2234 return d->tabPosition;
2235}
2236
2237void QMdiArea::setTabPosition(QTabWidget::TabPosition position)
2238{
2239 Q_D(QMdiArea);
2240 if (d->tabPosition == position)
2241 return;
2242
2243 d->tabPosition = position;
2244 d->refreshTabBar();
2245}
2246#endif // QT_CONFIG(tabwidget)
2247
2252{
2253 Q_D(QMdiArea);
2254 if (childEvent->type() == QEvent::ChildPolished) {
2255 if (QMdiSubWindow *mdiChild = qobject_cast<QMdiSubWindow *>(childEvent->child())) {
2256 if (d->childWindows.indexOf(mdiChild) == -1)
2257 d->appendChild(mdiChild);
2258 }
2259 }
2260}
2261
2266{
2267 Q_D(QMdiArea);
2268 if (d->childWindows.isEmpty()) {
2269 resizeEvent->ignore();
2270 return;
2271 }
2272
2273#if QT_CONFIG(tabbar)
2274 d->updateTabBarGeometry();
2275#endif
2276
2277 // Re-tile the views if we're in tiled mode. Re-tile means we will change
2278 // the geometry of the children, which in turn means 'isSubWindowsTiled'
2279 // is set to false, so we have to update the state at the end.
2280 if (d->isSubWindowsTiled) {
2281 d->tileCalledFromResizeEvent = true;
2283 d->tileCalledFromResizeEvent = false;
2284 d->isSubWindowsTiled = true;
2285 d->startResizeTimer();
2286 // We don't have scroll bars or any maximized views.
2287 return;
2288 }
2289
2290 // Resize maximized views.
2291 bool hasMaximizedSubWindow = false;
2292 // Take a copy because child->resize() may call QCoreApplication::sendEvent()
2293 // which may invoke unknown code, that could e.g. recurse into the class
2294 // modifying d->childWindows.
2295 const auto subWindows = d->childWindows;
2296 for (QMdiSubWindow *child : subWindows) {
2297 if (sanityCheck(child, "QMdiArea::resizeEvent") && child->isMaximized()
2298 && child->size() != resizeEvent->size()) {
2299 auto realSize = resizeEvent->size();
2300 const auto minSizeHint = child->minimumSizeHint();
2301 // QMdiSubWindow is no tlw so minimumSize() is not set by the layout manager
2302 // and therefore we have to take care by ourself that we're not getting smaller
2303 // than allowed
2304 if (minSizeHint.isValid())
2305 realSize = realSize.expandedTo(minSizeHint);
2306 child->resize(realSize);
2307 if (!hasMaximizedSubWindow)
2308 hasMaximizedSubWindow = true;
2309 }
2310 }
2311
2312 d->updateScrollBars();
2313
2314 // Minimized views are stacked under maximized views so there's
2315 // no need to re-arrange minimized views on-demand. Start a timer
2316 // just to make things faster with subsequent resize events.
2317 if (hasMaximizedSubWindow)
2318 d->startResizeTimer();
2319 else
2320 d->arrangeMinimizedSubWindows();
2321}
2322
2327{
2328 Q_D(QMdiArea);
2329 if (timerEvent->timerId() == d->resizeTimerId) {
2330 killTimer(d->resizeTimerId);
2331 d->resizeTimerId = -1;
2332 d->arrangeMinimizedSubWindows();
2333 } else if (timerEvent->timerId() == d->tabToPreviousTimerId) {
2334 killTimer(d->tabToPreviousTimerId);
2335 d->tabToPreviousTimerId = -1;
2336 if (d->indexToHighlighted < 0)
2337 return;
2338#if QT_CONFIG(rubberband)
2339 // We're not doing a "quick switch" ... show rubber band.
2340 Q_ASSERT(d->indexToHighlighted < d->childWindows.size());
2341 Q_ASSERT(d->rubberBand);
2342 d->showRubberBandFor(d->childWindows.at(d->indexToHighlighted));
2343#endif
2344 }
2345}
2346
2351{
2352 Q_D(QMdiArea);
2353 if (!d->pendingRearrangements.isEmpty()) {
2354 bool skipPlacement = false;
2355 // Take a copy because d->rearrange() may modify d->pendingRearrangements
2356 const auto pendingRearrange = d->pendingRearrangements;
2357 for (Rearranger *rearranger : pendingRearrange) {
2358 // If this is the case, we don't have to lay out pending child windows
2359 // since the rearranger will find a placement for them.
2360 if (rearranger->type() != Rearranger::IconTiler && !skipPlacement)
2361 skipPlacement = true;
2362 d->rearrange(rearranger);
2363 }
2364 d->pendingRearrangements.clear();
2365
2366 if (skipPlacement && !d->pendingPlacements.isEmpty())
2367 d->pendingPlacements.clear();
2368 }
2369
2370 if (!d->pendingPlacements.isEmpty()) {
2371 // Nothing obvious in the loop body changes the container (in this code path)
2372 // during iteration, this is calling into a non-const method that does change
2373 // the container when called from other places. So take a copy anyway for good
2374 // measure.
2375 const auto copy = d->pendingPlacements;
2376 for (QMdiSubWindow *window : copy) {
2377 if (!window)
2378 continue;
2379 if (d->viewMode == TabbedView && window->d_func()->isActive && !d->active) {
2380 d->showActiveWindowMaximized = true;
2381 d->emitWindowActivated(window); // Also maximizes the window
2382 continue;
2383 }
2384 if (!window->testAttribute(Qt::WA_Resized)) {
2385 QSize newSize(window->sizeHint().boundedTo(viewport()->size()));
2386 window->resize(newSize.expandedTo(qSmartMinSize(window)));
2387 }
2388 if (!window->testAttribute(Qt::WA_Moved) && !window->isMinimized()
2389 && !window->isMaximized()) {
2390 d->place(d->placer, window);
2391 }
2392 }
2393 d->pendingPlacements.clear();
2394 }
2395
2396 d->setChildActivationEnabled(true);
2397 d->activateCurrentWindow();
2398
2399 QAbstractScrollArea::showEvent(showEvent);
2400}
2401
2406{
2407 Q_D(QMdiArea);
2408 switch (event->type()) {
2409 case QEvent::ChildRemoved: {
2410 d->isSubWindowsTiled = false;
2411 QObject *removedChild = static_cast<QChildEvent *>(event)->child();
2412 for (int i = 0; i < d->childWindows.size(); ++i) {
2413 QObject *child = d->childWindows.at(i);
2414 if (!child || child == removedChild || !child->parent()
2415 || child->parent() != viewport()) {
2417 // In this case we can only rely on the child being a QObject
2418 // (or 0), but let's try and see if we can get more information.
2419 QWidget *mdiChild = qobject_cast<QWidget *>(removedChild);
2420 if (mdiChild && mdiChild->isMaximized())
2421 d->showActiveWindowMaximized = true;
2422 }
2423 d->disconnectSubWindow(child);
2424 const bool activeRemoved = i == d->indicesToActivatedChildren.at(0);
2425 d->childWindows.removeAt(i);
2426 d->indicesToActivatedChildren.removeAll(i);
2427 d->updateActiveWindow(i, activeRemoved);
2428 d->arrangeMinimizedSubWindows();
2429 break;
2430 }
2431 }
2432 d->updateScrollBars();
2433 break;
2434 }
2435 case QEvent::Destroy:
2436 d->isSubWindowsTiled = false;
2437 d->resetActiveWindow();
2438 d->childWindows.clear();
2439 qWarning("QMdiArea: Deleting the view port is undefined, use setViewport instead.");
2440 break;
2441 default:
2442 break;
2443 }
2444 return QAbstractScrollArea::viewportEvent(event);
2445}
2446
2450void QMdiArea::scrollContentsBy(int dx, int dy)
2451{
2452 Q_D(QMdiArea);
2453 const bool wasSubWindowsTiled = d->isSubWindowsTiled;
2454 d->ignoreGeometryChange = true;
2455 viewport()->scroll(isLeftToRight() ? dx : -dx, dy);
2456 d->arrangeMinimizedSubWindows();
2457 d->ignoreGeometryChange = false;
2458 if (wasSubWindowsTiled)
2459 d->isSubWindowsTiled = true;
2460}
2461
2468{
2469 Q_D(QMdiArea);
2470 if (!d->regularTiler)
2471 d->regularTiler = new RegularTiler;
2472 d->rearrange(d->regularTiler);
2473}
2474
2481{
2482 Q_D(QMdiArea);
2483 if (!d->cascader)
2484 d->cascader = new SimpleCascader;
2485 d->rearrange(d->cascader);
2486}
2487
2492{
2493 Q_D(QMdiArea);
2494 switch (event->type()) {
2496 d->isActivated = true;
2497 if (d->childWindows.isEmpty())
2498 break;
2499 if (!d->active)
2500 d->activateCurrentWindow();
2501 d->setChildActivationEnabled(false, true);
2502 break;
2503 }
2505 d->isActivated = false;
2506 d->setChildActivationEnabled(false, true);
2507 break;
2509 // Re-tile the views if we're in tiled mode. Re-tile means we will change
2510 // the geometry of the children, which in turn means 'isSubWindowsTiled'
2511 // is set to false, so we have to update the state at the end.
2512 if (d->isSubWindowsTiled) {
2514 d->isSubWindowsTiled = true;
2515 }
2516 break;
2518 // Take a copy because QCoreApplication::sendEvent() may call unknown code,
2519 // that may cause recursing into the class
2520 const auto subWindows = d->childWindows;
2521 for (QMdiSubWindow *window : subWindows) {
2522 if (sanityCheck(window, "QMdiArea::WindowIconChange"))
2524 }
2525 break;
2526 }
2527 case QEvent::Hide:
2528 d->setActive(d->active, false, false);
2529 d->setChildActivationEnabled(false);
2530 break;
2531#if QT_CONFIG(tabbar)
2533 d->updateTabBarGeometry();
2534 break;
2535#endif
2536 default:
2537 break;
2538 }
2539 return QAbstractScrollArea::event(event);
2540}
2541
2546{
2547 if (!object)
2548 return QAbstractScrollArea::eventFilter(object, event);
2549
2550 Q_D(QMdiArea);
2551 // Global key events with Ctrl modifier.
2552 if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) {
2553
2554 QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
2555 // Ignore key events without a Ctrl modifier (except for press/release on the modifier itself).
2556 if (!(keyEvent->modifiers() & Qt::ControlModifier) && keyEvent->key() != Qt::Key_Control)
2557 return QAbstractScrollArea::eventFilter(object, event);
2558
2559 // Find closest mdi area (in case we have a nested workspace).
2560 QMdiArea *area = mdiAreaParent(static_cast<QWidget *>(object));
2561 if (!area)
2562 return QAbstractScrollArea::eventFilter(object, event);
2563
2564 const bool keyPress = (event->type() == QEvent::KeyPress);
2565
2566 // 1) Ctrl-Tab once -> activate the previously active window.
2567 // 2) Ctrl-Tab (Tab, Tab, ...) -> iterate through all windows (activateNextSubWindow()).
2568 // 3) Ctrl-Shift-Tab (Tab, Tab, ...) -> iterate through all windows in the opposite
2569 // direction (activatePreviousSubWindow())
2570 switch (keyEvent->key()) {
2571 case Qt::Key_Control:
2572 if (keyPress)
2573 area->d_func()->startTabToPreviousTimer();
2574 else
2575 area->d_func()->activateHighlightedWindow();
2576 break;
2577 case Qt::Key_Tab:
2578 case Qt::Key_Backtab:
2579 if (keyPress)
2580 area->d_func()->highlightNextSubWindow(keyEvent->key() == Qt::Key_Tab ? 1 : -1);
2581 return true;
2582#if QT_CONFIG(rubberband)
2583 case Qt::Key_Escape:
2584 area->d_func()->hideRubberBand();
2585 break;
2586#endif
2587 default:
2588 break;
2589 }
2590 return QAbstractScrollArea::eventFilter(object, event);
2591 }
2592
2593 QMdiSubWindow *subWindow = qobject_cast<QMdiSubWindow *>(object);
2594
2595 if (!subWindow) {
2596 // QApplication events:
2597 if (event->type() == QEvent::ApplicationActivate && !d->active
2598 && isVisible() && !window()->isMinimized()) {
2599 d->activateCurrentWindow();
2600 } else if (event->type() == QEvent::ApplicationDeactivate && d->active) {
2601 d->setActive(d->active, false, false);
2602 }
2603 return QAbstractScrollArea::eventFilter(object, event);
2604 }
2605
2606 if (subWindow->mdiArea() != this)
2607 return QAbstractScrollArea::eventFilter(object, event);
2608
2609 // QMdiSubWindow events:
2610 switch (event->type()) {
2611 case QEvent::Move:
2612 case QEvent::Resize:
2613 if (d->tileCalledFromResizeEvent)
2614 break;
2615 d->updateScrollBars();
2616 if (!subWindow->isMinimized())
2617 d->isSubWindowsTiled = false;
2618 break;
2619 case QEvent::Show:
2620#if QT_CONFIG(tabbar)
2621 if (d->tabBar) {
2622 const int tabIndex = d->childWindows.indexOf(subWindow);
2623 if (!d->tabBar->isTabEnabled(tabIndex))
2624 d->tabBar->setTabEnabled(tabIndex, true);
2625 }
2626#endif // QT_CONFIG(tabbar)
2627 Q_FALLTHROUGH();
2628 case QEvent::Hide:
2629 // Do not reset the isSubWindowsTiled flag if the event is a spontaneous system window event.
2630 // This ensures that tiling will be performed during the resizeEvent after an application
2631 // window minimize (hide) and then restore (show).
2632 if (!event->spontaneous())
2633 d->isSubWindowsTiled = false;
2634 break;
2635#if QT_CONFIG(rubberband)
2636 case QEvent::Close:
2637 if (d->childWindows.indexOf(subWindow) == d->indexToHighlighted)
2638 d->hideRubberBand();
2639 break;
2640#endif
2641#if QT_CONFIG(tabbar)
2644 if (d->tabBar)
2645 d->tabBar->setTabText(d->childWindows.indexOf(subWindow), tabTextFor(subWindow));
2646 break;
2648 if (d->tabBar)
2649 d->tabBar->setTabIcon(d->childWindows.indexOf(subWindow), subWindow->windowIcon());
2650 break;
2651#endif // QT_CONFIG(tabbar)
2652 default:
2653 break;
2654 }
2655 return QAbstractScrollArea::eventFilter(object, event);
2656}
2657
2662{
2663 Q_D(QMdiArea);
2664 QPainter painter(d->viewport);
2665 for (const QRect &exposedRect : paintEvent->region())
2666 painter.fillRect(exposedRect, d->background);
2667}
2668
2677{
2678 Q_D(QMdiArea);
2679 if (viewport)
2680 viewport->setAttribute(Qt::WA_OpaquePaintEvent, d->background.isOpaque());
2681 // Take a copy because the child->setParent() call below may call QCoreApplication::sendEvent()
2682 // which may call unknown code that could e.g. recurse into the class modifying d->childWindows.
2683 const auto subWindows = d->childWindows;
2684 for (QMdiSubWindow *child : subWindows) {
2685 if (!sanityCheck(child, "QMdiArea::setupViewport"))
2686 continue;
2687 child->setParent(viewport, child->windowFlags());
2688 }
2689}
2690
2692
2693#include "moc_qmdiarea.cpp"
static QFont font()
Returns the default application font.
\inmodule QtGui
Definition qbrush.h:30
\inmodule QtCore
Definition qcoreevent.h:379
The QContextMenuEvent class contains parameters that describe a context menu event.
Definition qevent.h:594
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:424
Qt::KeyboardModifiers modifiers() const
Returns the keyboard modifier flags that existed immediately after the event occurred.
Definition qevent.cpp:1468
int key() const
Returns the code of the key that was pressed or released.
Definition qevent.h:434
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.
qsizetype size() const noexcept
Definition qlist.h:397
bool isEmpty() const noexcept
Definition qlist.h:401
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
void move(qsizetype from, qsizetype to)
Definition qlist.h:610
void prepend(rvalue_ref t)
Definition qlist.h:473
void append(parameter_type t)
Definition qlist.h:458
void internalRaise(QMdiSubWindow *child) const
void place(QMdi::Placer *placer, QMdiSubWindow *child)
Definition qmdiarea.cpp:836
void resetActiveWindow(QMdiSubWindow *child=nullptr)
QMdi::Placer * placer
Definition qmdiarea_p.h:114
QPointer< QMdiSubWindow > aboutToBecomeActive
Definition qmdiarea_p.h:124
void activateCurrentWindow()
Definition qmdiarea.cpp:970
QList< int > indicesToActivatedChildren
Definition qmdiarea_p.h:122
bool scrollBarsEnabled() const
void appendChild(QMdiSubWindow *child)
Definition qmdiarea.cpp:783
void activateHighlightedWindow()
Definition qmdiarea.cpp:979
void emitWindowActivated(QMdiSubWindow *child)
Definition qmdiarea.cpp:997
QMdi::Rearranger * iconTiler
Definition qmdiarea_p.h:113
QPointer< QMdiSubWindow > active
Definition qmdiarea_p.h:123
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:126
bool isExplicitlyDeactivated(QMdiSubWindow *subWindow) const
Definition qmdiarea_p.h:212
void arrangeMinimizedSubWindows()
Definition qmdiarea.cpp:931
QMdiAreaTabBar * tabBar
Definition qmdiarea_p.h:118
bool lastWindowAboutToBeDestroyed() const
bool ignoreGeometryChange
Definition qmdiarea_p.h:138
void activateWindow(QMdiSubWindow *child)
Definition qmdiarea.cpp:941
void highlightNextSubWindow(int increaseFactor)
QList< QMdi::Rearranger * > pendingRearrangements
Definition qmdiarea_p.h:119
QMdiArea::AreaOptions options
Definition qmdiarea_p.h:127
bool tileCalledFromResizeEvent
Definition qmdiarea_p.h:143
void disconnectSubWindow(QObject *subWindow)
void _q_moveTab(int from, int to)
Definition qmdiarea.cpp:770
bool windowStaysOnTop(QMdiSubWindow *subWindow) const
Definition qmdiarea_p.h:205
QList< QPointer< QMdiSubWindow > > pendingPlacements
Definition qmdiarea_p.h:120
bool ignoreWindowStateChange
Definition qmdiarea_p.h:139
void _q_currentTabChanged(int index)
Definition qmdiarea.cpp:735
bool updatesDisabledByUs
Definition qmdiarea_p.h:144
QList< QPointer< QMdiSubWindow > > childWindows
Definition qmdiarea_p.h:121
void _q_deactivateAllWindows(QMdiSubWindow *aboutToActivate=nullptr)
Definition qmdiarea.cpp:662
void scrollBarPolicyChanged(Qt::Orientation, Qt::ScrollBarPolicy) override
bool showActiveWindowMaximized
Definition qmdiarea_p.h:142
QMdiArea::ViewMode viewMode
Definition qmdiarea_p.h:128
void updateActiveWindow(int removedIndex, bool activeRemoved)
void rearrange(QMdi::Rearranger *rearranger)
Definition qmdiarea.cpp:875
void setChildActivationEnabled(bool enable=true, bool onlyNextActivationEvent=false) const
void _q_closeTab(int index)
Definition qmdiarea.cpp:759
void _q_processWindowStateChanged(Qt::WindowStates oldState, Qt::WindowStates newState)
Definition qmdiarea.cpp:702
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.
The QMdiSubWindow class provides a subwindow class for QMdiArea.
SubWindowOption
This enum describes options that customize the behavior of QMdiSubWindow.
@ AllowOutsideAreaHorizontally
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
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
\inmodule QtGui
Definition qevent.h:196
\inmodule QtCore
Definition qobject.h:103
const QObjectList & children() const
Returns a list of child objects.
Definition qobject.h:201
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
Definition qobject.cpp:3236
The QPaintEvent class contains event parameters for paint events.
Definition qevent.h:486
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:25
constexpr int x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:130
constexpr int y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:135
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr int height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:239
constexpr bool isValid() const noexcept
Returns true if the rectangle is valid, otherwise returns false.
Definition qrect.h:170
QRect intersected(const QRect &other) const noexcept
Definition qrect.h:415
constexpr int bottom() const noexcept
Returns the y-coordinate of the rectangle's bottom edge.
Definition qrect.h:182
constexpr int top() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:176
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:855
constexpr int left() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:173
constexpr void setWidth(int w) noexcept
Sets the width of the rectangle to the given width.
Definition qrect.h:381
constexpr int width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:236
constexpr void setHeight(int h) noexcept
Sets the height of the rectangle to the given height.
Definition qrect.h:384
constexpr int right() const noexcept
Returns the x-coordinate of the rectangle's right edge.
Definition qrect.h:179
The QResizeEvent class contains event parameters for resize events.
Definition qevent.h:548
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:578
Exception-safe wrapper around QObject::blockSignals().
Definition qobject.h:483
\inmodule QtCore
Definition qsize.h:25
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:133
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:130
constexpr int & rheight() noexcept
Returns a reference to the height.
Definition qsize.h:157
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:192
constexpr int & rwidth() noexcept
Returns a reference to the width.
Definition qsize.h:154
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QString & replace(qsizetype i, qsizetype len, QChar after)
Definition qstring.cpp:3824
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
\variable QStyleOptionToolBox::selectedPosition
void initFrom(const QWidget *w)
@ SH_ScrollView_FrameOnlyAroundContents
Definition qstyle.h:602
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:2143
@ PM_FocusFrameVMargin
Definition qstyle.h:498
@ PM_TitleBarHeight
Definition qstyle.h:448
@ PM_DefaultFrameWidth
Definition qstyle.h:420
@ PM_MdiSubWindowMinimizedWidth
Definition qstyle.h:474
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:2122
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:366
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
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:2876
QWidget * focusWidget() const
Returns the last child of this widget that setFocus had been called on.
Definition qwidget.cpp:6828
int height
the height of the widget excluding any window frame
Definition qwidget.h:115
void stackUnder(QWidget *)
Places the widget under w in the parent widget's stack.
QSize sizeHint
the recommended size for the widget
Definition qwidget.h:148
void showMaximized()
Shows the widget maximized.
Definition qwidget.cpp:3044
QStyle * style() const
Definition qwidget.cpp:2600
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
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:3060
void activateWindow()
Sets the top-level widget containing this widget to be the active window.
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:253
@ WindowMaximized
Definition qnamespace.h:254
@ WindowActive
Definition qnamespace.h:256
@ MiddleButton
Definition qnamespace.h:60
@ WA_Resized
Definition qnamespace.h:308
@ WA_Moved
Definition qnamespace.h:309
@ WA_OpaquePaintEvent
Definition qnamespace.h:287
@ WA_DeleteOnClose
Definition qnamespace.h:321
@ LeftToRight
@ NoFocus
Definition qnamespace.h:107
Orientation
Definition qnamespace.h:98
@ Horizontal
Definition qnamespace.h:99
@ Vertical
Definition qnamespace.h:100
@ Key_Escape
Definition qnamespace.h:663
@ Key_Tab
Definition qnamespace.h:664
@ Key_Backtab
Definition qnamespace.h:665
@ Key_Control
Definition qnamespace.h:684
ScrollBarPolicy
@ ScrollBarAlwaysOff
@ ScrollBarAlwaysOn
@ ScrollBarAsNeeded
@ ControlModifier
@ WindowStaysOnTopHint
Definition qnamespace.h:233
@ SubWindow
Definition qnamespace.h:216
Definition brush.cpp:5
static jboolean copy(JNIEnv *, jobject)
#define Q_FALLTHROUGH()
#define Q_UNLIKELY(x)
DBusConnection const char DBusError * error
qfloat16 qSqrt(qfloat16 f)
Definition qfloat16.h:289
static int area(const QSize &s)
Definition qicon.cpp:153
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:166
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:52
#define SIGNAL(a)
Definition qobjectdefs.h:53
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:187
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:5992
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:962
bool contains(const AT &t) const noexcept
Definition qlist.h:45