aboutsummaryrefslogtreecommitdiffstats
path: root/lib/qtcreator/qtcomponents/TableView.qml
diff options
context:
space:
mode:
authorDaniel Molkentin <daniel.molkentin@nokia.com>2011-08-02 17:11:29 +0200
committerEike Ziller <eike.ziller@nokia.com>2011-08-03 16:12:35 +0200
commit9743b43663f2dac99df0e1e5219b0d65bee2d7f2 (patch)
treea41f3e18eaae73aac5cebc7150f7aed5662974e9 /lib/qtcreator/qtcomponents/TableView.qml
parent6c8edcf99ed0cd77a3667e61417a224461060ab7 (diff)
Make Components installable. Fix Shadow Build.
Task-Number: QTCREATORBUG-5672 Done-with: Oswald Buddenhagen Change-Id: I61f8a83205bc338ba12e43b7471eaa957da2b004 Reviewed-on: http://codereview.qt.nokia.com/2451 Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com> Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@nokia.com> Reviewed-by: Eike Ziller <eike.ziller@nokia.com>
Diffstat (limited to 'lib/qtcreator/qtcomponents/TableView.qml')
-rw-r--r--lib/qtcreator/qtcomponents/TableView.qml604
1 files changed, 604 insertions, 0 deletions
diff --git a/lib/qtcreator/qtcomponents/TableView.qml b/lib/qtcreator/qtcomponents/TableView.qml
new file mode 100644
index 0000000000..132610c3f6
--- /dev/null
+++ b/lib/qtcreator/qtcomponents/TableView.qml
@@ -0,0 +1,604 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+import QtQuick 1.0
+
+/*
+*
+* TableView
+*
+* This component provides an item-view with resizable
+* header sections.
+*
+* You can style the drawn delegate by overriding the itemDelegate
+* property. The following properties are supported for custom
+* delegates:
+*
+* Note: Currently only row selection is available for this component
+*
+* itemheight - default platform size of item
+* itemwidth - default platform width of item
+* itemselected - if the row is currently selected
+* itemvalue - The text for this item
+* itemforeground - The default text color for an item
+*
+* For example:
+* itemDelegate: Item {
+* Text {
+* anchors.verticalCenter: parent.verticalCenter
+* color: itemForeground
+* elide: Text.ElideRight
+* text: itemValue
+* }
+* }
+*
+* Data for each row is provided through a model:
+*
+* ListModel {
+* ListElement{ column1: "value 1"; column2: "value 2"}
+* ListElement{ column1: "value 3"; column2: "value 4"}
+* }
+*
+* You provide title and size properties on TableColumns
+* by setting the default header property :
+*
+* TableView {
+* TableColumn{ property: "column1" ; caption: "Column 1" ; width:100}
+* TableColumn{ property: "column2" ; caption: "Column 2" ; width:200}
+* model: datamodel
+* }
+*
+* The header sections are attached to values in the datamodel by defining
+* the listmodel property they attach to. Each property in the model, will
+* then be shown in each column section.
+*
+* The view itself does not provide sorting. This has to
+* be done on the model itself. However you can provide sorting
+* on the model and enable sort indicators on headers.
+*
+* sortColumn - The index of the currently selected sort header
+* sortIndicatorVisible - If sort indicators should be enabled
+* sortIndicatorDirection - "up" or "down" depending on state
+*
+*/
+
+FocusScope{
+ id: root
+ property variant model
+ property int frameWidth: frame ? styleitem.pixelMetric("defaultframewidth") : 0;
+ property alias contentHeight : tree.contentHeight
+ property alias contentWidth: tree.contentWidth
+ property bool frame: true
+ property bool highlightOnFocus: false
+ property bool frameAroundContents: styleitem.styleHint("framearoundcontents")
+ property int sortColumn // Index of currently selected sort column
+
+ property bool sortIndicatorVisible: false // enables or disables sort indicator
+ property string sortIndicatorDirection: "down" // "up" or "down" depending on current state
+
+ property bool alternateRowColor: true
+ property alias contentX: tree.contentX
+ property alias contentY: tree.contentY
+
+ property alias currentIndex: tree.currentIndex // Should this be currentRowIndex?
+
+ property int headerHeight: headerrow.height
+
+ property Component itemDelegate: standardDelegate
+ property Component rowDelegate: rowDelegate
+ property Component headerDelegate: headerDelegate
+ property alias cacheBuffer: tree.cacheBuffer
+
+ property bool headerVisible: true
+
+ default property alias header: tree.header
+
+ signal activated
+
+ Component {
+ id: standardDelegate
+ Item {
+ property int implicitWidth: sizehint.paintedWidth + 4
+ Text {
+ width: parent.width
+ anchors.margins: 4
+ anchors.left: parent.left
+ anchors.verticalCenter: parent.verticalCenter
+ elide: itemElideMode
+ text: itemValue ? itemValue : ""
+ color: itemForeground
+ }
+ Text {
+ id: sizehint
+ text: itemValue ? itemValue : ""
+ visible:false
+ }
+ }
+ }
+
+ Component {
+ id: nativeDelegate
+ // This gives more native styling, but might be less performant
+ QStyleItem {
+ elementType: "item"
+ text: itemValue
+ selected: itemSelected
+ }
+ }
+
+ Component {
+ id: headerDelegate
+ QStyleItem {
+ elementType: "header"
+ activeControl: itemSort
+ raised: true
+ sunken: itemPressed
+ text: itemValue
+ hover: itemContainsMouse
+ }
+ }
+
+ Component {
+ id: rowDelegate
+ QStyleItem {
+ id: rowstyle
+ elementType: "itemrow"
+ activeControl: itemAlternateBackground ? "alternate" : ""
+ selected: itemSelected ? "true" : "false"
+ }
+ }
+
+ Rectangle {
+ id: colorRect
+ color: "white"
+ anchors.fill: frameitem
+ anchors.margins: frameWidth
+ anchors.rightMargin: (!frameAroundContents && vscrollbar.visible ? vscrollbar.width : 0) + frameWidth
+ anchors.bottomMargin: (!frameAroundContents && hscrollbar.visible ? hscrollbar.height : 0) +frameWidth
+ }
+
+ QStyleItem {
+ id: frameitem
+ elementType: "frame"
+ onElementTypeChanged: scrollarea.frameWidth = styleitem.pixelMetric("defaultframewidth");
+ sunken: true
+ visible: frame
+ anchors.fill: parent
+ anchors.rightMargin: frame ? (frameAroundContents ? (vscrollbar.visible ? vscrollbar.width + 2 * frameMargins : 0) : -frameWidth) : 0
+ anchors.bottomMargin: frame ? (frameAroundContents ? (hscrollbar.visible ? hscrollbar.height + 2 * frameMargins : 0) : -frameWidth) : 0
+ anchors.topMargin: frame ? (frameAroundContents ? 0 : -frameWidth) : 0
+ property int scrollbarspacing: styleitem.pixelMetric("scrollbarspacing");
+ property int frameMargins : frame ? scrollbarspacing : 0
+ }
+ MouseArea {
+ id: mousearea
+
+ anchors.fill: tree
+
+ property bool autoincrement: false
+ property bool autodecrement: false
+
+ onReleased: {
+ autoincrement = false
+ autodecrement = false
+ }
+
+ // Handle vertical scrolling whem dragging mouse outside boundraries
+
+ Timer { running: mousearea.autoincrement; repeat: true; interval: 30 ; onTriggered: tree.incrementCurrentIndex()}
+ Timer { running: mousearea.autodecrement; repeat: true; interval: 30 ; onTriggered: tree.decrementCurrentIndex()}
+
+ onMousePositionChanged: {
+ if (mouseY > tree.height) {
+ autodecrement = false
+ autoincrement = true
+ } else if (mouseY < 0) {
+ autoincrement = false
+ autodecrement = true
+ } else {
+ autoincrement = false
+ autodecrement = false
+ }
+
+ var y = Math.min(contentY + tree.height - 5, Math.max(mouseY + contentY, contentY))
+
+ var newIndex = tree.indexAt(0, y)
+ if (newIndex > 0)
+ tree.currentIndex = tree.indexAt(0, y)
+ }
+ onPressed: {
+ tree.forceActiveFocus()
+ var x = Math.min(contentWidth - 5, Math.max(mouseX + contentX, 0))
+ var y = Math.min(contentHeight - 5, Math.max(mouseY + contentY, 0))
+ tree.currentIndex = tree.indexAt(x, y)
+ }
+
+ onDoubleClicked: {
+ parent.activated()
+ }
+ }
+
+ ListView {
+ id: tree
+ property list<TableColumn> header
+ property bool blockUpdates: false
+ highlightFollowsCurrentItem: true
+ model: root.model
+
+ interactive: false
+ anchors.top: tableColumn.bottom
+ anchors.topMargin: -frameWidth
+ anchors.left: frameitem.left
+ anchors.right: frameitem.right
+ anchors.bottom: frameitem.bottom
+ anchors.margins: frameWidth
+
+ anchors.rightMargin: (!frameAroundContents && vscrollbar.visible ? vscrollbar.width: 0) + frameWidth
+ anchors.bottomMargin: (!frameAroundContents && hscrollbar.visible ? hscrollbar.height : 0) + frameWidth
+
+ focus: true
+ clip: true
+
+ Keys.onUpPressed: {
+ blockUpdates = true
+ if (currentIndex > 0) currentIndex = currentIndex - 1
+ wheelarea.verticalValue = contentY/wheelarea.scale
+ blockUpdates = false
+ }
+ Keys.onDownPressed: {
+ blockUpdates = true
+ if (currentIndex< count - 1) currentIndex = currentIndex + 1
+ wheelarea.verticalValue = contentY/wheelarea.scale
+ blockUpdates = false
+ }
+ Keys.onPressed: {
+ if (event.key == Qt.Key_PageUp) {
+ vscrollbar.value = vscrollbar.value - tree.height
+ } else if (event.key == Qt.Key_PageDown)
+ vscrollbar.value = vscrollbar.value + tree.height
+ }
+
+ onContentYChanged: {
+ // positionViewAtIndex(currentIndex, ListView.Visible)
+ // highlight follows item
+ blockUpdates = true
+ vscrollbar.value = tree.contentY
+ blockUpdates = false
+ }
+
+ delegate: Item {
+ id: rowitem
+ width: row.width
+ height: row.height
+ anchors.margins: frameWidth
+ property int rowIndex: model.index
+ property bool itemAlternateBackground: alternateRowColor && rowIndex % 2 == 1
+ Loader {
+ id: rowstyle
+ // row delegate
+ sourceComponent: root.rowDelegate
+ // Row fills the tree width regardless of item size
+ // But scrollbar should not adjust to it
+ width: frameitem.width
+ height: row.height
+ x: contentX
+
+ property bool itemAlternateBackground: rowitem.itemAlternateBackground
+ property bool itemSelected: rowitem.ListView.isCurrentItem
+ }
+ Row {
+ id: row
+ anchors.left: parent.left
+
+ Repeater {
+ id: repeater
+ model: root.header.length
+ Loader {
+ id: itemDelegateLoader
+ visible: header[index].visible
+ sourceComponent: itemDelegate
+ property variant model: tree.model
+ property variant itemProperty: header[index].property
+
+ width: header[index].width
+ height: item ? item.height : Math.max(16, styleitem.sizeFromContents(16, 16).height)
+
+ function getValue() {
+ if (index < header.length &&
+ root.model.get(rowIndex).hasOwnProperty(header[index].property))
+ return root.model.get(rowIndex)[ header[index].property]
+ }
+ property variant itemValue: root.model.get(rowIndex)[ header[index].property]
+ property bool itemSelected: rowitem.ListView.isCurrentItem
+ property color itemForeground: itemSelected ? rowstyleitem.highlightedTextColor : rowstyleitem.textColor
+ property int rowIndex: rowitem.rowIndex
+ property int columnIndex: index
+ property int itemElideMode: header[index].elideMode
+ }
+ }
+ onWidthChanged: tree.contentWidth = width
+ }
+ }
+ }
+ Text{ id:text }
+
+ Item {
+ id: tableColumn
+ clip: true
+ anchors.top: frameitem.top
+ anchors.left: frameitem.left
+ anchors.right: frameitem.right
+ anchors.margins: frameWidth
+ visible: headerVisible
+ Behavior on height { NumberAnimation{duration:80}}
+ height: headerVisible ? styleitem.sizeFromContents(text.font.pixelSize, styleitem.fontHeight).height : frameWidth
+
+ Row {
+ id: headerrow
+
+ anchors.top: parent.top
+ height:parent.height
+ x: -tree.contentX
+
+ Repeater {
+ id: repeater
+ model: header.length
+ property int targetIndex: -1
+ property int dragIndex: -1
+ delegate: Item {
+ z:-index
+ width: header[index].width
+ visible: header[index].visible
+ height: headerrow.height
+
+ Loader {
+ sourceComponent: root.headerDelegate
+ anchors.fill: parent
+ property string itemValue: header[index].caption
+ property string itemSort: (sortIndicatorVisible && index == sortColumn) ? (sortIndicatorDirection == "up" ? "up" : "down") : "";
+ property bool itemPressed: headerClickArea.pressed
+ property bool itemContainsMouse: headerClickArea.containsMouse
+ }
+ 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
+ }
+
+ MouseArea{
+ id: headerClickArea
+ drag.axis: Qt.YAxis
+ hoverEnabled: true
+ anchors.fill: parent
+ onClicked: {
+ if (sortColumn == index)
+ sortIndicatorDirection = sortIndicatorDirection === "up" ? "down" : "up"
+ sortColumn = index
+ }
+ // Here we handle moving header sections
+ onMousePositionChanged: {
+ if (pressed) { // only do this while dragging
+ for (var h = 0 ; h < header.length ; ++h) {
+ if (drag.target.x > headerrow.children[h].x - 10) {
+ repeater.targetIndex = header.length - h - 1
+ break
+ }
+ }
+ }
+ }
+
+ onPressed: {
+ repeater.dragIndex = index
+ draghandle.x = parent.x
+ }
+
+ onReleased: {
+ if (repeater.targetIndex >= 0 && repeater.targetIndex != index ) {
+ // Rearrange the header sections
+ var items = new Array
+ for (var i = 0 ; i< header.length ; ++i)
+ items.push(header[i])
+ items.splice(index, 1);
+ items.splice(repeater.targetIndex, 0, header[index]);
+ header = items
+ if (sortColumn == index)
+ sortColumn = repeater.targetIndex
+ }
+ repeater.targetIndex = -1
+ }
+ drag.maximumX: 1000
+ drag.minimumX: -1000
+ drag.target: draghandle
+ }
+
+ Loader {
+ id: draghandle
+ parent: tableColumn
+ sourceComponent: root.headerDelegate
+ width: header[index].width
+ height: parent.height
+ property string itemValue: header[index].caption
+ property string itemSort: (sortIndicatorVisible && index == sortColumn) ? (sortIndicatorDirection == "up" ? "up" : "down") : "";
+ property bool itemPressed: headerClickArea.pressed
+ property bool itemContainsMouse: headerClickArea.containsMouse
+ visible: headerClickArea.pressed
+ opacity: 0.5
+ }
+
+
+ MouseArea {
+ id: headerResizeHandle
+ property int offset: 0
+ property int minimumSize: 20
+ anchors.rightMargin: -width/2
+ width: 16 ; height: parent.height
+ anchors.right: parent.right
+ onPositionChanged: {
+ var newHeaderWidth = header[index].width + (mouseX - offset)
+ header[index].width = Math.max(minimumSize, newHeaderWidth)
+ }
+ property bool found:false
+
+ onDoubleClicked: {
+ var row
+ var minWidth = 0
+ var listdata = tree.children[0]
+ for (row = 0 ; row < listdata.children.length ; ++row){
+ var item = listdata.children[row+1]
+ if (item && item.children[1] && item.children[1].children[index] &&
+ item.children[1].children[index].children[0].hasOwnProperty("implicitWidth"))
+ minWidth = Math.max(minWidth, item.children[1].children[index].children[0].implicitWidth)
+ }
+ if (minWidth)
+ header[index].width = minWidth
+ }
+ onPressedChanged: if(pressed)offset=mouseX
+ QStyleItem {
+ anchors.fill: parent
+ cursor: "splithcursor"
+ }
+ }
+ }
+ }
+ }
+ Loader {
+ id: loader
+ z:-1
+ sourceComponent: root.headerDelegate
+ anchors.top: parent.top
+ anchors.right: parent.right
+ anchors.bottom: headerrow.bottom
+ anchors.rightMargin: -2
+ width: root.width - headerrow.width
+ property string itemValue
+ property string itemSort
+ property bool itemPressed
+ property bool itemContainsMouse
+ }
+ }
+
+ WheelArea {
+ id: wheelarea
+ anchors.fill: parent
+ property int scale: 5
+ horizontalMinimumValue: hscrollbar.minimumValue/scale
+ horizontalMaximumValue: hscrollbar.maximumValue/scale
+ verticalMinimumValue: vscrollbar.minimumValue/scale
+ verticalMaximumValue: vscrollbar.maximumValue/scale
+
+ verticalValue: contentY/scale
+ horizontalValue: contentX/scale
+
+ onVerticalValueChanged: {
+ if(!tree.blockUpdates) {
+ contentY = verticalValue * scale
+ vscrollbar.value = contentY
+ }
+ }
+
+ onHorizontalValueChanged: {
+ if(!tree.blockUpdates) {
+ contentX = horizontalValue * scale
+ hscrollbar.value = contentX
+ }
+ }
+ }
+
+ ScrollBar {
+ id: hscrollbar
+ orientation: Qt.Horizontal
+ property int availableWidth: root.width - vscrollbar.width
+ visible: contentWidth > availableWidth
+ maximumValue: contentWidth > availableWidth ? tree.contentWidth - availableWidth : 0
+ minimumValue: 0
+ anchors.bottom: parent.bottom
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.leftMargin: frameWidth
+ anchors.bottomMargin: styleitem.frameoffset
+ anchors.rightMargin: vscrollbar.visible ? scrollbarExtent : (frame ? 1 : 0)
+ onValueChanged: {
+ if (!tree.blockUpdates)
+ contentX = value
+ }
+ property int scrollbarExtent : styleitem.pixelMetric("scrollbarExtent");
+ }
+
+ ScrollBar {
+ id: vscrollbar
+ orientation: Qt.Vertical
+ // We cannot bind directly to tree.height due to binding loops so we have to redo the calculation here
+ property int availableHeight : root.height - (hscrollbar.visible ? hscrollbar.height : 0) - tableColumn.height
+ visible: contentHeight > availableHeight
+ maximumValue: contentHeight > availableHeight ? tree.contentHeight - availableHeight : 0
+ minimumValue: 0
+ anchors.rightMargin: styleitem.frameoffset
+ anchors.right: parent.right
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ anchors.topMargin: styleitem.style == "mac" ? tableColumn.height : 0
+ onValueChanged: {
+ if(!tree.blockUpdates)
+ contentY = value
+ }
+ anchors.bottomMargin: hscrollbar.visible ? hscrollbar.height : styleitem.frameoffset
+
+ Keys.onUpPressed: if (tree.currentIndex > 0) tree.currentIndex = tree.currentIndex - 1
+ Keys.onDownPressed: if (tree.currentIndex< tree.count - 1) tree.currentIndex = tree.currentIndex + 1
+ }
+
+ QStyleItem {
+ z: 2
+ anchors.fill: parent
+ anchors.margins: -4
+ visible: highlightOnFocus && parent.activeFocus && styleitem.styleHint("focuswidget")
+ elementType: "focusframe"
+ }
+
+ QStyleItem {
+ id: styleitem
+ elementType: "header"
+ visible:false
+ property int frameoffset: style === "mac" ? -1 : 0
+ }
+ QStyleItem {
+ id: rowstyleitem
+ elementType: "item"
+ visible:false
+ property color textColor: styleHint("textColor")
+ property color highlightedTextColor: styleHint("highlightedTextColor")
+ }
+ SystemPalette{id:palette}
+}