Add QMainWindow::resizeDocks
authorOlivier Goffart <ogoffart@woboq.com>
Thu, 19 Mar 2015 16:47:13 +0000 (17:47 +0100)
committerOlivier Goffart (Woboq GmbH) <ogoffart@woboq.com>
Sun, 16 Aug 2015 08:23:32 +0000 (08:23 +0000)
This API allows to programatically resize QDockWidgets

Task-number: QTBUG-32001
Change-Id: I58072a391f8e7f325a26745b5bedd3fe49508e91
Reviewed-by: Jocelyn Turcotte (Woboq GmbH) <jturcotte@woboq.com>
src/widgets/widgets/qdockarealayout.cpp
src/widgets/widgets/qdockarealayout_p.h
src/widgets/widgets/qmainwindow.cpp
src/widgets/widgets/qmainwindow.h
tests/auto/widgets/widgets/qmainwindow/tst_qmainwindow.cpp

index c61984a457583f47b0c2fd9ecaab46d02bd207b6..0a0008613867dd1e0a91262999aa3a8ab2f04365 100644 (file)
@@ -3101,6 +3101,53 @@ void QDockAreaLayout::tabifyDockWidget(QDockWidget *first, QDockWidget *second)
         remove(index);
 }
 
+void QDockAreaLayout::resizeDocks(const QList<QDockWidget *> &docks,
+                                  const QList<int> &sizes, Qt::Orientation o)
+{
+    if (docks.count() != sizes.count()) {
+        qWarning("QMainWidget::resizeDocks: size of the lists are not the same");
+        return;
+    }
+    int count = docks.count();
+    fallbackToSizeHints = false;
+    for (int i = 0; i < count; ++i) {
+        QList<int> path = indexOf(docks[i]);
+        if (path.isEmpty()) {
+            qWarning("QMainWidget::resizeDocks: one QDockWidget is not part of the layout");
+            continue;
+        }
+        int size = sizes[i];
+        if (size <= 0) {
+            qWarning("QMainWidget::resizeDocks: all sizes need to be larger than 0");
+            size = 1;
+        }
+
+        while (path.size() > 1) {
+            QDockAreaLayoutInfo *info = this->info(path);
+            if (!info->tabbed && info->o == o) {
+                info->item_list[path.last()].size = size;
+                int totalSize = 0;
+                foreach (const QDockAreaLayoutItem &item, info->item_list) {
+                    if (!item.skip()) {
+                        if (totalSize != 0)
+                            totalSize += sep;
+                        totalSize += item.size == -1 ? pick(o, item.sizeHint()) : item.size;
+                    }
+                }
+                size = totalSize;
+            }
+            path.removeLast();
+        }
+
+        const int dockNum = path.first();
+        Q_ASSERT(dockNum < QInternal::DockCount);
+        QRect &r = this->docks[dockNum].rect;
+        QSize s = r.size();
+        rpick(o, s) = size;
+        r.setSize(s);
+    }
+}
+
 void QDockAreaLayout::splitDockWidget(QDockWidget *after,
                                                QDockWidget *dockWidget,
                                                Qt::Orientation orientation)
index 93b005f64f359fcf4cb1cae97a6064bf920b94c3..5d352f01247b3838f4a2c4ea2a55c375dc87d8a2 100644 (file)
@@ -268,6 +268,7 @@ public:
     void splitDockWidget(QDockWidget *after, QDockWidget *dockWidget,
                          Qt::Orientation orientation);
     void tabifyDockWidget(QDockWidget *first, QDockWidget *second);
+    void resizeDocks(const QList<QDockWidget *> &docks, const QList<int> &sizes, Qt::Orientation o);
 
     void apply(bool animate);
 
index 5d53e7def458de857f0964d2365dce1fa85a0fd3..ff4bb3cc98c6f4413f1bf00fd69bb1f8d71493e0 100644 (file)
@@ -1237,6 +1237,35 @@ void QMainWindow::removeDockWidget(QDockWidget *dockwidget)
 Qt::DockWidgetArea QMainWindow::dockWidgetArea(QDockWidget *dockwidget) const
 { return d_func()->layout->dockWidgetArea(dockwidget); }
 
+
+/*!
+    \since 5.6
+    Resizes the dock widgets in the list \a docks to the corresponding size in
+    pixels from the list \a sizes. If \a orientation is Qt::Horizontal, adjusts
+    the width, otherwise adjusts the height of the dock widgets.
+    The sizes will be adjusted such that the maximum and the minimum sizes are
+    respected and the QMainWindow itself will not be resized.
+    Any additional/missing space is distributed amongst the widgets according
+    to the relative weight of the sizes.
+
+    Example:
+    \code
+    resizeDocks({blueWidget, yellowWidget}, {20 , 40}, Qt::Horizontal);
+    \endcode
+    If the blue and the yellow widget are nested on the same level they will be
+    resized such that the yellowWidget is twice as big as the blueWidget
+
+    If some widgets are grouped in tabs, only one widget per group should be
+    specified. Widgets not in the list might be changed to repect the constraints.
+*/
+void QMainWindow::resizeDocks(const QList<QDockWidget *> &docks,
+                              const QList<int> &sizes, Qt::Orientation orientation)
+{
+    d_func()->layout->layoutState.dockAreaLayout.resizeDocks(docks, sizes, orientation);
+    d_func()->layout->invalidate();
+}
+
+
 #endif // QT_NO_DOCKWIDGET
 
 /*!
index ab6ee22748b1ec9f7a6f4d9822a63d834fd54d40..70d78a7904690d831ad6f86befb6b52dcd0d95d1 100644 (file)
@@ -165,6 +165,9 @@ public:
     bool restoreDockWidget(QDockWidget *dockwidget);
 
     Qt::DockWidgetArea dockWidgetArea(QDockWidget *dockwidget) const;
+
+    void resizeDocks(const QList<QDockWidget *> &docks,
+                     const QList<int> &sizes, Qt::Orientation orientation);
 #endif // QT_NO_DOCKWIDGET
 
     QByteArray saveState(int version = 0) const;
index e8c533f301e65e50faea298dceccdddb5df7e547..62820287463cc1926de88dc75f793f7ca891371e 100644 (file)
@@ -149,6 +149,8 @@ private slots:
     void toggleUnifiedTitleAndToolBarOnMac();
 #endif
     void QTBUG21378_animationFinished();
+    void resizeDocks();
+    void resizeDocks_data();
 };
 
 
@@ -1950,5 +1952,96 @@ void tst_QMainWindow::QTBUG21378_animationFinished()
     delete mwClickTimer;
     QVERIFY(true);
 }
+
+Q_DECLARE_METATYPE(Qt::Orientation)
+
+void tst_QMainWindow::resizeDocks_data()
+{
+    QTest::addColumn<Qt::Orientation>("orientation");
+    QTest::addColumn<QStringList>("docks");
+    QTest::addColumn<QList<int> >("sizes");
+
+    QTest::newRow("1") << Qt::Horizontal
+        << (QStringList() << "blue" << "orange" << "green" << "gray")
+        << (QList<int>() << 190 << 190 << 320 << 160);
+
+    QTest::newRow("2") << Qt::Vertical
+        << (QStringList() << "yellow"  << "orange")
+        << (QList<int>() << 147   <<  133 );
+
+
+    QTest::newRow("3") << Qt::Horizontal
+        << (QStringList() << "blue" << "yellow")
+        << (QList<int>() << 190 <<  600);
+}
+
+void tst_QMainWindow::resizeDocks()
+{
+    AddList addList;
+    addList
+        << AddDockWidget("blue", Qt::LeftDockWidgetArea)
+        << AddDockWidget("red", Qt::TopDockWidgetArea)
+        << AddDockWidget("pink", "red")
+        << AddDockWidget("yellow", Qt::RightDockWidgetArea)
+        << AddDockWidget("orange", Qt::RightDockWidgetArea)
+        << AddDockWidget("green", "orange", Qt::Horizontal)
+        << AddDockWidget("gray", "orange", Qt::Horizontal);
+    /*
+        +--------------------------------+
+        |          red/pink              |
+        +------+-+-----------------------+
+        |      | |         yellow        |
+        | blue + +--------+------+-------+
+        |      | | orange | gray | green |
+        +------+-+--------+------+-------+
+
+    */
+
+    QMainWindow mw(0, Qt::BypassWindowManagerHint);
+    mw.setDockNestingEnabled(true);
+    mw.resize(1800, 600);
+
+    foreach (const AddDockWidget &i, addList)
+        i.apply(&mw);
+
+    foreach (QDockWidget *dw, mw.findChildren<QDockWidget *>())
+        dw->setStyleSheet( "* { background-color: " + dw->objectName() +" }");
+
+    mw.setCentralWidget(new QTextEdit);
+
+    mw.show();
+    QTest::qWaitForWindowExposed(&mw);
+
+    QFETCH(Qt::Orientation, orientation);
+    QFETCH(QStringList, docks);
+    QFETCH(QList<int>, sizes);
+
+    QList<QDockWidget *> list;
+    foreach (const QString &name, docks) {
+        QDockWidget *d = mw.findChild<QDockWidget *>(name);
+        QVERIFY(d);
+        list << d;
+    }
+
+    mw.resizeDocks(list, sizes, orientation);
+
+    qApp->processEvents();
+
+    int totalFromList = 0;
+    int actualTotal = 0;
+    for (int i = 0; i < docks.count(); ++i) {
+        totalFromList += sizes[i];
+        QSize s = list[i]->size();
+        actualTotal += (orientation == Qt::Horizontal) ? s.width() : s.height();
+//        qDebug() << list[i] << list[i]->size() << sizes[i];
+    }
+
+    for (int i = 0; i < docks.count(); ++i) {
+        QSize s = list[i]->size();
+        int value = (orientation == Qt::Horizontal) ? s.width() : s.height();
+        QCOMPARE(value,  qRound(sizes[i]*actualTotal/double(totalFromList)));
+    }
+}
+
 QTEST_MAIN(tst_QMainWindow)
 #include "tst_qmainwindow.moc"