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
              }
          }
      ]
  }