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
20import "../Components/ListItems" as ListItems
24 readonly property alias previewShown: previewLoader.onScreen
25 property bool enableHeightBehaviorOnNextCreation: false
27 moving: categoryView.moving
30 pageHeader.resetSearch();
31 previewLoader.open = false;
34 onMovementStarted: categoryView.showHeader()
36 onPositionedAtBeginning: categoryView.positionAtBeginning()
39 target: scopeView.scope
40 property: "searchQuery"
41 value: pageHeader.searchQuery
46 property: "searchQuery"
47 value: scopeView.scope.searchQuery
52 onSearchClicked: if (isCurrent) {
53 pageHeader.triggerSearch()
54 categoryView.showHeader()
59 target: scopeView.scope
60 onShowDash: previewLoader.open = false;
61 onHideDash: previewLoader.open = false;
66 objectName: "categoryListView"
68 model: scopeView.categories
69 forceNoClip: previewLoader.onScreen
71 onAtYEndChanged: if (atYEnd) endReached()
72 onMovingChanged: if (moving && atYEnd) endReached()
74 property string expandedCategoryId: ""
76 delegate: ListItems.Base {
78 highlightWhenPressed: false
80 readonly property bool expandable: rendererLoader.item ? rendererLoader.item.expandable : false
81 readonly property bool filtered: rendererLoader.item ? rendererLoader.item.filter : true
82 readonly property string category: categoryId
92 source: getRenderer(model.renderer, model.contentType, model.rendererHint)
95 if (item.enableHeightBehavior !== undefined && item.enableHeightBehaviorOnNextCreation !== undefined) {
96 item.enableHeightBehavior = scopeView.enableHeightBehaviorOnNextCreation;
97 scopeView.enableHeightBehaviorOnNextCreation = false;
99 if (source.toString().indexOf("Apps/RunningApplicationsGrid.qml") != -1) {
100 // TODO: the running apps grid doesn't support standard scope results model yet
101 item.firstModel = Qt.binding(function() { return results.firstModel })
102 item.secondModel = Qt.binding(function() { return results.secondModel })
103 item.canEnableTerminationMode = Qt.binding(function() { return scopeView.isCurrent })
105 item.model = Qt.binding(function() { return results })
107 item.objectName = Qt.binding(function() { return categoryId })
108 if (item.expandable) {
109 var shouldFilter = categoryId != categoryView.expandedCategoryId;
110 if (shouldFilter != item.filter) {
111 item.filter = shouldFilter;
114 updateDelegateCreationRange();
117 Component.onDestruction: {
118 if (item.enableHeightBehavior !== undefined && item.enableHeightBehaviorOnNextCreation !== undefined) {
119 scopeView.enableHeightBehaviorOnNextCreation = item.enableHeightBehaviorOnNextCreation;
124 target: rendererLoader.item
126 effect.positionPx = mapToItem(categoryView, 0, itemY).y
127 scopeView.scope.activate(delegateItem.model.uri,
128 delegateItem.model.icon,
129 delegateItem.model.category,
131 delegateItem.model.mimetype,
132 delegateItem.model.title,
133 delegateItem.model.comment,
134 delegateItem.model.dndUri,
135 delegateItem.model.metadata)
138 effect.positionPx = mapToItem(categoryView, 0, itemY).y
139 scopeView.scope.preview( delegateItem.model.uri,
140 delegateItem.model.icon,
141 delegateItem.model.category,
143 delegateItem.model.mimetype,
144 delegateItem.model.title,
145 delegateItem.model.comment,
146 delegateItem.model.dndUri,
147 delegateItem.model.metadata)
152 onExpandedCategoryIdChanged: {
153 var item = rendererLoader.item;
154 if (item.expandable) {
155 var shouldFilter = categoryId != categoryView.expandedCategoryId;
156 if (shouldFilter != item.filter) {
157 // If the filter animation will be seen start it, otherwise, just flip the switch
158 var shrinkingVisible = shouldFilter && y + item.collapsedHeight < categoryView.height;
159 var growingVisible = !shouldFilter && y + height < categoryView.height;
160 if (shrinkingVisible || growingVisible) {
161 item.startFilterAnimation(shouldFilter)
163 item.filter = shouldFilter;
166 categoryView.maximizeVisibleArea(index, item.uncollapsedHeight);
171 onContentYChanged: rendererLoader.updateDelegateCreationRange();
172 onHeightChanged: rendererLoader.updateDelegateCreationRange();
175 function updateDelegateCreationRange() {
176 // Do not update the range if we are overshooting up or down, since we'll come back
177 // to the stable position and delete/create items without any reason
178 if (categoryView.contentY < categoryView.originY) {
180 } else if (categoryView.contentY + categoryView.height > categoryView.contentHeight) {
184 if (item.hasOwnProperty("delegateCreationBegin")) {
185 if (baseItem.y + baseItem.height <= 0) {
186 // Not visible (item at top of the list)
187 item.delegateCreationBegin = baseItem.height
188 item.delegateCreationEnd = baseItem.height
189 } else if (baseItem.y >= categoryView.height) {
190 // Not visible (item at bottom of the list)
191 item.delegateCreationBegin = 0
192 item.delegateCreationEnd = 0
194 item.delegateCreationBegin = Math.max(-baseItem.y, 0)
195 item.delegateCreationEnd = Math.min(categoryView.height + item.delegateCreationBegin, baseItem.height)
202 sectionProperty: "name"
203 sectionDelegate: ListItems.Header {
204 property var delegate: categoryView.item(delegateIndex)
205 width: categoryView.width
208 if (delegate && delegate.expandable)
209 return delegate.filtered ? "graphics/header_handlearrow.png" : "graphics/header_handlearrow2.png"
213 if (categoryView.expandedCategoryId != delegate.category)
214 categoryView.expandedCategoryId = delegate.category;
216 categoryView.expandedCategoryId = "";
219 pageHeader: PageHeader {
221 objectName: "pageHeader"
222 width: categoryView.width
223 text: scopeView.scope.name
224 searchEntryEnabled: true
225 scope: scopeView.scope
229 function getDefaultRendererId(contentType) {
230 switch (contentType) {
231 default: return "grid";
235 function getRenderer(rendererId, contentType, rendererHint) {
236 if (rendererId == "default") {
237 rendererId = getDefaultRendererId(contentType);
239 switch (rendererId) {
241 switch (contentType) {
242 case "video": return "Video/VideoFilterGrid.qml";
243 case "music": return "Music/MusicFilterGrid.qml";
245 if (rendererHint == "toggled")
246 return "Apps/DashPluginFilterGrid.qml";
248 return "Generic/GenericFilterGrid.qml";
250 case "weather": return "Generic/WeatherFilterGrid.qml";
251 default: return "Generic/GenericFilterGrid.qml";
255 switch (contentType) {
256 case "music": return "Music/MusicCarousel.qml";
257 default: return "Generic/GenericCarousel.qml";
261 switch (contentType) {
262 case "apps": return "Apps/RunningApplicationsGrid.qml";
263 default: return "Generic/GenericFilterGrid.qml";
266 default: return "Generic/GenericFilterGrid.qml";
274 bottomMargin: -bottomOverflow
276 sourceItem: categoryView
280 topGapPx: (1 - gap) * positionPx
281 topOpacity: (1 - gap * 1.2)
282 bottomGapPx: positionPx + gap * (targetBottomGapPx - positionPx)
283 bottomOverflow: units.gu(20)
284 bottomOpacity: 1 - (gap * 0.8)
286 property int targetBottomGapPx: height - units.gu(8) - bottomOverflow
287 property real gap: previewLoader.open ? 1.0 : 0.0
292 easing.type: Easing.InOutQuad
294 if (!previewLoader.open && !running) {
295 previewLoader.onScreen = false
303 target: scopeView.scope
305 previewLoader.previewData = preview
306 previewLoader.open = true
310 PreviewDelegateMapper {
311 id: previewDelegateMapper
315 ignoreUnknownSignals: true
316 target: previewLoader.valid ? previewLoader.item : null
318 previewLoader.open = false
323 objectName: "previewLoader"
325 property var previewData
326 height: effect.bottomGapPx - effect.topGapPx
329 topMargin: effect.topGapPx
333 source: onScreen ? previewDelegateMapper.map(previewLoader.previewData.rendererName) : ""
335 property bool open: false
336 property bool onScreen: false
337 property bool valid: item !== null
346 item.previewData = Qt.binding(function() { return previewLoader.previewData })
350 // TODO: Move as InverseMouseArea to DashPreview
352 enabled: previewLoader.onScreen
355 topMargin: effect.bottomGapPx
358 previewLoader.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