diff --git a/src/controls/TableView.qml b/src/controls/TableView.qml
index 4cde5d3e37193c550243d9043f2db9f2f2397689..93d75e92c3cc5f42f4300919d41bfb9ae90b7b6a 100644
--- a/src/controls/TableView.qml
+++ b/src/controls/TableView.qml
@@ -200,9 +200,8 @@ ScrollView {
     */
     property int sortIndicatorOrder: Qt.AscendingOrder
 
-    /*! \qmlproperty list<TableViewColumn> TableView::columns
-    This property contains the TableViewColumn items */
-    default property alias columns: listView.columnheader
+    /*! \internal */
+    default property alias __columns: root.data
 
     /*! \qmlproperty Component TableView::contentHeader
     This is the content header of the TableView */
@@ -216,8 +215,9 @@ ScrollView {
     The current number of rows */
     readonly property alias rowCount: listView.count
 
-    /*! The current number of columns */
-    readonly property int columnCount: columns.length
+    /*! \qmlproperty int TableView::columnCount
+    The current number of columns */
+    readonly property alias columnCount: columnModel.count
 
     /*! \qmlproperty string TableView::section.property
         \qmlproperty enumeration TableView::section.criteria
@@ -288,6 +288,73 @@ ScrollView {
         return listView.indexAt(obj.x, obj.y)
     }
 
+    /*! Adds a \a column and returns the added column.
+
+        The \a column argument can be an instance of TableViewColumn,
+        or a Component. The component has to contain a TableViewColumn.
+        Otherwise  \c null is returned.
+    */
+    function addColumn(column) {
+        return insertColumn(columnCount, column)
+    }
+
+    /*! Inserts a \a column at the given \a index and returns the inserted column.
+
+        The \a column argument can be an instance of TableViewColumn,
+        or a Component. The component has to contain a TableViewColumn.
+        Otherwise  \c null is returned.
+    */
+    function insertColumn(index, column) {
+        var object = column
+        if (typeof column['createObject'] === 'function')
+            object = column.createObject(root)
+
+        if (index >= 0 && index <= columnCount && object.Accessible.role === Accessible.ColumnHeader) {
+            columnModel.insert(index, {columnItem: object})
+            return object
+        }
+
+        if (object !== column)
+            object.destroy()
+        console.warn("TableView::insertColumn(): invalid argument")
+        return null
+    }
+
+    /*! Removes and destroys a column at the given \a index. */
+    function removeColumn(index) {
+        if (index < 0 || index >= columnCount) {
+            console.warn("TableView::removeColumn(): invalid argument")
+            return
+        }
+        var column = columnModel.get(index).columnItem
+        columnModel.remove(index, 1)
+        column.destroy()
+    }
+
+    /*! Moves a column \a from index \a to another. */
+    function moveColumn(from, to) {
+        if (from < 0 || from >= columnCount || to < 0 || to >= columnCount) {
+            console.warn("TableView::moveColumn(): invalid argument")
+            return
+        }
+        columnModel.move(from, to, 1)
+    }
+
+    /*! Returns the column at the given \a index
+        or \c null if the \a index is invalid. */
+    function getColumn(index) {
+        if (index < 0 || index >= columnCount)
+            return null
+        return columnModel.get(index).columnItem
+    }
+
+    Component.onCompleted: {
+        for (var i = 0; i < __columns.length; ++i) {
+            var column = __columns[i]
+            if (column.Accessible.role === Accessible.ColumnHeader)
+                addColumn(column)
+        }
+    }
 
     style: Qt.createComponent(Settings.style + "/TableViewStyle.qml", root)
 
@@ -429,7 +496,10 @@ ScrollView {
             }
         }
 
-        property list<TableViewColumn> columnheader
+        ListModel {
+            id: columnModel
+        }
+
         highlightFollowsCurrentItem: true
         model: root.model
 
@@ -483,7 +553,7 @@ ScrollView {
                 height: parent.height
                 Repeater {
                     id: repeater
-                    model: root.columnCount
+                    model: columnModel
 
                     Loader {
                         id: itemDelegateLoader
@@ -509,7 +579,7 @@ ScrollView {
                             readonly property string role: __column.role
                         }
 
-                        readonly property TableViewColumn __column: columns[index]
+                        readonly property TableViewColumn __column: columnItem
                         readonly property bool __hasModelRole: styleData.role && itemModel.hasOwnProperty(styleData.role)
                         readonly property bool __hasModelDataRole: styleData.role && modelData && modelData.hasOwnProperty(styleData.role)
                     }
@@ -548,12 +618,12 @@ ScrollView {
                     property int targetIndex: -1
                     property int dragIndex: -1
 
-                    model: columnCount
+                    model: columnModel
 
                     delegate: Item {
                         z:-index
-                        width: columns[index].width
-                        visible: columns[index].visible
+                        width: modelData.width
+                        visible: modelData.visible
                         height: headerVisible ? headerStyle.height : 0
 
                         Loader {
@@ -562,7 +632,7 @@ ScrollView {
                             anchors.left: parent.left
                             anchors.right: parent.right
                             property QtObject styleData: QtObject {
-                                readonly property string value: columns[index].title
+                                readonly property string value: modelData.title
                                 readonly property bool pressed: headerClickArea.pressed
                                 readonly property bool containsMouse: headerClickArea.containsMouse
                                 readonly property int column: index
@@ -608,13 +678,7 @@ ScrollView {
 
                             onReleased: {
                                 if (repeater.targetIndex >= 0 && repeater.targetIndex != index ) {
-                                    // Rearrange the header sections
-                                    var items = new Array
-                                    for (var i = 0 ; i< columnCount ; ++i)
-                                        items.push(columns[i])
-                                    items.splice(index, 1);
-                                    items.splice(repeater.targetIndex, 0, columns[index]);
-                                    columns = items
+                                    columnModel.move(index, repeater.targetIndex, 1)
                                     if (sortIndicatorColumn == index)
                                         sortIndicatorColumn = repeater.targetIndex
                                 }
@@ -628,14 +692,14 @@ ScrollView {
                         Loader {
                             id: draghandle
                             property QtObject styleData: QtObject{
-                                readonly property string value: columns[index].title
+                                readonly property string value: modelData.title
                                 readonly property bool pressed: headerClickArea.pressed
                                 readonly property bool containsMouse: headerClickArea.containsMouse
                                 readonly property int column: index
                             }
 
                             parent: tableHeader
-                            width: columns[index].width
+                            width: modelData.width
                             height: parent.height
                             sourceComponent: root.headerDelegate
                             visible: headerClickArea.pressed
@@ -651,8 +715,8 @@ ScrollView {
                             width: 16 ; height: parent.height
                             anchors.right: parent.right
                             onPositionChanged:  {
-                                var newHeaderWidth = columns[index].width + (mouseX - offset)
-                                columns[index].width = Math.max(minimumSize, newHeaderWidth)
+                                var newHeaderWidth = modelData.width + (mouseX - offset)
+                                modelData.width = Math.max(minimumSize, newHeaderWidth)
                             }
                             property bool found:false
 
@@ -667,7 +731,7 @@ ScrollView {
                                         minWidth = Math.max(minWidth, item.children[1].children[index].children[0].implicitWidth)
                                 }
                                 if (minWidth)
-                                    columns[index].width = minWidth
+                                    modelData.width = minWidth
                             }
                             onPressedChanged: if (pressed) offset=mouseX
                             cursorShape: Qt.SplitHCursor
diff --git a/src/controls/TableViewColumn.qml b/src/controls/TableViewColumn.qml
index 919f30de455787582dae7d93f06197f8ccc9df7c..2c629dfbdf9f7fc078b31a8eadafd71bba3ac054 100644
--- a/src/controls/TableViewColumn.qml
+++ b/src/controls/TableViewColumn.qml
@@ -89,4 +89,6 @@ QtObject {
     /*! The delegate of the column. This can be used to set the
     \l TableView::itemDelegate for a specific column. */
     property Component delegate
+
+    Accessible.role: Accessible.ColumnHeader
 }
diff --git a/tests/auto/controls/data/tableview/table_dynamiccolumns.qml b/tests/auto/controls/data/tableview/table_dynamiccolumns.qml
new file mode 100644
index 0000000000000000000000000000000000000000..ce2cb93c4ce9964339f0b348caed1005260472c2
--- /dev/null
+++ b/tests/auto/controls/data/tableview/table_dynamiccolumns.qml
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Quick Controls module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+**   * Redistributions of source code must retain the above copyright
+**     notice, this list of conditions and the following disclaimer.
+**   * Redistributions in binary form must reproduce the above copyright
+**     notice, this list of conditions and the following disclaimer in
+**     the documentation and/or other materials provided with the
+**     distribution.
+**   * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+**     of its contributors may be used to endorse or promote products derived
+**     from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.1
+import QtQuick.Controls 1.0
+
+TableView {
+    id: tableView
+
+    TableViewColumn { title: "static" }
+
+    Component {
+        id: component
+        TableViewColumn { }
+    }
+
+    Component.onCompleted: {
+        addColumn(component.createObject(tableView, {title: "added item"}))
+
+        var col1 = addColumn(component)
+        col1.title = "added component"
+
+        insertColumn(0, component.createObject(tableView, {title: "inserted item"}))
+
+        var col2 = insertColumn(0, component)
+        col2.title = "inserted component"
+    }
+}
diff --git a/tests/auto/controls/data/tst_tableview.qml b/tests/auto/controls/data/tst_tableview.qml
index 6de8d57791a119852603d9412626d4bb1cdcdcff..d092ae9d599c20f2365c1abce60a571d0b28e457 100644
--- a/tests/auto/controls/data/tst_tableview.qml
+++ b/tests/auto/controls/data/tst_tableview.qml
@@ -55,6 +55,11 @@ TestCase {
     width:400
     height:400
 
+    Component {
+        id: newColumn
+        TableViewColumn { }
+    }
+
     function test_usingqmlmodel_data() {
         return [
                     {tag: "listmodel", a: "tableview/table5_listmodel.qml", expected: "A"},
@@ -173,7 +178,14 @@ TestCase {
         compare(component.status, Component.Ready)
         var table =  component.createObject(container);
         verify(table !== null, "table created is null")
-        table.forceActiveFocus();
+
+        // wait for items to be created
+        var timeout = 2000
+        while (timeout >= 0 && table.rowAt(15, 55) === -1) {
+            timeout -= 50
+            wait(50)
+        }
+
         compare(table.test, 0)
         mouseClick(table, 15 , 55, Qt.LeftButton)
         compare(table.test, 1)
@@ -228,6 +240,128 @@ TestCase {
         table.destroy()
     }
 
+    function test_dynamicColumns() {
+        var component = Qt.createComponent("tableview/table_dynamiccolumns.qml")
+        compare(component.status, Component.Ready)
+        var table = component.createObject(container)
+
+        // insertColumn(component), insertColumn(item),
+        // addColumn(component), addColumn(item), and static TableViewColumn {}
+        compare(table.columnCount, 5)
+        compare(table.getColumn(0).title, "inserted component")
+        compare(table.getColumn(1).title, "inserted item")
+        table.destroy()
+    }
+
+    function test_addRemoveColumn() {
+        var tableView = Qt.createQmlObject('import QtQuick 2.1; import QtQuick.Controls 1.0; TableView { }', testCase, '');
+        compare(tableView.columnCount, 0)
+        tableView.addColumn(newColumn.createObject(testCase, {title: "title 1"}))
+        compare(tableView.columnCount, 1)
+        tableView.addColumn(newColumn.createObject(testCase, {title: "title 2"}))
+        compare(tableView.columnCount, 2)
+        compare(tableView.getColumn(0).title, "title 1")
+        compare(tableView.getColumn(1).title, "title 2")
+
+        tableView.insertColumn(1, newColumn.createObject(testCase, {title: "title 3"}))
+        compare(tableView.columnCount, 3)
+        compare(tableView.getColumn(0).title, "title 1")
+        compare(tableView.getColumn(1).title, "title 3")
+        compare(tableView.getColumn(2).title, "title 2")
+
+        tableView.insertColumn(0, newColumn.createObject(testCase, {title: "title 4"}))
+        compare(tableView.columnCount, 4)
+        compare(tableView.getColumn(0).title, "title 4")
+        compare(tableView.getColumn(1).title, "title 1")
+        compare(tableView.getColumn(2).title, "title 3")
+        compare(tableView.getColumn(3).title, "title 2")
+
+        tableView.removeColumn(0)
+        compare(tableView.columnCount, 3)
+        compare(tableView.getColumn(0).title, "title 1")
+        compare(tableView.getColumn(1).title, "title 3")
+        compare(tableView.getColumn(2).title, "title 2")
+
+        tableView.removeColumn(1)
+        compare(tableView.columnCount, 2)
+        compare(tableView.getColumn(0).title, "title 1")
+        compare(tableView.getColumn(1).title, "title 2")
+
+        tableView.removeColumn(1)
+        compare(tableView.columnCount, 1)
+        compare(tableView.getColumn(0).title, "title 1")
+
+        tableView.removeColumn(0)
+        compare(tableView.columnCount, 0)
+        tableView.destroy()
+    }
+
+    function test_moveColumn_data() {
+        return [
+            {tag:"0->1 (0)", from: 0, to: 1},
+            {tag:"0->1 (1)", from: 0, to: 1},
+            {tag:"0->1 (2)", from: 0, to: 1},
+
+            {tag:"0->2 (0)", from: 0, to: 2},
+            {tag:"0->2 (1)", from: 0, to: 2},
+            {tag:"0->2 (2)", from: 0, to: 2},
+
+            {tag:"1->0 (0)", from: 1, to: 0},
+            {tag:"1->0 (1)", from: 1, to: 0},
+            {tag:"1->0 (2)", from: 1, to: 0},
+
+            {tag:"1->2 (0)", from: 1, to: 2},
+            {tag:"1->2 (1)", from: 1, to: 2},
+            {tag:"1->2 (2)", from: 1, to: 2},
+
+            {tag:"2->0 (0)", from: 2, to: 0},
+            {tag:"2->0 (1)", from: 2, to: 0},
+            {tag:"2->0 (2)", from: 2, to: 0},
+
+            {tag:"2->1 (0)", from: 2, to: 1},
+            {tag:"2->1 (1)", from: 2, to: 1},
+            {tag:"2->1 (2)", from: 2, to: 1},
+
+            {tag:"0->0", from: 0, to: 0},
+            {tag:"-1->0", from: -1, to: 0},
+            {tag:"0->-1", from: 0, to: -1},
+            {tag:"1->10", from: 1, to: 10},
+            {tag:"10->2", from: 10, to: 2},
+            {tag:"10->-1", from: 10, to: -1}
+        ]
+    }
+
+    function test_moveColumn(data) {
+        var tableView = Qt.createQmlObject('import QtQuick 2.1; import QtQuick.Controls 1.0; TableView { }', testCase, '');
+        compare(tableView.columnCount, 0)
+
+        var titles = ["title 1", "title 2", "title 3"]
+
+        var i = 0;
+        for (i = 0; i < titles.length; ++i)
+            tableView.addColumn(newColumn.createObject(testCase, {title: titles[i]}))
+
+        compare(tableView.columnCount, titles.length)
+        for (i = 0; i < tableView.columnCount; ++i)
+            compare(tableView.getColumn(i).title, titles[i])
+
+        tableView.moveColumn(data.from, data.to)
+
+        compare(tableView.columnCount, titles.length)
+
+        if (data.from >= 0 && data.from < tableView.columnCount && data.to >= 0 && data.to < tableView.columnCount) {
+            var title = titles[data.from]
+            titles.splice(data.from, 1)
+            titles.splice(data.to, 0, title)
+        }
+
+        compare(tableView.columnCount, titles.length)
+        for (i = 0; i < tableView.columnCount; ++i)
+            compare(tableView.getColumn(i).title, titles[i])
+
+        tableView.destroy()
+    }
+
     // In TableView, drawn text = table.__currentRowItem.children[1].children[1].itemAt(0).children[0].children[0].text
 
     function findAChild(item, name)