main.qml Example File

qmlbars/qml/qmlbars/main.qml
 /****************************************************************************
 **
 ** Copyright (C) 2016 The Qt Company Ltd.
 ** Contact: https://www.qt.io/licensing/
 **
 ** This file is part of the Qt Data Visualization module of the Qt Toolkit.
 **
 ** $QT_BEGIN_LICENSE:GPL$
 ** 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 https://www.qt.io/terms-conditions. For further
 ** information use the contact form at https://www.qt.io/contact-us.
 **
 ** GNU General Public License Usage
 ** Alternatively, this file may be used under the terms of the GNU
 ** General Public License version 3 or (at your option) any later version
 ** approved by the KDE Free Qt Foundation. The licenses are as published by
 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
 ** included in the packaging of this file. Please review the following
 ** information to ensure the GNU General Public License requirements will
 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
 **
 ** $QT_END_LICENSE$
 **
 ****************************************************************************/

 import QtQuick 2.1
 import QtQuick.Controls 1.0
 import QtQuick.Layouts 1.0
 import QtDataVisualization 1.1
 import QtQuick.Window 2.0
 import "."

 Rectangle {
     id: mainview
     width: 1280
     height: 1024

     property int buttonLayoutHeight: 180;
     state: Screen.width < Screen.height ? "portrait" : "landscape"

     Data {
         id: graphData
     }

     Axes {
         id: graphAxes
     }

     property Bar3DSeries selectedSeries
     selectedSeries: barSeries

     function handleSelectionChange(series, position) {
         if (position != series.invalidSelectionPosition) {
             selectedSeries = series
         }

         // Set tableView current row to selected bar
         var rowRole = series.dataProxy.rowLabels[position.x];
         var colRole
         if (barGraph.columnAxis === graphAxes.total)
             colRole = "01";
         else
             colRole = series.dataProxy.columnLabels[position.y];
         var checkTimestamp = rowRole + "-" + colRole
         var currentRow = tableView.currentRow
         if (currentRow === -1 || checkTimestamp !== graphData.model.get(currentRow).timestamp) {
             var totalRows = tableView.rowCount;
             for (var i = 0; i < totalRows; i++) {
                 var modelTimestamp = graphData.model.get(i).timestamp
                 if (modelTimestamp === checkTimestamp) {
                     tableView.currentRow = i
                     // Workaround to 5.2 row selection issue
                     if (typeof tableView.selection != "undefined") {
                         tableView.selection.clear()
                         tableView.selection.select(i)
                     }
                     break
                 }
             }
         }
     }

     Item {
         id: dataView
         anchors.right: mainview.right;
         anchors.bottom: mainview.bottom

         Bars3D {
             id: barGraph
             width: dataView.width
             height: dataView.height
             shadowQuality: AbstractGraph3D.ShadowQualityMedium
             selectionMode: AbstractGraph3D.SelectionItem
             theme: Theme3D {
                 type: Theme3D.ThemeRetro
                 labelBorderEnabled: true
                 font.pointSize: 35
                 labelBackgroundEnabled: true
                 colorStyle: Theme3D.ColorStyleRangeGradient
                 singleHighlightGradient: customGradient

                 ColorGradient {
                     id: customGradient
                     ColorGradientStop { position: 1.0; color: "#FFFF00" }
                     ColorGradientStop { position: 0.0; color: "#808000" }
                 }
             }
             barThickness: 0.7
             barSpacing: Qt.size(0.5, 0.5)
             barSpacingRelative: false
             scene.activeCamera.cameraPreset: Camera3D.CameraPresetIsometricLeftHigh
             columnAxis: graphAxes.column
             rowAxis: graphAxes.row
             valueAxis: graphAxes.value

             Bar3DSeries {
                 id: secondarySeries
                 visible: false
                 itemLabelFormat: "Expenses, @colLabel, @rowLabel: -@valueLabel"
                 baseGradient: secondaryGradient

                 ItemModelBarDataProxy {
                     id: secondaryProxy
                     itemModel: graphData.model
                     rowRole: "timestamp"
                     columnRole: "timestamp"
                     valueRole: "expenses"
                     rowRolePattern: /^(\d\d\d\d).*$/
                     columnRolePattern: /^.*-(\d\d)$/
                     valueRolePattern: /-/
                     rowRoleReplace: "\\1"
                     columnRoleReplace: "\\1"
                     multiMatchBehavior: ItemModelBarDataProxy.MMBCumulative
                 }

                 ColorGradient {
                     id: secondaryGradient
                     ColorGradientStop { position: 1.0; color: "#FF0000" }
                     ColorGradientStop { position: 0.0; color: "#600000" }
                 }

                 onSelectedBarChanged: handleSelectionChange(secondarySeries, position)
             }

             Bar3DSeries {
                 id: barSeries
                 itemLabelFormat: "Income, @colLabel, @rowLabel: @valueLabel"
                 baseGradient: barGradient

                 ItemModelBarDataProxy {
                     id: modelProxy
                     itemModel: graphData.model
                     rowRole: "timestamp"
                     columnRole: "timestamp"
                     valueRole: "income"
                     rowRolePattern: /^(\d\d\d\d).*$/
                     columnRolePattern: /^.*-(\d\d)$/
                     rowRoleReplace: "\\1"
                     columnRoleReplace: "\\1"
                     multiMatchBehavior: ItemModelBarDataProxy.MMBCumulative
                 }

                 ColorGradient {
                     id: barGradient
                     ColorGradientStop { position: 1.0; color: "#00FF00" }
                     ColorGradientStop { position: 0.0; color: "#006000" }
                 }

                 onSelectedBarChanged: handleSelectionChange(barSeries, position)
             }
         }
     }

     TableView {
         id: tableView
         anchors.top: parent.top
         anchors.left: parent.left
         TableViewColumn{ role: "timestamp" ; title: "Month" ; width: tableView.width / 2 }
         TableViewColumn{ role: "expenses" ; title: "Expenses" ; width: tableView.width / 4 }
         TableViewColumn{ role: "income" ; title: "Income" ; width: tableView.width / 4 }
         itemDelegate: Item {
             Text {
                 id: delegateText
                 anchors.verticalCenter: parent.verticalCenter
                 width: parent.width
                 anchors.leftMargin: 4
                 anchors.left: parent.left
                 anchors.right: parent.right
                 color: styleData.textColor
                 elide: styleData.elideMode
                 text: customText
                 horizontalAlignment: styleData.textAlignment

                 property string originalText: styleData.value
                 property string customText

                 onOriginalTextChanged: {
                     if (styleData.column === 0) {
                         if (delegateText.originalText !== "") {
                             var pattern = /(\d\d\d\d)-(\d\d)/
                             var matches = pattern.exec(delegateText.originalText)
                             var colIndex = parseInt(matches[2], 10) - 1
                             delegateText.customText = matches[1] + " - " + graphAxes.column.labels[colIndex]
                         }
                     } else {
                         delegateText.customText = originalText
                     }
                 }
             }
         }

         model: graphData.model

         onCurrentRowChanged: {
             var timestamp = graphData.model.get(currentRow).timestamp
             var pattern = /(\d\d\d\d)-(\d\d)/
             var matches = pattern.exec(timestamp)
             var rowIndex = modelProxy.rowCategoryIndex(matches[1])
             var colIndex
             if (barGraph.columnAxis === graphAxes.total)
                 colIndex = 0 // Just one column when showing yearly totals
             else
                 colIndex = modelProxy.columnCategoryIndex(matches[2])
             if (selectedSeries.visible)
                 mainview.selectedSeries.selectedBar = Qt.point(rowIndex, colIndex)
             else if (barSeries.visible)
                 barSeries.selectedBar = Qt.point(rowIndex, colIndex)
             else
                 secondarySeries.selectedBar = Qt.point(rowIndex, colIndex)
         }
     }

     ColumnLayout {
         id: controlLayout
         spacing: 0

         Button {
             id: changeDataButton
             Layout.fillWidth: true
             Layout.fillHeight: true
             text: "Show 2010 - 2012"
             clip: true
             onClicked: {
                 if (text === "Show yearly totals") {
                     modelProxy.autoRowCategories = true
                     secondaryProxy.autoRowCategories = true
                     modelProxy.columnRolePattern = /^.*$/
                     secondaryProxy.columnRolePattern = /^.*$/
                     graphAxes.value.autoAdjustRange = true
                     barGraph.columnAxis = graphAxes.total
                     text = "Show all years"
                 } else if (text === "Show all years") {
                     modelProxy.autoRowCategories = true
                     secondaryProxy.autoRowCategories = true
                     modelProxy.columnRolePattern = /^.*-(\d\d)$/
                     secondaryProxy.columnRolePattern = /^.*-(\d\d)$/
                     graphAxes.value.min = 0
                     graphAxes.value.max = 35
                     barGraph.columnAxis = graphAxes.column
                     text = "Show 2010 - 2012"
                 } else { // text === "Show 2010 - 2012"
                     // Explicitly defining row categories, since we do not want to show data for
                     // all years in the model, just for the selected ones.
                     modelProxy.autoRowCategories = false
                     secondaryProxy.autoRowCategories = false
                     modelProxy.rowCategories = ["2010", "2011", "2012"]
                     secondaryProxy.rowCategories = ["2010", "2011", "2012"]
                     text = "Show yearly totals"
                 }
             }
         }

         Button {
             id: shadowToggle
             Layout.fillWidth: true
             Layout.fillHeight: true
             text: barGraph.shadowsSupported ? "Hide Shadows" : "Shadows not supported"
             clip: true
             enabled: barGraph.shadowsSupported
             onClicked: {
                 if (barGraph.shadowQuality == AbstractGraph3D.ShadowQualityNone) {
                     barGraph.shadowQuality = AbstractGraph3D.ShadowQualityMedium;
                     text = "Hide Shadows"
                 } else {
                     barGraph.shadowQuality = AbstractGraph3D.ShadowQualityNone;
                     text = "Show Shadows"
                 }
             }
         }

         Button {
             id: seriesToggle
             Layout.fillWidth: true
             Layout.fillHeight: true
             text: "Show Expenses"
             clip: true
             onClicked: {
                 if (text === "Show Expenses") {
                     barSeries.visible = false
                     secondarySeries.visible = true
                     barGraph.valueAxis.labelFormat = "-%.2f M\u20AC"
                     secondarySeries.itemLabelFormat = "Expenses, @colLabel, @rowLabel: @valueLabel"
                     text = "Show Both"
                 } else if (text === "Show Both") {
                     barSeries.visible = true
                     barGraph.valueAxis.labelFormat = "%.2f M\u20AC"
                     secondarySeries.itemLabelFormat = "Expenses, @colLabel, @rowLabel: -@valueLabel"
                     text = "Show Income"
                 } else { // text === "Show Income"
                     secondarySeries.visible = false
                     text = "Show Expenses"
                 }
             }
         }
     }

     states: [
         State  {
             name: "landscape"
             PropertyChanges {
                 target: dataView
                 width: mainview.width / 4 * 3
                 height: mainview.height
             }
             PropertyChanges  {
                 target: tableView
                 height: mainview.height - buttonLayoutHeight
                 anchors.right: dataView.left
                 anchors.left: mainview.left
                 anchors.bottom: undefined
             }
             PropertyChanges  {
                 target: controlLayout
                 width: mainview.width / 4
                 height: buttonLayoutHeight
                 anchors.top: tableView.bottom
                 anchors.bottom: mainview.bottom
                 anchors.left: mainview.left
                 anchors.right: dataView.left
             }
         },
         State  {
             name: "portrait"
             PropertyChanges {
                 target: dataView
                 width: mainview.height / 4 * 3
                 height: mainview.width
             }
             PropertyChanges  {
                 target: tableView
                 height: mainview.width
                 anchors.right: controlLayout.left
                 anchors.left: mainview.left
                 anchors.bottom: dataView.top
             }
             PropertyChanges  {
                 target: controlLayout
                 width: mainview.height / 4
                 height: mainview.width / 4
                 anchors.top: mainview.top
                 anchors.bottom: dataView.top
                 anchors.left: undefined
                 anchors.right: mainview.right
             }
         }
     ]
 }