Unity 8
 All Classes Functions Properties
DashContent.qml
1 /*
2  * Copyright (C) 2013, 2014 Canonical, Ltd.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 3.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  */
16 
17 import QtQuick 2.0
18 import Ubuntu.Components 0.1
19 import Unity 0.2
20 import Utils 0.1
21 import "../Components"
22 
23 Item {
24  id: dashContent
25 
26  property var model: null
27  property var scopes: null
28  readonly property alias currentIndex: dashContentList.currentIndex
29  property alias previewOpen: previewListView.open
30 
31  property ListModel searchHistory
32 
33  signal scopeLoaded(string scopeId)
34  signal gotoScope(string scopeId)
35  signal openScope(var scope)
36 
37  // If we set the current scope index before the scopes have been added,
38  // then we need to wait until the loaded signals gets emitted from the scopes
39  property var set_current_index: undefined
40  Connections {
41  target: scopes
42  onLoadedChanged: {
43  if (scopes.loaded && set_current_index != undefined) {
44  setCurrentScopeAtIndex(set_current_index[0], set_current_index[1], set_current_index[2]);
45  set_current_index = undefined;
46  }
47  }
48  }
49 
50  function setCurrentScopeAtIndex(index, animate, reset) {
51  // if the scopes haven't loaded yet, then wait until they are.
52  if (!scopes.loaded) {
53  set_current_index = [ index, animate, reset ]
54  return;
55  }
56 
57  var storedMoveDuration = dashContentList.highlightMoveDuration
58  var storedMoveSpeed = dashContentList.highlightMoveVelocity
59  if (!animate) {
60  dashContentList.highlightMoveVelocity = units.gu(4167)
61  dashContentList.highlightMoveDuration = 0
62  }
63 
64  set_current_index = undefined;
65 
66  if (dashContentList.count > index)
67  {
68  dashContentList.currentIndex = index
69 
70  if (reset) {
71  dashContentList.currentItem.item.positionAtBeginning()
72  }
73  }
74 
75  if (!animate) {
76  dashContentList.highlightMoveDuration = storedMoveDuration
77  dashContentList.highlightMoveVelocity = storedMoveSpeed
78  }
79  }
80 
81  function closeScope(scope) {
82  dashContentList.currentItem.theScope.closeScope(scope)
83  }
84 
85  function closePreview() {
86  previewListView.open = false;
87  }
88 
89  Item {
90  id: dashContentListHolder
91 
92  x: previewListView.open ? -width : 0
93  Behavior on x { UbuntuNumberAnimation { } }
94  width: parent.width
95  height: parent.height
96 
97  ListView {
98  id: dashContentList
99  objectName: "dashContentList"
100 
101  interactive: dashContent.scopes.loaded && !previewListView.open && currentItem && !currentItem.moving
102 
103  anchors.fill: parent
104  model: dashContent.model
105  orientation: ListView.Horizontal
106  boundsBehavior: Flickable.DragAndOvershootBounds
107  flickDeceleration: units.gu(625)
108  maximumFlickVelocity: width * 5
109  snapMode: ListView.SnapOneItem
110  highlightMoveDuration: 250
111  highlightRangeMode: ListView.StrictlyEnforceRange
112  // TODO Investigate if we can switch to a smaller cache buffer when/if UbuntuShape gets more performant
113  cacheBuffer: 1073741823
114  onMovementStarted: currentItem.item.showHeader();
115  clip: parent.x != 0
116 
117  // If the number of items is less than the current index, then need to reset to another item.
118  onCountChanged: {
119  if (count > 0) {
120  if (currentIndex >= count) {
121  dashContent.setCurrentScopeAtIndex(count-1, true, true)
122  } else if (currentIndex < 0) {
123  // setting currentIndex directly, cause we don't want to loose set_current_index
124  dashContentList.currentIndex = 0
125  }
126  }
127  }
128 
129  delegate:
130  Loader {
131  width: ListView.view.width
132  height: ListView.view.height
133  asynchronous: true
134  // TODO This if will eventually go away since we're killing DashApps.qml
135  // once we move app closing to the spread
136  source: (scope.id == "clickscope") ? "DashApps.qml" : "GenericScopeView.qml"
137  objectName: scope.id + " loader"
138 
139  readonly property bool moving: item ? item.moving : false
140  readonly property var categoryView: item ? item.categoryView : null
141  readonly property Scope theScope: scope
142 
143  // these are needed for autopilot tests
144  readonly property string scopeId: scope.id
145  readonly property bool isCurrent: ListView.isCurrentItem
146  readonly property bool isLoaded: status == Loader.Ready
147 
148  onLoaded: {
149  item.objectName = scope.id
150  item.pageHeader = dashPageHeader;
151  item.previewListView = previewListView;
152  item.scope = Qt.binding(function() { return scope })
153  item.isCurrent = Qt.binding(function() { return visible && ListView.isCurrentItem })
154  item.tabBarHeight = dashPageHeader.implicitHeight;
155  dashContent.scopeLoaded(item.scope.id)
156  }
157  Connections {
158  target: isCurrent ? scope : null
159  onGotoScope: {
160  // Note here scopeId is the signal parameter and not the loader property
161  dashContent.gotoScope(scopeId);
162  }
163  onOpenScope: {
164  dashContent.openScope(scope);
165  }
166  }
167 
168  Component.onDestruction: active = false
169  }
170  }
171 
172  PageHeader {
173  id: dashPageHeader
174  objectName: "pageHeader"
175  width: parent.width
176  searchEntryEnabled: true
177  searchHistory: dashContent.searchHistory
178  scope: dashContentList.currentItem && dashContentList.currentItem.theScope
179 
180  childItem: TabBar {
181  id: tabBar
182  objectName: "tabbar"
183  height: units.gu(6.5)
184  width: parent.width
185  style: DashContentTabBarStyle {}
186 
187  SortFilterProxyModel {
188  id: tabBarModel
189 
190  model: dashContentList.model
191 
192  property int selectedIndex: -1
193  onSelectedIndexChanged: {
194  if (dashContentList.currentIndex == -1 && tabBar.selectedIndex != -1) {
195  // TODO This together with the Timer below
196  // are a workaround for the first tab sometimes not showing the text.
197  // But Tabs are going away in the future so not sure if makes
198  // sense invetigating what's the problem at this stage
199  selectionModeTimer.restart();
200  }
201  dashContentList.currentIndex = selectedIndex;
202  }
203  }
204 
205  model: tabBarModel.count > 0 ? tabBarModel : null
206 
207  Connections {
208  target: dashContentList
209  onCurrentIndexChanged: {
210  tabBarModel.selectedIndex = dashContentList.currentIndex
211  }
212  }
213 
214  Timer {
215  id: selectionModeTimer
216  interval: 1
217  onTriggered: tabBar.selectionMode = false
218  }
219  }
220  }
221  }
222 
223  PreviewListView {
224  id: previewListView
225  objectName: "dashContentPreviewList"
226  visible: x != width
227  scope: dashContentList.currentItem ? dashContentList.currentItem.theScope : null
228  pageHeader: dashPageHeader
229  width: parent.width
230  height: parent.height
231  anchors.left: dashContentListHolder.right
232  }
233 }