QtBase  v6.3.1
tst_qmdiarea.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21 ** included in the packaging of this file. Please review the following
22 ** information to ensure the GNU General Public License requirements will
23 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24 **
25 ** $QT_END_LICENSE$
26 **
27 ****************************************************************************/
28 
29 
30 #include <QTest>
31 #include <QSignalSpy>
32 #include <QMdiSubWindow>
33 #include <QMdiArea>
34 
35 #include <QApplication>
36 #include <QMainWindow>
37 #include <QMenuBar>
38 #include <QPushButton>
39 #include <QStyle>
40 #include <QStyleOption>
41 #include <QVBoxLayout>
42 #include <QLineEdit>
43 #include <QDockWidget>
44 #include <QScrollBar>
45 #include <QTextEdit>
46 #ifndef QT_NO_OPENGL
47 #include <QtOpenGL>
48 #include <QOpenGLContext>
49 #endif
50 #include <QStyleHints>
51 
52 static const Qt::WindowFlags DefaultWindowFlags
55 
58 
59 static bool tabBetweenSubWindowsIn(QMdiArea *mdiArea, int tabCount = -1, bool reverse = false)
60 {
61  if (!mdiArea) {
62  qWarning("Null pointer to mdi area");
63  return false;
64  }
65 
66  QList<QMdiSubWindow *> subWindows = mdiArea->subWindowList();
67  const bool walkThrough = tabCount == -1;
68 
69  if (walkThrough) {
70  QMdiSubWindow *active = reverse ? subWindows.front() : subWindows.back();
71  mdiArea->setActiveSubWindow(active);
72  if (mdiArea->activeSubWindow() != active) {
73  qWarning("Failed to set active sub window");
74  return false;
75  }
76  tabCount = subWindows.size();
77  }
78 
79  QWidget *focusWidget = qApp->focusWidget();
80  if (!focusWidget) {
81  qWarning("No focus widget");
82  return false;
83  }
84 
85  Qt::KeyboardModifiers modifiers = reverse ? Qt::ShiftModifier : Qt::NoModifier;
86  Qt::Key key;
87 #ifdef Q_OS_MAC
88  key = Qt::Key_Meta;
89  modifiers |= Qt::MetaModifier;
90 #else
92  modifiers |= Qt::ControlModifier;
93 #endif
94 
95  QTest::keyPress(focusWidget, key, modifiers);
96  for (int i = 0; i < tabCount; ++i) {
97  QTest::keyPress(focusWidget, reverse ? Qt::Key_Backtab : Qt::Key_Tab, modifiers);
98  if (tabCount > 1)
99  QTest::qWait(500);
100  if (walkThrough) {
101  QRubberBand *rubberBand = mdiArea->findChild<QRubberBand *>();
102  if (!rubberBand) {
103  qWarning("No rubber band");
104  return false;
105  }
106  QMdiSubWindow *subWindow = subWindows.at(reverse ? subWindows.size() -1 - i : i);
107  if (rubberBand->geometry() != subWindow->geometry()) {
108  qWarning().nospace() << "Rubber band of tab " << i << " has different geometry: "
109  << rubberBand->geometry() << " (sub window: " << subWindow->geometry() << ").";
110  return false;
111  }
112  }
113  qApp->processEvents();
114  }
115  QTest::keyRelease(focusWidget, key);
116 
117  return true;
118 }
119 
120 static inline QTabBar::Shape tabBarShapeFrom(QTabWidget::TabShape shape, QTabWidget::TabPosition position)
121 {
122  const bool rounded = (shape == QTabWidget::Rounded);
127  if (position == QTabWidget::East)
129  if (position == QTabWidget::West)
131  return QTabBar::RoundedNorth;
132 }
133 
134 static int cascadedDeltaY(const QMdiArea *area)
135 {
136  // Calculate the delta (dx, dy) between two cascaded subwindows.
137  const QWidget *subWindow = area->subWindowList().first();
138  const QStyle *style = subWindow->style();
139  QStyleOptionTitleBar options;
140  options.initFrom(subWindow);
141  int titleBarHeight = style->pixelMetric(QStyle::PM_TitleBarHeight, &options);
142  // ### Remove this after the QMacStyle has been fixed
143  if (style->inherits("QMacStyle"))
144  titleBarHeight -= 4;
145  const QFontMetrics fontMetrics = QFontMetrics(QApplication::font("QMdiSubWindowTitleBar"));
146  return qMax(titleBarHeight - (titleBarHeight - fontMetrics.height()) / 2, 1)
147  + style->pixelMetric(QStyle::PM_FocusFrameVMargin);
148 }
149 
152  Cascaded
153 };
154 
155 static bool verifyArrangement(QMdiArea *mdiArea, Arrangement arrangement, const QList<int> &expectedIndices)
156 {
157  if (!mdiArea || expectedIndices.isEmpty() || mdiArea->subWindowList().isEmpty())
158  return false;
159 
160  const QList<QMdiSubWindow *> subWindows = mdiArea->subWindowList();
161 
162  switch (arrangement) {
163  case Tiled:
164  {
165  // Calculate the number of rows and columns.
166  const int n = subWindows.count();
167  const int numColumns = qMax(qCeil(qSqrt(qreal(n))), 1);
168  const int numRows = qMax((n % numColumns) ? (n / numColumns + 1) : (n / numColumns), 1);
169 
170  // Ensure that the geometry of all the subwindows are as expected by using
171  // QWidget::childAt starting from the middle of the topleft cell and subsequently
172  // adding rowWidth and rowHeight (going from left to right).
173  const int columnWidth = mdiArea->viewport()->width() / numColumns;
174  const int rowHeight = mdiArea->viewport()->height() / numRows;
175  QPoint subWindowPos(columnWidth / 2, rowHeight / 2);
176  for (int i = 0; i < numRows; ++i) {
177  for (int j = 0; j < numColumns; ++j) {
178  const int index = expectedIndices.at(i * numColumns + j);
179  QWidget *actual = mdiArea->viewport()->childAt(subWindowPos);
180  QMdiSubWindow *expected = subWindows.at(index);
181  if (actual != expected && !expected->isAncestorOf(actual))
182  return false;
183  subWindowPos.rx() += columnWidth;
184  }
185  subWindowPos.rx() = columnWidth / 2;
186  subWindowPos.ry() += rowHeight;
187  }
188  break;
189  }
190  case Cascaded:
191  {
192  const int dy = cascadedDeltaY(mdiArea);
193  const int dx = 10;
194 
195  // Current activation/stacking order.
196  const QList<QMdiSubWindow *> activationOrderList = mdiArea->subWindowList(QMdiArea::ActivationHistoryOrder);
197 
198  // Ensure that the geometry of all the subwindows are as expected by using
199  // QWidget::childAt with the position of the first one and subsequently adding
200  // dx and dy.
201  QPoint subWindowPos(20, 5);
202  foreach (int expectedIndex, expectedIndices) {
203  QMdiSubWindow *expected = subWindows.at(expectedIndex);
204  expected->raise();
205  if (mdiArea->viewport()->childAt(subWindowPos) != expected)
206  return false;
207  expected->lower();
208  subWindowPos.rx() += dx;
209  subWindowPos.ry() += dy;
210  }
211 
212  // Restore stacking order.
213  foreach (QMdiSubWindow *subWindow, activationOrderList) {
214  mdiArea->setActiveSubWindow(subWindow);
215  qApp->processEvents();
216  }
217  break;
218  }
219  default:
220  return false;
221  }
222  return true;
223 }
224 
225 class tst_QMdiArea : public QObject
226 {
227  Q_OBJECT
228 public:
229  tst_QMdiArea();
230 public slots:
231  void cleanup();
232 
233 protected slots:
235 
236 private slots:
237  // Tests from QWorkspace
238  void subWindowActivated_data();
239  void subWindowActivated();
240  void subWindowActivated2();
241  void subWindowActivatedWithMinimize();
242  void showWindows();
243  void changeWindowTitle();
244  void changeModified();
245  void childSize();
246  void fixedSize();
247  // New tests
248  void minimumSizeHint();
249  void sizeHint();
250  void setActiveSubWindow();
251  void activeSubWindow();
252  void currentSubWindow();
253  void addAndRemoveWindows();
254  void addAndRemoveWindowsWithReparenting();
255  void removeSubWindow_2();
256  void closeWindows();
257  void activateNextAndPreviousWindow();
258  void subWindowList_data();
259  void subWindowList();
260  void setBackground();
261  void setViewport();
262  void tileSubWindows();
263  void cascadeAndTileSubWindows();
264  void resizeMaximizedChildWindows_data();
265  void resizeMaximizedChildWindows();
266  void focusWidgetAfterAddSubWindow();
267  void dontMaximizeSubWindowOnActivation();
268  void delayedPlacement();
269  void iconGeometryInMenuBar();
270  void resizeTimer();
271  void updateScrollBars();
272  void setActivationOrder_data();
273  void setActivationOrder();
274  void tabBetweenSubWindows();
275  void setViewMode();
276  void setTabsClosable();
277  void setTabsMovable();
278  void setTabShape();
279  void setTabPosition_data();
280  void setTabPosition();
281  void nativeSubWindows();
282  void task_209615();
283  void task_236750();
284  void qtbug92240_title_data();
285  void qtbug92240_title();
286  void tabbedview_activefirst();
287  void tabbedview_activesecond();
288  void tabbedview_activethird();
289 
290 private:
291  QMdiSubWindow *activeWindow;
292 };
293 
295  : activeWindow(0)
296 {
297  qRegisterMetaType<QMdiSubWindow *>();
298 }
299 
301 {
303 }
304 
305 // Old QWorkspace tests
307 {
308  activeWindow = child;
309 }
310 
311 void tst_QMdiArea::subWindowActivated_data()
312 {
313  // define the test elements we're going to use
314  QTest::addColumn<int>("count");
315 
316  // create a first testdata instance and fill it with data
317  QTest::newRow( "data0" ) << 0;
318  QTest::newRow( "data1" ) << 1;
319  QTest::newRow( "data2" ) << 2;
320 }
321 
322 void tst_QMdiArea::subWindowActivated()
323 {
324  QMainWindow mw(0) ;
325  mw.menuBar();
326  QMdiArea *workspace = new QMdiArea(&mw);
327  workspace->setObjectName(QLatin1String("testWidget"));
328  mw.setCentralWidget(workspace);
329  QSignalSpy spy(workspace, SIGNAL(subWindowActivated(QMdiSubWindow*)));
330  connect( workspace, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(activeChanged(QMdiSubWindow*)));
331  mw.show();
332  qApp->setActiveWindow(&mw);
333 
334  QFETCH( int, count );
335  int i;
336 
337  for ( i = 0; i < count; ++i ) {
338  QWidget *widget = new QWidget(workspace, {});
340  widget->setFocus();
341  workspace->addSubWindow(widget)->show();
342  widget->show();
343  qApp->processEvents();
344  QVERIFY( activeWindow == workspace->activeSubWindow() );
345  QCOMPARE(spy.count(), 1);
346  spy.clear();
347  }
348 
349  QList<QMdiSubWindow *> windows = workspace->subWindowList();
350  QCOMPARE( (int)windows.count(), count );
351 
352  for ( i = 0; i < count; ++i ) {
354  window->showMinimized();
355  qApp->processEvents();
356  QVERIFY( activeWindow == workspace->activeSubWindow() );
357  if ( i == 1 )
358  QVERIFY( activeWindow == window );
359  }
360 
361  for ( i = 0; i < count; ++i ) {
363  window->showNormal();
364  qApp->processEvents();
365  QVERIFY( window == activeWindow );
366  QVERIFY( activeWindow == workspace->activeSubWindow() );
367  }
368  spy.clear();
369 
370  while (workspace->activeSubWindow() ) {
371  workspace->activeSubWindow()->close();
372  qApp->processEvents();
373  QCOMPARE(activeWindow, workspace->activeSubWindow());
374  QCOMPARE(spy.count(), 1);
375  spy.clear();
376  }
377 
378  QVERIFY(!activeWindow);
379  QVERIFY(!workspace->activeSubWindow());
380  QCOMPARE(workspace->subWindowList().count(), 0);
381 
382  {
383  workspace->hide();
386  QMdiSubWindow *window = workspace->addSubWindow(widget);
387  widget->show();
388  QCOMPARE(spy.count(), 0);
389  workspace->show();
390  QCOMPARE(spy.count(), 1);
391  spy.clear();
392  QVERIFY( activeWindow == window );
393  window->close();
394  qApp->processEvents();
395  QCOMPARE(spy.count(), 1);
396  spy.clear();
397  QVERIFY( activeWindow == 0 );
398  }
399 
400  {
401  workspace->hide();
404  QMdiSubWindow *window = workspace->addSubWindow(widget);
406  qApp->sendPostedEvents();
407  QCOMPARE(spy.count(), 0);
408  spy.clear();
409  workspace->show();
410  QCOMPARE(spy.count(), 1);
411  spy.clear();
412  QVERIFY( activeWindow == window );
413  window->close();
414  qApp->processEvents();
415  QCOMPARE(spy.count(), 1);
416  spy.clear();
417  QVERIFY( activeWindow == 0 );
418  }
419 
420  {
423  QMdiSubWindow *window = workspace->addSubWindow(widget);
425  QCOMPARE(spy.count(), 1);
426  spy.clear();
427  QVERIFY( activeWindow == window );
428  QCOMPARE(workspace->activeSubWindow(), window);
429  window->close();
430  qApp->processEvents();
431  QCOMPARE(spy.count(), 1);
432  spy.clear();
433  QVERIFY(!workspace->activeSubWindow());
434  QVERIFY(!activeWindow);
435  }
436 }
437 
438 #ifdef Q_OS_MAC
439 #include <Security/AuthSession.h>
440 bool macHasAccessToWindowsServer()
441 {
442  SecuritySessionId mySession;
443  SessionAttributeBits sessionInfo;
444  SessionGetInfo(callerSecuritySession, &mySession, &sessionInfo);
445  return (sessionInfo & sessionHasGraphicAccess);
446 }
447 #endif
448 
449 
450 void tst_QMdiArea::subWindowActivated2()
451 {
453  QSKIP("Wayland: This fails. Figure out why.");
454 
455  QMdiArea mdiArea;
456  QSignalSpy spy(&mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow*)));
457  for (int i = 0; i < 5; ++i)
458  mdiArea.addSubWindow(new QWidget);
459  QCOMPARE(spy.count(), 0);
460  mdiArea.show();
461  mdiArea.activateWindow();
463 
464  QTRY_COMPARE(spy.count(), 5);
465  QCOMPARE(mdiArea.activeSubWindow(), mdiArea.subWindowList().back());
466  spy.clear();
467 
468  // Just to make sure another widget is on top wrt. stacking order.
469  // This will typically become the active window if things are broken.
470  QMdiSubWindow *staysOnTopWindow = mdiArea.subWindowList().at(3);
471  staysOnTopWindow->setWindowFlags(Qt::WindowStaysOnTopHint);
472  mdiArea.setActiveSubWindow(staysOnTopWindow);
473  QCOMPARE(spy.count(), 1);
474  QCOMPARE(mdiArea.activeSubWindow(), staysOnTopWindow);
475  spy.clear();
476 
477  QMdiSubWindow *activeSubWindow = mdiArea.subWindowList().at(2);
478  mdiArea.setActiveSubWindow(activeSubWindow);
479  QCOMPARE(spy.count(), 1);
480  QCOMPARE(mdiArea.activeSubWindow(), activeSubWindow);
481  spy.clear();
482 
483  // Check that we only emit _one_ signal and the active window
484  // is unchanged after hide/show.
485  mdiArea.hide();
486  QTest::qWait(100);
487  QTRY_COMPARE(spy.count(), 1);
488  QVERIFY(!mdiArea.activeSubWindow());
489  QCOMPARE(mdiArea.currentSubWindow(), activeSubWindow);
490  spy.clear();
491 
492  mdiArea.show();
493  mdiArea.activateWindow();
495  QTRY_VERIFY(!spy.isEmpty()); // Normally 1, but 2 events might be received on some X11 window managers
496  QVERIFY(mdiArea.currentSubWindow());
497  QTRY_COMPARE(mdiArea.activeSubWindow(), activeSubWindow);
498  spy.clear();
499 
500  if (qGuiApp->styleHints()->showIsFullScreen())
501  QSKIP("Platform is auto maximizing, so no showMinimized()");
502 
503  // Check that we only emit _one_ signal and the active window
504  // is unchanged after showMinimized/showNormal.
505  mdiArea.showMinimized();
506 #if defined (Q_OS_MAC)
507  if (!macHasAccessToWindowsServer())
508  QEXPECT_FAIL("", "showMinimized doesn't really minimize if you don't have access to the server", Abort);
509 #endif
510 #ifdef Q_OS_MAC
511  QSKIP("QTBUG-25298: This test is unstable on Mac.");
512 #endif
514  QSKIP("QTBUG-25298: Unstable on some X11 window managers");
515  QTRY_COMPARE(spy.count(), 1);
516  QVERIFY(!mdiArea.activeSubWindow());
517  QCOMPARE(mdiArea.currentSubWindow(), activeSubWindow);
518  spy.clear();
519 
520  // For this test, the QMdiArea widget must be active after minimizing and
521  // showing it again. QMdiArea has no active sub window if it is inactive itself.
522  mdiArea.showNormal();
523  mdiArea.activateWindow();
525  QTRY_COMPARE(spy.count(), 1);
526  QCOMPARE(mdiArea.activeSubWindow(), activeSubWindow);
527  spy.clear();
528 }
529 
530 void tst_QMdiArea::subWindowActivatedWithMinimize()
531 {
532  QMainWindow mw(0) ;
533  mw.menuBar();
534  QMdiArea *workspace = new QMdiArea(&mw);
535  workspace->setObjectName(QLatin1String("testWidget"));
536  mw.setCentralWidget(workspace);
537  QSignalSpy spy(workspace, SIGNAL(subWindowActivated(QMdiSubWindow*)));
538  connect( workspace, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(activeChanged(QMdiSubWindow*)) );
539  mw.show();
540  qApp->setActiveWindow(&mw);
543  QMdiSubWindow *window1 = workspace->addSubWindow(widget);
544  QWidget *widget2 = new QWidget(workspace);
546  QMdiSubWindow *window2 = workspace->addSubWindow(widget2);
547 
549  QVERIFY( activeWindow == window1 );
550  widget2->showMinimized();
551  QVERIFY( activeWindow == window2 );
552 
553  window2->close();
554  qApp->processEvents();
555  QVERIFY( activeWindow == window1 );
556 
557  window1->close();
558  qApp->processEvents();
559  QVERIFY(!workspace->activeSubWindow());
560  QVERIFY(!activeWindow);
561 
562  QVERIFY( workspace->subWindowList().count() == 0 );
563 }
564 
565 void tst_QMdiArea::showWindows()
566 {
567  QMdiArea *ws = new QMdiArea( 0 );
568 
569  QWidget *widget = 0;
570  ws->show();
571 
572  widget = new QWidget(ws);
573  widget->show();
574  QVERIFY( widget->isVisible() );
575 
576  widget = new QWidget(ws);
578  QVERIFY( widget->isMaximized() );
579  widget->showNormal();
580  QVERIFY( !widget->isMaximized() );
581 
582  widget = new QWidget(ws);
584  QVERIFY( widget->isMinimized() );
585  widget->showNormal();
586  QVERIFY( !widget->isMinimized() );
587 
588  ws->hide();
589 
590  widget = new QWidget(ws);
591  ws->show();
592  QVERIFY( widget->isVisible() );
593 
594  ws->hide();
595 
596  widget = new QWidget(ws);
598  QVERIFY( widget->isMaximized() );
599  ws->show();
600  QVERIFY( widget->isVisible() );
601  QVERIFY( widget->isMaximized() );
602  ws->hide();
603 
604  widget = new QWidget(ws);
606  ws->show();
607  QVERIFY( widget->isMinimized() );
608  ws->hide();
609 
610  delete ws;
611 }
612 
613 
614 //#define USE_SHOW
615 
616 #if !defined(Q_OS_DARWIN)
617 static inline QString windowTitle(const QString &t, const QString &f)
618 {
619  return t + QLatin1String(" - [") + f + QLatin1Char(']');
620 }
621 #endif
622 
623 void tst_QMdiArea::changeWindowTitle()
624 {
625  const QString mwc = QString::fromLatin1("MainWindow's Caption");
626  const QString mwc2 = QString::fromLatin1("MainWindow's New Caption");
627  const QString wc = QString::fromLatin1("Widget's Caption");
628  const QString wc2 = QString::fromLatin1("Widget's New Caption");
629 
630  QMainWindow *mw = new QMainWindow;
631  mw->setWindowTitle( mwc );
632  QMdiArea *ws = new QMdiArea( mw );
633  mw->setCentralWidget( ws );
634  mw->menuBar()->setNativeMenuBar(false);
635  mw->show();
637 
638  QWidget *widget = new QWidget( ws );
639  widget->setWindowTitle( wc );
640  ws->addSubWindow(widget);
641 
642  QCOMPARE( mw->windowTitle(), mwc );
643 
644 #ifdef USE_SHOW
646 #else
648 #endif
649 #if !defined(Q_OS_DARWIN)
650  QTRY_COMPARE( mw->windowTitle(), windowTitle(mwc, wc) );
651 #endif
652 
653  mw->hide();
654  qApp->processEvents();
655  mw->show();
657 
658 #if !defined(Q_OS_DARWIN)
659  QTRY_COMPARE( mw->windowTitle(), windowTitle(mwc, wc) );
660 #endif
661 
662 #ifdef USE_SHOW
663  widget->showNormal();
664 #else
666 #endif
667  qApp->processEvents();
668  QCOMPARE( mw->windowTitle(), mwc );
669 
670 #ifdef USE_SHOW
672 #else
674 #endif
675  qApp->processEvents();
676 #if !defined(Q_OS_DARWIN)
677  QTRY_COMPARE( mw->windowTitle(), windowTitle(mwc, wc) );
678  widget->setWindowTitle( wc2 );
679  QCOMPARE( mw->windowTitle(), windowTitle(mwc, wc2) );
680  mw->setWindowTitle( mwc2 );
681  QCOMPARE( mw->windowTitle(), windowTitle(mwc2, wc2) );
682 #endif
683 
684  mw->show();
685  qApp->setActiveWindow(mw);
686 
687 #ifdef USE_SHOW
688  mw->showFullScreen();
689 #else
691 #endif
692 
693  qApp->processEvents();
694 #if !defined(Q_OS_DARWIN)
695  QCOMPARE( mw->windowTitle(), windowTitle(mwc2, wc2) );
696 #endif
697 #ifdef USE_SHOW
698  widget->showNormal();
699 #else
701 #endif
702  qApp->processEvents();
703 #if defined(Q_OS_DARWIN)
704  QCOMPARE(mw->windowTitle(), mwc);
705 #else
706  QCOMPARE( mw->windowTitle(), mwc2 );
707 #endif
708 
709 #ifdef USE_SHOW
711 #else
713 #endif
714  qApp->processEvents();
715 #if !defined(Q_OS_DARWIN)
716  QCOMPARE( mw->windowTitle(), windowTitle(mwc2, wc2) );
717 #endif
718 
719 #ifdef USE_SHOW
720  mw->showNormal();
721 #else
723 #endif
724  qApp->processEvents();
725 #ifdef USE_SHOW
726  widget->showNormal();
727 #else
729 #endif
730 
731  delete mw;
732 }
733 
734 void tst_QMdiArea::changeModified()
735 {
736  const QString mwc = QString::fromLatin1("MainWindow's Caption");
737  const QString wc = QString::fromLatin1("Widget's Caption[*]");
738 
739  QMainWindow *mw = new QMainWindow(0);
740  mw->setWindowTitle( mwc );
741  QMdiArea *ws = new QMdiArea( mw );
742  mw->setCentralWidget( ws );
743  mw->menuBar()->setNativeMenuBar(false);
744  mw->show();
745 
746  QWidget *widget = new QWidget( ws );
747  widget->setWindowTitle( wc );
748  ws->addSubWindow(widget);
749 
750  QCOMPARE( mw->isWindowModified(), false);
751  QCOMPARE( widget->isWindowModified(), false);
753  QCOMPARE( mw->isWindowModified(), false);
754  QCOMPARE( widget->isWindowModified(), false);
755 
757  QCOMPARE( mw->isWindowModified(), false);
758  QCOMPARE( widget->isWindowModified(), false);
759 
760  widget->setWindowModified(true);
761  QCOMPARE( mw->isWindowModified(), false);
762  QCOMPARE( widget->isWindowModified(), true);
764 #if !defined(Q_OS_DARWIN)
765  QCOMPARE( mw->isWindowModified(), true);
766 #endif
767  QCOMPARE( widget->isWindowModified(), true);
768 
770  QCOMPARE( mw->isWindowModified(), false);
771  QCOMPARE( widget->isWindowModified(), true);
772 
774 #if !defined(Q_OS_DARWIN)
775  QCOMPARE( mw->isWindowModified(), true);
776 #endif
777  QCOMPARE( widget->isWindowModified(), true);
778 
779  widget->setWindowModified(false);
780  QCOMPARE( mw->isWindowModified(), false);
781  QCOMPARE( widget->isWindowModified(), false);
782 
783  widget->setWindowModified(true);
784 #if !defined(Q_OS_DARWIN)
785  QCOMPARE( mw->isWindowModified(), true);
786 #endif
787  QCOMPARE( widget->isWindowModified(), true);
788 
790  QCOMPARE( mw->isWindowModified(), false);
791  QCOMPARE( widget->isWindowModified(), true);
792 
793  delete mw;
794 }
795 
796 class MyChild : public QWidget
797 {
798 public:
799  MyChild(QWidget *parent = nullptr) : QWidget(parent) {}
800  QSize sizeHint() const override { return QSize(234, 123); }
801 };
802 
803 void tst_QMdiArea::childSize()
804 {
805  QMdiArea ws;
806 
807  MyChild *child = new MyChild(&ws);
808  child->show();
809  QCOMPARE(child->size(), child->sizeHint());
810  delete child;
811 
812  child = new MyChild(&ws);
813  child->setFixedSize(200, 200);
814  child->show();
815  QCOMPARE(child->size(), child->minimumSize());
816  delete child;
817 
818  child = new MyChild(&ws);
819  child->resize(150, 150);
820  child->show();
821  QCOMPARE(child->size(), QSize(150,150));
822  delete child;
823 }
824 
825 void tst_QMdiArea::fixedSize()
826 {
827  QMdiArea *ws = new QMdiArea;
828  int i;
829 
830  ws->resize(500, 500);
831 // ws->show();
832 
833  QSize fixed(300, 300);
834  for (i = 0; i < 4; ++i) {
835  QWidget *child = new QWidget(ws);
836  child->setFixedSize(fixed);
837  child->show();
838  }
839 
840  QList<QMdiSubWindow *> windows = ws->subWindowList();
841  for (i = 0; i < (int)windows.count(); ++i) {
843  QCOMPARE(child->size(), fixed);
844  }
845 
846  ws->cascadeSubWindows();
847  ws->resize(800, 800);
848  for (i = 0; i < (int)windows.count(); ++i) {
850  QCOMPARE(child->size(), fixed);
851  }
852  ws->resize(500, 500);
853 
854  ws->tileSubWindows();
855  ws->resize(800, 800);
856  for (i = 0; i < (int)windows.count(); ++i) {
858  QCOMPARE(child->size(), fixed);
859  }
860  ws->resize(500, 500);
861 
862  for (i = 0; i < (int)windows.count(); ++i) {
864  delete child;
865  }
866 
867  delete ws;
868 }
869 
870 class LargeWidget : public QWidget
871 {
872 public:
874  QSize sizeHint() const override { return QSize(1280, 1024); }
875  QSize minimumSizeHint() const override { return QSize(300, 300); }
876 };
877 
878 // New tests
879 void tst_QMdiArea::minimumSizeHint()
880 {
882  workspace.show();
883  QSize expectedSize(workspace.style()->pixelMetric(QStyle::PM_MdiSubWindowMinimizedWidth),
884  workspace.style()->pixelMetric(QStyle::PM_TitleBarHeight));
885  qApp->processEvents();
886  QAbstractScrollArea dummyScrollArea;
887  dummyScrollArea.setFrameStyle(QFrame::NoFrame);
888  expectedSize = expectedSize.expandedTo(dummyScrollArea.minimumSizeHint());
889  QCOMPARE(workspace.minimumSizeHint(), expectedSize);
890 
891  QWidget *window = workspace.addSubWindow(new QWidget);
892  qApp->processEvents();
893  window->show();
894  QCOMPARE(workspace.minimumSizeHint(), expectedSize.expandedTo(window->minimumSizeHint()));
895 
896  QMdiSubWindow *subWindow = workspace.addSubWindow(new LargeWidget);
897  subWindow->show();
898  QCOMPARE(workspace.minimumSizeHint(), expectedSize.expandedTo(subWindow->minimumSizeHint()));
899 
900  workspace.setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
901  workspace.setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
902  QCOMPARE(workspace.minimumSizeHint(), expectedSize);
903 }
904 
905 void tst_QMdiArea::sizeHint()
906 {
908  workspace.show();
909  QSize desktopSize = QGuiApplication::primaryScreen()->size();
910  QSize expectedSize(desktopSize.width() * 2/3, desktopSize.height() * 2/3);
911  QCOMPARE(workspace.sizeHint(), expectedSize);
912 
913  QWidget *window = workspace.addSubWindow(new QWidget);
914  qApp->processEvents();
915  window->show();
916  QCOMPARE(workspace.sizeHint(), expectedSize.expandedTo(window->sizeHint()));
917 
918  QMdiSubWindow *nested = workspace.addSubWindow(new QMdiArea);
919  expectedSize = QSize(desktopSize.width() * 2/6, desktopSize.height() * 2/6);
920  QCOMPARE(nested->widget()->sizeHint(), expectedSize);
921 }
922 
923 void tst_QMdiArea::setActiveSubWindow()
924 {
926  workspace.show();
927 
928  QSignalSpy spy(&workspace, SIGNAL(subWindowActivated(QMdiSubWindow*)));
929  connect(&workspace, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(activeChanged(QMdiSubWindow*)));
930  qApp->setActiveWindow(&workspace);
931 
932  // Activate hidden windows
933  const int windowCount = 10;
934  QMdiSubWindow *windows[windowCount];
935  for (int i = 0; i < windowCount; ++i) {
936  windows[i] = qobject_cast<QMdiSubWindow *>(workspace.addSubWindow(new QWidget));
937  qApp->processEvents();
938  QVERIFY(windows[i]->isHidden());
939  workspace.setActiveSubWindow(windows[i]);
940  }
941  QCOMPARE(spy.count(), 0);
942  QVERIFY(!activeWindow);
943  spy.clear();
944 
945  // Activate visible windows
946  for (int i = 0; i < windowCount; ++i) {
947  windows[i]->show();
948  QVERIFY(!windows[i]->isHidden());
949  workspace.setActiveSubWindow(windows[i]);
950  qApp->processEvents();
951  QCOMPARE(spy.count(), 1);
952  QCOMPARE(activeWindow, windows[i]);
953  spy.clear();
954  }
955 
956  // Deactivate active window
957  QCOMPARE(workspace.activeSubWindow(), windows[windowCount - 1]);
958  workspace.setActiveSubWindow(0);
959  QCOMPARE(spy.count(), 1);
960  QVERIFY(!activeWindow);
961  QVERIFY(!workspace.activeSubWindow());
962 
963  // Activate widget which is not child of any window inside workspace
964  QMdiSubWindow fakeWindow;
965  QTest::ignoreMessage(QtWarningMsg, "QMdiArea::setActiveSubWindow: window is not inside workspace");
966  workspace.setActiveSubWindow(&fakeWindow);
967 
968 }
969 
970 void tst_QMdiArea::activeSubWindow()
971 {
973  QSKIP("Wayland: This fails. Figure out why.");
974 
976 
977  QMdiArea *mdiArea = new QMdiArea;
978  QLineEdit *subWindowLineEdit = new QLineEdit;
979  QMdiSubWindow *subWindow = mdiArea->addSubWindow(subWindowLineEdit);
980  mainWindow.setCentralWidget(mdiArea);
981 
982  QDockWidget *dockWidget = new QDockWidget(QLatin1String("Dock Widget"), &mainWindow);
984  QLineEdit *dockWidgetLineEdit = new QLineEdit;
985  dockWidget->setWidget(dockWidgetLineEdit);
987 
988  mainWindow.show();
989  qApp->setActiveWindow(&mainWindow);
991  QCOMPARE(mdiArea->activeSubWindow(), subWindow);
992  QCOMPARE(qApp->focusWidget(), (QWidget *)subWindowLineEdit);
993 
994  dockWidgetLineEdit->setFocus();
995  QCOMPARE(qApp->focusWidget(), (QWidget *)dockWidgetLineEdit);
996  QCOMPARE(mdiArea->activeSubWindow(), subWindow);
997 
998  QEvent deactivateEvent(QEvent::WindowDeactivate);
999  qApp->sendEvent(subWindow, &deactivateEvent);
1000  QVERIFY(!mdiArea->activeSubWindow());
1001  QCOMPARE(qApp->focusWidget(), (QWidget *)dockWidgetLineEdit);
1002 
1003  QEvent activateEvent(QEvent::WindowActivate);
1004  qApp->sendEvent(subWindow, &activateEvent);
1005  QCOMPARE(mdiArea->activeSubWindow(), subWindow);
1006  QCOMPARE(qApp->focusWidget(), (QWidget *)subWindowLineEdit);
1007 
1008  QLineEdit dummyTopLevel;
1009  dummyTopLevel.show();
1010  QVERIFY(QTest::qWaitForWindowExposed(&dummyTopLevel));
1011 
1012  qApp->setActiveWindow(&dummyTopLevel);
1013  QCOMPARE(mdiArea->activeSubWindow(), subWindow);
1014 
1015  qApp->setActiveWindow(&mainWindow);
1016  QCOMPARE(mdiArea->activeSubWindow(), subWindow);
1017 
1018  //task 202657
1019  dockWidgetLineEdit->setFocus();
1020  qApp->setActiveWindow(&mainWindow);
1021  QVERIFY(dockWidgetLineEdit->hasFocus());
1022 }
1023 
1024 void tst_QMdiArea::currentSubWindow()
1025 {
1026  QMdiArea mdiArea;
1027  mdiArea.show();
1029 
1030  for (int i = 0; i < 5; ++i)
1031  mdiArea.addSubWindow(new QLineEdit)->show();
1032 
1033  qApp->setActiveWindow(&mdiArea);
1034  QCOMPARE(qApp->activeWindow(), (QWidget *)&mdiArea);
1035 
1036  // Check that the last added window is the active and the current.
1037  QMdiSubWindow *active = mdiArea.activeSubWindow();
1038  QVERIFY(active);
1039  QCOMPARE(mdiArea.subWindowList().back(), active);
1040  QCOMPARE(mdiArea.currentSubWindow(), active);
1041 
1042  QLineEdit dummyTopLevel;
1043  dummyTopLevel.show();
1044  QVERIFY(QTest::qWaitForWindowExposed(&dummyTopLevel));
1045 
1046  // Move focus to another top-level and check that we still
1047  // have an active window.
1048  qApp->setActiveWindow(&dummyTopLevel);
1049  QCOMPARE(qApp->activeWindow(), (QWidget *)&dummyTopLevel);
1050  QVERIFY(mdiArea.activeSubWindow());
1051 
1052  delete active;
1053  active = 0;
1054 
1055  // We just deleted the current sub-window -> current should then
1056  // be the next in list (which in this case is the first sub-window).
1057  QVERIFY(mdiArea.currentSubWindow());
1058  QCOMPARE(mdiArea.currentSubWindow(), mdiArea.subWindowList().front());
1059 
1060  // Activate mdi area and check that active == current.
1061  qApp->setActiveWindow(&mdiArea);
1062  active = mdiArea.activeSubWindow();
1063  QVERIFY(active);
1064  QCOMPARE(mdiArea.activeSubWindow(), mdiArea.subWindowList().front());
1065 
1066  active->hide();
1067  QCOMPARE(mdiArea.activeSubWindow(), active);
1068  QCOMPARE(mdiArea.currentSubWindow(), active);
1069 
1070  qApp->setActiveWindow(&dummyTopLevel);
1071  QVERIFY(mdiArea.activeSubWindow());
1072  QCOMPARE(mdiArea.currentSubWindow(), active);
1073 
1074  qApp->setActiveWindow(&mdiArea);
1075  active->show();
1076  QCOMPARE(mdiArea.activeSubWindow(), active);
1077 
1078  mdiArea.setActiveSubWindow(0);
1079  QVERIFY(!mdiArea.activeSubWindow());
1080  QVERIFY(!mdiArea.currentSubWindow());
1081 
1082  mdiArea.setActiveSubWindow(active);
1083  QCOMPARE(mdiArea.activeSubWindow(), active);
1084  QEvent windowDeactivate(QEvent::WindowDeactivate);
1085  qApp->sendEvent(active, &windowDeactivate);
1086  QVERIFY(!mdiArea.activeSubWindow());
1087  QVERIFY(!mdiArea.currentSubWindow());
1088 
1089  QEvent windowActivate(QEvent::WindowActivate);
1090  qApp->sendEvent(active, &windowActivate);
1091  QVERIFY(mdiArea.activeSubWindow());
1092  QVERIFY(mdiArea.currentSubWindow());
1093 }
1094 
1095 void tst_QMdiArea::addAndRemoveWindows()
1096 {
1097  QWidget topLevel;
1098  QMdiArea workspace(&topLevel);
1099  workspace.resize(800, 600);
1100  topLevel.show();
1102 
1103  { // addSubWindow with large widget
1104  QCOMPARE(workspace.subWindowList().count(), 0);
1105  QWidget *window = workspace.addSubWindow(new LargeWidget);
1106  QVERIFY(window);
1107  qApp->processEvents();
1108  QCOMPARE(workspace.subWindowList().count(), 1);
1109  QCOMPARE(window->windowFlags(), DefaultWindowFlags);
1110  QCOMPARE(window->size(), workspace.viewport()->size());
1111  }
1112 
1113  { // addSubWindow, minimumSize set.
1115  window->setMinimumSize(900, 900);
1116  workspace.addSubWindow(window);
1117  QVERIFY(window);
1118  qApp->processEvents();
1119  QCOMPARE(workspace.subWindowList().count(), 2);
1120  QCOMPARE(window->windowFlags(), DefaultWindowFlags);
1121  QCOMPARE(window->size(), window->minimumSize());
1122  }
1123 
1124  { // addSubWindow, resized
1126  window->setWidget(new QWidget);
1127  window->resize(1500, 1500);
1128  workspace.addSubWindow(window);
1129  QVERIFY(window);
1130  qApp->processEvents();
1131  QCOMPARE(workspace.subWindowList().count(), 3);
1132  QCOMPARE(window->windowFlags(), DefaultWindowFlags);
1133  QCOMPARE(window->size(), QSize(1500, 1500));
1134  }
1135 
1136  { // addSubWindow with 0 pointer
1137  QTest::ignoreMessage(QtWarningMsg, "QMdiArea::addSubWindow: null pointer to widget");
1138  QWidget *window = workspace.addSubWindow(0);
1139  QVERIFY(!window);
1140  QCOMPARE(workspace.subWindowList().count(), 3);
1141  }
1142 
1143  { // addChildWindow
1145  workspace.addSubWindow(window);
1146  qApp->processEvents();
1147  QCOMPARE(window->windowFlags(), DefaultWindowFlags);
1148  window->setWidget(new QWidget);
1149  QCOMPARE(workspace.subWindowList().count(), 4);
1150  QTest::ignoreMessage(QtWarningMsg, "QMdiArea::addSubWindow: window is already added");
1151  workspace.addSubWindow(window);
1152  }
1153 
1154  { // addChildWindow with 0 pointer
1155  QTest::ignoreMessage(QtWarningMsg, "QMdiArea::addSubWindow: null pointer to widget");
1156  workspace.addSubWindow(0);
1157  QCOMPARE(workspace.subWindowList().count(), 4);
1158  }
1159 
1160  // removeSubWindow
1161  foreach (QWidget *window, workspace.subWindowList()) {
1162  workspace.removeSubWindow(window);
1163  delete window;
1164  }
1165  QCOMPARE(workspace.subWindowList().count(), 0);
1166 
1167  // removeSubWindow with 0 pointer
1168  QTest::ignoreMessage(QtWarningMsg, "QMdiArea::removeSubWindow: null pointer to widget");
1169  workspace.removeSubWindow(0);
1170 
1171  workspace.addSubWindow(new QPushButton(QLatin1String("Dummy to make workspace non-empty")));
1172  qApp->processEvents();
1173  QCOMPARE(workspace.subWindowList().count(), 1);
1174 
1175  // removeSubWindow with window not inside workspace
1176  QTest::ignoreMessage(QtWarningMsg,"QMdiArea::removeSubWindow: window is not inside workspace");
1177  QMdiSubWindow *fakeWindow = new QMdiSubWindow;
1178  workspace.removeSubWindow(fakeWindow);
1179  delete fakeWindow;
1180 
1181  // Check that newly added windows don't occupy maximized windows'
1182  // restore space.
1183  workspace.closeAllSubWindows();
1185  workspace.show();
1186  QMdiSubWindow *window1 = workspace.addSubWindow(new QWidget);
1187  window1->show();
1188  const QRect window1RestoreGeometry = window1->geometry();
1189  QCOMPARE(window1RestoreGeometry.topLeft(), QPoint(0, 0));
1190 
1191  window1->showMinimized();
1192 
1193  // Occupy space.
1194  QMdiSubWindow *window2 = workspace.addSubWindow(new QWidget);
1195  window2->show();
1196  const QRect window2RestoreGeometry = window2->geometry();
1197  QCOMPARE(window2RestoreGeometry.topLeft(), QPoint(0, 0));
1198 
1199  window2->showMaximized();
1200 
1201  // Don't occupy space.
1202  QMdiSubWindow *window3 = workspace.addSubWindow(new QWidget);
1203  window3->show();
1204  QCOMPARE(window3->geometry().topLeft(), QPoint(window2RestoreGeometry.right() + 1, 0));
1205 }
1206 
1207 void tst_QMdiArea::addAndRemoveWindowsWithReparenting()
1208 {
1211  QCOMPARE(window.windowFlags(), DefaultWindowFlags);
1212 
1213  // 0 because the window list contains widgets and not actual
1214  // windows. Silly, but that's the behavior.
1215  QCOMPARE(workspace.subWindowList().count(), 0);
1216  window.setWidget(new QWidget);
1217  qApp->processEvents();
1218 
1219  QCOMPARE(workspace.subWindowList().count(), 1);
1220  window.setParent(0); // Will also reset window flags
1221  QCOMPARE(workspace.subWindowList().count(), 0);
1222  window.setParent(&workspace);
1223  QCOMPARE(workspace.subWindowList().count(), 1);
1224  QCOMPARE(window.windowFlags(), DefaultWindowFlags);
1225 
1226  QTest::ignoreMessage(QtWarningMsg, "QMdiArea::addSubWindow: window is already added");
1227  workspace.addSubWindow(&window);
1228  QCOMPARE(workspace.subWindowList().count(), 1);
1229 }
1230 
1232 {
1233 public:
1234  using QObject::receivers;
1235 };
1236 
1237 static int numberOfConnectedSignals(MySubWindow *subWindow)
1238 {
1239  if (!subWindow)
1240  return 0;
1241 
1242  int numConnectedSignals = 0;
1243  for (int i = 0; i < subWindow->metaObject()->methodCount(); ++i) {
1244  QMetaMethod method = subWindow->metaObject()->method(i);
1245  if (method.methodType() == QMetaMethod::Signal) {
1247  signature += QLatin1String(method.methodSignature().constData());
1248  numConnectedSignals += subWindow->receivers(signature.toLatin1());
1249  }
1250  }
1251  return numConnectedSignals;
1252 }
1253 
1254 void tst_QMdiArea::removeSubWindow_2()
1255 {
1256  QMdiArea mdiArea;
1257  MySubWindow *subWindow = new MySubWindow;
1258  QCOMPARE(numberOfConnectedSignals(subWindow), 0);
1259 
1260  // Connected to aboutToActivate() and windowStateChanged().
1261  mdiArea.addSubWindow(subWindow);
1262  QVERIFY(numberOfConnectedSignals(subWindow) >= 2);
1263 
1264  // Ensure we disconnect from all signals.
1265  mdiArea.removeSubWindow(subWindow);
1266  QCOMPARE(numberOfConnectedSignals(subWindow), 0);
1267 
1268  mdiArea.addSubWindow(subWindow);
1269  QVERIFY(numberOfConnectedSignals(subWindow) >= 2);
1270  subWindow->setParent(0);
1271  QScopedPointer<MySubWindow> subWindowGuard(subWindow);
1272  QCOMPARE(numberOfConnectedSignals(subWindow), 0);
1273 }
1274 
1275 void tst_QMdiArea::closeWindows()
1276 {
1278  workspace.show();
1279  qApp->setActiveWindow(&workspace);
1280 
1281  // Close widget
1282  QWidget *widget = new QWidget;
1283  QMdiSubWindow *subWindow = workspace.addSubWindow(widget);
1284  qApp->processEvents();
1285  QCOMPARE(workspace.subWindowList().count(), 1);
1286  subWindow->close();
1287  QCOMPARE(workspace.subWindowList().count(), 0);
1288 
1289  // Close window
1290  QWidget *window = workspace.addSubWindow(new QWidget);
1291  qApp->processEvents();
1292  QCOMPARE(workspace.subWindowList().count(), 1);
1293  window->close();
1294  qApp->processEvents();
1295  QCOMPARE(workspace.subWindowList().count(), 0);
1296 
1297  const int windowCount = 10;
1298 
1299  // Close active window
1300  for (int i = 0; i < windowCount; ++i)
1301  workspace.addSubWindow(new QWidget)->show();
1302  qApp->processEvents();
1303  QCOMPARE(workspace.subWindowList().count(), windowCount);
1304  int activeSubWindowCount = 0;
1305  while (workspace.activeSubWindow()) {
1306  workspace.activeSubWindow()->close();
1307  qApp->processEvents();
1308  ++activeSubWindowCount;
1309  }
1310  QCOMPARE(activeSubWindowCount, windowCount);
1311  QCOMPARE(workspace.subWindowList().count(), 0);
1312 
1313  // Close all windows
1314  for (int i = 0; i < windowCount; ++i)
1315  workspace.addSubWindow(new QWidget)->show();
1316  qApp->processEvents();
1317  QCOMPARE(workspace.subWindowList().count(), windowCount);
1318  QSignalSpy spy(&workspace, SIGNAL(subWindowActivated(QMdiSubWindow*)));
1319  connect(&workspace, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(activeChanged(QMdiSubWindow*)));
1320  workspace.closeAllSubWindows();
1321  qApp->processEvents();
1322  QCOMPARE(workspace.subWindowList().count(), 0);
1323  QCOMPARE(spy.count(), 1);
1324  QVERIFY(!activeWindow);
1325 }
1326 
1327 void tst_QMdiArea::activateNextAndPreviousWindow()
1328 {
1330  workspace.show();
1331  qApp->setActiveWindow(&workspace);
1332 
1333  const int windowCount = 10;
1334  QMdiSubWindow *windows[windowCount];
1335  for (int i = 0; i < windowCount; ++i) {
1336  windows[i] = qobject_cast<QMdiSubWindow *>(workspace.addSubWindow(new QWidget));
1337  windows[i]->show();
1338  qApp->processEvents();
1339  }
1340 
1341  QSignalSpy spy(&workspace, SIGNAL(subWindowActivated(QMdiSubWindow*)));
1342  connect(&workspace, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(activeChanged(QMdiSubWindow*)));
1343 
1344  // activateNextSubWindow
1345  for (int i = 0; i < windowCount; ++i) {
1346  workspace.activateNextSubWindow();
1347  qApp->processEvents();
1348  QCOMPARE(workspace.activeSubWindow(), windows[i]);
1349  QCOMPARE(spy.count(), 1);
1350  spy.clear();
1351  }
1352  QVERIFY(activeWindow);
1353  QCOMPARE(workspace.activeSubWindow(), windows[windowCount - 1]);
1354  QCOMPARE(workspace.activeSubWindow(), activeWindow);
1355 
1356  // activatePreviousSubWindow
1357  for (int i = windowCount - 2; i >= 0; --i) {
1358  workspace.activatePreviousSubWindow();
1359  qApp->processEvents();
1360  QCOMPARE(workspace.activeSubWindow(), windows[i]);
1361  QCOMPARE(spy.count(), 1);
1362  spy.clear();
1363  if (i % 2 == 0)
1364  windows[i]->hide(); // 10, 8, 6, 4, 2, 0
1365  }
1366  QVERIFY(activeWindow);
1367  QCOMPARE(workspace.activeSubWindow(), windows[0]);
1368  QCOMPARE(workspace.activeSubWindow(), activeWindow);
1369 
1370  // activateNextSubWindow with every 2nd window hidden
1371  for (int i = 0; i < windowCount / 2; ++i) {
1372  workspace.activateNextSubWindow(); // 1, 3, 5, 7, 9
1373  QCOMPARE(spy.count(), 1);
1374  spy.clear();
1375  }
1376  QCOMPARE(workspace.activeSubWindow(), windows[windowCount - 1]);
1377 
1378  // activatePreviousSubWindow with every 2nd window hidden
1379  for (int i = 0; i < windowCount / 2; ++i) {
1380  workspace.activatePreviousSubWindow(); // 7, 5, 3, 1, 9
1381  QCOMPARE(spy.count(), 1);
1382  spy.clear();
1383  }
1384  QCOMPARE(workspace.activeSubWindow(), windows[windowCount - 1]);
1385 
1386  workspace.setActiveSubWindow(0);
1387  QVERIFY(!activeWindow);
1388 }
1389 
1390 void tst_QMdiArea::subWindowList_data()
1391 {
1392  QTest::addColumn<QMdiArea::WindowOrder>("windowOrder");
1393  QTest::addColumn<int>("windowCount");
1394  QTest::addColumn<int>("activeSubWindow");
1395  QTest::addColumn<int>("staysOnTop1");
1396  QTest::addColumn<int>("staysOnTop2");
1397 
1398  QTest::newRow("CreationOrder") << QMdiArea::CreationOrder << 10 << 4 << 8 << 5;
1399  QTest::newRow("StackingOrder") << QMdiArea::StackingOrder << 10 << 6 << 3 << 9;
1400  QTest::newRow("ActivationHistoryOrder") << QMdiArea::ActivationHistoryOrder << 10 << 7 << 2 << 1;
1401 }
1402 void tst_QMdiArea::subWindowList()
1403 {
1405  QSKIP("Wayland: This fails. Figure out why.");
1406 
1407  QFETCH(QMdiArea::WindowOrder, windowOrder);
1408  QFETCH(int, windowCount);
1409  QFETCH(int, activeSubWindow);
1410  QFETCH(int, staysOnTop1);
1411  QFETCH(int, staysOnTop2);
1412 
1414  workspace.show();
1415  qApp->setActiveWindow(&workspace);
1417 
1418  QList<QMdiSubWindow *> activationOrder;
1420  for (int i = 0; i < windowCount; ++i) {
1421  windows.append(qobject_cast<QMdiSubWindow *>(workspace.addSubWindow(new QWidget)));
1422  windows[i]->show();
1423  activationOrder.append(windows[i]);
1424  }
1425 
1426  {
1427  QList<QMdiSubWindow *> widgets = workspace.subWindowList(windowOrder);
1428  QCOMPARE(widgets.count(), windowCount);
1429  for (int i = 0; i < widgets.count(); ++i)
1430  QCOMPARE(widgets.at(i), windows[i]);
1431  }
1432 
1433  windows[staysOnTop1]->setWindowFlags(windows[staysOnTop1]->windowFlags() | Qt::WindowStaysOnTopHint);
1434  workspace.setActiveSubWindow(windows[activeSubWindow]);
1435  QTRY_COMPARE(workspace.activeSubWindow(), windows[activeSubWindow]);
1436  activationOrder.move(activationOrder.indexOf(windows[activeSubWindow]), windowCount - 1);
1437 
1438  QList<QMdiSubWindow *> subWindows = workspace.subWindowList(windowOrder);
1439  if (windowOrder == QMdiArea::CreationOrder) {
1440  QCOMPARE(subWindows.at(activeSubWindow), windows[activeSubWindow]);
1441  QCOMPARE(subWindows.at(staysOnTop1), windows[staysOnTop1]);
1442  for (int i = 0; i < windowCount; ++i)
1443  QCOMPARE(subWindows.at(i), windows[i]);
1444  return;
1445  }
1446 
1447  if (windowOrder == QMdiArea::StackingOrder) {
1448  QCOMPARE(subWindows.at(subWindows.count() - 1), windows[staysOnTop1]);
1449  QCOMPARE(subWindows.at(subWindows.count() - 2), windows[activeSubWindow]);
1450  QCOMPARE(subWindows.count(), windowCount);
1451  } else { // ActivationHistoryOrder
1452  QCOMPARE(subWindows, activationOrder);
1453  }
1454 
1455  windows[staysOnTop2]->setWindowFlags(windows[staysOnTop2]->windowFlags() | Qt::WindowStaysOnTopHint);
1456  workspace.setActiveSubWindow(windows[staysOnTop2]);
1457  QTRY_COMPARE(workspace.activeSubWindow(), windows[staysOnTop2]);
1458  activationOrder.move(activationOrder.indexOf(windows[staysOnTop2]), windowCount - 1);
1459 
1460  workspace.setActiveSubWindow(windows[activeSubWindow]);
1461  QTRY_COMPARE(workspace.activeSubWindow(), windows[activeSubWindow]);
1462  activationOrder.move(activationOrder.indexOf(windows[activeSubWindow]), windowCount - 1);
1463 
1464  QList<QMdiSubWindow *> widgets = workspace.subWindowList(windowOrder);
1465  QCOMPARE(widgets.count(), windowCount);
1466  if (windowOrder == QMdiArea::StackingOrder) {
1467  QCOMPARE(widgets.at(widgets.count() - 1), windows[staysOnTop2]);
1468  QCOMPARE(widgets.at(widgets.count() - 2), windows[staysOnTop1]);
1469  QCOMPARE(widgets.at(widgets.count() - 3), windows[activeSubWindow]);
1470  } else { // ActivationHistory
1471  QCOMPARE(widgets, activationOrder);
1472  }
1473 
1474  windows[activeSubWindow]->raise();
1475  windows[staysOnTop2]->lower();
1476 
1477  widgets = workspace.subWindowList(windowOrder);
1478  if (windowOrder == QMdiArea::StackingOrder) {
1479  QCOMPARE(widgets.at(widgets.count() - 1), windows[activeSubWindow]);
1480  QCOMPARE(widgets.at(widgets.count() - 2), windows[staysOnTop1]);
1481  QCOMPARE(widgets.at(0), windows[staysOnTop2]);
1482  } else { // ActivationHistoryOrder
1483  QCOMPARE(widgets, activationOrder);
1484  }
1485 
1486  windows[activeSubWindow]->stackUnder(windows[staysOnTop1]);
1487  windows[staysOnTop2]->raise();
1488 
1489  widgets = workspace.subWindowList(windowOrder);
1490  if (windowOrder == QMdiArea::StackingOrder) {
1491  QCOMPARE(widgets.at(widgets.count() - 1), windows[staysOnTop2]);
1492  QCOMPARE(widgets.at(widgets.count() - 2), windows[staysOnTop1]);
1493  QCOMPARE(widgets.at(widgets.count() - 3), windows[activeSubWindow]);
1494  } else { // ActivationHistoryOrder
1495  QCOMPARE(widgets, activationOrder);
1496  }
1497 
1498  workspace.setActiveSubWindow(windows[staysOnTop1]);
1499  activationOrder.move(activationOrder.indexOf(windows[staysOnTop1]), windowCount - 1);
1500 
1501  widgets = workspace.subWindowList(windowOrder);
1502  if (windowOrder == QMdiArea::StackingOrder) {
1503  QCOMPARE(widgets.at(widgets.count() - 1), windows[staysOnTop1]);
1504  QCOMPARE(widgets.at(widgets.count() - 2), windows[staysOnTop2]);
1505  QCOMPARE(widgets.at(widgets.count() - 3), windows[activeSubWindow]);
1506  } else { // ActivationHistoryOrder
1507  QCOMPARE(widgets, activationOrder);
1508  }
1509 }
1510 
1511 void tst_QMdiArea::setBackground()
1512 {
1514  QCOMPARE(workspace.background(), workspace.palette().brush(QPalette::Dark));
1515  workspace.setBackground(QBrush(Qt::green));
1516  QCOMPARE(workspace.background(), QBrush(Qt::green));
1517 }
1518 
1519 void tst_QMdiArea::setViewport()
1520 {
1521 #ifdef Q_OS_MACOS
1522  QSKIP("Sometimes crashes in the CI, see QTBUG-58520");
1523 #endif
1524 
1526  workspace.show();
1527 
1528  QWidget *firstViewport = workspace.viewport();
1529  QVERIFY(firstViewport);
1530 
1531  const int windowCount = 10;
1532  for (int i = 0; i < windowCount; ++i) {
1533  QMdiSubWindow *window = workspace.addSubWindow(new QWidget);
1534  window->show();
1535  if (i % 2 == 0) {
1536  window->showMinimized();
1537  QVERIFY(window->isMinimized());
1538  } else {
1539  window->showMaximized();
1540  QVERIFY(window->isMaximized());
1541  }
1542  }
1543 
1544  qApp->processEvents();
1545  QList<QMdiSubWindow *> windowsBeforeViewportChange = workspace.subWindowList();
1546  QCOMPARE(windowsBeforeViewportChange.count(), windowCount);
1547 
1548  workspace.setViewport(new QWidget);
1549  qApp->processEvents();
1550  QVERIFY(workspace.viewport() != firstViewport);
1551 
1552  QList<QMdiSubWindow *> windowsAfterViewportChange = workspace.subWindowList();
1553  QCOMPARE(windowsAfterViewportChange.count(), windowCount);
1554  QCOMPARE(windowsAfterViewportChange, windowsBeforeViewportChange);
1555 
1556  // for (int i = 0; i < windowCount; ++i) {
1557  // QMdiSubWindow *window = windowsAfterViewportChange.at(i);
1558  // if (i % 2 == 0)
1559  // QVERIFY(!window->isMinimized());
1560  //else
1561  // QVERIFY(!window->isMaximized());
1562  // }
1563 
1564  QTest::ignoreMessage(QtWarningMsg, "QMdiArea: Deleting the view port is undefined, "
1565  "use setViewport instead.");
1566  delete workspace.viewport();
1567  qApp->processEvents();
1568 
1569  QCOMPARE(workspace.subWindowList().count(), 0);
1570  QVERIFY(!workspace.activeSubWindow());
1571 }
1572 
1573 void tst_QMdiArea::tileSubWindows()
1574 {
1576  QSKIP("Wayland: This fails. Figure out why.");
1577 
1579  workspace.resize(600,480);
1580  workspace.show();
1582 
1583  const int windowCount = 10;
1584  for (int i = 0; i < windowCount; ++i) {
1585  QMdiSubWindow *subWindow = workspace.addSubWindow(new QWidget);
1586  subWindow->setMinimumSize(50, 30);
1587  subWindow->show();
1588  }
1589  workspace.tileSubWindows();
1590  workspace.setActiveSubWindow(0);
1591  QCOMPARE(workspace.viewport()->childrenRect(), workspace.viewport()->rect());
1592 
1593  QList<QMdiSubWindow *> windows = workspace.subWindowList();
1594  for (int i = 0; i < windowCount; ++i) {
1596  for (int j = 0; j < windowCount; ++j) {
1597  if (i == j)
1598  continue;
1599  QVERIFY(!window->geometry().intersects(windows.at(j)->geometry()));
1600  }
1601  }
1602 
1603  // Keep the views tiled through any subsequent resize events.
1604  for (int i = 0; i < 5; ++i) {
1605  workspace.resize(workspace.size() - QSize(10, 10));
1606  qApp->processEvents();
1607  }
1608  workspace.setActiveSubWindow(0);
1609  QCOMPARE(workspace.viewport()->childrenRect(), workspace.viewport()->rect());
1610 
1612 
1613  // Change the geometry of one of the children and verify
1614  // that the views are not tiled anymore.
1615  window->move(window->x() + 1, window->y());
1616  workspace.resize(workspace.size() - QSize(10, 10));
1617  workspace.setActiveSubWindow(0);
1618  QVERIFY(workspace.viewport()->childrenRect() != workspace.viewport()->rect());
1619  qApp->processEvents();
1620 
1621  // Re-tile.
1622  workspace.tileSubWindows();
1623  workspace.setActiveSubWindow(0);
1624  QCOMPARE(workspace.viewport()->childrenRect(), workspace.viewport()->rect());
1625 
1626  // Close one of the children and verify that the views
1627  // are not tiled anymore.
1628  window->close();
1629  workspace.resize(workspace.size() - QSize(10, 10));
1630  workspace.setActiveSubWindow(0);
1631  QVERIFY(workspace.viewport()->childrenRect() != workspace.viewport()->rect());
1632  qApp->processEvents();
1633 
1634  // Re-tile.
1635  workspace.tileSubWindows();
1636  workspace.setActiveSubWindow(0);
1637  QCOMPARE(workspace.viewport()->childrenRect(), workspace.viewport()->rect());
1638 
1639  window = windows.at(1);
1640 
1641  // Maximize one of the children and verify that the views
1642  // are not tiled anymore.
1643  workspace.tileSubWindows();
1644  window->showMaximized();
1645  workspace.resize(workspace.size() - QSize(10, 10));
1646  workspace.setActiveSubWindow(0);
1647  QVERIFY(workspace.viewport()->childrenRect() != workspace.viewport()->rect());
1648  qApp->processEvents();
1649 
1650  // Re-tile.
1651  workspace.tileSubWindows();
1652  workspace.setActiveSubWindow(0);
1653  QCOMPARE(workspace.viewport()->childrenRect(), workspace.viewport()->rect());
1654 
1655  // Minimize one of the children and verify that the views
1656  // are not tiled anymore.
1657  workspace.tileSubWindows();
1658  window->showMinimized();
1659  workspace.resize(workspace.size() - QSize(10, 10));
1660  workspace.setActiveSubWindow(0);
1661  QVERIFY(workspace.viewport()->childrenRect() != workspace.viewport()->rect());
1662  qApp->processEvents();
1663 
1664  // Re-tile.
1665  workspace.tileSubWindows();
1666  workspace.setActiveSubWindow(0);
1667  QCOMPARE(workspace.viewport()->childrenRect(), workspace.viewport()->rect());
1668 
1669  // Active/deactivate windows and verify that the views are tiled.
1670  workspace.setActiveSubWindow(windows.at(5));
1671  workspace.resize(workspace.size() - QSize(10, 10));
1672  workspace.setActiveSubWindow(0);
1673  QTest::qWait(250); // delayed re-arrange of minimized windows
1674  QTRY_COMPARE(workspace.viewport()->childrenRect(), workspace.viewport()->rect());
1675 
1676  // Add another window and verify that the views are not tiled anymore.
1677  workspace.addSubWindow(new QPushButton(QLatin1String("I'd like to mess up tiled views")))->show();
1678  workspace.resize(workspace.size() - QSize(10, 10));
1679  workspace.setActiveSubWindow(0);
1680  QVERIFY(workspace.viewport()->childrenRect() != workspace.viewport()->rect());
1681 
1682  // Re-tile.
1683  workspace.tileSubWindows();
1684  workspace.setActiveSubWindow(0);
1685  QCOMPARE(workspace.viewport()->childrenRect(), workspace.viewport()->rect());
1686 
1687  // Cascade and verify that the views are not tiled anymore.
1688  workspace.cascadeSubWindows();
1689  workspace.resize(workspace.size() - QSize(10, 10));
1690  workspace.setActiveSubWindow(0);
1691  QVERIFY(workspace.viewport()->childrenRect() != workspace.viewport()->rect());
1692 
1693  // Make sure the active window does not move position after a tile regardless
1694  // of whether we have any windows with staysOnTopHint or not.
1695  workspace.tileSubWindows();
1696  windows.at(3)->setWindowFlags(windows.at(3)->windowFlags() | Qt::WindowStaysOnTopHint);
1697  QMdiSubWindow *activeSubWindow = windows.at(6);
1698  workspace.setActiveSubWindow(activeSubWindow);
1699  QCOMPARE(workspace.activeSubWindow(), activeSubWindow);
1700  QPoint pos = activeSubWindow->geometry().topLeft();
1701  workspace.tileSubWindows();
1702  QCOMPARE(activeSubWindow->geometry().topLeft(), pos);
1703 
1704  // Verify that we try to resize the area such that all sub-windows are visible.
1705  // It's important that tiled windows are NOT overlapping.
1706  workspace.resize(350, 150);
1707  qApp->processEvents();
1708  QTRY_COMPARE(workspace.size(), QSize(350, 150));
1709 
1710  const QSize minSize(600, 130);
1711  foreach (QMdiSubWindow *subWindow, workspace.subWindowList())
1712  subWindow->setMinimumSize(minSize);
1713 
1714  QCOMPARE(workspace.size(), QSize(350, 150));
1715 
1716  // Prevent scrollbars from messing up the expected viewport calculation below
1717  workspace.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1718  workspace.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1719  QCOMPARE(workspace.horizontalScrollBarPolicy(), Qt::ScrollBarAlwaysOff);
1720  QCOMPARE(workspace.verticalScrollBarPolicy(), Qt::ScrollBarAlwaysOff);
1721 
1722  workspace.tileSubWindows();
1723  // The sub-windows are now tiled like this:
1724  // | win 1 || win 2 || win 3 |
1725  // +-------++-------++-------+
1726  // +-------++-------++-------+
1727  // | win 4 || win 5 || win 6 |
1728  // +-------++-------++-------+
1729  // +-------++-------++-------+
1730  // | win 7 || win 8 || win 9 |
1731  workspace.setActiveSubWindow(0);
1732  int frameWidth = 0;
1734  frameWidth = workspace.style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
1735  const int spacing = 2 * frameWidth + 2;
1736  const QSize expectedViewportSize(3 * minSize.width() + spacing, 3 * minSize.height() + spacing);
1737  QTRY_COMPARE(workspace.viewport()->rect().size(), expectedViewportSize);
1738 
1739  // Enable scroll bar for test below (default property for QMdiArea is Qt::ScrollBarAlwaysOff)
1740  workspace.setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
1741  workspace.setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
1742  QCOMPARE(workspace.horizontalScrollBarPolicy(), Qt::ScrollBarAsNeeded);
1743  QCOMPARE(workspace.verticalScrollBarPolicy(), Qt::ScrollBarAsNeeded);
1744 
1745  // Not enough space for all sub-windows to be visible -> provide scroll bars.
1746  workspace.resize(160, 150);
1747  qApp->processEvents();
1748  QTRY_COMPARE(workspace.size(), QSize(160, 150));
1749 
1750  // Horizontal scroll bar.
1751  QScrollBar *hBar = workspace.horizontalScrollBar();
1752  QCOMPARE(workspace.horizontalScrollBarPolicy(), Qt::ScrollBarAsNeeded);
1753  QTRY_VERIFY(hBar->isVisible());
1754  QCOMPARE(hBar->value(), 0);
1755  QCOMPARE(hBar->minimum(), 0);
1756 
1757  // Vertical scroll bar.
1758  QScrollBar *vBar = workspace.verticalScrollBar();
1759  QCOMPARE(workspace.verticalScrollBarPolicy(), Qt::ScrollBarAsNeeded);
1760  QVERIFY(vBar->isVisible());
1761  QCOMPARE(vBar->value(), 0);
1762  QCOMPARE(vBar->minimum(), 0);
1763 
1764  // Tile windows with scroll bars enabled.
1765  workspace.tileSubWindows();
1767  qApp->processEvents();
1768 
1769  // Workspace should not have changed size after tile.
1770  QTRY_VERIFY(workspace.size() == QSize(160, 150));
1771  // Scroll bars should be visible.
1772  QTRY_VERIFY(vBar->isVisible());
1773  QTRY_VERIFY(hBar->isVisible());
1774 }
1775 
1776 void tst_QMdiArea::cascadeAndTileSubWindows()
1777 {
1779  workspace.resize(400, 400);
1780  workspace.show();
1782 
1783  const int windowCount = 10;
1785  for (int i = 0; i < windowCount; ++i) {
1786  QMdiSubWindow *window = workspace.addSubWindow(new MyChild);
1787  if (i % 3 == 0) {
1788  window->showMinimized();
1789  QVERIFY(window->isMinimized());
1790  } else {
1791  window->showMaximized();
1792  QVERIFY(window->isMaximized());
1793  }
1795  }
1796 
1797  // cascadeSubWindows
1798  qApp->processEvents();
1799  workspace.cascadeSubWindows();
1800  qApp->processEvents();
1801 
1802  // Check dy between two cascaded windows
1803  const int dy = cascadedDeltaY(&workspace);
1804 #ifdef Q_OS_MAC
1805  QEXPECT_FAIL("", "QTBUG-25298", Abort);
1806 #endif
1807  QCOMPARE(windows.at(2)->geometry().top() - windows.at(1)->geometry().top(), dy);
1808 
1809  for (int i = 0; i < windows.count(); ++i) {
1811  if (i % 3 == 0) {
1812  QVERIFY(window->isMinimized());
1813  } else {
1814  QVERIFY(!window->isMaximized());
1815  QCOMPARE(window->size(), window->sizeHint());
1816  window->showMaximized();
1817  QVERIFY(window->isMaximized());
1818  }
1819  }
1820 }
1821 
1822 void tst_QMdiArea::resizeMaximizedChildWindows_data()
1823 {
1824  QTest::addColumn<int>("startSize");
1825  QTest::addColumn<int>("increment");
1826  QTest::addColumn<int>("windowCount");
1827 
1828  QTest::newRow("multiple children") << 400 << 20 << 10;
1829 }
1830 
1831 void tst_QMdiArea::resizeMaximizedChildWindows()
1832 {
1833  QFETCH(int, startSize);
1834  QFETCH(int, increment);
1835  QFETCH(int, windowCount);
1836 
1837  QWidget topLevel;
1838  QMdiArea workspace(&topLevel);
1839  topLevel.show();
1841  workspace.resize(startSize, startSize);
1843  QSize workspaceSize = workspace.size();
1844  QVERIFY(workspaceSize.isValid());
1845  QCOMPARE(workspaceSize, QSize(startSize, startSize));
1846 
1848  for (int i = 0; i < windowCount; ++i) {
1849  QMdiSubWindow *window = workspace.addSubWindow(new QWidget);
1851  qApp->processEvents();
1852  window->showMaximized();
1853  QTest::qWait(100);
1854  QVERIFY(window->isMaximized());
1855  QSize windowSize = window->size();
1856  QVERIFY(windowSize.isValid());
1857  QCOMPARE(window->rect(), workspace.contentsRect());
1858 
1859  workspace.resize(workspaceSize + QSize(increment, increment));
1860  QTest::qWait(100);
1861  qApp->processEvents();
1862  QTRY_COMPARE(workspace.size(), workspaceSize + QSize(increment, increment));
1864  workspaceSize = workspace.size();
1865  }
1866 
1867  int newSize = startSize + increment * windowCount;
1868  QCOMPARE(workspaceSize, QSize(newSize, newSize));
1869  foreach (QWidget *window, windows)
1870  QCOMPARE(window->rect(), workspace.contentsRect());
1871 }
1872 
1873 // QWidget::setParent clears focusWidget so make sure
1874 // we restore it after QMdiArea::addSubWindow.
1875 void tst_QMdiArea::focusWidgetAfterAddSubWindow()
1876 {
1877  QWidget *view = new QWidget;
1878  view->setLayout(new QVBoxLayout);
1879 
1880  QLineEdit *lineEdit1 = new QLineEdit;
1881  QLineEdit *lineEdit2 = new QLineEdit;
1882  view->layout()->addWidget(lineEdit1);
1883  view->layout()->addWidget(lineEdit2);
1884 
1885  lineEdit2->setFocus();
1886  QCOMPARE(view->focusWidget(), static_cast<QWidget *>(lineEdit2));
1887 
1888  QMdiArea mdiArea;
1889  mdiArea.addSubWindow(view);
1890  QCOMPARE(view->focusWidget(), static_cast<QWidget *>(lineEdit2));
1891 
1892  mdiArea.show();
1893  view->show();
1894  qApp->setActiveWindow(&mdiArea);
1895  QCOMPARE(qApp->focusWidget(), static_cast<QWidget *>(lineEdit2));
1896 }
1897 
1898 void tst_QMdiArea::dontMaximizeSubWindowOnActivation()
1899 {
1900  QMdiArea mdiArea;
1901  mdiArea.show();
1903  qApp->setActiveWindow(&mdiArea);
1904 
1905  // Add one maximized window.
1906  mdiArea.addSubWindow(new QWidget)->showMaximized();
1907  QVERIFY(mdiArea.activeSubWindow());
1908  QVERIFY(mdiArea.activeSubWindow()->isMaximized());
1909 
1910  // Add few more windows and verify that they are maximized.
1911  for (int i = 0; i < 5; ++i) {
1912  QMdiSubWindow *window = mdiArea.addSubWindow(new QWidget);
1913  window->show();
1914  QVERIFY(window->isMaximized());
1915  qApp->processEvents();
1916  }
1917 
1918  // Verify that activated windows still are maximized on activation.
1919  QList<QMdiSubWindow *> subWindows = mdiArea.subWindowList();
1920  for (int i = 0; i < subWindows.count(); ++i) {
1921  mdiArea.activateNextSubWindow();
1922  QMdiSubWindow *window = subWindows.at(i);
1923  QCOMPARE(mdiArea.activeSubWindow(), window);
1924  QVERIFY(window->isMaximized());
1925  qApp->processEvents();
1926  }
1927 
1928  // Restore active window and verify that other windows aren't
1929  // maximized on activation.
1930  mdiArea.activeSubWindow()->showNormal();
1931  for (int i = 0; i < subWindows.count(); ++i) {
1932  mdiArea.activateNextSubWindow();
1933  QMdiSubWindow *window = subWindows.at(i);
1934  QCOMPARE(mdiArea.activeSubWindow(), window);
1935  QVERIFY(!window->isMaximized());
1936  qApp->processEvents();
1937  }
1938 
1939  // Enable 'DontMaximizedSubWindowOnActivation' and maximize the active window.
1941  mdiArea.activeSubWindow()->showMaximized();
1942  int indexOfMaximized = subWindows.indexOf(mdiArea.activeSubWindow());
1943 
1944  // Verify that windows are not maximized on activation.
1945  for (int i = 0; i < subWindows.count(); ++i) {
1946  mdiArea.activateNextSubWindow();
1947  QMdiSubWindow *window = subWindows.at(i);
1948  QCOMPARE(mdiArea.activeSubWindow(), window);
1949  if (indexOfMaximized != i)
1950  QVERIFY(!window->isMaximized());
1951  qApp->processEvents();
1952  }
1953  QVERIFY(mdiArea.activeSubWindow()->isMaximized());
1954 
1955  // Minimize all windows.
1956  foreach (QMdiSubWindow *window, subWindows) {
1957  window->showMinimized();
1958  QVERIFY(window->isMinimized());
1959  qApp->processEvents();
1960  }
1961 
1962  // Disable 'DontMaximizedSubWindowOnActivation' and maximize the active window.
1964  mdiArea.activeSubWindow()->showMaximized();
1965 
1966  // Verify that minimized windows are maximized on activation.
1967  for (int i = 0; i < subWindows.count(); ++i) {
1968  mdiArea.activateNextSubWindow();
1969  QMdiSubWindow *window = subWindows.at(i);
1970  QCOMPARE(mdiArea.activeSubWindow(), window);
1971  QVERIFY(window->isMaximized());
1972  qApp->processEvents();
1973  }
1974 
1975  // Verify that activated windows are maximized after closing
1976  // the active window
1977  for (int i = 0; i < subWindows.count(); ++i) {
1978  QVERIFY(mdiArea.activeSubWindow());
1979  QVERIFY(mdiArea.activeSubWindow()->isMaximized());
1980  mdiArea.activeSubWindow()->close();
1981  qApp->processEvents();
1982  }
1983 
1984  QVERIFY(!mdiArea.activeSubWindow());
1985  QCOMPARE(mdiArea.subWindowList().size(), 0);
1986 
1987  // Verify that new windows are not maximized.
1988  mdiArea.addSubWindow(new QWidget)->show();
1989  QVERIFY(mdiArea.activeSubWindow());
1990  QVERIFY(!mdiArea.activeSubWindow()->isMaximized());
1991 }
1992 
1993 void tst_QMdiArea::delayedPlacement()
1994 {
1995  QMdiArea mdiArea;
1996 
1997  QMdiSubWindow *window1 = mdiArea.addSubWindow(new QWidget);
1998  QCOMPARE(window1->geometry().topLeft(), QPoint(0, 0));
1999 
2000  QMdiSubWindow *window2 = mdiArea.addSubWindow(new QWidget);
2001  QCOMPARE(window2->geometry().topLeft(), QPoint(0, 0));
2002 
2003  QMdiSubWindow *window3 = mdiArea.addSubWindow(new QWidget);
2004  QCOMPARE(window3->geometry().topLeft(), QPoint(0, 0));
2005 
2006  mdiArea.resize(window3->minimumSizeHint().width() * 3, 400);
2007  mdiArea.show();
2009 
2010  QCOMPARE(window1->geometry().topLeft(), QPoint(0, 0));
2011  QCOMPARE(window2->geometry().topLeft(), window1->geometry().topRight() + QPoint(1, 0));
2012  QCOMPARE(window3->geometry().topLeft(), window2->geometry().topRight() + QPoint(1, 0));
2013 }
2014 
2015 void tst_QMdiArea::iconGeometryInMenuBar()
2016 {
2017 #if !defined (Q_OS_DARWIN)
2019  QMenuBar *menuBar = mainWindow.menuBar();
2020  menuBar->setNativeMenuBar(false);
2021  QMdiArea *mdiArea = new QMdiArea;
2022  QMdiSubWindow *subWindow = mdiArea->addSubWindow(new QWidget);
2023  mainWindow.setCentralWidget(mdiArea);
2024  mainWindow.show();
2026 
2027  subWindow->showMaximized();
2028  QVERIFY(subWindow->isMaximized());
2029 
2030  QWidget *leftCornerWidget = menuBar->cornerWidget(Qt::TopLeftCorner);
2031  QVERIFY(leftCornerWidget);
2032  int topMargin = (menuBar->height() - leftCornerWidget->height()) / 2;
2033  int leftMargin = qApp->style()->pixelMetric(QStyle::PM_MenuBarHMargin)
2034  + qApp->style()->pixelMetric(QStyle::PM_MenuBarPanelWidth);
2035  QPoint pos(leftMargin, topMargin);
2036  QRect geometry = QStyle::visualRect(qApp->layoutDirection(), menuBar->rect(),
2037  QRect(pos, leftCornerWidget->size()));
2038  QCOMPARE(leftCornerWidget->geometry(), geometry);
2039 #endif
2040 }
2041 
2042 class EventSpy : public QObject
2043 {
2044 public:
2046  : eventToSpy(event), _count(0)
2047  {
2048  if (object)
2049  object->installEventFilter(this);
2050  }
2051 
2052  int count() const { return _count; }
2053  void clear() { _count = 0; }
2054 
2055 protected:
2056  bool eventFilter(QObject *object, QEvent *event) override
2057  {
2058  if (event->type() == eventToSpy)
2059  ++_count;
2060  return QObject::eventFilter(object, event);
2061  }
2062 
2063 private:
2064  QEvent::Type eventToSpy;
2065  int _count;
2066 };
2067 
2068 void tst_QMdiArea::resizeTimer()
2069 {
2071  QSKIP("Wayland: This fails. Figure out why.");
2072 
2073  QMdiArea mdiArea;
2074  QMdiSubWindow *subWindow = mdiArea.addSubWindow(new QWidget);
2075  mdiArea.show();
2077 
2078  int time = 250;
2079 
2080  EventSpy timerEventSpy(subWindow, QEvent::Timer);
2081  QCOMPARE(timerEventSpy.count(), 0);
2082 
2083  mdiArea.tileSubWindows();
2084  QTest::qWait(time); // Wait for timer events to occur.
2085  QCOMPARE(timerEventSpy.count(), 1);
2086  timerEventSpy.clear();
2087 
2088  mdiArea.resize(mdiArea.size() + QSize(2, 2));
2089  QTest::qWait(time); // Wait for timer events to occur.
2090  QCOMPARE(timerEventSpy.count(), 1);
2091  timerEventSpy.clear();
2092 
2093  // Check that timers are killed.
2094  QTest::qWait(time); // Wait for timer events to occur.
2095  QCOMPARE(timerEventSpy.count(), 0);
2096 }
2097 
2098 void tst_QMdiArea::updateScrollBars()
2099 {
2100  QMdiArea mdiArea;
2101  mdiArea.setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
2102  mdiArea.setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
2103 
2104  QMdiSubWindow *subWindow1 = mdiArea.addSubWindow(new QWidget);
2105  QMdiSubWindow *subWindow2 = mdiArea.addSubWindow(new QWidget);
2106 
2107  mdiArea.show();
2109  qApp->processEvents();
2110 
2111  QScrollBar *hbar = mdiArea.horizontalScrollBar();
2112  QVERIFY(hbar);
2114 
2115  QScrollBar *vbar = mdiArea.verticalScrollBar();
2116  QVERIFY(vbar);
2118 
2119  // Move sub-window 2 away.
2120  subWindow2->move(10000, 10000);
2121  qApp->processEvents();
2124 
2125  for (int i = 0; i < 2; ++i) {
2126  // Maximize sub-window 1 and make sure we don't have any scroll bars.
2127  subWindow1->showMaximized();
2128  qApp->processEvents();
2129  QVERIFY(subWindow1->isMaximized());
2132 
2133  // We still shouldn't get any scroll bars.
2134  mdiArea.resize(mdiArea.size() - QSize(20, 20));
2136  qApp->processEvents();
2137  QVERIFY(subWindow1->isMaximized());
2140 
2141  // Restore sub-window 1 and make sure we have scroll bars again.
2142  subWindow1->showNormal();
2143  qApp->processEvents();
2144  QVERIFY(!subWindow1->isMaximized());
2147  if (i == 0) {
2148  // Now, do the same when the viewport is scrolled.
2149  hbar->setValue(1000);
2150  vbar->setValue(1000);
2151  }
2152  }
2153 }
2154 
2155 void tst_QMdiArea::setActivationOrder_data()
2156 {
2157  QTest::addColumn<QMdiArea::WindowOrder>("activationOrder");
2158  QTest::addColumn<int>("subWindowCount");
2159  QTest::addColumn<int>("staysOnTopIndex");
2160  QTest::addColumn<int>("firstActiveIndex");
2161  QTest::addColumn<QList<int> >("expectedActivationIndices");
2162  // The order of expectedCascadeIndices:
2163  // window 1 -> (index 0)
2164  // window 2 -> (index 1)
2165  // window 3 -> (index 2)
2166  // ....
2167  QTest::addColumn<QList<int> >("expectedCascadeIndices");
2168 
2169  // The order of expectedTileIndices (the same as reading a book LTR).
2170  // +--------------------+--------------------+--------------------+
2171  // | window 1 (index 0) | window 2 (index 1) | window 3 (index 2) |
2172  // | +--------------------+--------------------+
2173  // | (index 3) | window 4 (index 4) | window 5 (index 5) |
2174  // +--------------------------------------------------------------+
2175  QTest::addColumn<QList<int> >("expectedTileIndices");
2176 
2177  QList<int> list;
2178  QList<int> list2;
2179  QList<int> list3;
2180 
2181  list << 2 << 1 << 0 << 1 << 2 << 3 << 4;
2182  list2 << 0 << 1 << 2 << 3 << 4;
2183  list3 << 4 << 3 << 2 << 4 << 1 << 0; // Most recently created window is in top-left position
2184  QTest::newRow("CreationOrder") << QMdiArea::CreationOrder << 5 << 3 << 1 << list << list2 << list3;
2185 
2186  list = QList<int>();
2187  list << 3 << 1 << 4 << 3 << 1 << 2 << 0;
2188  list2 = QList<int>();
2189  list2 << 0 << 2 << 4 << 1 << 3;
2190  list3 = QList<int>();
2191  list3 << 3 << 1 << 4 << 3 << 2 << 0; // Window with "stays-on-top" flag set will be in the top-left position
2192  QTest::newRow("StackingOrder") << QMdiArea::StackingOrder << 5 << 3 << 1 << list << list2 << list3;
2193 
2194  list = QList<int>();
2195  list << 0 << 1 << 0 << 1 << 4 << 3 << 2;
2196  list2 = QList<int>();
2197  list2 << 0 << 2 << 3 << 4 << 1;
2198  list3 = QList<int>();
2199  list3 << 1 << 4 << 3 << 1 << 2 << 0;
2200  QTest::newRow("ActivationHistoryOrder") << QMdiArea::ActivationHistoryOrder << 5 << 3 << 1 << list << list2 << list3;
2201 }
2202 
2203 void tst_QMdiArea::setActivationOrder()
2204 {
2205  QFETCH(QMdiArea::WindowOrder, activationOrder);
2206  QFETCH(int, subWindowCount);
2207  QFETCH(int, staysOnTopIndex);
2208  QFETCH(int, firstActiveIndex);
2209  QFETCH(QList<int>, expectedActivationIndices);
2210  QFETCH(QList<int>, expectedCascadeIndices);
2211  QFETCH(QList<int>, expectedTileIndices);
2212 
2213  // Default order.
2214  QMdiArea mdiArea;
2216 
2217  // New order.
2218  mdiArea.setActivationOrder(activationOrder);
2219  QCOMPARE(mdiArea.activationOrder(), activationOrder);
2220 
2221  QList<QMdiSubWindow *> subWindows;
2222  for (int i = 0; i < subWindowCount; ++i)
2223  subWindows << mdiArea.addSubWindow(new QPushButton(tr("%1").arg(i)));
2224  QCOMPARE(mdiArea.subWindowList(activationOrder), subWindows);
2225 
2226  mdiArea.show();
2228 
2229  for (int i = 0; i < subWindows.count(); ++i) {
2230  mdiArea.activateNextSubWindow();
2231  QCOMPARE(mdiArea.activeSubWindow(), subWindows.at(i));
2232  qApp->processEvents();
2233  }
2234 
2235  QMdiSubWindow *staysOnTop = subWindows.at(staysOnTopIndex);
2236  staysOnTop->setWindowFlags(staysOnTop->windowFlags() | Qt::WindowStaysOnTopHint);
2237  staysOnTop->raise();
2238 
2239  mdiArea.setActiveSubWindow(subWindows.at(firstActiveIndex));
2240  QCOMPARE(mdiArea.activeSubWindow(), subWindows.at(firstActiveIndex));
2241 
2242  // Verify the actual arrangement/geometry.
2243  mdiArea.tileSubWindows();
2244  QTest::qWait(100);
2245  QVERIFY(verifyArrangement(&mdiArea, Tiled, expectedTileIndices));
2246 
2247  mdiArea.cascadeSubWindows();
2248 #ifdef Q_OS_MAC
2249  QEXPECT_FAIL("", "QTBUG-25298", Abort);
2250 #endif
2251  QVERIFY(verifyArrangement(&mdiArea, Cascaded, expectedCascadeIndices));
2252  QTest::qWait(100);
2253 
2254  mdiArea.activateNextSubWindow();
2255  QCOMPARE(mdiArea.activeSubWindow(), subWindows.at(expectedActivationIndices.takeFirst()));
2256 
2257  mdiArea.activatePreviousSubWindow();
2258  QCOMPARE(mdiArea.activeSubWindow(), subWindows.at(expectedActivationIndices.takeFirst()));
2259 
2260  mdiArea.activatePreviousSubWindow();
2261  QCOMPARE(mdiArea.activeSubWindow(), subWindows.at(expectedActivationIndices.takeFirst()));
2262 
2263  for (int i = 0; i < subWindowCount; ++i) {
2264  mdiArea.closeActiveSubWindow();
2265  qApp->processEvents();
2266  if (i == subWindowCount - 1) { // Last window closed.
2267  QVERIFY(!mdiArea.activeSubWindow());
2268  break;
2269  }
2270  QVERIFY(mdiArea.activeSubWindow());
2271  QCOMPARE(mdiArea.activeSubWindow(), subWindows.at(expectedActivationIndices.takeFirst()));
2272  }
2273 
2274  QVERIFY(mdiArea.subWindowList(activationOrder).isEmpty());
2275  QVERIFY(expectedActivationIndices.isEmpty());
2276 }
2277 
2278 void tst_QMdiArea::tabBetweenSubWindows()
2279 {
2280  QMdiArea mdiArea;
2281  QList<QMdiSubWindow *> subWindows;
2282  for (int i = 0; i < 5; ++i)
2283  subWindows << mdiArea.addSubWindow(new QLineEdit);
2284 
2285  mdiArea.show();
2287 
2288  qApp->setActiveWindow(&mdiArea);
2289  QWidget *focusWidget = subWindows.back()->widget();
2290  QCOMPARE(qApp->focusWidget(), focusWidget);
2291 
2292  QSignalSpy spy(&mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow*)));
2293  QCOMPARE(spy.count(), 0);
2294 
2295  // Walk through the entire list of sub windows.
2296 #ifdef Q_OS_MAC
2297  QEXPECT_FAIL("", "QTBUG-25298", Abort);
2298 #endif
2299  QVERIFY(tabBetweenSubWindowsIn(&mdiArea));
2300  QCOMPARE(mdiArea.activeSubWindow(), subWindows.back());
2301  QCOMPARE(spy.count(), 0);
2302 
2303  mdiArea.setActiveSubWindow(subWindows.front());
2304  QCOMPARE(mdiArea.activeSubWindow(), subWindows.front());
2305  spy.clear();
2306 
2307  // Walk through the entire list of sub windows in the opposite direction (Ctrl-Shift-Tab).
2308  QVERIFY(tabBetweenSubWindowsIn(&mdiArea, -1, true));
2309  QCOMPARE(mdiArea.activeSubWindow(), subWindows.front());
2310  QCOMPARE(spy.count(), 0);
2311 
2312  // Ctrl-Tab-Tab-Tab
2313  QVERIFY(tabBetweenSubWindowsIn(&mdiArea, 3));
2314  QCOMPARE(mdiArea.activeSubWindow(), subWindows.at(3));
2315  QCOMPARE(spy.count(), 1);
2316 
2317  mdiArea.setActiveSubWindow(subWindows.at(1));
2318  QCOMPARE(mdiArea.activeSubWindow(), subWindows.at(1));
2319  spy.clear();
2320 
2321  // Quick switch (Ctrl-Tab once) -> switch back to the previously active sub-window.
2322  QVERIFY(tabBetweenSubWindowsIn(&mdiArea, 1));
2323  QCOMPARE(mdiArea.activeSubWindow(), subWindows.at(3));
2324  QCOMPARE(spy.count(), 1);
2325 }
2326 
2327 void tst_QMdiArea::setViewMode()
2328 {
2329  QMdiArea mdiArea;
2330 
2331  QPixmap iconPixmap(16, 16);
2332  iconPixmap.fill(Qt::red);
2333  for (int i = 0; i < 5; ++i) {
2334  QMdiSubWindow *subWindow = mdiArea.addSubWindow(new QWidget);
2335  subWindow->setWindowTitle(QLatin1String("Title ") + QString::number(i));
2336  subWindow->setWindowIcon(iconPixmap);
2337  }
2338 
2339  mdiArea.show();
2341 
2342  QMdiSubWindow *activeSubWindow = mdiArea.activeSubWindow();
2343  QList<QMdiSubWindow *> subWindows = mdiArea.subWindowList();
2344 
2345  // Default.
2346  QVERIFY(!activeSubWindow->isMaximized());
2347  QTabBar *tabBar = mdiArea.findChild<QTabBar *>();
2348  QVERIFY(!tabBar);
2350 
2351  // Tabbed view.
2354  tabBar = mdiArea.findChild<QTabBar *>();
2355  QVERIFY(tabBar);
2356  QVERIFY(tabBar->isVisible());
2357 
2358  QCOMPARE(tabBar->count(), subWindows.count());
2359  QVERIFY(activeSubWindow->isMaximized());
2360  QCOMPARE(tabBar->currentIndex(), subWindows.indexOf(activeSubWindow));
2361 
2362  // Check that tabIcon and tabText are set properly.
2363  for (int i = 0; i < subWindows.size(); ++i) {
2364  QMdiSubWindow *subWindow = subWindows.at(i);
2365  QCOMPARE(tabBar->tabText(i), subWindow->windowTitle());
2366  QCOMPARE(tabBar->tabIcon(i), subWindow->windowIcon());
2367  }
2368 
2369  // Check that tabText and tabIcon are updated.
2370  activeSubWindow->setWindowTitle(QLatin1String("Dude, I want another window title"));
2371  QCOMPARE(tabBar->tabText(tabBar->currentIndex()), activeSubWindow->windowTitle());
2372  iconPixmap.fill(Qt::green);
2373  activeSubWindow->setWindowIcon(iconPixmap);
2374  QCOMPARE(tabBar->tabIcon(tabBar->currentIndex()), activeSubWindow->windowIcon());
2375 
2376  // If there's an empty window title, tabText should return "(Untitled)" (as in firefox).
2377  activeSubWindow->setWindowTitle(QString());
2378  QCOMPARE(tabBar->tabText(tabBar->currentIndex()), QLatin1String("(Untitled)"));
2379 
2380  // If there's no window icon, tabIcon should return ... an empty icon :)
2381  activeSubWindow->setWindowIcon(QIcon());
2382  QCOMPARE(tabBar->tabIcon(tabBar->currentIndex()), QIcon());
2383 
2384  // Check that the current tab changes when activating another sub-window.
2385  for (int i = 0; i < subWindows.size(); ++i) {
2386  mdiArea.activateNextSubWindow();
2387  activeSubWindow = mdiArea.activeSubWindow();
2388  QCOMPARE(tabBar->currentIndex(), subWindows.indexOf(activeSubWindow));
2389  }
2390 
2391  activeSubWindow = mdiArea.activeSubWindow();
2392  const int tabIndex = tabBar->currentIndex();
2393 
2394  // The current tab should not change when the sub-window is hidden.
2395  activeSubWindow->hide();
2396  QCOMPARE(tabBar->currentIndex(), tabIndex);
2397  activeSubWindow->show();
2398  QCOMPARE(tabBar->currentIndex(), tabIndex);
2399 
2400  // Disable the tab when the sub-window is hidden and another sub-window is activated.
2401  activeSubWindow->hide();
2402  mdiArea.activateNextSubWindow();
2403  QVERIFY(tabBar->currentIndex() != tabIndex);
2404  QVERIFY(!tabBar->isTabEnabled(tabIndex));
2405 
2406  // Enable it again.
2407  activeSubWindow->show();
2408  QCOMPARE(tabBar->currentIndex(), tabIndex);
2409  QVERIFY(tabBar->isTabEnabled(tabIndex));
2410 
2411  // Remove sub-windows and make sure the tab is removed.
2412  foreach (QMdiSubWindow *subWindow, subWindows) {
2413  if (subWindow != activeSubWindow) {
2414  mdiArea.removeSubWindow(subWindow);
2415  delete subWindow;
2416  }
2417  }
2418  subWindows.clear();
2419  QCOMPARE(tabBar->count(), 1);
2420 
2421  // Go back to default (QMdiArea::SubWindowView).
2423  QVERIFY(!activeSubWindow->isMaximized());
2424  tabBar = mdiArea.findChild<QTabBar *>();
2425  QVERIFY(!tabBar);
2427 }
2428 
2429 void tst_QMdiArea::setTabsClosable()
2430 {
2431  QMdiArea mdiArea;
2432  mdiArea.addSubWindow(new QWidget);
2433 
2434  // test default
2435  QCOMPARE(mdiArea.tabsClosable(), false);
2436 
2437  // change value before tab bar exists
2438  QTabBar *tabBar = mdiArea.findChild<QTabBar *>();
2439  QVERIFY(!tabBar);
2440  mdiArea.setTabsClosable(true);
2441  QCOMPARE(mdiArea.tabsClosable(), true);
2442 
2443  // force tab bar creation
2445  tabBar = mdiArea.findChild<QTabBar *>();
2446  QVERIFY(tabBar);
2447 
2448  // value must've been propagated
2449  QCOMPARE(tabBar->tabsClosable(), true);
2450 
2451  // change value when tab bar exists
2452  mdiArea.setTabsClosable(false);
2453  QCOMPARE(mdiArea.tabsClosable(), false);
2454  QCOMPARE(tabBar->tabsClosable(), false);
2455 }
2456 
2457 void tst_QMdiArea::setTabsMovable()
2458 {
2459  QMdiArea mdiArea;
2460  QMdiSubWindow *subWindow1 = mdiArea.addSubWindow(new QWidget);
2461  QMdiSubWindow *subWindow2 = mdiArea.addSubWindow(new QWidget);
2462  QMdiSubWindow *subWindow3 = mdiArea.addSubWindow(new QWidget);
2463 
2464  // test default
2465  QCOMPARE(mdiArea.tabsMovable(), false);
2466 
2467  // change value before tab bar exists
2468  QTabBar *tabBar = mdiArea.findChild<QTabBar *>();
2469  QVERIFY(!tabBar);
2470  mdiArea.setTabsMovable(true);
2471  QCOMPARE(mdiArea.tabsMovable(), true);
2472 
2473  // force tab bar creation
2475  tabBar = mdiArea.findChild<QTabBar *>();
2476  QVERIFY(tabBar);
2477 
2478  // value must've been propagated
2479  QCOMPARE(tabBar->isMovable(), true);
2480 
2481  // test tab moving
2482  QList<QMdiSubWindow *> subWindows;
2483  subWindows << subWindow1 << subWindow2 << subWindow3;
2484  QCOMPARE(mdiArea.subWindowList(QMdiArea::CreationOrder), subWindows);
2485  tabBar->moveTab(1, 2); // 1,3,2
2486  subWindows.clear();
2487  subWindows << subWindow1 << subWindow3 << subWindow2;
2488  QCOMPARE(mdiArea.subWindowList(QMdiArea::CreationOrder), subWindows);
2489  tabBar->moveTab(0, 2); // 3,2,1
2490  subWindows.clear();
2491  subWindows << subWindow3 << subWindow2 << subWindow1;
2492  QCOMPARE(mdiArea.subWindowList(QMdiArea::CreationOrder), subWindows);
2493 
2494  // change value when tab bar exists
2495  mdiArea.setTabsMovable(false);
2496  QCOMPARE(mdiArea.tabsMovable(), false);
2497  QCOMPARE(tabBar->isMovable(), false);
2498 }
2499 
2500 void tst_QMdiArea::setTabShape()
2501 {
2502  QMdiArea mdiArea;
2503  mdiArea.addSubWindow(new QWidget);
2504  mdiArea.show();
2506 
2507  // Default.
2508  QCOMPARE(mdiArea.tabShape(), QTabWidget::Rounded);
2509 
2510  // Triangular.
2511  mdiArea.setTabShape(QTabWidget::Triangular);
2512  QCOMPARE(mdiArea.tabShape(), QTabWidget::Triangular);
2513 
2515 
2516  QTabBar *tabBar = mdiArea.findChild<QTabBar *>();
2517  QVERIFY(tabBar);
2519 
2520  // Back to default (Rounded).
2521  mdiArea.setTabShape(QTabWidget::Rounded);
2522  QCOMPARE(mdiArea.tabShape(), QTabWidget::Rounded);
2523  QCOMPARE(tabBar->shape(), QTabBar::RoundedNorth);
2524 }
2525 
2526 void tst_QMdiArea::setTabPosition_data()
2527 {
2528  QTest::addColumn<QTabWidget::TabPosition>("tabPosition");
2529  QTest::addColumn<bool>("hasLeftMargin");
2530  QTest::addColumn<bool>("hasTopMargin");
2531  QTest::addColumn<bool>("hasRightMargin");
2532  QTest::addColumn<bool>("hasBottomMargin");
2533 
2534  QTest::newRow("North") << QTabWidget::North << false << true << false << false;
2535  QTest::newRow("South") << QTabWidget::South << false << false << false << true;
2536  QTest::newRow("East") << QTabWidget::East << false << false << true << false;
2537  QTest::newRow("West") << QTabWidget::West << true << false << false << false;
2538 }
2539 
2540 void tst_QMdiArea::setTabPosition()
2541 {
2542  QFETCH(QTabWidget::TabPosition, tabPosition);
2543  QFETCH(bool, hasLeftMargin);
2544  QFETCH(bool, hasTopMargin);
2545  QFETCH(bool, hasRightMargin);
2546  QFETCH(bool, hasBottomMargin);
2547 
2548  QMdiArea mdiArea;
2549  mdiArea.addSubWindow(new QWidget);
2550  mdiArea.show();
2552 
2553  // Make sure there are no margins.
2554  mdiArea.setContentsMargins(0, 0, 0, 0);
2555 
2556  // Default.
2557  QCOMPARE(mdiArea.tabPosition(), QTabWidget::North);
2559  QTabBar *tabBar = mdiArea.findChild<QTabBar *>();
2560  QVERIFY(tabBar);
2561  QCOMPARE(tabBar->shape(), QTabBar::RoundedNorth);
2562 
2563  // New position.
2564  mdiArea.setTabPosition(tabPosition);
2565  QCOMPARE(mdiArea.tabPosition(), tabPosition);
2566  QCOMPARE(tabBar->shape(), tabBarShapeFrom(QTabWidget::Rounded, tabPosition));
2567 
2568  const Qt::LayoutDirection originalLayoutDirection = qApp->layoutDirection();
2569 
2570  // Check that we have correct geometry in both RightToLeft and LeftToRight.
2571  for (int i = 0; i < 2; ++i) {
2572  // Check viewportMargins.
2573  const QRect viewportGeometry = mdiArea.viewport()->geometry();
2574  const int left = viewportGeometry.left();
2575  const int top = viewportGeometry.y();
2576  const int right = mdiArea.width() - viewportGeometry.width();
2577  const int bottom = mdiArea.height() - viewportGeometry.height();
2578 
2579  const QSize sizeHint = tabBar->sizeHint();
2580 
2581  if (hasLeftMargin)
2582  QCOMPARE(qApp->isLeftToRight() ? left : right, sizeHint.width());
2583  if (hasRightMargin)
2584  QCOMPARE(qApp->isLeftToRight() ? right : left, sizeHint.width());
2585  if (hasTopMargin || hasBottomMargin)
2586  QCOMPARE(hasTopMargin ? top : bottom, sizeHint.height());
2587 
2588  // Check actual tab bar geometry.
2589  const QRegion expectedTabBarGeometry = QRegion(mdiArea.rect()).subtracted(viewportGeometry);
2590  QVERIFY(!expectedTabBarGeometry.isEmpty());
2591  QCOMPARE(QRegion(tabBar->geometry()), expectedTabBarGeometry);
2592 
2593  if (i == 0)
2594  qApp->setLayoutDirection(originalLayoutDirection == Qt::LeftToRight ? Qt::RightToLeft : Qt::LeftToRight);
2595  qApp->processEvents();
2596  }
2597 
2598  qApp->setLayoutDirection(originalLayoutDirection);
2599 }
2600 
2601 void tst_QMdiArea::nativeSubWindows()
2602 {
2603  const QString platformName = QGuiApplication::platformName();
2604  if (platformName != QLatin1String("xcb") && platformName != QLatin1String("windows"))
2605  QSKIP(qPrintable(QString::fromLatin1("nativeSubWindows() does not work on this platform (%1).").arg(platformName)));
2606 #if defined(Q_OS_WIN) && !defined(QT_NO_OPENGL)
2608  QSKIP("nativeSubWindows() does not work with ANGLE on Windows, QTBUG-28545.");
2609 #endif
2610  { // Add native widgets after show.
2611  QMdiArea mdiArea;
2612  mdiArea.addSubWindow(new QWidget);
2613  mdiArea.addSubWindow(new QWidget);
2614  mdiArea.show();
2616 
2617  // No native widgets.
2618  QVERIFY(!mdiArea.viewport()->internalWinId());
2619  foreach (QMdiSubWindow *subWindow, mdiArea.subWindowList())
2620  QVERIFY(!subWindow->internalWinId());
2621 
2622  QWidget *nativeWidget = new QWidget;
2623  QVERIFY(nativeWidget->winId()); // enforce native window.
2624  QMdiSubWindow *subWin = mdiArea.addSubWindow(nativeWidget);
2625  QVERIFY(subWin->internalWinId());
2626 
2627  // The viewport and all the sub-windows must be native.
2628  QVERIFY(mdiArea.viewport()->internalWinId());
2629  foreach (QMdiSubWindow *subWindow, mdiArea.subWindowList())
2630  QVERIFY(subWindow->internalWinId());
2631 
2632  // Add a non-native widget. This should become native.
2633  QMdiSubWindow *subWindow = new QMdiSubWindow;
2634  subWindow->setWidget(new QWidget);
2635  QVERIFY(!subWindow->internalWinId());
2636  mdiArea.addSubWindow(subWindow);
2637  QVERIFY(subWindow->internalWinId());
2638  }
2639 
2640  { // Add native widgets before show.
2641  QMdiArea mdiArea;
2642  mdiArea.addSubWindow(new QWidget);
2643  QWidget *nativeWidget = new QWidget;
2644  (void)nativeWidget->winId();
2645  mdiArea.addSubWindow(nativeWidget);
2646  mdiArea.show();
2648 
2649  // The viewport and all the sub-windows must be native.
2650  QVERIFY(mdiArea.viewport()->internalWinId());
2651  foreach (QMdiSubWindow *subWindow, mdiArea.subWindowList())
2652  QVERIFY(subWindow->internalWinId());
2653  }
2654 
2655  { // Make a sub-window native *after* it's added to the area.
2656  QMdiArea mdiArea;
2657  mdiArea.addSubWindow(new QWidget);
2658  mdiArea.addSubWindow(new QWidget);
2659  mdiArea.show();
2661 
2662  QMdiSubWindow *nativeSubWindow = mdiArea.subWindowList().last();
2663  QVERIFY(!nativeSubWindow->internalWinId());
2664  (void)nativeSubWindow->winId();
2665 
2666  // All the sub-windows should be native at this point
2667  QVERIFY(mdiArea.viewport()->internalWinId());
2668  foreach (QMdiSubWindow *subWindow, mdiArea.subWindowList())
2669  QVERIFY(subWindow->internalWinId());
2670  }
2671 }
2672 
2673 void tst_QMdiArea::task_209615()
2674 {
2675  QTabWidget tabWidget;
2676  QMdiArea *mdiArea1 = new QMdiArea;
2677  QMdiArea *mdiArea2 = new QMdiArea;
2678  QMdiSubWindow *subWindow = mdiArea1->addSubWindow(new QLineEdit);
2679 
2680  tabWidget.addTab(mdiArea1, QLatin1String("1"));
2681  tabWidget.addTab(mdiArea2, QLatin1String("2"));
2682  tabWidget.show();
2683 
2684  mdiArea1->removeSubWindow(subWindow);
2685  mdiArea2->addSubWindow(subWindow);
2686 
2687  // Please do not assert/crash.
2688  tabWidget.setCurrentIndex(1);
2689 }
2690 
2691 void tst_QMdiArea::task_236750()
2692 {
2693  QMdiArea mdiArea;
2694  QMdiSubWindow *subWindow = mdiArea.addSubWindow(new QTextEdit);
2695  mdiArea.show();
2696 
2697  subWindow->setWindowFlags(subWindow->windowFlags() | Qt::FramelessWindowHint);
2698  // Please do not crash (floating point exception).
2699  subWindow->showMinimized();
2700 }
2701 
2702 // QTBUG-92240: When subwindows are maximized, their title is supposed to
2703 // appear on the main window. When DontMaximizeSubWindowOnActivation was set,
2704 // titles of previously created maximized windows interfered, resulting in
2705 // "QTBUG-92240 - [1] - [2]".
2706 void tst_QMdiArea::qtbug92240_title_data()
2707 {
2708  QTest::addColumn<bool>("dontMaximize");
2709  QTest::newRow("default") << false;
2710  QTest::newRow("dontMaximize") << true;
2711 }
2712 
2713 void tst_QMdiArea::qtbug92240_title()
2714 {
2715  QFETCH(bool, dontMaximize);
2716 
2717 #ifdef Q_OS_MACOS
2718  QSKIP("Not supported on macOS");
2719 #endif
2720 
2721  QMainWindow w;
2722  const QString title = QStringLiteral("QTBUG-92240");
2723  w.setWindowTitle(title);
2724  w.menuBar()->addMenu(QStringLiteral("File"));
2725  w.show();
2726 
2727  auto *mdiArea = new QMdiArea;
2728  w.setCentralWidget(mdiArea);
2729  if (dontMaximize)
2731  auto *sw1 = mdiArea->addSubWindow(new QWidget);
2732  sw1->setWindowTitle(QStringLiteral("1"));
2733  sw1->showMaximized();
2734  QTRY_COMPARE(w.windowTitle(), QLatin1String("QTBUG-92240 - [1]"));
2735  auto *sw2 = mdiArea->addSubWindow(new QWidget);
2736  sw2->setWindowTitle(QStringLiteral("2"));
2737  sw2->showMaximized();
2738  QTRY_COMPARE(w.windowTitle(), QLatin1String("QTBUG-92240 - [2]"));
2739 }
2740 
2741 static void setupMdiAreaWithTabbedView(QMdiArea &mdiArea)
2742 {
2744 
2745  auto *mdiWin1 = new QWidget(&mdiArea);
2746  mdiWin1->setWindowTitle(QLatin1String("Sub1"));
2747  mdiArea.addSubWindow(mdiWin1);
2748 
2749  auto *mdiWin2 = new QWidget(&mdiArea);
2750  mdiWin2->setWindowTitle(QLatin1String("Sub2"));
2751  mdiArea.addSubWindow(mdiWin2);
2752 
2753  auto *mdiWin3 = new QWidget(&mdiArea);
2754  mdiWin3->setWindowTitle(QLatin1String("Sub3"));
2755  mdiArea.addSubWindow(mdiWin3);
2756 }
2757 
2758 void tst_QMdiArea::tabbedview_activefirst()
2759 {
2760  QMdiArea mdiArea;
2761  setupMdiAreaWithTabbedView(mdiArea);
2762 
2763  auto sub0 = mdiArea.subWindowList().at(0);
2764  mdiArea.setActiveSubWindow(sub0);
2765  mdiArea.show();
2767  QCOMPARE(mdiArea.activeSubWindow(), sub0);
2768 }
2769 
2770 void tst_QMdiArea::tabbedview_activesecond()
2771 {
2772  QMdiArea mdiArea;
2773  setupMdiAreaWithTabbedView(mdiArea);
2774 
2775  auto sub1 = mdiArea.subWindowList().at(1);
2776  mdiArea.setActiveSubWindow(sub1);
2777  mdiArea.show();
2779  QCOMPARE(mdiArea.activeSubWindow(), sub1);
2780 }
2781 
2782 void tst_QMdiArea::tabbedview_activethird()
2783 {
2784  QMdiArea mdiArea;
2785  setupMdiAreaWithTabbedView(mdiArea);
2786 
2787  auto sub2 = mdiArea.subWindowList().at(2);
2788  mdiArea.setActiveSubWindow(sub2);
2789  mdiArea.show();
2791  QCOMPARE(mdiArea.activeSubWindow(), sub2);
2792 }
2793 
2794 
2796 #include "tst_qmdiarea.moc"
2797 
small capitals from c petite p scientific i
[1]
Definition: afcover.h:80
Arabic default style
Definition: afstyles.h:94
EventSpy(QObject *object, QEvent::Type event)
void clear()
bool eventFilter(QObject *object, QEvent *event) override
int count() const
LargeWidget(QWidget *parent=nullptr)
QSize sizeHint() const override
QSize minimumSizeHint() const override
MyChild(QWidget *parent=nullptr)
QSize sizeHint() const override
int receivers(const char *signal) const
Definition: qobject.cpp:2554
int value
the slider's current value
int minimum
the sliders's minimum value
static QWidgetList topLevelWidgets()
static QFont font()
The QBrush class defines the fill pattern of shapes drawn by QPainter.
Definition: qbrush.h:66
The QDockWidget class provides a widget that can be docked inside a QMainWindow or floated as a top-l...
Definition: qdockwidget.h:56
void setAllowedAreas(Qt::DockWidgetAreas areas)
void setWidget(QWidget *widget)
The QEvent class is the base class of all event classes. Event objects contain event parameters.
Definition: qcoreevent.h:58
@ WindowActivate
Definition: qcoreevent.h:96
@ Timer
Definition: qcoreevent.h:72
@ WindowDeactivate
Definition: qcoreevent.h:97
The QFontMetrics class provides font metrics information.
Definition: qfontmetrics.h:56
@ NoFrame
Definition: qframe.h:75
QScreen * primaryScreen
the primary (or default) screen of the application.
QString platformName
The name of the underlying platform plugin.
The QIcon class provides scalable icons in different modes and states.
Definition: qicon.h:56
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal.
Definition: qstring.h:84
virtual QSize minimumSize() const =0
virtual QSize sizeHint() const =0
The QLineEdit widget is a one-line text editor.
Definition: qlineedit.h:64
Definition: qlist.h:108
qsizetype size() const noexcept
Definition: qlist.h:414
bool isEmpty() const noexcept
Definition: qlist.h:418
reference back()
Definition: qlist.h:701
const_reference at(qsizetype i) const noexcept
Definition: qlist.h:457
void move(qsizetype from, qsizetype to)
Definition: qlist.h:608
reference front()
Definition: qlist.h:699
qsizetype count() const noexcept
Definition: qlist.h:415
void append(parameter_type t)
Definition: qlist.h:469
void clear()
Definition: qlist.h:445
The QMainWindow class provides a main application window.\inmodule QtWidgets.
Definition: qmainwindow.h:61
void setCentralWidget(QWidget *widget)
The QMdiArea widget provides an area in which MDI windows are displayed.
Definition: qmdiarea.h:57
WindowOrder activationOrder
the ordering criteria for subwindow lists
Definition: qmdiarea.h:60
void setActivationOrder(WindowOrder order)
Definition: qmdiarea.cpp:2093
QMdiSubWindow * addSubWindow(QWidget *widget, Qt::WindowFlags flags=Qt::WindowFlags())
Definition: qmdiarea.cpp:1966
void setViewMode(ViewMode mode)
Definition: qmdiarea.cpp:2137
void closeActiveSubWindow()
Definition: qmdiarea.cpp:1857
ViewMode viewMode
the way sub-windows are displayed in the QMdiArea.
Definition: qmdiarea.h:61
void activateNextSubWindow()
Definition: qmdiarea.cpp:1914
WindowOrder
Definition: qmdiarea.h:77
@ StackingOrder
Definition: qmdiarea.h:79
@ CreationOrder
Definition: qmdiarea.h:78
@ ActivationHistoryOrder
Definition: qmdiarea.h:80
QMdiSubWindow * activeSubWindow() const
Definition: qmdiarea.cpp:1819
void cascadeSubWindows()
Definition: qmdiarea.cpp:2483
void setOption(AreaOption option, bool on=true)
Definition: qmdiarea.cpp:2106
void tileSubWindows()
Definition: qmdiarea.cpp:2470
void activatePreviousSubWindow()
Definition: qmdiarea.cpp:1932
QMdiSubWindow * currentSubWindow() const
Definition: qmdiarea.cpp:1787
void removeSubWindow(QWidget *widget)
Definition: qmdiarea.cpp:2011
@ TabbedView
Definition: qmdiarea.h:86
@ SubWindowView
Definition: qmdiarea.h:85
QList< QMdiSubWindow * > subWindowList(WindowOrder order=CreationOrder) const
Definition: qmdiarea.cpp:1875
@ DontMaximizeSubWindowOnActivation
Definition: qmdiarea.h:73
void setActiveSubWindow(QMdiSubWindow *window)
Definition: qmdiarea.cpp:1831
The QMdiSubWindow class provides a subwindow class for QMdiArea.
Definition: qmdisubwindow.h:56
QSize minimumSizeHint() const override
QWidget * widget() const
void setWidget(QWidget *widget)
The QMenuBar class provides a horizontal menu bar.
Definition: qmenubar.h:56
QWidget * cornerWidget(Qt::Corner corner=Qt::TopRightCorner) const
Definition: qmenubar.cpp:1766
void setNativeMenuBar(bool nativeMenuBar)
Definition: qmenubar.cpp:1802
The QMetaMethod class provides meta-data about a member function.
Definition: qmetaobject.h:54
QByteArray signature() const
The QObject class is the base class of all Qt objects.
Definition: qobject.h:125
QObject * parent() const
Definition: qobject.h:409
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
Definition: qobject.cpp:2772
virtual bool eventFilter(QObject *watched, QEvent *event)
Definition: qobject.cpp:1484
friend class QWidget
Definition: qobject.h:445
int receivers(const char *signal) const
Definition: qobject.cpp:2554
static OpenGLModuleType openGLModuleType()
@ Dark
Definition: qpalette.h:86
The QPixmap class is an off-screen image representation that can be used as a paint device.
Definition: qpixmap.h:63
The QPoint class defines a point in the plane using integer precision.
Definition: qpoint.h:52
constexpr int & ry() noexcept
Definition: qpoint.h:185
constexpr int & rx() noexcept
Definition: qpoint.h:180
The QPushButton widget provides a command button.
Definition: qpushbutton.h:56
The QRect class defines a rectangle in the plane using integer precision.
Definition: qrect.h:59
constexpr int height() const noexcept
Definition: qrect.h:266
constexpr QPoint topLeft() const noexcept
Definition: qrect.h:248
constexpr int top() const noexcept
Definition: qrect.h:203
constexpr QPoint topRight() const noexcept
Definition: qrect.h:254
constexpr int left() const noexcept
Definition: qrect.h:200
constexpr int width() const noexcept
Definition: qrect.h:263
constexpr int y() const noexcept
Definition: qrect.h:215
constexpr int right() const noexcept
Definition: qrect.h:206
The QRegion class specifies a clip region for a painter.
Definition: qregion.h:63
bool isEmpty() const
QRegion subtracted(const QRegion &r) const
The QRubberBand class provides a rectangle or line that can indicate a selection or a boundary.
Definition: qrubberband.h:54
The QScopedPointer class stores a pointer to a dynamically allocated object, and deletes it upon dest...
QSize size
the pixel resolution of the screen
Definition: qscreen.h:77
The QScrollBar widget provides a vertical or horizontal scroll bar.
Definition: qscrollbar.h:56
The QSize class defines the size of a two-dimensional object using integer point precision.
Definition: qsize.h:55
constexpr int height() const noexcept
Definition: qsize.h:160
constexpr int width() const noexcept
Definition: qsize.h:157
constexpr bool isValid() const noexcept
Definition: qsize.h:154
The QString class provides a Unicode character string.
Definition: qstring.h:388
static QString fromLatin1(QByteArrayView ba)
Definition: qstring.cpp:5488
static QString number(int, int base=10)
Definition: qstring.cpp:7538
The QStyle class is an abstract base class that encapsulates the look and feel of a GUI.
Definition: qstyle.h:65
@ SH_ScrollView_FrameOnlyAroundContents
Definition: qstyle.h:636
@ SH_ScrollBar_Transient
Definition: qstyle.h:715
virtual int styleHint(StyleHint stylehint, const QStyleOption *opt=nullptr, const QWidget *widget=nullptr, QStyleHintReturn *returnData=nullptr) const =0
static QRect visualRect(Qt::LayoutDirection direction, const QRect &boundingRect, const QRect &logicalRect)
Definition: qstyle.cpp:2179
@ PM_MenuBarHMargin
Definition: qstyle.h:496
@ PM_FocusFrameVMargin
Definition: qstyle.h:532
@ PM_TitleBarHeight
Definition: qstyle.h:484
@ PM_DefaultFrameWidth
Definition: qstyle.h:456
@ PM_MenuBarPanelWidth
Definition: qstyle.h:493
@ PM_MdiSubWindowMinimizedWidth
Definition: qstyle.h:508
void initFrom(const QWidget *w)
the position of the selected tab in relation to this tab
Definition: qstyleoption.h:630
The QTabBar class provides a tab bar, e.g. for use in tabbed dialogs.
Definition: qtabbar.h:55
int count
the number of tabs in the tab bar
Definition: qtabbar.h:60
int currentIndex
the index of the tab bar's visible tab
Definition: qtabbar.h:59
QSize sizeHint() const override
Definition: qtabbar.cpp:1511
QString tabText(int index) const
Definition: qtabbar.cpp:1205
bool isMovable() const
Definition: qtabbar.cpp:2695
QIcon tabIcon(int index) const
Definition: qtabbar.cpp:1265
bool isTabEnabled(int index) const
Definition: qtabbar.cpp:1129
Shape shape
the shape of the tabs in the tab bar
Definition: qtabbar.h:58
void moveTab(int from, int to)
Definition: qtabbar.cpp:2020
@ RoundedSouth
Definition: qtabbar.h:78
@ RoundedNorth
Definition: qtabbar.h:78
@ TriangularEast
Definition: qtabbar.h:79
@ RoundedWest
Definition: qtabbar.h:78
@ TriangularSouth
Definition: qtabbar.h:79
@ RoundedEast
Definition: qtabbar.h:78
@ TriangularWest
Definition: qtabbar.h:79
@ TriangularNorth
Definition: qtabbar.h:79
bool tabsClosable
Whether or not a tab bar should place close buttons on each tab.
Definition: qtabbar.h:65
The QTabWidget class provides a stack of tabbed widgets.
Definition: qtabwidget.h:56
void setCurrentIndex(int index)
Definition: qtabwidget.cpp:711
int addTab(QWidget *widget, const QString &)
Definition: qtabwidget.cpp:395
The QTextEdit class provides a widget that is used to edit and display both plain and rich text.
Definition: qtextedit.h:63
The QVBoxLayout class lines up widgets vertically.
Definition: qboxlayout.h:127
The QWidget class is the base class of all user interface objects.
Definition: qwidget.h:133
void setAttribute(Qt::WidgetAttribute, bool on=true)
Definition: qwidget.cpp:11088
WId internalWinId() const
Definition: qwidget.h:251
void raise()
Definition: qwidget.cpp:11707
Qt::WindowFlags windowFlags() const
Definition: qwidget.h:836
void setParent(QWidget *parent)
Definition: qwidget.cpp:10512
void setMinimumSize(const QSize &)
Definition: qwidget.h:865
bool isMinimized() const
Definition: qwidget.cpp:2848
QSize size
the size of the widget excluding any window frame
Definition: qwidget.h:147
QRect geometry
the geometry of the widget relative to its parent and excluding the window frame
Definition: qwidget.h:140
void showMinimized()
Definition: qwidget.cpp:2859
bool isMaximized() const
Definition: qwidget.cpp:2888
bool close()
Definition: qwidget.cpp:8468
void move(int x, int y)
Definition: qwidget.h:913
void showFullScreen()
Definition: qwidget.cpp:3033
void hide()
Definition: qwidget.cpp:8078
int height
the height of the widget excluding any window frame
Definition: qwidget.h:149
QRect rect
the internal geometry of the widget excluding any window frame
Definition: qwidget.h:150
void setWindowState(Qt::WindowStates state)
Definition: qwidget.cpp:2949
void setFocus()
Definition: qwidget.h:454
void show()
Definition: qwidget.cpp:7825
QIcon windowIcon
the widget's icon
Definition: qwidget.h:186
void lower()
Definition: qwidget.cpp:11761
QSize sizeHint
the recommended size for the widget
Definition: qwidget.h:182
void showMaximized()
Definition: qwidget.cpp:3056
void setWindowModified(bool)
Definition: qwidget.cpp:11394
WId winId() const
Definition: qwidget.cpp:2359
void setWindowTitle(const QString &)
Definition: qwidget.cpp:6119
bool isWindowModified() const
Definition: qwidget.cpp:11389
QStyle * style() const
Definition: qwidget.cpp:2612
void setWindowIcon(const QIcon &icon)
Definition: qwidget.cpp:6188
QString windowTitle
the window title (caption)
Definition: qwidget.h:185
bool hasFocus() const
Definition: qwidget.cpp:6430
bool isAncestorOf(const QWidget *child) const
Definition: qwidget.cpp:8728
void showNormal()
Definition: qwidget.cpp:3072
bool isVisible() const
Definition: qwidget.h:907
void setWindowFlags(Qt::WindowFlags type)
Definition: qwidget.cpp:10410
void activeChanged(QMdiSubWindow *child)
QPushButton
[1]
QOpenGLWidget * widget
[1]
qreal spacing
QSignalSpy spy(myCustomObject, SIGNAL(mySignal(int, QString, double)))
[0]
QCOMPARE(spy.count(), 1)
fontMetrics
JDIMENSION DCTELEM * workspace
Definition: jsimddct.h:16
QList< QWindow * > windows
QHighDpiScaling::Point position(T, QHighDpiScaling::Point::Kind)
Q_TESTLIB_EXPORT QTestData & newRow(const char *dataTag)
Definition: qtestcase.cpp:2658
Q_GUI_EXPORT bool qWaitForWindowActive(QWindow *window, int timeout=5000)
Q_GUI_EXPORT bool qWaitForWindowExposed(QWindow *window, int timeout=5000)
Q_TESTLIB_EXPORT void ignoreMessage(QtMsgType type, const char *message)
Definition: qtestcase.cpp:2292
Q_CORE_EXPORT void qWait(int ms)
@ WindowFullScreen
Definition: qnamespace.h:280
@ WindowNoState
Definition: qnamespace.h:277
@ WindowMaximized
Definition: qnamespace.h:279
@ TopLeftCorner
Definition: qnamespace.h:1288
@ LeftDockWidgetArea
Definition: qnamespace.h:1218
@ WA_DeleteOnClose
Definition: qnamespace.h:346
LayoutDirection
Definition: qnamespace.h:1462
@ LeftToRight
Definition: qnamespace.h:1463
@ RightToLeft
Definition: qnamespace.h:1464
@ green
Definition: qnamespace.h:67
@ red
Definition: qnamespace.h:66
@ Key_Tab
Definition: qnamespace.h:685
@ Key_Backtab
Definition: qnamespace.h:686
@ Key_Control
Definition: qnamespace.h:705
@ Key_Meta
Definition: qnamespace.h:706
QTextStream & ws(QTextStream &stream)
QTextStream & fixed(QTextStream &stream)
@ ScrollBarAlwaysOff
Definition: qnamespace.h:1278
@ ScrollBarAsNeeded
Definition: qnamespace.h:1277
@ ShiftModifier
Definition: qnamespace.h:1075
@ ControlModifier
Definition: qnamespace.h:1076
@ MetaModifier
Definition: qnamespace.h:1078
@ NoModifier
Definition: qnamespace.h:1074
@ CaseInsensitive
Definition: qnamespace.h:1283
@ FramelessWindowHint
Definition: qnamespace.h:250
@ WindowStaysOnTopHint
Definition: qnamespace.h:258
@ WindowMinMaxButtonsHint
Definition: qnamespace.h:255
@ SubWindow
Definition: qnamespace.h:241
@ WindowTitleHint
Definition: qnamespace.h:251
@ WindowSystemMenuHint
Definition: qnamespace.h:252
@ WindowCloseButtonHint
Definition: qnamespace.h:266
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool startsWith(QByteArrayView haystack, QByteArrayView needle) noexcept
MyMainWidget mySession(nullptr)
#define QString()
Definition: parse-defines.h:51
void
Definition: png.h:1080
#define qApp
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char * method
QT_END_INCLUDE_NAMESPACE typedef double qreal
Definition: qglobal.h:341
#define qGuiApp
@ QtWarningMsg
Definition: qlogging.h:62
#define qWarning
Definition: qlogging.h:179
auto qSqrt(T v)
Definition: qmath.h:132
int qCeil(T v)
Definition: qmath.h:72
#define Q_DECLARE_METATYPE(TYPE)
Definition: qmetatype.h:1417
#define SLOT(a)
Definition: qobjectdefs.h:87
#define SIGNAL(a)
Definition: qobjectdefs.h:88
GLuint64 key
GLfloat GLfloat GLfloat w
[0]
GLuint index
[2]
GLdouble GLdouble GLdouble GLdouble top
GLenum GLenum GLsizei count
GLdouble GLdouble right
GLfloat GLfloat f
GLint left
GLint GLint bottom
GLfloat n
struct _cl_event * event
Definition: qopenglext.h:2998
GLdouble GLdouble t
[9]
Definition: qopenglext.h:243
SSL_CTX int(*) void arg)
#define QStringLiteral(str)
#define tr(X)
#define QTEST_MAIN(TestObject)
Definition: qtest.h:664
#define QSKIP(statement,...)
Definition: qtestcase.h:222
#define QFETCH(Type, name)
Definition: qtestcase.h:230
#define QEXPECT_FAIL(dataIndex, comment, mode)
Definition: qtestcase.h:224
#define QTRY_COMPARE(expr, expected)
Definition: qtestcase.h:214
#define QVERIFY(statement)
Definition: qtestcase.h:64
#define QTRY_VERIFY(expr)
Definition: qtestcase.h:196
#define Q_OBJECT
Definition: qtmetamacros.h:158
#define slots
Definition: qtmetamacros.h:76
QtConcurrent::task([]{ qDebug("Hello, world!");}).spawn(FutureResult void increment(QPromise< int > &promise, int i)
[10]
QList< QWidget * > widgets
[11]
QString title
[35]
QTime time
[5]
QLayoutItem * child
[0]
aWidget window() -> setWindowTitle("New Window Title")
[2]
QDockWidget * dockWidget
[0]
QMenuBar * menuBar
[0]
QQuickView * view
[0]
QStringList list
[0]
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:53
qsizetype indexOf(const AT &t, qsizetype from=0) const noexcept
Definition: qlist.h:966
void compare(Input input, FnUnderTest fn_under_test, const QByteArray &output)
@ windowSize
Arrangement
@ Tiled
@ Cascaded