2 * Copyright (C) 2013 Canonical, Ltd.
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.
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.
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/>.
18import Ubuntu.Components 0.1
22import "../Components/ListItems" as ListItems
27 property Scope scope: null
28 property SortFilterProxyModel categories: categoryFilter
29 property bool isCurrent: false
30 property alias moving: categoryView.moving
31 property int tabBarHeight: 0
32 property PageHeader pageHeader: null
33 property Item previewListView: null
35 signal movementStarted
36 signal positionedAtBeginning
38 property bool enableHeightBehaviorOnNextCreation: false
39 property var categoryView: categoryView
41 // FIXME delay the search so that daemons have time to settle, note that
42 // removing this will break ScopeView::test_changeScope
46 scope.activateApplication.connect(activateApp);
50 function activateApp(appId) {
51 shell.activateApplication(appId);
57 value: isCurrent && !previewListView.open
63 onTriggered: scope.searchQuery = ""
66 SortFilterProxyModel {
68 model: scope ? scope.categories : null
69 dynamicSortFilter: true
70 filterRole: Categories.RoleCount
76 pageHeader.resetSearch();
77 previewListView.open = false;
80 onMovementStarted: categoryView.showHeader()
82 onPositionedAtBeginning: categoryView.positionAtBeginning()
85 target: scopeView.scope
86 property: "searchQuery"
87 value: pageHeader.searchQuery
93 property: "searchQuery"
94 value: scopeView.scope ? scopeView.scope.searchQuery : ""
100 onSearchClicked: if (isCurrent) {
101 pageHeader.triggerSearch()
102 categoryView.showHeader()
107 target: scopeView.scope
108 onShowDash: previewListView.open = false;
109 onHideDash: previewListView.open = false;
114 objectName: "categoryListView"
116 model: scopeView.categories
117 forceNoClip: previewListView.open
119 property string expandedCategoryId: ""
121 onContentYChanged: pageHeader.positionRealHeader();
122 onOriginYChanged: pageHeader.positionRealHeader();
123 onContentHeightChanged: pageHeader.positionRealHeader();
125 delegate: ListItems.Base {
127 objectName: "dashCategory" + category
128 highlightWhenPressed: false
131 readonly property bool expandable: rendererLoader.item ? rendererLoader.item.expandable : false
132 readonly property bool filtered: rendererLoader.item ? rendererLoader.item.filter : true
133 readonly property string category: categoryId
134 readonly property var item: rendererLoader.item
140 template: model.renderer
141 components: model.components
142 viewWidth: parent.width
154 switch (cardTool.categoryLayout) {
155 case "carousel": return "CardCarousel.qml";
156 case "running-apps": return "Apps/RunningApplicationsGrid.qml";
158 default: return "CardFilterGrid.qml";
163 if (item.enableHeightBehavior !== undefined && item.enableHeightBehaviorOnNextCreation !== undefined) {
164 item.enableHeightBehavior = scopeView.enableHeightBehaviorOnNextCreation;
165 scopeView.enableHeightBehaviorOnNextCreation = false;
167 if (source.toString().indexOf("Apps/RunningApplicationsGrid.qml") != -1) {
168 // TODO: this is still a kludge :D Ideally add some kind of hook so that we
169 // can do this from DashApps.qml or think a better way that needs no special casing
170 item.firstModel = Qt.binding(function() { return mainStageApplicationsModel })
171 item.secondModel = Qt.binding(function() { return sideStageApplicationModel })
172 item.canEnableTerminationMode = Qt.binding(function() { return scopeView.isCurrent })
174 item.model = Qt.binding(function() { return results })
176 item.objectName = Qt.binding(function() { return categoryId })
177 if (item.expandable) {
178 var shouldFilter = categoryId != categoryView.expandedCategoryId;
179 if (shouldFilter != item.filter) {
180 item.filter = shouldFilter;
183 updateDelegateCreationRange();
184 item.cardTool = cardTool;
187 Component.onDestruction: {
188 if (item.enableHeightBehavior !== undefined && item.enableHeightBehaviorOnNextCreation !== undefined) {
189 scopeView.enableHeightBehaviorOnNextCreation = item.enableHeightBehaviorOnNextCreation;
194 target: rendererLoader.item
196 if (scopeView.scope.id === "scopes" || (scopeView.scope.id == "clickscope" && categoryId == "local")) {
197 // TODO Technically it is possible that calling activate() will make the scope emit
198 // previewRequested so that we show a preview but there's no scope that does that yet
199 // so it's not implemented
200 var item = target.model.get(index);
201 scopeView.scope.activate(item.result)
203 previewListView.model = target.model;
204 previewListView.currentIndex = -1
205 previewListView.currentIndex = index;
206 previewListView.open = true
210 previewListView.model = target.model;
211 previewListView.currentIndex = -1
212 previewListView.currentIndex = index;
213 previewListView.open = true
218 onExpandedCategoryIdChanged: {
219 collapseAllButExpandedCategory();
221 function collapseAllButExpandedCategory() {
222 var item = rendererLoader.item;
223 if (item.expandable) {
224 var shouldFilter = categoryId != categoryView.expandedCategoryId;
225 if (shouldFilter != item.filter) {
226 // If the filter animation will be seen start it, otherwise, just flip the switch
227 var shrinkingVisible = shouldFilter && y + item.collapsedHeight < categoryView.height;
228 var growingVisible = !shouldFilter && y + height < categoryView.height;
229 if (!previewListView.open || !shouldFilter) {
230 if (shrinkingVisible || growingVisible) {
231 item.startFilterAnimation(shouldFilter)
233 item.filter = shouldFilter;
235 if (!shouldFilter && !previewListView.open) {
236 categoryView.maximizeVisibleArea(index, item.uncollapsedHeight);
242 onOriginYChanged: rendererLoader.updateDelegateCreationRange();
243 onContentYChanged: rendererLoader.updateDelegateCreationRange();
244 onHeightChanged: rendererLoader.updateDelegateCreationRange();
245 onContentHeightChanged: rendererLoader.updateDelegateCreationRange();
248 function updateDelegateCreationRange() {
249 // Do not update the range if we are overshooting up or down, since we'll come back
250 // to the stable position and delete/create items without any reason
251 if (categoryView.contentY < categoryView.originY) {
253 } else if (categoryView.contentHeight > categoryView.height && categoryView.contentY + categoryView.height > categoryView.contentHeight) {
257 if (item && item.hasOwnProperty("delegateCreationBegin")) {
258 if (baseItem.y + baseItem.height <= 0) {
259 // Not visible (item at top of the list)
260 item.delegateCreationBegin = baseItem.height
261 item.delegateCreationEnd = baseItem.height
262 } else if (baseItem.y >= categoryView.height) {
263 // Not visible (item at bottom of the list)
264 item.delegateCreationBegin = 0
265 item.delegateCreationEnd = 0
267 item.delegateCreationBegin = Math.max(-baseItem.y, 0)
268 item.delegateCreationEnd = Math.min(categoryView.height + item.delegateCreationBegin, baseItem.height)
280 fillMode: Image.Stretch
281 source: "graphics/dash_divider_top_lightgrad.png"
286 // FIXME Should not rely on model.count but view.count, but ListViewWithPageHeader doesn't expose it yet.
287 visible: index != categoryView.model.count - 1
289 bottom: parent.bottom
293 fillMode: Image.Stretch
294 source: "graphics/dash_divider_top_darkgrad.png"
299 onHeightChanged: rendererLoader.updateDelegateCreationRange();
300 onYChanged: rendererLoader.updateDelegateCreationRange();
303 sectionProperty: "name"
304 sectionDelegate: ListItems.Header {
305 objectName: "dashSectionHeader" + (delegate ? delegate.category : "")
306 property var delegate: categoryView.item(delegateIndex)
307 width: categoryView.width
310 if (delegate && delegate.expandable)
311 return delegate.filtered ? "graphics/header_handlearrow.png" : "graphics/header_handlearrow2.png"
315 if (categoryView.expandedCategoryId != delegate.category)
316 categoryView.expandedCategoryId = delegate.category;
318 categoryView.expandedCategoryId = "";
322 implicitHeight: scopeView.tabBarHeight
324 if (scopeView.pageHeader && scopeView.isCurrent) {
325 scopeView.pageHeader.height = height;
328 onYChanged: positionRealHeader();
330 function positionRealHeader() {
331 if (scopeView.pageHeader && scopeView.isCurrent) {
332 scopeView.pageHeader.y = y + parent.y;
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list