on bc2a7bd help sign in
unity8/Dash/DashApps.qml
182 lines 6.9 kB history raw
1/*
2 * Copyright (C) 2013 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 */
17import QtQuick 2.0
18import Ubuntu.Components 0.1
19import Utils 0.1
20import "../Components"
21import "../Components/ListItems"
22import "Apps"
24ScopeView {
25 id: scopeView
27 // FIXME: a way to aggregate these models would be ideal
28 property var mainStageApplicationsModel: shell.applicationManager.mainStageApplications
29 property var sideStageApplicationModel: shell.applicationManager.sideStageApplications
31 onMovementStarted: categoryView.showHeader()
32 onPositionedAtBeginning: {
33 if (isCurrent) {
34 categoryView.positionAtBeginning()
35 }
36 }
38 onIsCurrentChanged: {
39 pageHeader.resetSearch();
40 }
42 Binding {
43 target: scopeView.scope
44 property: "searchQuery"
45 value: pageHeader.searchQuery
46 }
48 Connections {
49 target: panel
50 onSearchClicked: if (isCurrent) {
51 pageHeader.triggerSearch()
52 categoryView.showHeader()
53 }
54 }
56 ListModel {
57 id: categoryListModel
58 // specifies app categories, type of delegate and model used in each category
59 ListElement { category: "Running apps"; component: "RunningApplicationsGrid"; modelName: "RunningApplicationsModel" }
60 ListElement { category: "Frequently used"; component: "ApplicationsFilterGrid"; modelName: "FrequentlyUsedAppsModel" }
61 ListElement { category: "Installed"; component: "ApplicationsFilterGrid"; modelName: "InstalledApplicationsModel" }
62 ListElement { category: "Available for download"; component: "ApplicationsFilterGrid"; modelName: "AppsAvailableForDownloadModel" }
63 function getCategory(category1) {
64 if (category1 === "Running apps") {
65 return i18n.tr("Running apps");
66 }
67 if (category1 === "Frequently used") {
68 return i18n.tr("Frequently used");
69 }
70 if (category1 === "Installed") {
71 return i18n.tr("Installed");
72 }
73 if (category1 === "Available for download") {
74 return i18n.tr("Available for download");
75 }
76 return ""
77 }
78 }
80 FrequentlyUsedAppsModel { id: frequentlyUsedAppsModel }
81 AppsAvailableForDownloadModel { id: appsAvailableForDownloadModel }
83 // FIXME this should not be needed, the backend should handle all that itself
84 SortFilterProxyModel {
85 id: installedFilter
86 dynamicSortFilter: true
87 filterRole: 2 // this is the category id for each result
88 filterRegExp: /^3$/ // only proxy items that are category 3 - Installed
89 model: dashContent.scopes.get("applications.scope").results
90 }
92 property var categoryModels: {
93 "FrequentlyUsedAppsModel": frequentlyUsedAppsModel,
94 "InstalledApplicationsModel": installedFilter,
95 "AppsAvailableForDownloadModel": appsAvailableForDownloadModel,
96 }
98 /* Workaround for bug: https://bugreports.qt-project.org/browse/QTBUG-28403
99 When using Loader to load external QML file in the list deelgate, the ListView has
100 a bug where it can position the delegate content to overlap the section header
101 of the ListView - a workaround is to use sourceComponent of Loader instead */
102 Component { id: runningApplicationsGrid; RunningApplicationsGrid { clip: true } }
103 Component {
104 id: applicationsFilterGrid;
105 ApplicationsFilterGrid {
106 onClicked: shell.activateApplication(data)
107 }
108 }
110 property var componentModels: {
111 "RunningApplicationsGrid": runningApplicationsGrid,
112 "ApplicationsFilterGrid": applicationsFilterGrid,
113 }
115 ScopeListView {
116 id: categoryView
117 anchors.fill: parent
118 model: SortFilterProxyModel {
119 model: categoryListModel
120 filterRole: 0 // 0 == modelName
121 // FIXME: need to use invertMatch here, otherwise the filter won't update correctly
122 // if filterRegExp is set before invertMatch. Bug in SortFilterProxyModel?
123 filterRegExp: invertMatch ? ((mainStageApplicationsModel.count === 0
124 && sideStageApplicationModel.count === 0) ? RegExp("RunningApplicationsModel") : RegExp("")) :
125 RegExp("InstalledApplicationsModel")
126 invertMatch: pageHeader.searchQuery.length == 0
127 }
129 onAtYEndChanged: if (atYEnd) endReached()
130 onMovingChanged: if (moving && atYEnd) endReached()
132 delegate: Base {
133 id: container
134 highlightWhenPressed: false
136 Loader {
137 anchors {
138 top: parent.top
139 left: parent.left
140 right: parent.right
141 }
142 sourceComponent: componentModels[component]
143 onLoaded: {
144 if (modelName == "RunningApplicationsModel") {
145 item.firstModel = mainStageApplicationsModel
146 item.secondModel = sideStageApplicationModel
147 item.canEnableTerminationMode =
148 Qt.binding(function() { return isCurrent; })
149 } else {
150 item.model = categoryModels[modelName]
151 }
152 }
153 }
155 ListView.onRemove: SequentialAnimation {
156 PropertyAction {
157 target: container; property: "ListView.delayRemove"; value: true
158 }
159 NumberAnimation {
160 target: container; property: "height"; to: 0;
161 duration: 250; easing.type: Easing.InOutQuad
162 }
163 PropertyAction {
164 target: container; property: "ListView.delayRemove"; value: false
165 }
166 }
167 }
169 sectionProperty: "category"
170 sectionDelegate: Header {
171 width: categoryView.width
172 text: categoryListModel.getCategory(section)
173 }
174 pageHeader: PageHeader {
175 id: pageHeader
176 width: categoryView.width
177 text: i18n.tr("Apps")
178 searchEntryEnabled: true
179 searchHistory: scopeView.searchHistory
180 }
181 }