diff options
Diffstat (limited to 'src/controls/TableView.qml')
-rw-r--r-- | src/controls/TableView.qml | 350 |
1 files changed, 241 insertions, 109 deletions
diff --git a/src/controls/TableView.qml b/src/controls/TableView.qml index ca0df45a..b02a49c0 100644 --- a/src/controls/TableView.qml +++ b/src/controls/TableView.qml @@ -65,8 +65,7 @@ import QtQuick.Controls.Styles 1.0 \endcode You provide title and size of a column header - by adding a \l TableViewColumn to the default \l header property - as demonstrated below. + by adding a \l TableViewColumn as demonstrated below. \code TableView { @@ -124,26 +123,37 @@ ScrollView { 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 itemSelected - if the item is currently selected - \li itemValue - the value or text for this item - \li itemTextColor - the default text color for an item - \li row - the index of the row - \li column - the index of the column - \li itemElideMode - the elide mode of the column - \li itemTextAlignment - the horizontal text alignment of the column + \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 \endlist + Example: \code itemDelegate: Item { Text { anchors.verticalCenter: parent.verticalCenter - color: itemTextColor - elide: itemElideMode - text: itemValue + color: styleData.textColor + elide: styleData.elideMode + text: styleData.value } } \endcode */ @@ -153,20 +163,23 @@ ScrollView { In the row delegate you have access to the following special properties: \list - \li alternateBackground - if the row uses the alternate background color - \li rowSelected - if the row is currently selected - \li index - the index of the row + \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 \endlist */ property Component rowDelegate: __style ? __style.rowDelegate : null - /*! \qmlproperty color TableView::backgroundColor + /*! This property defines a delegate to draw a header. - This property sets the background color of the viewport. - The default value is the base color of the SystemPalette. */ - property alias backgroundColor: colorRect.color - - /*! 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 + \endlist + */ property Component headerDelegate: __style ? __style.headerDelegate : null /*! Index of the current sort column. @@ -190,9 +203,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 */ @@ -206,8 +218,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 @@ -226,10 +239,30 @@ ScrollView { /*! \internal */ property alias __currentRowItem: listView.currentItem - /*! \qmlsignal TableView::activated() - Emitted when the user activates an item by single or double-clicking (depending on the platform). + /*! \qmlsignal TableView::activated(int row) + + Emitted when the user activates an item by mouse or keyboard interaction. + Mouse activation is triggered by single- or double-clicking, depending on the platform. + + \a row int provides access to the activated row index. */ - signal activated + signal activated(int row) + + /*! \qmlsignal TableView::clicked(int row) + + Emitted when the user clicks a valid row by single clicking + + \a row int provides access to the clicked row index. + */ + signal clicked(int row) + + /*! \qmlsignal TableView::doubleClicked(int row) + + Emitted when the user double clicks a valid row. + + \a row int provides access to the clicked row index. + */ + signal doubleClicked(int row) /*! \qmlmethod TableView::positionViewAtRow( int row, PositionMode mode ) @@ -255,13 +288,13 @@ ScrollView { 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 {Timer}. + delay the call to positionViewAtRow by using a \l {QtQml::Timer}{Timer}. \note This method should only be called after the component has completed. */ function positionViewAtRow(row, mode) { - listView.positionViewAtRow(row, mode) + listView.positionViewAtIndex(row, mode) } /*! @@ -278,17 +311,89 @@ 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) + + 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 + } + + 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) Accessible.role: Accessible.Table - width: 200 - height: 200 + implicitWidth: 200 + implicitHeight: 150 frameVisible: true - __scrollBarTopMargin: Qt.platform.os === "mac" ? headerrow.height : 0 + __scrollBarTopMargin: Qt.platform.os === "osx" ? headerrow.height : 0 __viewTopMargin: headerrow.height /*! \internal */ @@ -327,7 +432,7 @@ ScrollView { id: colorRect parent: viewport anchors.fill: parent - color: palette.base + color: __style ? __style.backgroundColor : palette.base z: -1 } @@ -362,28 +467,39 @@ ScrollView { autoincrement = false; autodecrement = false; } - var y = Math.min(listView.contentY + listView.height - 5, Math.max(mouseY + listView.contentY, listView.contentY)); - var newIndex = listView.indexAt(0, y); - if (newIndex >= 0) - listView.currentIndex = listView.indexAt(0, y); + + if (pressed) { + var newIndex = listView.indexAt(0, mouseY + listView.contentY) + if (newIndex >= 0) + listView.currentIndex = newIndex; + } } onClicked: { - if (root.__activateItemOnSingleClick) - root.activated() + var clickIndex = listView.indexAt(0, mouseY + listView.contentY) + if (clickIndex > -1) { + if (root.__activateItemOnSingleClick) + root.activated(clickIndex) + root.clicked(clickIndex) + } mouse.accepted = false } onPressed: { + var newIndex = listView.indexAt(0, mouseY + listView.contentY) listView.forceActiveFocus() - var x = Math.min(listView.contentWidth - 5, Math.max(mouseX + listView.contentX, 0)) - var y = Math.min(listView.contentHeight - 5, Math.max(mouseY + listView.contentY, 0)) - listView.currentIndex = listView.indexAt(x, y) + if (newIndex > -1) { + listView.currentIndex = newIndex + } } onDoubleClicked: { - if (!root.__activateItemOnSingleClick) - root.activated() + var clickIndex = listView.indexAt(0, mouseY + listView.contentY) + if (clickIndex > -1) { + if (!root.__activateItemOnSingleClick) + root.activated(clickIndex) + root.doubleClicked(clickIndex) + } } // Note: with boolean preventStealing we are keeping the flickable from @@ -395,7 +511,7 @@ ScrollView { // Fills extra rows with alternate color Column { id: rowfiller - property int rowHeight: listView.contentHeight/count + property int rowHeight: count ? listView.contentHeight/count : height property int paddedRowCount: height/rowHeight property int count: listView.count y: listView.contentHeight @@ -408,21 +524,33 @@ ScrollView { width: rowfiller.width height: rowfiller.rowHeight sourceComponent: root.rowDelegate - readonly property bool alternateBackground: (index + rowCount) % 2 === 1 - readonly property bool rowSelected: false + property QtObject styleData: QtObject { + readonly property bool alternate: (index + rowCount) % 2 === 1 + readonly property bool selected: false + readonly property bool hasActiveFocus: root.activeFocus + } readonly property var model: listView.model readonly property var modelData: null - readonly property bool hasActiveFocus: root.activeFocus } } } - property list<TableViewColumn> columnheader + ListModel { + id: columnModel + } + highlightFollowsCurrentItem: true model: root.model - Keys.onUpPressed: root.__decrementCurrentIndex() - Keys.onDownPressed: root.__incrementCurrentIndex() + Keys.onUpPressed: { + event.accepted = false + root.__decrementCurrentIndex() + } + + Keys.onDownPressed: { + event.accepted = false + root.__incrementCurrentIndex() + } Keys.onPressed: { if (event.key === Qt.Key_PageUp) { @@ -431,7 +559,11 @@ ScrollView { verticalScrollBar.value = __verticalScrollBar.value + listView.height } - Keys.onReturnPressed: root.activated(); + Keys.onReturnPressed: { + event.accepted = false + if (currentRow > -1) + root.activated(currentRow); + } delegate: Item { id: rowitem @@ -439,7 +571,7 @@ ScrollView { height: rowstyle.height readonly property int rowIndex: model.index - readonly property bool alternateBackground: alternatingRowColors && rowIndex % 2 == 1 + readonly property bool alternate: alternatingRowColors && rowIndex % 2 == 1 readonly property var itemModelData: typeof modelData == "undefined" ? null : modelData readonly property var itemModel: model readonly property bool itemSelected: ListView.isCurrentItem @@ -457,19 +589,21 @@ ScrollView { // these properties are exposed to the row delegate // Note: these properties should be mirrored in the row filler as well - readonly property bool alternateBackground: rowitem.alternateBackground - readonly property bool rowSelected: rowitem.itemSelected - readonly property int row: rowitem.rowIndex + 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: root.activeFocus + } readonly property var model: listView.model readonly property var modelData: rowitem.itemModelData - readonly property bool hasActiveFocus: root.activeFocus } Row { id: itemrow height: parent.height Repeater { id: repeater - model: root.columnCount + model: columnModel Loader { id: itemDelegateLoader @@ -482,20 +616,22 @@ ScrollView { readonly property var model: listView.model readonly property var modelData: itemModelData - readonly property var itemValue: __hasModelRole ? itemModel[role] // Qml ListModel and QAbstractItemModel - : __hasModelDataRole ? modelData[role] // QObjectList / QObject - : modelData != undefined ? modelData : "" // Models without role - readonly property bool itemSelected: rowitem.itemSelected - readonly property color itemTextColor: rowitem.itemTextColor - readonly property int row: rowitem.rowIndex - readonly property int column: index - readonly property int itemElideMode: __column.elideMode - readonly property int itemTextAlignment: __column.horizontalAlignment - readonly property string role: __column.role - - readonly property TableViewColumn __column: columns[index] - readonly property bool __hasModelRole: role && itemModel.hasOwnProperty(role) - readonly property bool __hasModelDataRole: role && modelData && modelData.hasOwnProperty(role) + property QtObject styleData: QtObject { + readonly property var value: __hasModelRole ? itemModel[role] // Qml ListModel and QAbstractItemModel + : __hasModelDataRole ? modelData[role] // QObjectList / QObject + : modelData != undefined ? modelData : "" // Models without role + readonly property int row: rowitem.rowIndex + readonly property int column: index + readonly property int elideMode: __column.elideMode + readonly property int textAlignment: __column.horizontalAlignment + readonly property bool selected: rowitem.itemSelected + readonly property color textColor: rowitem.itemTextColor + readonly property string role: __column.role + } + + 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) } } onWidthChanged: listView.contentWidth = width @@ -513,7 +649,7 @@ ScrollView { anchors.topMargin: viewport.anchors.topMargin anchors.leftMargin: viewport.anchors.leftMargin anchors.margins: viewport.anchors.margins - anchors.rightMargin: __scroller.rightMargin + + anchors.rightMargin: (frameVisible ? __scroller.rightMargin : 0) + (__scroller.outerFrame && __scrollBarTopMargin ? 0 : __verticalScrollBar.width + __scroller.scrollBarSpacing + root.__style.padding.right) @@ -532,12 +668,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: columnCount == 1 ? viewport.width + __verticalScrollBar.width : modelData.width + visible: modelData.visible height: headerVisible ? headerStyle.height : 0 Loader { @@ -545,13 +681,12 @@ ScrollView { sourceComponent: root.headerDelegate anchors.left: parent.left anchors.right: parent.right - property string itemValue: columns[index].title - property string itemSort: (sortIndicatorVisible && index == sortIndicatorColumn) ? (sortIndicatorOrder == Qt.AscendingOrder ? "up" : "down") : ""; - property bool itemPressed: headerClickArea.pressed - property bool itemContainsMouse: headerClickArea.containsMouse - property string itemPosition: columnCount === 1 ? "only" : - index===columnCount-1 ? "end" : - index===0 ? "beginning" : "" + 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 + } } Rectangle{ id: targetmark @@ -576,7 +711,7 @@ ScrollView { // NOTE: the direction is different from the master branch // so this indicates that I am using an invalid assumption on item ordering onPositionChanged: { - if (pressed) { // only do this while dragging + if (pressed && columnCount > 1) { // only do this while dragging for (var h = columnCount-1 ; h >= 0 ; --h) { if (drag.target.x > headerrow.children[h].x) { repeater.targetIndex = h @@ -593,13 +728,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 } @@ -607,19 +736,20 @@ ScrollView { } drag.maximumX: 1000 drag.minimumX: -1000 - drag.target: draghandle + drag.target: columnCount > 1 ? draghandle : null } Loader { id: draghandle - property string itemValue: columns[index].title - property string itemSort: (sortIndicatorVisible && index == sortIndicatorColumn) ? (sortIndicatorOrder == Qt.AscendingOrder ? "up" : "down") : ""; - property bool itemPressed: headerClickArea.pressed - property bool itemContainsMouse: headerClickArea.containsMouse - property string itemPosition + 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 + } parent: tableHeader - width: columns[index].width + width: modelData.width height: parent.height sourceComponent: root.headerDelegate visible: headerClickArea.pressed @@ -634,9 +764,10 @@ ScrollView { anchors.rightMargin: -width/2 width: 16 ; height: parent.height anchors.right: parent.right + enabled: columnCount > 1 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 @@ -651,21 +782,22 @@ 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 + cursorShape: enabled ? Qt.SplitHCursor : Qt.ArrowCursor } } } } Loader { id: loader - property string itemValue - property string itemSort - property bool itemPressed - property bool itemContainsMouse - property string itemPosition + property QtObject styleData: QtObject{ + readonly property string value: "" + readonly property bool pressed: false + readonly property bool containsMouse: false + readonly property int column: -1 + } anchors.top: parent.top anchors.right: parent.right |