From a6deb27ba0252bc06fd6f28fb76b552e6320853f Mon Sep 17 00:00:00 2001
From: J-P Nurmi <jpnurmi@digia.com>
Date: Tue, 30 Apr 2013 14:18:03 +0200
Subject: [PATCH] Fix TabView not to insert duplicate tabs

There are three ways to add tabs:
- declare 'static' Tab { } child elements
- call addTab() / insertTab()
- Component::createObject(tabView)

=> Do not rely on the calling order of Component.onCompleted()
and make sure that the same tabs are not accidentally re-inserted.

Task-number: QTBUG-30873
Change-Id: Ib30cfb676debbb302c5e9f7d757f66aab6fcc684
Reviewed-by: Caroline Chao <caroline.chao@digia.com>
---
 src/controls/Tab.qml                     |  4 ++
 src/controls/TabView.qml                 | 48 +++++++++++-------------
 tests/auto/controls/data/tst_tabview.qml | 39 +++++++++++++------
 3 files changed, 54 insertions(+), 37 deletions(-)

diff --git a/src/controls/Tab.qml b/src/controls/Tab.qml
index 0f88e2388..0cf263410 100644
--- a/src/controls/Tab.qml
+++ b/src/controls/Tab.qml
@@ -57,6 +57,10 @@ Loader {
 
     /*! This property holds the title of the tab. */
     property string title
+
+    /*! \internal */
+    property bool __inserted: false
+
     Accessible.role: Accessible.LayeredPane
     active: false
     visible: false
diff --git a/src/controls/TabView.qml b/src/controls/TabView.qml
index 6bcaab75c..153c24005 100644
--- a/src/controls/TabView.qml
+++ b/src/controls/TabView.qml
@@ -85,13 +85,7 @@ FocusScope {
         Returns the newly added tab.
     */
     function addTab(title, component) {
-        var tab = tabcomp.createObject(stack)
-        tab.sourceComponent = component
-        __tabs.append({tab: tab})
-        tab.parent = stack
-        tab.title = title
-        __setOpacities()
-        return tab
+        return insertTab(__tabs.count, title, component)
     }
 
     /*! Inserts a new tab with title at index, with an optional Component.
@@ -102,6 +96,7 @@ FocusScope {
         tab.sourceComponent = component
         tab.parent = stack
         tab.title = title
+        tab.__inserted = true
         __tabs.insert(index, {tab: tab})
         __setOpacities()
         return tab
@@ -206,12 +201,26 @@ FocusScope {
             property string style
             property int baseOverlap
 
-            Component.onCompleted: {
-                for (var i = 0 ; i < stack.children.length ; ++i) {
-                    if (stack.children[i].Accessible.role === Accessible.LayeredPane)
-                        __tabs.append({tab: stack.children[i]})
+            Component.onCompleted: addTabs(stack.children)
+
+            function addTabs(tabs) {
+                var tabAdded = false
+                for (var i = 0 ; i < tabs.length ; ++i) {
+                    var tab = tabs[i]
+                    if (!tab.__inserted && tab.Accessible.role === Accessible.LayeredPane) {
+                        tab.__inserted = true
+                        if (tab.parent === root) {
+                            tab.parent = stack
+                            // a tab added dynamically by Component::createObject() and passing the
+                            // tab view as a parent should also get automatically removed when destructed
+                            tab.Component.onDestruction.connect(stack.onDynamicTabDestroyed.bind(tab))
+                        }
+                        __tabs.append({tab: tab})
+                        tabAdded = true
+                    }
                 }
-                __setOpacities()
+                if (tabAdded)
+                    __setOpacities()
             }
 
             function onDynamicTabDestroyed() {
@@ -226,20 +235,7 @@ FocusScope {
         onLoaded: { item.z = -1 }
     }
 
-    onChildrenChanged: {
-        var tabAdded = false
-        for (var i = 0; i < children.length; ++i) {
-            var child = children[i]
-            if (child.Accessible.role === Accessible.LayeredPane) {
-                __tabs.append({tab: child})
-                child.parent = stack
-                child.Component.onDestruction.connect(stack.onDynamicTabDestroyed.bind(child))
-                tabAdded = true
-            }
-        }
-        if (tabAdded)
-            __setOpacities()
-    }
+    onChildrenChanged: stack.addTabs(root.children)
 
     states: [
         State {
diff --git a/tests/auto/controls/data/tst_tabview.qml b/tests/auto/controls/data/tst_tabview.qml
index 973b6fde5..ad1322658 100644
--- a/tests/auto/controls/data/tst_tabview.qml
+++ b/tests/auto/controls/data/tst_tabview.qml
@@ -192,18 +192,35 @@ TestCase {
     }
 
     function test_dynamicTabs() {
-        var tabView = Qt.createQmlObject('import QtQuick 2.1; import QtQuick.Controls 1.0; TabView { property Component tabComponent: Component { Tab { } } }', testCase, '');
-        compare(tabView.count, 0)
-        var tab1 = tabView.tabComponent.createObject(tabView)
-        compare(tabView.count, 1)
-        var tab2 = tabView.tabComponent.createObject(tabView)
-        compare(tabView.count, 2)
-        tab1.destroy()
-        wait(0)
-        compare(tabView.count, 1)
-        tab2.destroy()
+        var test_tabView = '                                \
+        import QtQuick 2.1;                                 \
+        import QtQuick.Controls 1.0;                        \
+        TabView {                                           \
+            id: tabView;                                    \
+            Tab { title: "static" }                         \
+            property Component tabComponent: Component {    \
+                id: tabComponent;                           \
+                Tab { title: "dynamic" }                    \
+            }                                               \
+            Component.onCompleted: {                        \
+                addTab("added", tabComponent);              \
+                insertTab(0, "inserted", tabComponent);     \
+                tabComponent.createObject(tabView);         \
+            }                                               \
+        }                                                   '
+
+        var tabView = Qt.createQmlObject(test_tabView, testCase, '')
+        // insertTab(), addTab(), createObject() and static Tab {}
+        compare(tabView.count, 4)
+        compare(tabView.tabAt(0).title, "inserted")
+
+        var tab = tabView.tabComponent.createObject(tabView)
+        compare(tabView.count, 5)
+        compare(tabView.tabAt(4).title, "dynamic")
+        tab.destroy()
         wait(0)
-        compare(tabView.count, 0)
+        compare(tabView.count, 4)
+        tabView.destroy()
     }
 
     function test_mousePressOnTabBar() {
-- 
GitLab