summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/controls/Private/BasicTableView.qml800
-rw-r--r--src/controls/Private/private.pri1
-rw-r--r--src/controls/Private/qmldir1
-rw-r--r--src/controls/TableView.qml1068
-rw-r--r--src/controls/TableViewColumn.qml21
-rw-r--r--tests/auto/controls/data/tableview/tv_keys.qml6
-rw-r--r--tests/auto/controls/data/tst_tableview.qml4
7 files changed, 1036 insertions, 865 deletions
diff --git a/src/controls/Private/BasicTableView.qml b/src/controls/Private/BasicTableView.qml
new file mode 100644
index 000000000..cac673eb9
--- /dev/null
+++ b/src/controls/Private/BasicTableView.qml
@@ -0,0 +1,800 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+import QtQuick 2.4
+import QtQuick.Controls 1.3
+import QtQuick.Controls.Private 1.0
+import QtQuick.Controls.Styles 1.2
+import QtQuick.Window 2.2
+
+/*!
+ \qmltype BasicTableView
+ \internal
+ \qmlabstract
+ \inqmlmodule QtQuick.Controls.Private
+*/
+
+ScrollView {
+ id: root
+
+ /*! \qmlproperty bool BasicTableView::alternatingRowColors
+
+ This property is set to \c true if the view alternates the row color.
+ The default value is \c true.
+ */
+ property bool alternatingRowColors: true
+
+ /*! \qmlproperty bool BasicTableView::headerVisible
+
+ This property determines if the header is visible.
+ The default value is \c true.
+ */
+ property bool headerVisible: true
+
+ /*! \qmlproperty bool BasicTableView::backgroundVisible
+
+ This property determines if the background should be filled or not.
+
+ The default value is \c true.
+
+ \note The rowDelegate is not affected by this property
+ */
+ property alias backgroundVisible: colorRect.visible
+
+ /*! \qmlproperty Component BasicTableView::itemDelegate
+
+ This property defines a delegate to draw a specific cell.
+
+ In the item delegate you have access to the following special properties:
+ \list
+ \li styleData.selected - if the item is currently selected
+ \li styleData.value - the value or text for this item
+ \li styleData.textColor - the default text color for an item
+ \li styleData.row - the index of the row
+ \li styleData.column - the index of the column
+ \li styleData.elideMode - the elide mode of the column
+ \li styleData.textAlignment - the horizontal text alignment of the column
+ \li styleData.pressed - true when the item is pressed (since QtQuick.Controls 1.3)
+ \li styleData.hasActiveFocus - true when the row has focus (since QtQuick.Controls 1.3)
+ \endlist
+
+ Example:
+ \code
+ itemDelegate: Item {
+ Text {
+ anchors.verticalCenter: parent.verticalCenter
+ color: styleData.textColor
+ elide: styleData.elideMode
+ text: styleData.value
+ }
+ }
+ \endcode
+
+ \note For performance reasons, created delegates can be recycled
+ across multiple table rows. This implies that when you make use of implicit
+ properties such as \c styleData.row or \c model, these values can change
+ after the delegate has been constructed. This means that you should not assume
+ that content is fixed when \c Component.onCompleted is called, but instead rely on
+ bindings to such properties.
+ */
+ property Component itemDelegate: __style ? __style.itemDelegate : null
+
+ /*! \qmlproperty Component BasicTableView::rowDelegate
+
+ This property defines a delegate to draw a row.
+
+ In the row delegate you have access to the following special properties:
+ \list
+ \li styleData.alternate - true when the row uses the alternate background color
+ \li styleData.selected - true when the row is currently selected
+ \li styleData.row - the index of the row
+ \li styleData.hasActiveFocus - true when the row has focus (since QtQuick.Controls 1.3)
+ \li styleData.pressed - true when the row is pressed (since QtQuick.Controls 1.3)
+ \endlist
+
+ \note For performance reasons, created delegates can be recycled
+ across multiple table rows. This implies that when you make use of implicit
+ properties such as \c styleData.row or \c model, these values can change
+ after the delegate has been constructed. This means that you should not assume
+ that content is fixed when \c Component.onCompleted is called, but instead rely on
+ bindings to such properties.
+ */
+ property Component rowDelegate: __style ? __style.rowDelegate : null
+
+ /*! \qmlproperty Component BasicTableView::headerDelegate
+
+ This property defines a delegate to draw a header.
+
+ In the header delegate you have access to the following special properties:
+ \list
+ \li styleData.value - the value or text for this item
+ \li styleData.column - the index of the column
+ \li styleData.pressed - true when the column is being pressed
+ \li styleData.containsMouse - true when the column is under the mouse
+ \li styleData.textAlignment - the horizontal text alignment of the column (since QtQuickControls 1.1)
+ \endlist
+ */
+ property Component headerDelegate: __style ? __style.headerDelegate : null
+
+ /*! \qmlproperty int BasicTableView::sortIndicatorColumn
+
+ Index of the current sort column.
+ The default value is \c {0}.
+ */
+ property int sortIndicatorColumn
+
+ /*! \qmlproperty bool BasicTableView::sortIndicatorVisible
+
+ This property shows or hides the sort indicator
+ The default value is \c false.
+ \note The view itself does not sort the data.
+ */
+ property bool sortIndicatorVisible: false
+
+ /*! \qmlproperty enumeration BasicTableView::sortIndicatorOrder
+
+ This sets the sorting order of the sort indicator
+ The allowed values are:
+ \list
+ \li Qt.AscendingOrder - the default
+ \li Qt.DescendingOrder
+ \endlist
+ */
+ property int sortIndicatorOrder: Qt.AscendingOrder
+
+ /*! \qmlproperty Component BasicTableView::contentHeader
+ This is the content header of the view.
+ */
+ property alias contentHeader: listView.header
+
+ /*! \qmlproperty Component BasicTableView::contentFooter
+ This is the content footer of the view.
+ */
+ property alias contentFooter: listView.footer
+
+ /*! \qmlproperty int BasicTableView::columnCount
+ The current number of columns
+ */
+ readonly property alias columnCount: columnModel.count
+
+ /*! \qmlproperty string BasicTableView::section.property
+ \qmlproperty enumeration BasicTableView::section.criteria
+ \qmlproperty Component BasicTableView::section.delegate
+ \qmlproperty enumeration BasicTableView::section.labelPositioning
+
+ These properties determine the section labels.
+ \sa ListView::section
+ */
+ property alias section: listView.section
+
+ /*!
+ \qmlproperty enumeration BasicTableView::selectionMode
+ \since QtQuick.Controls 1.1
+
+ This enum indicates how the view responds to user selections:
+
+ The possible modes are:
+
+ \list
+
+ \li SelectionMode.NoSelection - Items cannot be selected.
+
+ \li SelectionMode.SingleSelection - When the user selects an item,
+ any already-selected item becomes unselected, and the user cannot
+ unselect the selected item. (Default)
+
+ \li SelectionMode.MultiSelection - When the user selects an item in the usual way,
+ the selection status of that item is toggled and the other items are left alone.
+
+ \li SelectionMode.ExtendedSelection - When the user selects an item in the usual way,
+ the selection is cleared and the new item selected. However, if the user presses the
+ Ctrl key when clicking on an item, the clicked item gets toggled and all other items
+ are left untouched. If the user presses the Shift key while clicking
+ on an item, all items between the current item and the clicked item are selected or unselected,
+ depending on the state of the clicked item. Multiple items can be selected by dragging the
+ mouse over them.
+
+ \li SelectionMode.ContiguousSelection - When the user selects an item in the usual way,
+ the selection is cleared and the new item selected. However, if the user presses the Shift key while
+ clicking on an item, all items between the current item and the clicked item are selected.
+
+ \endlist
+ */
+ property int selectionMode: SelectionMode.SingleSelection
+
+ /*!
+ \qmlmethod TableViewColumn BasicTableView::addColumn(object column)
+
+ 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)
+ }
+
+ /*!
+ \qmlmethod TableViewColumn BasicTableView::insertColumn(int index, object 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)
+
+ else if (object.__view) {
+ console.warn(__viewTypeName + "::insertColumn(): you cannot add a column to multiple views")
+ return null
+ }
+ if (index >= 0 && index <= columnCount && object.Accessible.role === Accessible.ColumnHeader) {
+ object.__view = root
+ columnModel.insert(index, {columnItem: object})
+ return object
+ }
+
+ if (object !== column)
+ object.destroy()
+ console.warn(__viewTypeName + "::insertColumn(): invalid argument")
+ return null
+ }
+
+ /*!
+ \qmlmethod void BasicTableView::removeColumn(int index)
+
+ Removes and destroys a column at the given \a index.
+ */
+ function removeColumn(index) {
+ if (index < 0 || index >= columnCount) {
+ console.warn(__viewTypeName + "::removeColumn(): invalid argument")
+ return
+ }
+ var column = columnModel.get(index).columnItem
+ columnModel.remove(index, 1)
+ column.destroy()
+ }
+
+ /*!
+ \qmlmethod void BasicTableView::moveColumn(int from, int to)
+
+ Moves a column \a from index \a to another.
+ */
+ function moveColumn(from, to) {
+ if (from < 0 || from >= columnCount || to < 0 || to >= columnCount) {
+ console.warn(__viewTypeName + "::moveColumn(): invalid argument")
+ return
+ }
+ columnModel.move(from, to, 1)
+ }
+
+ /*!
+ \qmlmethod TableViewColumn BasicTableView::getColumn(int index)
+
+ 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
+ }
+
+ /*!
+ \qmlmethod void BasicTableView::resizeColumnsToContents()
+
+ Resizes all columns to ensure that the column contents and the headers will fit.
+ \since QtQuick.Controls 1.2
+ */
+ function resizeColumnsToContents () {
+ for (var i = 0; i < __columns.length; ++i) {
+ var col = getColumn(i)
+ var header = repeater.itemAt(i)
+ if (col) {
+ col.__index = i
+ col.resizeToContents()
+ if (col.width < header.implicitWidth)
+ col.width = header.implicitWidth
+ }
+ }
+ }
+
+ // Internal stuff. Do not look
+
+ Component.onCompleted: {
+ for (var i = 0; i < __columns.length; ++i) {
+ var column = __columns[i]
+ if (column.Accessible.role === Accessible.ColumnHeader)
+ addColumn(column)
+ }
+ }
+
+ implicitWidth: 200
+ implicitHeight: 150
+
+ frameVisible: true
+ __scrollBarTopMargin: (__style && __style.transientScrollBars || Qt.platform.os === "osx") ? headerrow.height : 0
+ __viewTopMargin: headerrow.height
+
+ /*! \internal
+ Use this to display user-friendly messages in TableView and TreeView common functions.
+ */
+ property string __viewTypeName
+
+ /*! \internal */
+ default property alias __columns: root.data
+
+ /*! \internal */
+ property alias __currentRowItem: listView.currentItem
+
+ /*! \internal
+ This property is forwarded to TableView::currentRow, but not to any TreeView property.
+ */
+ property alias __currentRow: listView.currentIndex
+
+ /*! \internal */
+ readonly property alias __listView: listView
+
+ /*! \internal
+ Allows to override the model property in cases like TreeView,
+ where we want to use a proxy/adaptor model between the user's model
+ and whatever a ListView can swallow.
+ */
+ property var __model
+
+ /*! \internal */
+ property bool __activateItemOnSingleClick: __style ? __style.activateItemOnSingleClick : false
+
+ /*! \internal */
+ property Item __mouseArea
+
+ ListView {
+ id: listView
+ focus: true
+ activeFocusOnTab: false
+ Keys.forwardTo: [__mouseArea]
+ anchors.topMargin: headerVisible ? tableHeader.height : 0
+ anchors.fill: parent
+ currentIndex: -1
+ visible: columnCount > 0
+ interactive: Settings.hasTouchScreen
+ property var rowItemStack: [] // Used as a cache for rowDelegates
+
+ function incrementCurrentIndexBlocking() {
+ var oldIndex = __listView.currentIndex
+ __scroller.blockUpdates = true;
+ incrementCurrentIndex();
+ __scroller.blockUpdates = false;
+ return oldIndex !== __listView.currentIndex
+ }
+
+ function decrementCurrentIndexBlocking() {
+ var oldIndex = __listView.currentIndex
+ __scroller.blockUpdates = true;
+ decrementCurrentIndex();
+ __scroller.blockUpdates = false;
+ return oldIndex !== __listView.currentIndex
+ }
+
+ function scrollIfNeeded(key) {
+ var diff = key === Qt.Key_PageDown ? height :
+ key === Qt.Key_PageUp ? -height : 0
+ if (diff !== 0)
+ __verticalScrollBar.value += diff
+ }
+
+ SystemPalette {
+ id: palette
+ colorGroup: enabled ? SystemPalette.Active : SystemPalette.Disabled
+ }
+
+ Rectangle {
+ id: colorRect
+ parent: viewport
+ anchors.fill: parent
+ color: __style ? __style.backgroundColor : palette.base
+ z: -2
+ }
+
+ // Fills extra rows with alternate color
+ Column {
+ id: rowfiller
+ Loader {
+ id: rowSizeItem
+ sourceComponent: root.rowDelegate
+ visible: false
+ property QtObject styleData: QtObject {
+ property bool alternate: false
+ property bool selected: false
+ property bool hasActiveFocus: false
+ property bool pressed: false
+ }
+ }
+ property int rowHeight: rowSizeItem.implicitHeight
+ property int paddedRowCount: height/rowHeight
+
+ y: listView.contentHeight - listView.contentY + listView.originY
+ width: parent.width
+ visible: alternatingRowColors
+ height: viewport.height - listView.contentHeight
+ Repeater {
+ model: visible ? parent.paddedRowCount : 0
+ Loader {
+ width: rowfiller.width
+ height: rowfiller.rowHeight
+ sourceComponent: root.rowDelegate
+ property QtObject styleData: QtObject {
+ readonly property bool alternate: (index + __listView.count) % 2 === 1
+ readonly property bool selected: false
+ readonly property bool hasActiveFocus: false
+ readonly property bool pressed: false
+ }
+ readonly property var model: null
+ readonly property var modelData: null
+ }
+ }
+ }
+
+ ListModel {
+ id: columnModel
+ }
+
+ highlightFollowsCurrentItem: true
+ model: root.__model
+
+ delegate: FocusScope {
+ id: rowItemContainer
+
+ activeFocusOnTab: false
+ z: rowItem.activeFocus ? 0.7 : rowItem.itemSelected ? 0.5 : 0
+
+ property Item rowItem
+ // We recycle instantiated row items to speed up list scrolling
+
+ Component.onDestruction: {
+ // move the rowItem back in cache
+ if (rowItem) {
+ rowItem.visible = false;
+ rowItem.parent = null;
+ rowItem.rowIndex = -1;
+ listView.rowItemStack.push(rowItem); // return rowItem to cache
+ }
+ }
+
+ Component.onCompleted: {
+ // retrieve row item from cache
+ if (listView.rowItemStack.length > 0)
+ rowItem = listView.rowItemStack.pop();
+ else
+ rowItem = rowComponent.createObject(listView);
+
+ // Bind container to item size
+ rowItemContainer.width = Qt.binding( function() { return rowItem.width });
+ rowItemContainer.height = Qt.binding( function() { return rowItem.height });
+
+ // Reassign row-specific bindings
+ rowItem.rowIndex = Qt.binding( function() { return model.index });
+ rowItem.itemModelData = Qt.binding( function() { return typeof modelData === "undefined" ? null : modelData });
+ rowItem.itemModel = Qt.binding( function() { return model });
+ rowItem.parent = rowItemContainer;
+ rowItem.visible = true;
+ }
+ }
+
+ Component {
+ id: rowComponent
+
+ FocusScope {
+ id: rowitem
+ visible: false
+
+ property int rowIndex
+ property var itemModelData
+ property var itemModel
+ property bool itemSelected: __mouseArea.selected(rowIndex)
+ property bool alternate: alternatingRowColors && rowIndex % 2 === 1
+ readonly property color itemTextColor: itemSelected ? __style.highlightedTextColor : __style.textColor
+
+ width: itemrow.width
+ height: rowstyle.height
+
+ onActiveFocusChanged: {
+ if (activeFocus)
+ listView.currentIndex = rowIndex
+ }
+
+ Loader {
+ id: rowstyle
+ // row delegate
+ sourceComponent: rowitem.itemModel !== undefined ? root.rowDelegate : null
+ // Row fills the view width regardless of item size
+ // But scrollbar should not adjust to it
+ height: item ? item.height : 16
+ width: parent.width + __horizontalScrollBar.width
+ x: listView.contentX
+
+ // these properties are exposed to the row delegate
+ // Note: these properties should be mirrored in the row filler as well
+ property QtObject styleData: QtObject {
+ readonly property int row: rowitem.rowIndex
+ readonly property bool alternate: rowitem.alternate
+ readonly property bool selected: rowitem.itemSelected
+ readonly property bool hasActiveFocus: rowitem.activeFocus
+ readonly property bool pressed: rowitem.rowIndex === __mouseArea.pressedRow
+ }
+ readonly property var model: rowitem.itemModel
+ readonly property var modelData: rowitem.itemModelData
+ }
+ Row {
+ id: itemrow
+ height: parent.height
+ Repeater {
+ id: repeater
+ model: columnModel
+
+ Loader {
+ id: itemDelegateLoader
+ width: columnItem.width
+ height: parent ? parent.height : 0
+ visible: columnItem.visible
+ sourceComponent: rowitem.itemModel !== undefined ? // delays construction until model is initialized
+ (columnItem.delegate ? columnItem.delegate : itemDelegate) : null
+
+ // these properties are exposed to the item delegate
+ readonly property var model: itemModel
+ readonly property var modelData: itemModelData
+
+ property QtObject styleData: QtObject {
+ readonly property int row: rowitem.rowIndex
+ readonly property int column: index
+ readonly property int elideMode: columnItem.elideMode
+ readonly property int textAlignment: columnItem.horizontalAlignment
+ readonly property bool selected: rowitem.itemSelected
+ readonly property bool hasActiveFocus: rowitem.activeFocus
+ readonly property bool pressed: row === __mouseArea.pressedRow && column === __mouseArea.pressedColumn
+ readonly property color textColor: rowitem.itemTextColor
+ readonly property string role: columnItem.role
+ readonly property var value: (itemModel && itemModel.hasOwnProperty(role))
+ ? itemModel[role] // Qml ListModel and QAbstractItemModel
+ : modelData && modelData.hasOwnProperty(role)
+ ? modelData[role] // QObjectList / QObject
+ : modelData != undefined ? modelData : "" // Models without role
+ }
+ }
+ }
+ }
+ }
+ }
+
+ Item {
+ id: tableHeader
+ clip: true
+ parent: __scroller
+ visible: headerVisible
+ anchors.top: parent.top
+ anchors.topMargin: viewport.anchors.topMargin
+ anchors.leftMargin: viewport.anchors.leftMargin
+ anchors.margins: viewport.anchors.margins
+ anchors.rightMargin: (frameVisible ? __scroller.rightMargin : 0) +
+ (__scroller.outerFrame && __scrollBarTopMargin ? 0
+ : __verticalScrollBar.width + __scroller.scrollBarSpacing + root.__style.padding.right)
+
+ anchors.left: parent.left
+ anchors.right: parent.right
+
+ height: headerrow.height
+
+ Row {
+ id: headerrow
+ x: -listView.contentX
+
+ Repeater {
+ id: repeater
+
+ property int targetIndex: -1
+ property int dragIndex: -1
+
+ model: columnModel
+
+ delegate: Item {
+ id: headerRowDelegate
+ readonly property int column: index
+ z:-index
+ width: modelData.width
+ implicitWidth: columnCount === 1 ? viewport.width + __verticalScrollBar.width : headerStyle.implicitWidth
+ visible: modelData.visible
+ height: headerStyle.height
+
+ Loader {
+ id: headerStyle
+ sourceComponent: root.headerDelegate
+ anchors.left: parent.left
+ anchors.right: parent.right
+ property QtObject styleData: QtObject {
+ readonly property string value: modelData.title
+ readonly property bool pressed: headerClickArea.pressed
+ readonly property bool containsMouse: headerClickArea.containsMouse
+ readonly property int column: index
+ readonly property int textAlignment: modelData.horizontalAlignment
+ readonly property bool resizable: modelData.resizable
+ }
+ }
+
+ Rectangle{
+ id: targetmark
+ width: parent.width
+ height:parent.height
+ opacity: (index === repeater.targetIndex && repeater.targetIndex !== repeater.dragIndex) ? 0.5 : 0
+ Behavior on opacity { NumberAnimation { duration: 160 } }
+ color: palette.highlight
+ visible: modelData.movable
+ }
+
+ MouseArea{
+ id: headerClickArea
+ drag.axis: Qt.YAxis
+ hoverEnabled: true
+ anchors.fill: parent
+ onClicked: {
+ if (sortIndicatorColumn === index)
+ sortIndicatorOrder = sortIndicatorOrder === Qt.AscendingOrder ? Qt.DescendingOrder : Qt.AscendingOrder
+ sortIndicatorColumn = index
+ }
+ // Here we handle moving header sections
+ // NOTE: the direction is different from the master branch
+ // so this indicates that I am using an invalid assumption on item ordering
+ onPositionChanged: {
+ if (modelData.movable && pressed && columnCount > 1) { // only do this while dragging
+ for (var h = columnCount-1 ; h >= 0 ; --h) {
+ if (drag.target.x + listView.contentX + headerRowDelegate.width/2 > headerrow.children[h].x) {
+ repeater.targetIndex = h
+ break
+ }
+ }
+ }
+ }
+
+ onPressed: {
+ repeater.dragIndex = index
+ }
+
+ onReleased: {
+ if (repeater.targetIndex >= 0 && repeater.targetIndex !== index ) {
+ var targetColumn = columnModel.get(repeater.targetIndex).columnItem
+ if (targetColumn.movable) {
+ columnModel.move(index, repeater.targetIndex, 1)
+ if (sortIndicatorColumn === index)
+ sortIndicatorColumn = repeater.targetIndex
+ }
+ }
+ repeater.targetIndex = -1
+ repeater.dragIndex = -1
+ }
+ drag.target: modelData.movable && columnCount > 1 ? draghandle : null
+ }
+
+ Loader {
+ id: draghandle
+ property QtObject styleData: QtObject{
+ readonly property string value: modelData.title
+ readonly property bool pressed: headerClickArea.pressed
+ readonly property bool containsMouse: headerClickArea.containsMouse
+ readonly property int column: index
+ readonly property int textAlignment: modelData.horizontalAlignment
+ }
+ parent: tableHeader
+ x: __implicitX
+ property double __implicitX: headerRowDelegate.x - listView.contentX
+ width: modelData.width
+ height: parent.height
+ sourceComponent: root.headerDelegate
+ visible: headerClickArea.pressed
+ onVisibleChanged: {
+ if (!visible)
+ x = Qt.binding(function () { return __implicitX })
+ }
+ opacity: 0.5
+ }
+
+
+ MouseArea {
+ id: headerResizeHandle
+ property int offset: 0
+ readonly property int minimumSize: 20
+ preventStealing: true
+ anchors.rightMargin: -width/2
+ width: Settings.hasTouchScreen ? Screen.pixelDensity * 3.5 : 16
+ height: parent.height
+ anchors.right: parent.right
+ enabled: modelData.resizable && columnCount > 0
+ onPositionChanged: {
+ var newHeaderWidth = modelData.width + (mouseX - offset)
+ modelData.width = Math.max(minimumSize, newHeaderWidth)
+ }
+
+ onDoubleClicked: getColumn(index).resizeToContents()
+ onPressedChanged: if (pressed) offset=mouseX
+ cursorShape: enabled && repeater.dragIndex==-1 ? Qt.SplitHCursor : Qt.ArrowCursor
+ }
+ }
+ }
+
+ onWidthChanged: listView.contentWidth = width
+ }
+
+ Loader {
+ id: loader
+ property QtObject styleData: QtObject{
+ readonly property string value: ""
+ readonly property bool pressed: false
+ readonly property bool containsMouse: false
+ readonly property int column: -1
+ readonly property int textAlignment: Text.AlignLeft
+ }
+
+ anchors.top: parent.top
+ anchors.right: parent.right
+ anchors.bottom: headerrow.bottom
+ anchors.rightMargin: -2
+ sourceComponent: root.headerDelegate
+ width: root.width - headerrow.width + 2
+ visible: root.columnCount
+ z:-1
+ }
+ }
+
+ function columnAt(offset) {
+ var item = headerrow.childAt(offset, 0)
+ return item ? item.column : -1
+ }
+ }
+}
diff --git a/src/controls/Private/private.pri b/src/controls/Private/private.pri
index e69d0a295..3d6a71624 100644
--- a/src/controls/Private/private.pri
+++ b/src/controls/Private/private.pri
@@ -61,6 +61,7 @@ PRIVATE_QML_FILES += \
$$PWD/EditMenu_base.qml \
$$PWD/EditMenu_ios.qml \
$$PWD/ToolMenuButton.qml \
+ $$PWD/BasicTableView.qml \
$$PWD/qmldir
QML_FILES += $$PRIVATE_QML_FILES
diff --git a/src/controls/Private/qmldir b/src/controls/Private/qmldir
index 82e1a9859..c2c2d7ca9 100644
--- a/src/controls/Private/qmldir
+++ b/src/controls/Private/qmldir
@@ -33,3 +33,4 @@ EditMenu 1.0 EditMenu.qml
EditMenu_base 1.0 EditMenu_base.qml
EditMenu_ios 1.0 EditMenu_ios.qml
ToolMenuButton 1.0 ToolMenuButton.qml
+BasicTableView 1.0 BasicTableView.qml
diff --git a/src/controls/TableView.qml b/src/controls/TableView.qml
index 218f21256..629c95dd0 100644
--- a/src/controls/TableView.qml
+++ b/src/controls/TableView.qml
@@ -35,7 +35,7 @@
****************************************************************************/
import QtQuick 2.2
-import QtQuick.Controls 1.2
+import QtQuick.Controls 1.3
import QtQuick.Controls.Private 1.0
import QtQuick.Controls.Styles 1.1
import QtQuick.Window 2.1
@@ -110,7 +110,7 @@ import QtQuick.Window 2.1
assigning a \l {QtQuick.Controls.Styles::TableViewStyle}{TableViewStyle}.
*/
-ScrollView {
+BasicTableView {
id: root
/*! \qmlproperty model TableView::model
@@ -124,160 +124,29 @@ ScrollView {
\code
model: ListModel {
- ListElement{ column1: "value 1" ; column2: "value 2" }
- ListElement{ column1: "value 3" ; column2: "value 4" }
+ ListElement {
+ column1: "value 1"
+ column2: "value 2"
+ }
+ ListElement {
+ column1: "value 3"
+ column2: "value 4"
+ }
}
\endcode
\sa {qml-data-models}{Data Models}
*/
property var model
- /*! This property is set to \c true if the view alternates the row color.
- The default value is \c true. */
- property bool alternatingRowColors: true
-
- /*! This property determines if the header is visible.
- The default value is \c true. */
- property bool headerVisible: true
-
- /*! \qmlproperty bool TableView::backgroundVisible
-
- This property determines if the background should be filled or not.
-
- The default value is \c true.
-
- \note The rowDelegate is not affected by this property
- */
- property alias backgroundVisible: colorRect.visible
-
- /*! This property defines a delegate to draw a specific cell.
-
- In the item delegate you have access to the following special properties:
- \list
- \li styleData.selected - if the item is currently selected
- \li styleData.value - the value or text for this item
- \li styleData.textColor - the default text color for an item
- \li styleData.row - the index of the row
- \li styleData.column - the index of the column
- \li styleData.elideMode - the elide mode of the column
- \li styleData.textAlignment - the horizontal text alignment of the column
- \li styleData.pressed - true when the item is pressed (since QtQuick.Controls 1.3)
- \li styleData.hasActiveFocus - true when the row has focus (since QtQuick.Controls 1.3)
- \endlist
-
- Example:
- \code
- itemDelegate: Item {
- Text {
- anchors.verticalCenter: parent.verticalCenter
- color: styleData.textColor
- elide: styleData.elideMode
- text: styleData.value
- }
- }
- \endcode
-
- \note For performance reasons, created delegates can be recycled
- across multiple table rows. This implies that when you make use of implicit
- properties such as \c styleData.row or \c model, these values can change
- after the delegate has been constructed. This means that you should not assume
- that content is fixed when \c Component.onCompleted is called, but instead rely on
- bindings to such properties.
- */
- property Component itemDelegate: __style ? __style.itemDelegate : null
-
- /*! This property defines a delegate to draw a row.
-
- In the row delegate you have access to the following special properties:
- \list
- \li styleData.alternate - true when the row uses the alternate background color
- \li styleData.selected - true when the row is currently selected
- \li styleData.row - the index of the row
- \li styleData.hasActiveFocus - true when the row has focus
- \li styleData.pressed - true when the row is pressed (since QtQuick.Controls 1.3)
- \endlist
-
- \note For performance reasons, created delegates can be recycled
- across multiple table rows. This implies that when you make use of implicit
- properties such as \c styleData.row or \c model, these values can change
- after the delegate has been constructed. This means that you should not assume
- that content is fixed when \c Component.onCompleted is called, but instead rely on
- bindings to such properties.
- */
- property Component rowDelegate: __style ? __style.rowDelegate : null
-
- /*! This property defines a delegate to draw a header.
-
- In the header delegate you have access to the following special properties:
- \list
- \li styleData.value - the value or text for this item
- \li styleData.column - the index of the column
- \li styleData.pressed - true when the column is being pressed
- \li styleData.containsMouse - true when the column is under the mouse
- \li styleData.textAlignment - the horizontal text alignment of the column (since QtQuickControls 1.1)
- \endlist
- */
- property Component headerDelegate: __style ? __style.headerDelegate : null
-
- /*! Index of the current sort column.
- The default value is \c {0}. */
- property int sortIndicatorColumn
-
- /*! This property shows or hides the sort indicator
- The default value is \c false.
- \note The view itself does not sort the data. */
- property bool sortIndicatorVisible: false
-
- /*!
- \qmlproperty enumeration TableView::sortIndicatorOrder
-
- This sets the sorting order of the sort indicator
- The allowed values are:
- \list
- \li Qt.AscendingOrder - the default
- \li Qt.DescendingOrder
- \endlist
- */
- property int sortIndicatorOrder: Qt.AscendingOrder
-
- /*! \internal */
- default property alias __columns: root.data
-
- /*! \qmlproperty Component TableView::contentHeader
- This is the content header of the TableView */
- property alias contentHeader: listView.header
-
- /*! \qmlproperty Component TableView::contentFooter
- This is the content footer of the TableView */
- property alias contentFooter: listView.footer
-
/*! \qmlproperty int TableView::rowCount
The current number of rows */
- readonly property alias rowCount: listView.count
-
- /*! \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
- \qmlproperty Component TableView::section.delegate
- \qmlproperty enumeration TableView::section.labelPositioning
- These properties determine the section labels.
- \sa ListView::section */
- property alias section: listView.section
+ readonly property int rowCount: __listView.count
/*! \qmlproperty int TableView::currentRow
The current row index of the view.
The default value is \c -1 to indicate that no row is selected.
*/
- property alias currentRow: listView.currentIndex
-
- /*! \internal */
- property alias __currentRowItem: listView.currentItem
-
- /*! \internal */
- property alias __listView: listView
+ property alias currentRow: root.__currentRow
/*! \qmlsignal TableView::activated(int row)
@@ -332,34 +201,33 @@ ScrollView {
/*!
\qmlmethod TableView::positionViewAtRow( int row, PositionMode mode )
- Positions the view such that the specified \a row is at the position defined by \a mode:
- \list
- \li ListView.Beginning - position item at the top of the view.
- \li ListView.Center - position item in the center of the view.
- \li ListView.End - position item at bottom of the view.
- \li ListView.Visible - if any part of the item is visible then take no action, otherwise bring the item into view.
- \li ListView.Contain - ensure the entire item is visible. If the item is larger than the view the item is positioned
- at the top of the view.
- \endlist
+ Positions the view such that the specified \a row is at the position defined by \a mode:
+ \list
+ \li ListView.Beginning - position item at the top of the view.
+ \li ListView.Center - position item in the center of the view.
+ \li ListView.End - position item at bottom of the view.
+ \li ListView.Visible - if any part of the item is visible then take no action, otherwise bring the item into view.
+ \li ListView.Contain - ensure the entire item is visible. If the item is larger than the view the item is positioned
+ at the top of the view.
+ \endlist
- If positioning the \a row creates an empty space at the beginning
- or end of the view, then the view is positioned at the boundary.
+ If positioning the \a row creates an empty space at the beginning
+ or end of the view, then the view is positioned at the boundary.
- For example, to position the view at the end at startup:
+ For example, to position the view at the end at startup:
- \code
- Component.onCompleted: table.positionViewAtRow(rowCount -1, ListView.Contain)
- \endcode
+ \code
+ Component.onCompleted: table.positionViewAtRow(rowCount -1, ListView.Contain)
+ \endcode
- Depending on how the model is populated, the model may not be ready when
- TableView Component.onCompleted is called. In that case you may need to
- delay the call to positionViewAtRow by using a \l {QtQml::Timer}{Timer}.
+ Depending on how the model is populated, the model may not be ready when
+ TableView Component.onCompleted is called. In that case you may need to
+ delay the call to positionViewAtRow by using a \l {QtQml::Timer}{Timer}.
- \note This method should only be called after the component has completed.
+ \note This method should only be called after the component has completed.
*/
-
function positionViewAtRow(row, mode) {
- listView.positionViewAtIndex(row, mode)
+ __listView.positionViewAtIndex(row, mode)
}
/*!
@@ -370,427 +238,237 @@ ScrollView {
\note This method should only be called after the component has completed.
*/
-
function rowAt(x, y) {
- var obj = root.mapToItem(listView.contentItem, x, y)
- 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)
-
- else if (object.__view) {
- console.warn("TableView::insertColumn(): you cannot add a column to multiple views")
- return null
- }
- if (index >= 0 && index <= columnCount && object.Accessible.role === Accessible.ColumnHeader) {
- object.__view = root
- 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
+ var obj = root.mapToItem(__listView.contentItem, x, y)
+ return __listView.indexAt(obj.x, obj.y)
}
/*! \qmlproperty Selection TableView::selection
- \since QtQuick.Controls 1.1
-
- This property contains the current row-selection of the \l TableView.
- The selection allows you to select, deselect or iterate over selected rows.
-
- \list
- \li function \b clear() - deselects all rows
- \li function \b selectAll() - selects all rows
- \li function \b select(from, to) - select a range
- \li functton \b deselect(from, to) - de-selects a range
- \li function \b forEach(callback) - iterates over all selected rows
- \li function \b contains(index) - checks whether the selection includes the given index
- \li signal \b selectionChanged() - the current row selection changed
- \li readonly property int \b count - the number of selected rows
- \endlist
-
- \b Example:
- \code
- tableview.selection.select(0) // select row index 0
-
- tableview.selection.select(1, 3) // select row indexes 1, 2 and 3
-
- tableview.selection.deselect(0, 1) // deselects row index 0 and 1
-
- tableview.selection.deselect(2) // deselects row index 2
- \endcode
-
- \b Example: To iterate over selected indexes, you can pass a callback function.
- \a rowIndex is passed as as an argument to the callback function.
- \code
- tableview.selection.forEach( function(rowIndex) {console.log(rowIndex)} )
- \endcode
-
- */
-
- readonly property alias selection: selectionObject
-
- /*!
- \qmlproperty enumeration TableView::selectionMode
\since QtQuick.Controls 1.1
- This enum indicates how the view responds to user selections:
-
- The possible modes are:
+ This property contains the current row-selection of the \l TableView.
+ The selection allows you to select, deselect or iterate over selected rows.
\list
+ \li function \b clear() - deselects all rows
+ \li function \b selectAll() - selects all rows
+ \li function \b select(from, to) - select a range
+ \li functton \b deselect(from, to) - de-selects a range
+ \li function \b forEach(callback) - iterates over all selected rows
+ \li function \b contains(index) - checks whether the selection includes the given index
+ \li signal \b selectionChanged() - the current row selection changed
+ \li readonly property int \b count - the number of selected rows
+ \endlist
- \li SelectionMode.NoSelection - Items cannot be selected.
-
- \li SelectionMode.SingleSelection - When the user selects an item,
- any already-selected item becomes unselected, and the user cannot
- unselect the selected item. (Default)
+ \b Example:
+ \code
+ tableview.selection.select(0) // select row index 0
- \li SelectionMode.MultiSelection - When the user selects an item in the usual way,
- the selection status of that item is toggled and the other items are left alone.
+ tableview.selection.select(1, 3) // select row indexes 1, 2 and 3
- \li SelectionMode.ExtendedSelection - When the user selects an item in the usual way,
- the selection is cleared and the new item selected. However, if the user presses the
- Ctrl key when clicking on an item, the clicked item gets toggled and all other items
- are left untouched. If the user presses the Shift key while clicking
- on an item, all items between the current item and the clicked item are selected or unselected,
- depending on the state of the clicked item. Multiple items can be selected by dragging the
- mouse over them.
+ tableview.selection.deselect(0, 1) // deselects row index 0 and 1
- \li SelectionMode.ContiguousSelection - When the user selects an item in the usual way,
- the selection is cleared and the new item selected. However, if the user presses the Shift key while
- clicking on an item, all items between the current item and the clicked item are selected.
+ tableview.selection.deselect(2) // deselects row index 2
+ \endcode
- \endlist
+ \b Example: To iterate over selected indexes, you can pass a callback function.
+ \a rowIndex is passed as as an argument to the callback function.
+ \code
+ tableview.selection.forEach( function(rowIndex) {console.log(rowIndex)} )
+ \endcode
*/
- property int selectionMode: SelectionMode.SingleSelection
-
- /*! Resizes all columns to ensure that the column contents and the headers will fit.
- \since QtQuick.Controls 1.2 */
- function resizeColumnsToContents () {
- for (var i = 0; i < __columns.length; ++i) {
- var col = getColumn(i)
- var header = repeater.itemAt(i)
- if (col) {
- col.__index = i
- col.resizeToContents()
- if (col.width < header.implicitWidth)
- col.width = header.implicitWidth
- }
- }
- }
+ readonly property alias selection: selectionObject
- Component.onCompleted: {
- for (var i = 0; i < __columns.length; ++i) {
- var column = __columns[i]
- if (column.Accessible.role === Accessible.ColumnHeader)
- addColumn(column)
- }
- }
+ onModelChanged: selection.clear()
style: Qt.createComponent(Settings.style + "/TableViewStyle.qml", root)
-
Accessible.role: Accessible.Table
- implicitWidth: 200
- implicitHeight: 150
-
- frameVisible: true
- __scrollBarTopMargin: (__style && __style.transientScrollBars || Qt.platform.os === "osx") ? headerrow.height : 0
- __viewTopMargin: headerrow.height
-
- /*! \internal */
- property bool __activateItemOnSingleClick: __style ? __style.activateItemOnSingleClick : false
+ __viewTypeName: "TableView"
+ __model: model
- /*! \internal */
- function __decrementCurrentIndex() {
- __scroller.blockUpdates = true;
- listView.decrementCurrentIndex();
- __scroller.blockUpdates = false;
+ __mouseArea: MouseArea {
+ id: mousearea
- var newIndex = listView.indexAt(0, listView.contentY)
- if (newIndex !== -1) {
- if (selectionMode > SelectionMode.SingleSelection)
- mousearea.dragRow = newIndex
- else if (selectionMode === SelectionMode.SingleSelection)
- selection.__selectOne(newIndex)
- }
- }
+ parent: __listView
+ width: __listView.width
+ height: __listView.height
+ z: -1
+ propagateComposedEvents: true
+ focus: true
- /*! \internal */
- function __incrementCurrentIndex() {
- __scroller.blockUpdates = true;
- listView.incrementCurrentIndex();
- __scroller.blockUpdates = false;
-
- var newIndex = Math.max(0, listView.indexAt(0, listView.height + listView.contentY))
- if (newIndex !== -1) {
- if (selectionMode > SelectionMode.SingleSelection)
- mousearea.dragRow = newIndex
- else if (selectionMode === SelectionMode.SingleSelection)
- selection.__selectOne(newIndex)
+ property bool autoincrement: false
+ property bool autodecrement: false
+ property int previousRow: 0
+ property int clickedRow: -1
+ property int dragRow: -1
+ property int firstKeyRow: -1
+ property int pressedRow: -1
+ property int pressedColumn: -1
+
+ TableViewSelection {
+ id: selectionObject
}
- }
-
- onModelChanged: selection.clear()
- ListView {
- id: listView
- focus: true
- activeFocusOnTab: false
- anchors.topMargin: headerVisible ? tableHeader.height : 0
- anchors.fill: parent
- currentIndex: -1
- visible: columnCount > 0
- interactive: Settings.hasTouchScreen
- property var rowItemStack: [] // Used as a cache for rowDelegates
-
- SystemPalette {
- id: palette
- colorGroup: enabled ? SystemPalette.Active : SystemPalette.Disabled
- }
+ function selected(rowIndex) {
+ if (dragRow > -1 && (rowIndex >= clickedRow && rowIndex <= dragRow
+ || rowIndex <= clickedRow && rowIndex >= dragRow))
+ return selection.contains(clickedRow)
- Rectangle {
- id: colorRect
- parent: viewport
- anchors.fill: parent
- color: __style ? __style.backgroundColor : palette.base
- z: -2
+ return selection.count && selection.contains(rowIndex)
}
- MouseArea {
- id: mousearea
-
- z: -1
- anchors.fill: listView
- propagateComposedEvents: true
-
- property bool autoincrement: false
- property bool autodecrement: false
- property int mouseModifiers: 0
- property int previousRow: 0
- property int clickedRow: -1
- property int dragRow: -1
- property int firstKeyRow: -1
- property int pressedRow: -1
- property int pressedColumn: -1
-
- onReleased: {
- pressedRow = -1
- pressedColumn = -1
- autoincrement = false
- autodecrement = false
- var clickIndex = listView.indexAt(0, mouseY + listView.contentY)
- if (clickIndex > -1) {
- if (Settings.hasTouchScreen) {
- listView.currentIndex = clickIndex
- mouseSelect(clickIndex, mouse.modifiers)
- }
- previousRow = clickIndex
+ onReleased: {
+ pressedRow = -1
+ pressedColumn = -1
+ autoincrement = false
+ autodecrement = false
+ var clickIndex = __listView.indexAt(0, mouseY + __listView.contentY)
+ if (clickIndex > -1) {
+ if (Settings.hasTouchScreen) {
+ __listView.currentIndex = clickIndex
+ mouseSelect(clickIndex, mouse.modifiers)
}
+ previousRow = clickIndex
+ }
- if (mousearea.dragRow >= 0) {
- selection.__select(selection.contains(mousearea.clickedRow), mousearea.clickedRow, mousearea.dragRow)
- mousearea.dragRow = -1
- }
+ if (mousearea.dragRow >= 0) {
+ selection.__select(selection.contains(mousearea.clickedRow), mousearea.clickedRow, mousearea.dragRow)
+ mousearea.dragRow = -1
}
+ }
- // Handle vertical scrolling whem dragging mouse outside boundraries
- Timer { running: mousearea.autoincrement && __verticalScrollBar.visible; repeat: true; interval: 20 ; onTriggered: __incrementCurrentIndex()}
- Timer { running: mousearea.autodecrement && __verticalScrollBar.visible; repeat: true; interval: 20 ; onTriggered: __decrementCurrentIndex()}
-
- onPositionChanged: {
- if (mouseY > listView.height && pressed) {
- if (autoincrement) return;
- autodecrement = false;
- autoincrement = true;
- } else if (mouseY < 0 && pressed) {
- if (autodecrement) return;
- autoincrement = false;
- autodecrement = true;
- } else {
- autoincrement = false;
- autodecrement = false;
- }
+ function decrementCurrentIndex() {
+ __listView.decrementCurrentIndexBlocking();
- if (pressed && containsMouse) {
- pressedRow = Math.max(0, listView.indexAt(0, mouseY + listView.contentY))
- pressedColumn = headerrow.columnAt(mouseX)
- if (!Settings.hasTouchScreen) {
- if (pressedRow >= 0 && pressedRow !== currentRow) {
- listView.currentIndex = pressedRow;
- if (selectionMode === SelectionMode.SingleSelection) {
- selection.__selectOne(pressedRow)
- } else if (selectionMode > 1) {
- dragRow = pressedRow
- }
- }
- }
- }
- mouseModifiers = mouse.modifiers
+ var newIndex = __listView.indexAt(0, __listView.contentY)
+ if (newIndex !== -1) {
+ if (selectionMode > SelectionMode.SingleSelection)
+ mousearea.dragRow = newIndex
+ else if (selectionMode === SelectionMode.SingleSelection)
+ selection.__selectOne(newIndex)
}
+ }
- onClicked: {
- var clickIndex = listView.indexAt(0, mouseY + listView.contentY)
- if (clickIndex > -1) {
- if (root.__activateItemOnSingleClick)
- root.activated(clickIndex)
- root.clicked(clickIndex)
- }
- }
+ function incrementCurrentIndex() {
+ __listView.incrementCurrentIndexBlocking();
- onPressed: {
- pressedRow = listView.indexAt(0, mouseY + listView.contentY)
- pressedColumn = headerrow.columnAt(mouseX)
- listView.forceActiveFocus()
- if (pressedRow > -1 && !Settings.hasTouchScreen) {
- listView.currentIndex = pressedRow
- mouseSelect(pressedRow, mouse.modifiers)
- mousearea.clickedRow = pressedRow
- }
- mouseModifiers = mouse.modifiers
+ var newIndex = Math.max(0, __listView.indexAt(0, __listView.height + __listView.contentY))
+ if (newIndex !== -1) {
+ if (selectionMode > SelectionMode.SingleSelection)
+ mousearea.dragRow = newIndex
+ else if (selectionMode === SelectionMode.SingleSelection)
+ selection.__selectOne(newIndex)
}
+ }
- onExited: {
- mousearea.pressedRow = -1
- mousearea.pressedColumn = -1
- }
+ // Handle vertical scrolling whem dragging mouse outside boundraries
+ Timer {
+ running: mousearea.autoincrement && __verticalScrollBar.visible
+ repeat: true
+ interval: 20
+ onTriggered: mousearea.incrementCurrentIndex()
+ }
- onCanceled: {
- mousearea.pressedRow = -1
- mousearea.pressedColumn = -1
+ Timer {
+ running: mousearea.autodecrement && __verticalScrollBar.visible
+ repeat: true
+ interval: 20
+ onTriggered: mousearea.decrementCurrentIndex()
+ }
+
+ onPositionChanged: {
+ if (mouseY > __listView.height && pressed) {
+ if (autoincrement) return;
+ autodecrement = false;
+ autoincrement = true;
+ } else if (mouseY < 0 && pressed) {
+ if (autodecrement) return;
+ autoincrement = false;
+ autodecrement = true;
+ } else {
+ autoincrement = false;
+ autodecrement = false;
}
- function mouseSelect(index, modifiers) {
- if (selectionMode) {
- if (modifiers & Qt.ShiftModifier && (selectionMode === SelectionMode.ExtendedSelection)) {
- selection.select(previousRow, index)
- } else if (selectionMode === SelectionMode.MultiSelection ||
- (selectionMode === SelectionMode.ExtendedSelection && modifiers & Qt.ControlModifier)) {
- selection.__select(!selection.contains(index) , index)
- } else {
- selection.__selectOne(index)
+ if (pressed && containsMouse) {
+ pressedRow = Math.max(0, __listView.indexAt(0, mouseY + __listView.contentY))
+ pressedColumn = __listView.columnAt(mouseX)
+ if (!Settings.hasTouchScreen) {
+ if (pressedRow >= 0 && pressedRow !== currentRow) {
+ __listView.currentIndex = pressedRow;
+ if (selectionMode === SelectionMode.SingleSelection) {
+ selection.__selectOne(pressedRow)
+ } else if (selectionMode > 1) {
+ dragRow = pressedRow
+ }
}
}
}
+ }
- onDoubleClicked: {
- var clickIndex = listView.indexAt(0, mouseY + listView.contentY)
- if (clickIndex > -1) {
- if (!root.__activateItemOnSingleClick)
- root.activated(clickIndex)
- root.doubleClicked(clickIndex)
- }
+ onClicked: {
+ var clickIndex = __listView.indexAt(0, mouseY + __listView.contentY)
+ if (clickIndex > -1) {
+ if (root.__activateItemOnSingleClick)
+ root.activated(clickIndex)
+ root.clicked(clickIndex)
}
+ }
- onPressAndHold: {
- var pressIndex = listView.indexAt(0, mouseY + listView.contentY)
- if (pressIndex > -1)
- root.pressAndHold(pressIndex)
+ onPressed: {
+ pressedRow = __listView.indexAt(0, mouseY + __listView.contentY)
+ pressedColumn = __listView.columnAt(mouseX)
+ __listView.forceActiveFocus()
+ if (pressedRow > -1 && !Settings.hasTouchScreen) {
+ __listView.currentIndex = pressedRow
+ mouseSelect(pressedRow, mouse.modifiers)
+ mousearea.clickedRow = pressedRow
}
+ }
- // Note: with boolean preventStealing we are keeping the flickable from
- // eating our mouse press events
- preventStealing: !Settings.hasTouchScreen
+ onExited: {
+ mousearea.pressedRow = -1
+ mousearea.pressedColumn = -1
+ }
- TableViewSelection { id: selectionObject }
+ onCanceled: {
+ mousearea.pressedRow = -1
+ mousearea.pressedColumn = -1
}
- // Fills extra rows with alternate color
- Column {
- id: rowfiller
- Loader {
- id: rowSizeItem
- sourceComponent: root.rowDelegate
- visible: false
- property QtObject styleData: QtObject {
- property bool alternate: false
- property bool selected: false
- property bool hasActiveFocus: false
- property bool pressed: false
+ function mouseSelect(index, modifiers) {
+ if (selectionMode) {
+ if (modifiers & Qt.ShiftModifier && (selectionMode === SelectionMode.ExtendedSelection)) {
+ selection.select(previousRow, index)
+ } else if (selectionMode === SelectionMode.MultiSelection ||
+ (selectionMode === SelectionMode.ExtendedSelection && modifiers & Qt.ControlModifier)) {
+ selection.__select(!selection.contains(index) , index)
+ } else {
+ selection.__selectOne(index)
}
}
- property int rowHeight: rowSizeItem.implicitHeight
- property int paddedRowCount: height/rowHeight
-
- y: listView.contentHeight - listView.contentY + listView.originY
- width: parent.width
- visible: alternatingRowColors
- height: viewport.height - listView.contentHeight
- Repeater {
- model: visible ? parent.paddedRowCount : 0
- Loader {
- width: rowfiller.width
- height: rowfiller.rowHeight
- sourceComponent: root.rowDelegate
- property QtObject styleData: QtObject {
- readonly property bool alternate: (index + rowCount) % 2 === 1
- readonly property bool selected: false
- readonly property bool hasActiveFocus: false
- readonly property bool pressed: false
- }
- readonly property var model: null
- readonly property var modelData: null
- }
+ }
+
+ onDoubleClicked: {
+ var clickIndex = __listView.indexAt(0, mouseY + __listView.contentY)
+ if (clickIndex > -1) {
+ if (!root.__activateItemOnSingleClick)
+ root.activated(clickIndex)
+ root.doubleClicked(clickIndex)
}
}
- ListModel {
- id: columnModel
+ onPressAndHold: {
+ var pressIndex = __listView.indexAt(0, mouseY + __listView.contentY)
+ if (pressIndex > -1)
+ root.pressAndHold(pressIndex)
}
- highlightFollowsCurrentItem: true
- model: root.model
+ // Note: with boolean preventStealing we are keeping the flickable from
+ // eating our mouse press events
+ preventStealing: !Settings.hasTouchScreen
function keySelect(shiftPressed, row) {
if (row < 0 || row > rowCount - 1)
@@ -803,37 +481,25 @@ ScrollView {
}
}
- Keys.forwardTo: root
+ Keys.forwardTo: [root]
+
Keys.onUpPressed: {
- var oldIndex = listView.currentIndex
- __scroller.blockUpdates = true;
- listView.decrementCurrentIndex();
- __scroller.blockUpdates = false;
- if (oldIndex === listView.currentIndex)
- event.accepted = false
+ event.accepted = __listView.decrementCurrentIndexBlocking()
if (selectionMode)
keySelect(event.modifiers & Qt.ShiftModifier, currentRow)
}
Keys.onDownPressed: {
- var oldIndex = listView.currentIndex
- __scroller.blockUpdates = true;
- listView.incrementCurrentIndex();
- __scroller.blockUpdates = false;
- if (oldIndex === listView.currentIndex)
- event.accepted = false
+ event.accepted = __listView.incrementCurrentIndexBlocking()
if (selectionMode)
keySelect(event.modifiers & Qt.ShiftModifier, currentRow)
}
Keys.onPressed: {
- if (event.key === Qt.Key_PageUp) {
- __verticalScrollBar.value = __verticalScrollBar.value - listView.height
- } else if (event.key === Qt.Key_PageDown)
- __verticalScrollBar.value = __verticalScrollBar.value + listView.height
+ __listView.scrollIfNeeded(event.key)
if (event.key === Qt.Key_Shift) {
- mousearea.firstKeyRow = currentRow
+ firstKeyRow = currentRow
}
if (event.key === Qt.Key_A && event.modifiers & Qt.ControlModifier) {
@@ -844,7 +510,7 @@ ScrollView {
Keys.onReleased: {
if (event.key === Qt.Key_Shift)
- mousearea.firstKeyRow = -1
+ firstKeyRow = -1
}
Keys.onReturnPressed: {
@@ -853,317 +519,5 @@ ScrollView {
else
event.accepted = false
}
-
- delegate: FocusScope {
- id: rowItemContainer
-
- activeFocusOnTab: false
- z: rowItem.activeFocus ? 0.7 : rowItem.itemSelected ? 0.5 : 0
-
- property Item rowItem
- // We recycle instantiated row items to speed up list scrolling
-
- Component.onDestruction: {
- // move the rowItem back in cache
- if (rowItem) {
- rowItem.visible = false;
- rowItem.parent = null;
- rowItem.rowIndex = -1;
- listView.rowItemStack.push(rowItem); // return rowItem to cache
- }
- }
-
- Component.onCompleted: {
- // retrieve row item from cache
- if (listView.rowItemStack.length > 0)
- rowItem = listView.rowItemStack.pop();
- else
- rowItem = rowComponent.createObject(listView);
-
- // Bind container to item size
- rowItemContainer.width = Qt.binding( function() { return rowItem.width });
- rowItemContainer.height = Qt.binding( function() { return rowItem.height });
-
- // Reassign row-specific bindings
- rowItem.rowIndex = Qt.binding( function() { return model.index });
- rowItem.itemModelData = Qt.binding( function() { return typeof modelData === "undefined" ? null : modelData });
- rowItem.itemModel = Qt.binding( function() { return model });
- rowItem.parent = rowItemContainer;
- rowItem.visible = true;
- }
- }
-
- Component {
- id: rowComponent
-
- FocusScope {
- id: rowitem
- visible: false
-
- property int rowIndex
- property var itemModelData
- property var itemModel
- property bool itemSelected: selected()
- property bool alternate: alternatingRowColors && rowIndex % 2 === 1
- readonly property color itemTextColor: itemSelected ? __style.highlightedTextColor : __style.textColor
-
- function selected() {
- if (mousearea.dragRow > -1 && (rowIndex >= mousearea.clickedRow && rowIndex <= mousearea.dragRow
- || rowIndex <= mousearea.clickedRow && rowIndex >=mousearea.dragRow))
- return selection.contains(mousearea.clickedRow)
-
- return selection.count && selection.contains(rowIndex)
- }
-
-
- width: itemrow.width
- height: rowstyle.height
-
- onActiveFocusChanged: {
- if (activeFocus)
- listView.currentIndex = rowIndex
- }
-
- Loader {
- id: rowstyle
- // row delegate
- sourceComponent: rowitem.itemModel !== undefined ? root.rowDelegate : null
- // Row fills the view width regardless of item size
- // But scrollbar should not adjust to it
- height: item ? item.height : 16
- width: parent.width + __horizontalScrollBar.width
- x: listView.contentX
-
- // these properties are exposed to the row delegate
- // Note: these properties should be mirrored in the row filler as well
- property QtObject styleData: QtObject {
- readonly property int row: rowitem.rowIndex
- readonly property bool alternate: rowitem.alternate
- readonly property bool selected: rowitem.itemSelected
- readonly property bool hasActiveFocus: rowitem.activeFocus
- readonly property bool pressed: rowitem.rowIndex === mousearea.pressedRow
- }
- readonly property var model: rowitem.itemModel
- readonly property var modelData: rowitem.itemModelData
- }
- Row {
- id: itemrow
- height: parent.height
- Repeater {
- id: repeater
- model: columnModel
-
- Loader {
- id: itemDelegateLoader
- width: columnItem.width
- height: parent ? parent.height : 0
- visible: columnItem.visible
- sourceComponent: rowitem.itemModel !== undefined ? // delays construction until model is initialized
- (columnItem.delegate ? columnItem.delegate : itemDelegate) : null
-
- // these properties are exposed to the item delegate
- readonly property var model: itemModel
- readonly property var modelData: itemModelData
-
- property QtObject styleData: QtObject {
- readonly property int row: rowitem.rowIndex
- readonly property int column: index
- readonly property int elideMode: columnItem.elideMode
- readonly property int textAlignment: columnItem.horizontalAlignment
- readonly property bool selected: rowitem.itemSelected
- readonly property bool hasActiveFocus: rowitem.activeFocus
- readonly property bool pressed: row === mousearea.pressedRow && column === mousearea.pressedColumn
- readonly property color textColor: rowitem.itemTextColor
- readonly property string role: columnItem.role
- readonly property var value: (itemModel && itemModel.hasOwnProperty(role))
- ? itemModel[role] // Qml ListModel and QAbstractItemModel
- : modelData && modelData.hasOwnProperty(role)
- ? modelData[role] // QObjectList / QObject
- : modelData != undefined ? modelData : "" // Models without role
- }
- }
- }
- }
- }
- }
-
- Item {
- id: tableHeader
- clip: true
- parent: __scroller
- visible: headerVisible
- anchors.top: parent.top
- anchors.topMargin: viewport.anchors.topMargin
- anchors.leftMargin: viewport.anchors.leftMargin
- anchors.margins: viewport.anchors.margins
- anchors.rightMargin: (frameVisible ? __scroller.rightMargin : 0) +
- (__scroller.outerFrame && __scrollBarTopMargin ? 0 : __verticalScrollBar.width
- + __scroller.scrollBarSpacing + root.__style.padding.right)
-
- anchors.left: parent.left
- anchors.right: parent.right
-
- height: headerrow.height
-
- Row {
- id: headerrow
- x: -listView.contentX
-
- function columnAt(offset) {
- var item = childAt(offset, 0)
- return item ? item.column : -1
- }
-
- Repeater {
- id: repeater
-
- property int targetIndex: -1
- property int dragIndex: -1
-
- model: columnModel
-
- delegate: Item {
- id: headerRowDelegate
- readonly property int column: index
- z:-index
- width: modelData.width
- implicitWidth: columnCount === 1 ? viewport.width + __verticalScrollBar.width : headerStyle.implicitWidth
- visible: modelData.visible
- height: headerStyle.height
-
- Loader {
- id: headerStyle
- sourceComponent: root.headerDelegate
- anchors.left: parent.left
- anchors.right: parent.right
- property QtObject styleData: QtObject {
- readonly property string value: modelData.title
- readonly property bool pressed: headerClickArea.pressed
- readonly property bool containsMouse: headerClickArea.containsMouse
- readonly property int column: index
- readonly property int textAlignment: modelData.horizontalAlignment
- readonly property bool resizable: modelData.resizable
- }
- }
- Rectangle{
- id: targetmark
- width: parent.width
- height:parent.height
- opacity: (index === repeater.targetIndex && repeater.targetIndex !== repeater.dragIndex) ? 0.5 : 0
- Behavior on opacity { NumberAnimation{duration:160}}
- color: palette.highlight
- visible: modelData.movable
- }
-
- MouseArea{
- id: headerClickArea
- drag.axis: Qt.YAxis
- hoverEnabled: true
- anchors.fill: parent
- onClicked: {
- if (sortIndicatorColumn === index)
- sortIndicatorOrder = sortIndicatorOrder === Qt.AscendingOrder ? Qt.DescendingOrder : Qt.AscendingOrder
- sortIndicatorColumn = index
- }
- // Here we handle moving header sections
- // NOTE: the direction is different from the master branch
- // so this indicates that I am using an invalid assumption on item ordering
- onPositionChanged: {
- if (modelData.movable && pressed && columnCount > 1) { // only do this while dragging
- for (var h = columnCount-1 ; h >= 0 ; --h) {
- if (drag.target.x + listView.contentX + headerRowDelegate.width/2 > headerrow.children[h].x) {
- repeater.targetIndex = h
- break
- }
- }
- }
- }
-
- onPressed: {
- repeater.dragIndex = index
- }
-
- onReleased: {
- if (repeater.targetIndex >= 0 && repeater.targetIndex !== index ) {
- var targetColumn = columnModel.get(repeater.targetIndex).columnItem
- if (targetColumn.movable) {
- columnModel.move(index, repeater.targetIndex, 1)
- if (sortIndicatorColumn === index)
- sortIndicatorColumn = repeater.targetIndex
- }
- }
- repeater.targetIndex = -1
- repeater.dragIndex = -1
- }
- drag.target: modelData.movable && columnCount > 1 ? draghandle : null
- }
-
- Loader {
- id: draghandle
- property QtObject styleData: QtObject{
- readonly property string value: modelData.title
- readonly property bool pressed: headerClickArea.pressed
- readonly property bool containsMouse: headerClickArea.containsMouse
- readonly property int column: index
- readonly property int textAlignment: modelData.horizontalAlignment
- }
- parent: tableHeader
- x: __implicitX
- property double __implicitX: headerRowDelegate.x - listView.contentX
- width: modelData.width
- height: parent.height
- sourceComponent: root.headerDelegate
- visible: headerClickArea.pressed
- onVisibleChanged: {
- if (!visible)
- x = Qt.binding(function () { return __implicitX })
- }
- opacity: 0.5
- }
-
-
- MouseArea {
- id: headerResizeHandle
- property int offset: 0
- readonly property int minimumSize: 20
- preventStealing: true
- anchors.rightMargin: -width/2
- width: Settings.hasTouchScreen ? Screen.pixelDensity * 3.5 : 16
- height: parent.height
- anchors.right: parent.right
- enabled: modelData.resizable && columnCount > 0
- onPositionChanged: {
- var newHeaderWidth = modelData.width + (mouseX - offset)
- modelData.width = Math.max(minimumSize, newHeaderWidth)
- }
-
- onDoubleClicked: getColumn(index).resizeToContents()
- onPressedChanged: if (pressed) offset=mouseX
- cursorShape: enabled && repeater.dragIndex==-1 ? Qt.SplitHCursor : Qt.ArrowCursor
- }
- }
- }
- onWidthChanged: listView.contentWidth = width
- }
- Loader {
- id: loader
- property QtObject styleData: QtObject{
- readonly property string value: ""
- readonly property bool pressed: false
- readonly property bool containsMouse: false
- readonly property int column: -1
- readonly property int textAlignment: Text.AlignLeft
- }
-
- anchors.top: parent.top
- anchors.right: parent.right
- anchors.bottom: headerrow.bottom
- anchors.rightMargin: -2
- sourceComponent: root.headerDelegate
- width: root.width - headerrow.width + 2
- visible: root.columnCount
- z:-1
- }
- }
}
}
diff --git a/src/controls/TableViewColumn.qml b/src/controls/TableViewColumn.qml
index 6fa07045c..fc6d6a3d5 100644
--- a/src/controls/TableViewColumn.qml
+++ b/src/controls/TableViewColumn.qml
@@ -139,14 +139,27 @@ QtObject {
function resizeToContents() {
var minWidth = 0
var listdata = __view.__listView.children[0]
- for (var i = 0; __index < 0 && i < __view.__columns.length; ++i)
+ for (var i = 0; __index === -1 && i < __view.__columns.length; ++i) {
if (__view.__columns[i] === this)
__index = i
+ }
+ // ### HACK We don't have direct access to the instantiated item,
+ // so we go spelunking. Each 'item' variable check is annotated
+ // with the expected object it should point to in BasicTableView.
for (var row = 0 ; row < listdata.children.length ; ++row) {
var item = listdata.children[row] ? listdata.children[row].rowItem : undefined
- if (item && item.children[1] && item.children[1].children[__index] && item.children[1].children[__index].children[0] &&
- item.children[1].children[__index].children[0].hasOwnProperty("implicitWidth"))
- minWidth = Math.max(minWidth, item.children[1].children[__index].children[0].implicitWidth)
+ if (item) { // FocusScope { id: rowitem }
+ item = item.children[1]
+ if (item) { // Row { id: itemrow }
+ item = item.children[__index]
+ if (item) { // Loader { id: itemDelegateLoader }
+ item = item.item
+ if (item && item.hasOwnProperty("implicitWidth")) {
+ minWidth = Math.max(minWidth, item.implicitWidth)
+ }
+ }
+ }
+ }
}
if (minWidth)
width = minWidth
diff --git a/tests/auto/controls/data/tableview/tv_keys.qml b/tests/auto/controls/data/tableview/tv_keys.qml
index 46428fa44..1ee39e677 100644
--- a/tests/auto/controls/data/tableview/tv_keys.qml
+++ b/tests/auto/controls/data/tableview/tv_keys.qml
@@ -45,11 +45,13 @@ Row {
TableView {
id: _control1
property bool gotit: false
+
+ TableViewColumn { }
+
Keys.onPressed: {
+ event.accepted = !gotit
if ((!gotit) && (event.key === Qt.Key_Down)) {
gotit = true;
- event.accepted = true;
- return;
}
}
}
diff --git a/tests/auto/controls/data/tst_tableview.qml b/tests/auto/controls/data/tst_tableview.qml
index 335990003..b149e76b6 100644
--- a/tests/auto/controls/data/tst_tableview.qml
+++ b/tests/auto/controls/data/tst_tableview.qml
@@ -512,7 +512,7 @@ TestCase {
table.forceActiveFocus();
// to go to next row (this model has 10 rows)
- table.__incrementCurrentIndex()
+ table.__listView.incrementCurrentIndex()
// read data from the model directly
var valuefrommodel = table.model.dataAt(table.currentRow)
@@ -541,7 +541,7 @@ TestCase {
table.forceActiveFocus();
// to go to next row (this model has 3 rows, read the second row)
- table.__incrementCurrentIndex()
+ table.__listView.incrementCurrentIndex()
verify(table.__currentRowItem !== undefined, "No current item found")
var label = findAChild(table.__currentRowItem, "label")