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
28 property SortFilterProxyModel categories: categoryFilter
29 property bool isCurrent
30 property alias moving: categoryView.moving
31 property int tabBarHeight: 0
32 property PageHeader pageHeader: null
33 property OpenEffect openEffect: null
34 property Item previewListView: null
37 signal movementStarted
38 signal positionedAtBeginning
39 signal headerPositionChanged(int position)
40 signal headerHeightChanged(int height)
42 property bool enableHeightBehaviorOnNextCreation: false
43 property var categoryView: categoryView
45 // FIXME delay the search so that daemons have time to settle, note that
46 // removing this will break ScopeView::test_changeScope
50 scope.activateApplication.connect(activateApp);
54 function activateApp(desktopFilePath) {
55 shell.activateApplication(desktopFilePath);
67 onTriggered: scope.searchQuery = ""
70 SortFilterProxyModel {
72 model: scope ? scope.categories : null
73 dynamicSortFilter: true
74 filterRole: Categories.RoleCount
80 pageHeader.resetSearch();
81 previewListView.open = false;
84 onMovementStarted: categoryView.showHeader()
86 onPositionedAtBeginning: categoryView.positionAtBeginning()
89 target: scopeView.scope
90 property: "searchQuery"
91 value: pageHeader.searchQuery
97 property: "searchQuery"
98 value: scopeView.scope.searchQuery
104 onSearchClicked: if (isCurrent) {
105 pageHeader.triggerSearch()
106 categoryView.showHeader()
111 target: scopeView.scope
112 onShowDash: previewListView.open = false;
113 onHideDash: previewListView.open = false;
118 objectName: "categoryListView"
120 model: scopeView.categories
121 forceNoClip: previewListView.onScreen
123 onAtYEndChanged: if (atYEnd) endReached()
124 onMovingChanged: if (moving && atYEnd) endReached()
126 property string expandedCategoryId: ""
127 signal correctExpandedCategory();
129 onContentYChanged: pageHeader.positionRealHeader();
130 onOriginYChanged: pageHeader.positionRealHeader();
131 onContentHeightChanged: pageHeader.positionRealHeader();
133 Behavior on contentY {
134 enabled: previewListView.open
135 UbuntuNumberAnimation {}
138 delegate: ListItems.Base {
140 highlightWhenPressed: false
142 readonly property bool expandable: rendererLoader.item ? rendererLoader.item.expandable : false
143 readonly property bool filtered: rendererLoader.item ? rendererLoader.item.filter : true
144 readonly property string category: categoryId
154 source: getRenderer(model.renderer, model.contentType, model.rendererHint)
157 if (item.enableHeightBehavior !== undefined && item.enableHeightBehaviorOnNextCreation !== undefined) {
158 item.enableHeightBehavior = scopeView.enableHeightBehaviorOnNextCreation;
159 scopeView.enableHeightBehaviorOnNextCreation = false;
161 if (source.toString().indexOf("Apps/RunningApplicationsGrid.qml") != -1) {
162 // TODO: the running apps grid doesn't support standard scope results model yet
163 item.firstModel = Qt.binding(function() { return results.firstModel })
164 item.secondModel = Qt.binding(function() { return results.secondModel })
165 item.canEnableTerminationMode = Qt.binding(function() { return scopeView.isCurrent })
167 item.model = Qt.binding(function() { return results })
169 item.objectName = Qt.binding(function() { return categoryId })
170 if (item.expandable) {
171 var shouldFilter = categoryId != categoryView.expandedCategoryId;
172 if (shouldFilter != item.filter) {
173 item.filter = shouldFilter;
176 updateDelegateCreationRange();
179 Component.onDestruction: {
180 if (item.enableHeightBehavior !== undefined && item.enableHeightBehaviorOnNextCreation !== undefined) {
181 scopeView.enableHeightBehaviorOnNextCreation = item.enableHeightBehaviorOnNextCreation;
186 target: rendererLoader.item
188 // Prepare the preview in case activate() triggers a preview only
189 openEffect.positionPx = Math.max(mapToItem(categoryView, 0, itemY).y, pageHeader.height + categoryView.stickyHeaderHeight);
190 previewListView.categoryId = categoryId
191 previewListView.categoryDelegate = rendererLoader.item
192 previewListView.model = target.model;
193 previewListView.init = true;
194 previewListView.currentIndex = index;
196 var item = target.model.get(index);
198 if ((scopeView.scope.id == "applications.scope" && categoryId == "installed")
199 || (scopeView.scope.id == "home.scope" && categoryId == "applications.scope")) {
200 scopeView.scope.activate(item.uri, item.icon, item.category, 0, item.mimetype, item.title,
201 item.comment, item.dndUri, item.metadata)
203 previewListView.open = true
205 scopeView.scope.preview( item.uri, item.icon, item.category, 0, item.mimetype, item.title,
206 item.comment, item.dndUri, item.metadata)
210 openEffect.positionPx = Math.max(mapToItem(categoryView, 0, itemY).y, pageHeader.height + categoryView.stickyHeaderHeight);
211 previewListView.categoryId = categoryId
212 previewListView.categoryDelegate = rendererLoader.item
213 previewListView.model = target.model;
214 previewListView.init = true;
215 previewListView.currentIndex = index;
216 previewListView.open = true
218 var item = target.model.get(index)
219 scopeView.scope.preview( item.uri, item.icon, item.category, 0, item.mimetype, item.title,
220 item.comment, item.dndUri, item.metadata)
225 onExpandedCategoryIdChanged: {
226 collapseAllButExpandedCategory();
228 onCorrectExpandedCategory: {
229 collapseAllButExpandedCategory();
231 function collapseAllButExpandedCategory() {
232 var item = rendererLoader.item;
233 if (item.expandable) {
234 var shouldFilter = categoryId != categoryView.expandedCategoryId;
235 if (shouldFilter != item.filter) {
236 // If the filter animation will be seen start it, otherwise, just flip the switch
237 var shrinkingVisible = shouldFilter && y + item.collapsedHeight < categoryView.height;
238 var growingVisible = !shouldFilter && y + height < categoryView.height;
239 if (!previewListView.open || !shouldFilter) {
240 if (shrinkingVisible || growingVisible) {
241 item.startFilterAnimation(shouldFilter)
243 item.filter = shouldFilter;
245 if (!shouldFilter && !previewListView.open) {
246 categoryView.maximizeVisibleArea(index, item.uncollapsedHeight);
252 onContentYChanged: rendererLoader.updateDelegateCreationRange();
253 onHeightChanged: rendererLoader.updateDelegateCreationRange();
256 function updateDelegateCreationRange() {
257 // Do not update the range if we are overshooting up or down, since we'll come back
258 // to the stable position and delete/create items without any reason
259 if (categoryView.contentY < categoryView.originY) {
261 } else if (categoryView.contentY + categoryView.height > categoryView.contentHeight) {
265 if (item.hasOwnProperty("delegateCreationBegin")) {
266 if (baseItem.y + baseItem.height <= 0) {
267 // Not visible (item at top of the list)
268 item.delegateCreationBegin = baseItem.height
269 item.delegateCreationEnd = baseItem.height
270 } else if (baseItem.y >= categoryView.height) {
271 // Not visible (item at bottom of the list)
272 item.delegateCreationBegin = 0
273 item.delegateCreationEnd = 0
275 item.delegateCreationBegin = Math.max(-baseItem.y, 0)
276 item.delegateCreationEnd = Math.min(categoryView.height + item.delegateCreationBegin, baseItem.height)
283 sectionProperty: "name"
284 sectionDelegate: ListItems.Header {
285 property var delegate: categoryView.item(delegateIndex)
286 width: categoryView.width
289 if (delegate && delegate.expandable)
290 return delegate.filtered ? "graphics/header_handlearrow.png" : "graphics/header_handlearrow2.png"
294 if (categoryView.expandedCategoryId != delegate.category)
295 categoryView.expandedCategoryId = delegate.category;
297 categoryView.expandedCategoryId = "";
301 implicitHeight: scopeView.tabBarHeight
302 onHeightChanged: scopeView.headerHeightChanged(height)
303 onYChanged: positionRealHeader();
305 function positionRealHeader() {
306 scopeView.headerPositionChanged(y + parent.y)
311 function getDefaultRendererId(contentType) {
312 switch (contentType) {
313 default: return "grid";
317 function getRenderer(rendererId, contentType, rendererHint) {
318 if (rendererId == "default") {
319 rendererId = getDefaultRendererId(contentType);
321 switch (rendererId) {
323 switch (contentType) {
324 case "music": return "Music/MusicCarouselLoader.qml";
325 case "video": return "Video/VideoCarouselLoader.qml";
326 default: return "Generic/GenericCarouselLoader.qml";
330 switch (contentType) {
332 if (rendererHint == "toggled")
333 return "Apps/DashPluginFilterGrid.qml";
335 return "Generic/GenericFilterGrid.qml";
337 case "music": return "Music/MusicFilterGrid.qml";
338 case "video": return "Video/VideoFilterGrid.qml";
339 case "weather": return "Generic/WeatherFilterGrid.qml";
340 default: return "Generic/GenericFilterGrid.qml";
344 switch (contentType) {
345 case "apps": return "Apps/RunningApplicationsGrid.qml";
346 default: return "Generic/GenericFilterGrid.qml";
349 default: return "Generic/GenericFilterGrid.qml";
354 target: scopeView.scope
356 if (previewListView.init) {
357 // Preview was triggered because of a click on the item. Need to expand now.
358 if (!previewListView.open) {
359 previewListView.open = true
362 var index = previewListView.currentIndex
363 previewListView.currentIndex = -1
364 previewListView.currentIndex = index
365 previewListView.init = false
367 previewListView.currentItem.previewData = preview
371 // TODO: Move as InverseMouseArea to DashPreview
373 objectName: "closePreviewMouseArea"
374 enabled: previewListView.onScreen
377 topMargin: openEffect.bottomGapPx
380 previewListView.open = false;
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