2 * Copyright (C) 2013-2014 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
23import "../Components/ListItems" as ListItems
28 property var scope: null
29 property SortFilterProxyModel categories: categoryFilter
30 property bool isCurrent: false
31 property alias moving: categoryView.moving
32 property bool hasBackAction: false
33 property bool enableHeightBehaviorOnNextCreation: false
34 property var categoryView: categoryView
36 property var scopeStyle: ScopeStyle {
37 style: scope ? scope.customizations : {}
44 scope.activateApplication.connect(activateApp);
48 function activateApp(appId) {
49 Qt.openUrlExternally(appId);
52 function positionAtBeginning() {
53 categoryView.positionAtBeginning()
56 function showHeader() {
57 categoryView.showHeader()
60 function closePreview() {
61 previewListView.open = false;
67 value: isCurrent && !previewListView.open
70 SortFilterProxyModel {
72 model: scope ? scope.categories : null
73 dynamicSortFilter: true
74 filterRole: Categories.RoleCount
80 pageHeader.resetSearch();
81 previewListView.open = false;
85 target: scopeView.scope
86 property: "searchQuery"
87 value: pageHeader.searchQuery
93 property: "searchQuery"
94 value: scopeView.scope ? scopeView.scope.searchQuery : ""
99 target: scopeView.scope
100 onShowDash: previewListView.open = false;
101 onHideDash: previewListView.open = false;
106 color: scopeView.scopeStyle ? scopeView.scopeStyle.background : "transparent"
107 visible: color != "transparent"
112 objectName: "categoryListView"
114 x: previewListView.open ? -width : 0
115 Behavior on x { UbuntuNumberAnimation { } }
117 height: parent.height
119 model: scopeView.categories
120 forceNoClip: previewListView.open
123 property string expandedCategoryId: ""
125 delegate: ListItems.Base {
127 objectName: "dashCategory" + category
128 highlightWhenPressed: false
131 readonly property bool expandable: {
132 if (categoryView.model.count === 1) return false;
133 if (cardTool.template && cardTool.template["collapsed-rows"] === 0) return false;
134 if (item && item.expandedHeight > item.collapsedHeight) return true;
137 property bool expanded: false
138 readonly property string category: categoryId
139 readonly property string headerLink: model.headerLink
140 readonly property var item: rendererLoader.item
142 function expand(expand, animate) {
143 heightBehaviour.enabled = animate;
149 objectName: "cardTool"
151 template: model.renderer
152 components: model.components
153 viewWidth: parent.width
156 onExpandableChanged: {
157 // This can happen with the VJ that doesn't know how height it will be on creation
158 // so doesn't set expandable until a bit too late for onLoaded
160 var shouldExpand = baseItem.category === categoryView.expandedCategoryId;
161 baseItem.expand(shouldExpand, false /*animate*/);
165 onHeightChanged: rendererLoader.updateDelegateCreationRange();
166 onYChanged: rendererLoader.updateDelegateCreationRange();
174 topMargin: name != "" ? 0 : units.gu(2)
180 animation: UbuntuNumberAnimation {
183 heightBehaviour.enabled = false
189 readonly property bool expanded: baseItem.expanded || !baseItem.expandable
190 height: expanded ? item.expandedHeight : item.collapsedHeight
193 switch (cardTool.categoryLayout) {
194 case "carousel": return "CardCarousel.qml";
195 case "vertical-journal": return "CardVerticalJournal.qml";
197 default: return "CardGrid.qml";
202 if (item.enableHeightBehavior !== undefined && item.enableHeightBehaviorOnNextCreation !== undefined) {
203 item.enableHeightBehavior = scopeView.enableHeightBehaviorOnNextCreation;
204 scopeView.enableHeightBehaviorOnNextCreation = false;
206 item.model = Qt.binding(function() { return results })
207 item.objectName = Qt.binding(function() { return categoryId })
208 item.scopeStyle = scopeView.scopeStyle;
209 if (baseItem.expandable) {
210 var shouldExpand = categoryId === categoryView.expandedCategoryId;
211 baseItem.expand(shouldExpand, false /*animate*/);
213 updateDelegateCreationRange();
214 item.cardTool = cardTool;
217 Component.onDestruction: {
218 if (item.enableHeightBehavior !== undefined && item.enableHeightBehaviorOnNextCreation !== undefined) {
219 scopeView.enableHeightBehaviorOnNextCreation = item.enableHeightBehaviorOnNextCreation;
224 target: rendererLoader.item
226 if (scopeView.scope.id === "scopes" || scopeView.scope.id == "clickscope") {
227 // TODO Technically it is possible that calling activate() will make the scope emit
228 // previewRequested so that we show a preview but there's no scope that does that yet
229 // so it's not implemented
230 scopeView.scope.activate(result)
235 onPressAndHold: openPreview(index)
237 function openPreview(index) {
238 if (!rendererLoader.expanded && !seeAllLabel.visible && target.collapsedItemCount > 0) {
239 previewLimitModel.model = target.model;
240 previewLimitModel.limit = target.collapsedItemCount;
241 previewListView.model = previewLimitModel;
243 previewListView.model = target.model;
245 previewListView.currentIndex = -1;
246 previewListView.currentIndex = index;
247 previewListView.open = true;
252 onExpandedCategoryIdChanged: {
253 collapseAllButExpandedCategory();
255 function collapseAllButExpandedCategory() {
256 var item = rendererLoader.item;
257 if (baseItem.expandable) {
258 var shouldExpand = categoryId === categoryView.expandedCategoryId;
259 if (shouldExpand != baseItem.expanded) {
260 // If the filter animation will be seen start it, otherwise, just flip the switch
261 var shrinkingVisible = !shouldExpand && y + item.collapsedHeight + seeAll.height < categoryView.height;
262 var growingVisible = shouldExpand && y + height < categoryView.height;
263 if (!previewListView.open || shouldExpand) {
264 var animate = shrinkingVisible || growingVisible;
265 baseItem.expand(shouldExpand, animate)
266 if (shouldExpand && !previewListView.open) {
267 categoryView.maximizeVisibleArea(index, item.expandedHeight + seeAll.height);
273 onOriginYChanged: rendererLoader.updateDelegateCreationRange();
274 onContentYChanged: rendererLoader.updateDelegateCreationRange();
275 onHeightChanged: rendererLoader.updateDelegateCreationRange();
276 onContentHeightChanged: rendererLoader.updateDelegateCreationRange();
279 function updateDelegateCreationRange() {
280 if (categoryView.moving) {
281 // Do not update the range if we are overshooting up or down, since we'll come back
282 // to the stable position and delete/create items without any reason
283 if (categoryView.contentY < categoryView.originY) {
285 } else if (categoryView.contentHeight - categoryView.originY > categoryView.height &&
286 categoryView.contentY + categoryView.height > categoryView.contentHeight) {
291 if (item && item.hasOwnProperty("displayMarginBeginning")) {
292 // TODO do we need item.originY here, test 1300302 once we have a silo
293 // and we can run it on the phone
294 if (baseItem.y + baseItem.height <= 0) {
295 // Not visible (item at top of the list viewport)
296 item.displayMarginBeginning = -baseItem.height;
297 item.displayMarginEnd = 0;
298 } else if (baseItem.y >= categoryView.height) {
299 // Not visible (item at bottom of the list viewport)
300 item.displayMarginBeginning = 0;
301 item.displayMarginEnd = -baseItem.height;
303 item.displayMarginBeginning = -Math.max(-baseItem.y, 0);
304 item.displayMarginEnd = -Math.max(baseItem.height - seeAll.height
305 - categoryView.height + baseItem.y, 0)
315 top: rendererLoader.bottom
319 height: seeAllLabel.visible ? seeAllLabel.font.pixelSize + units.gu(6) : 0
322 if (categoryView.expandedCategoryId != baseItem.category) {
323 categoryView.expandedCategoryId = baseItem.category;
325 categoryView.expandedCategoryId = "";
331 text: baseItem.expanded ? i18n.tr("See less") : i18n.tr("See all")
334 verticalCenterOffset: units.gu(-0.5)
337 font.weight: Font.Bold
338 color: scopeStyle ? scopeStyle.foreground : "grey"
339 visible: baseItem.expandable && !baseItem.headerLink
350 fillMode: Image.Stretch
351 source: "graphics/dash_divider_top_lightgrad.png"
356 // FIXME Should not rely on model.count but view.count, but ListViewWithPageHeader doesn't expose it yet.
357 visible: index != categoryView.model.count - 1
359 bottom: seeAll.bottom
363 fillMode: Image.Stretch
364 source: "graphics/dash_divider_top_darkgrad.png"
369 sectionProperty: "name"
370 sectionDelegate: ListItems.Header {
371 objectName: "dashSectionHeader" + (delegate ? delegate.category : "")
372 readonly property var delegate: categoryView.item(delegateIndex)
373 width: categoryView.width
374 height: section != "" ? units.gu(5) : 0
376 color: scopeStyle ? scopeStyle.foreground : "grey"
377 iconName: delegate && delegate.headerLink ? "go-next" : ""
379 if (delegate.headerLink) scopeView.scope.performQuery(delegate.headerLink);
383 pageHeader: PageHeader {
385 objectName: "scopePageHeader"
387 title: scopeView.scope ? scopeView.scope.name : ""
388 showBackButton: scopeView.hasBackAction
389 searchEntryEnabled: true
390 searchInProgress: scopeView.scope ? scopeView.scope.searchInProgress : false
391 scopeStyle: scopeView.scopeStyle
393 bottomItem: DashDepartments {
394 scope: scopeView.scope
395 width: parent.width <= units.gu(60) ? parent.width : units.gu(40)
396 anchors.right: parent.right
397 windowHeight: scopeView.height
398 windowWidth: scopeView.width
399 scopeStyle: scopeView.scopeStyle
402 onBackClicked: scopeView.backClicked()
407 id: previewLimitModel
412 objectName: "previewListView"
414 scope: scopeView.scope
415 scopeStyle: scopeView.scopeStyle
417 height: parent.height
418 anchors.left: categoryView.right
421 pageHeader.unfocus();
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