From a38a14b9fb411231443e80cf14d397492f3412dc Mon Sep 17 00:00:00 2001
From: J-P Nurmi <jpnurmi@gmail.com>
Date: Thu, 10 Feb 2011 11:00:11 +0100
Subject: Added QMdiArea::tabsMovable and tabsClosable

Task-number: QTBUG-3864
Reviewed-by: Thierry Bastian <thierry.bastian@nokia.com>

Merge-request: 2522
---
 src/gui/widgets/qmdiarea.cpp         | 79 ++++++++++++++++++++++++++++++++++++
 src/gui/widgets/qmdiarea.h           | 12 +++++-
 src/gui/widgets/qmdiarea_p.h         |  4 ++
 tests/auto/qmdiarea/tst_qmdiarea.cpp | 73 +++++++++++++++++++++++++++++++++
 4 files changed, 167 insertions(+), 1 deletion(-)

diff --git a/src/gui/widgets/qmdiarea.cpp b/src/gui/widgets/qmdiarea.cpp
index b02db4c..2a486bb 100644
--- a/src/gui/widgets/qmdiarea.cpp
+++ b/src/gui/widgets/qmdiarea.cpp
@@ -674,6 +674,8 @@ QMdiAreaPrivate::QMdiAreaPrivate()
       viewMode(QMdiArea::SubWindowView),
 #ifndef QT_NO_TABBAR
       documentMode(false),
+      tabsClosable(false),
+      tabsMovable(false),
 #endif
 #ifndef QT_NO_TABWIDGET
       tabShape(QTabWidget::Rounded),
@@ -792,6 +794,27 @@ void QMdiAreaPrivate::_q_currentTabChanged(int index)
 #endif // QT_NO_TABBAR
 }
 
+void QMdiAreaPrivate::_q_closeTab(int index)
+{
+#ifdef QT_NO_TABBAR
+    Q_UNUSED(index);
+#else
+    QMdiSubWindow *subWindow = childWindows.at(index);
+    Q_ASSERT(subWindow);
+    subWindow->close();
+#endif // QT_NO_TABBAR
+}
+
+void QMdiAreaPrivate::_q_moveTab(int from, int to)
+{
+#ifdef QT_NO_TABBAR
+    Q_UNUSED(from);
+    Q_UNUSED(to);
+#else
+    childWindows.move(from, to);
+#endif // QT_NO_TABBAR
+}
+
 /*!
     \internal
 */
@@ -1519,6 +1542,8 @@ void QMdiAreaPrivate::setViewMode(QMdiArea::ViewMode mode)
         Q_ASSERT(!tabBar);
         tabBar = new QMdiAreaTabBar(q);
         tabBar->setDocumentMode(documentMode);
+        tabBar->setTabsClosable(tabsClosable);
+        tabBar->setMovable(tabsMovable);
 #ifndef QT_NO_TABWIDGET
         tabBar->setShape(tabBarShapeFrom(tabShape, tabPosition));
 #endif
@@ -1550,6 +1575,8 @@ void QMdiAreaPrivate::setViewMode(QMdiArea::ViewMode mode)
         updateTabBarGeometry();
 
         QObject::connect(tabBar, SIGNAL(currentChanged(int)), q, SLOT(_q_currentTabChanged(int)));
+        QObject::connect(tabBar, SIGNAL(tabCloseRequested(int)), q, SLOT(_q_closeTab(int)));
+        QObject::connect(tabBar, SIGNAL(tabMoved(int,int)), q, SLOT(_q_moveTab(int,int)));
     } else
 #endif // QT_NO_TABBAR
     { // SubWindowView
@@ -1636,6 +1663,8 @@ void QMdiAreaPrivate::refreshTabBar()
         return;
 
     tabBar->setDocumentMode(documentMode);
+    tabBar->setTabsClosable(tabsClosable);
+    tabBar->setMovable(tabsMovable);
 #ifndef QT_NO_TABWIDGET
     tabBar->setShape(tabBarShapeFrom(tabShape, tabPosition));
 #endif
@@ -2114,6 +2143,56 @@ void QMdiArea::setDocumentMode(bool enabled)
     d->documentMode = enabled;
     d->refreshTabBar();
 }
+
+/*!
+    \property QMdiArea::tabsClosable
+    \brief whether the tab bar should place close buttons on each tab in tabbed view mode.
+    \since 4.8
+
+    Tabs are not closable by default.
+
+    \sa QTabBar::tabsClosable, setViewMode()
+*/
+bool QMdiArea::tabsClosable() const
+{
+    Q_D(const QMdiArea);
+    return d->tabsClosable;
+}
+
+void QMdiArea::setTabsClosable(bool closable)
+{
+    Q_D(QMdiArea);
+    if (d->tabsClosable == closable)
+        return;
+
+    d->tabsClosable = closable;
+    d->refreshTabBar();
+}
+
+/*!
+    \property QMdiArea::tabsMovable
+    \brief whether the user can move the tabs within the tabbar area in tabbed view mode.
+    \since 4.8
+
+    Tabs are not movable by default.
+
+    \sa QTabBar::tabsMovable, setViewMode()
+*/
+bool QMdiArea::tabsMovable() const
+{
+    Q_D(const QMdiArea);
+    return d->tabsMovable;
+}
+
+void QMdiArea::setTabsMovable(bool movable)
+{
+    Q_D(QMdiArea);
+    if (d->tabsMovable == movable)
+        return;
+
+    d->tabsMovable = movable;
+    d->refreshTabBar();
+}
 #endif // QT_NO_TABBAR
 
 #ifndef QT_NO_TABWIDGET
diff --git a/src/gui/widgets/qmdiarea.h b/src/gui/widgets/qmdiarea.h
index 809bfe4..a4b357c 100644
--- a/src/gui/widgets/qmdiarea.h
+++ b/src/gui/widgets/qmdiarea.h
@@ -65,6 +65,8 @@ class Q_GUI_EXPORT QMdiArea : public QAbstractScrollArea
     Q_PROPERTY(ViewMode viewMode READ viewMode WRITE setViewMode)
 #ifndef QT_NO_TABBAR
     Q_PROPERTY(bool documentMode READ documentMode WRITE setDocumentMode)
+    Q_PROPERTY(bool tabsClosable READ tabsClosable WRITE setTabsClosable)
+    Q_PROPERTY(bool tabsMovable READ tabsMovable WRITE setTabsMovable)
 #endif
 #ifndef QT_NO_TABWIDGET
     Q_PROPERTY(QTabWidget::TabShape tabShape READ tabShape WRITE setTabShape)
@@ -116,6 +118,12 @@ public:
 #ifndef QT_NO_TABBAR
     bool documentMode() const;
     void setDocumentMode(bool enabled);
+
+    void setTabsClosable(bool closable);
+    bool tabsClosable() const;
+
+    void setTabsMovable(bool movable);
+    bool tabsMovable() const;
 #endif
 #ifndef QT_NO_TABWIDGET
     void setTabShape(QTabWidget::TabShape shape);
@@ -156,7 +164,9 @@ private:
     Q_DECLARE_PRIVATE(QMdiArea)
     Q_PRIVATE_SLOT(d_func(), void _q_deactivateAllWindows())
     Q_PRIVATE_SLOT(d_func(), void _q_processWindowStateChanged(Qt::WindowStates, Qt::WindowStates))
-    Q_PRIVATE_SLOT(d_func(), void _q_currentTabChanged(int index))
+    Q_PRIVATE_SLOT(d_func(), void _q_currentTabChanged(int))
+    Q_PRIVATE_SLOT(d_func(), void _q_closeTab(int))
+    Q_PRIVATE_SLOT(d_func(), void _q_moveTab(int, int))
 };
 
 Q_DECLARE_OPERATORS_FOR_FLAGS(QMdiArea::AreaOptions)
diff --git a/src/gui/widgets/qmdiarea_p.h b/src/gui/widgets/qmdiarea_p.h
index 5d85659..e5e2057 100644
--- a/src/gui/widgets/qmdiarea_p.h
+++ b/src/gui/widgets/qmdiarea_p.h
@@ -165,6 +165,8 @@ public:
     QMdiArea::ViewMode viewMode;
 #ifndef QT_NO_TABBAR
     bool documentMode;
+    bool tabsClosable;
+    bool tabsMovable;
 #endif
 #ifndef QT_NO_TABWIDGET
     QTabWidget::TabShape tabShape;
@@ -189,6 +191,8 @@ public:
     void _q_deactivateAllWindows(QMdiSubWindow *aboutToActivate = 0);
     void _q_processWindowStateChanged(Qt::WindowStates oldState, Qt::WindowStates newState);
     void _q_currentTabChanged(int index);
+    void _q_closeTab(int index);
+    void _q_moveTab(int from, int to);
 
     // Functions.
     void appendChild(QMdiSubWindow *child);
diff --git a/tests/auto/qmdiarea/tst_qmdiarea.cpp b/tests/auto/qmdiarea/tst_qmdiarea.cpp
index d44e632..67d3d0d 100644
--- a/tests/auto/qmdiarea/tst_qmdiarea.cpp
+++ b/tests/auto/qmdiarea/tst_qmdiarea.cpp
@@ -287,6 +287,8 @@ private slots:
     void setActivationOrder();
     void tabBetweenSubWindows();
     void setViewMode();
+    void setTabsClosable();
+    void setTabsMovable();
     void setTabShape();
     void setTabPosition_data();
     void setTabPosition();
@@ -2464,6 +2466,77 @@ void tst_QMdiArea::setViewMode()
     QCOMPARE(mdiArea.viewMode(), QMdiArea::SubWindowView);
 }
 
+void tst_QMdiArea::setTabsClosable()
+{
+    QMdiArea mdiArea;
+    mdiArea.addSubWindow(new QWidget);
+
+    // test default
+    QCOMPARE(mdiArea.tabsClosable(), false);
+
+    // change value before tab bar exists
+    QTabBar *tabBar = qFindChild<QTabBar *>(&mdiArea);
+    QVERIFY(!tabBar);
+    mdiArea.setTabsClosable(true);
+    QCOMPARE(mdiArea.tabsClosable(), true);
+
+    // force tab bar creation
+    mdiArea.setViewMode(QMdiArea::TabbedView);
+    tabBar = qFindChild<QTabBar *>(&mdiArea);
+    QVERIFY(tabBar);
+
+    // value must've been propagated
+    QCOMPARE(tabBar->tabsClosable(), true);
+
+    // change value when tab bar exists
+    mdiArea.setTabsClosable(false);
+    QCOMPARE(mdiArea.tabsClosable(), false);
+    QCOMPARE(tabBar->tabsClosable(), false);
+}
+
+void tst_QMdiArea::setTabsMovable()
+{
+    QMdiArea mdiArea;
+    QMdiSubWindow *subWindow1 = mdiArea.addSubWindow(new QWidget);
+    QMdiSubWindow *subWindow2 = mdiArea.addSubWindow(new QWidget);
+    QMdiSubWindow *subWindow3 = mdiArea.addSubWindow(new QWidget);
+
+    // test default
+    QCOMPARE(mdiArea.tabsMovable(), false);
+
+    // change value before tab bar exists
+    QTabBar *tabBar = qFindChild<QTabBar *>(&mdiArea);
+    QVERIFY(!tabBar);
+    mdiArea.setTabsMovable(true);
+    QCOMPARE(mdiArea.tabsMovable(), true);
+
+    // force tab bar creation
+    mdiArea.setViewMode(QMdiArea::TabbedView);
+    tabBar = qFindChild<QTabBar *>(&mdiArea);
+    QVERIFY(tabBar);
+
+    // value must've been propagated
+    QCOMPARE(tabBar->isMovable(), true);
+
+    // test tab moving
+    QList<QMdiSubWindow *> subWindows;
+    subWindows << subWindow1 << subWindow2 << subWindow3;
+    QCOMPARE(mdiArea.subWindowList(QMdiArea::CreationOrder), subWindows);
+    tabBar->moveTab(1, 2); // 1,3,2
+    subWindows.clear();
+    subWindows << subWindow1 << subWindow3 << subWindow2;
+    QCOMPARE(mdiArea.subWindowList(QMdiArea::CreationOrder), subWindows);
+    tabBar->moveTab(0, 2); // 3,2,1
+    subWindows.clear();
+    subWindows << subWindow3 << subWindow2 << subWindow1;
+    QCOMPARE(mdiArea.subWindowList(QMdiArea::CreationOrder), subWindows);
+
+    // change value when tab bar exists
+    mdiArea.setTabsMovable(false);
+    QCOMPARE(mdiArea.tabsMovable(), false);
+    QCOMPARE(tabBar->isMovable(), false);
+}
+
 void tst_QMdiArea::setTabShape()
 {
     QMdiArea mdiArea;
-- 
cgit v0.12