on xenial help sign in
merge trunk
dd024c8Michael Zanetti
Dash/Apps/RunningApplicationsGrid.qml+1
@@ -19,6 +19,7 @@ import "../../Components"
19
19
20ResponsiveFlowView {
20ResponsiveFlowView {
21 id: root
21 id: root
22+ clip: true
22
23
23 signal updateScreenshots
24 signal updateScreenshots
24
25
Dash/DashApps.qml+11−22
@@ -56,10 +56,10 @@ ScopeView {
56 ListModel {
56 ListModel {
57 id: categoryListModel
57 id: categoryListModel
58 // specifies app categories, type of delegate and model used in each category
58 // specifies app categories, type of delegate and model used in each category
59− ListElement { category: "Running apps"; component: "RunningApplicationsGrid"; modelName: "RunningApplicationsModel" }
59+ ListElement { category: "Running apps"; component: "Apps/RunningApplicationsGrid.qml"; modelName: "RunningApplicationsModel" }
60− ListElement { category: "Frequently used"; component: "ApplicationsFilterGrid"; modelName: "FrequentlyUsedAppsModel" }
60+ ListElement { category: "Frequently used"; component: "Apps/ApplicationsFilterGrid.qml"; modelName: "FrequentlyUsedAppsModel" }
61− ListElement { category: "Installed"; component: "ApplicationsFilterGrid"; modelName: "InstalledApplicationsModel" }
61+ ListElement { category: "Installed"; component: "Apps/ApplicationsFilterGrid.qml"; modelName: "InstalledApplicationsModel" }
62− ListElement { category: "Available for download"; component: "ApplicationsFilterGrid"; modelName: "AppsAvailableForDownloadModel" }
62+ ListElement { category: "Available for download"; component: "Apps/ApplicationsFilterGrid.qml"; modelName: "AppsAvailableForDownloadModel" }
63 function getCategory(category1) {
63 function getCategory(category1) {
64 if (category1 === "Running apps") {
64 if (category1 === "Running apps") {
65 return i18n.tr("Running apps");
65 return i18n.tr("Running apps");
@@ -95,23 +95,6 @@ ScopeView {
95 "AppsAvailableForDownloadModel": appsAvailableForDownloadModel,
95 "AppsAvailableForDownloadModel": appsAvailableForDownloadModel,
96 }
96 }
97
97
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− }
109−
110− property var componentModels: {
111− "RunningApplicationsGrid": runningApplicationsGrid,
112− "ApplicationsFilterGrid": applicationsFilterGrid,
113− }
114−
115 ScopeListView {
98 ScopeListView {
116 id: categoryView
99 id: categoryView
117 anchors.fill: parent
100 anchors.fill: parent
@@ -139,7 +122,7 @@ ScopeView {
139 left: parent.left
122 left: parent.left
140 right: parent.right
123 right: parent.right
141 }
124 }
142− sourceComponent: componentModels[component]
125+ source: component
143 onLoaded: {
126 onLoaded: {
144 if (modelName == "RunningApplicationsModel") {
127 if (modelName == "RunningApplicationsModel") {
145 item.firstModel = mainStageApplicationsModel
128 item.firstModel = mainStageApplicationsModel
@@ -147,7 +130,13 @@ ScopeView {
147 item.canEnableTerminationMode =
130 item.canEnableTerminationMode =
148 Qt.binding(function() { return isCurrent; })
131 Qt.binding(function() { return isCurrent; })
149 } else {
132 } else {
133+ function activateApplication(index, data) {
134+ shell.activateApplication(data);
135+ }
136+
150 item.model = categoryModels[modelName]
137 item.model = categoryModels[modelName]
138+ item.clicked.connect(activateApplication);
139+
151 }
140 }
152 }
141 }
153 }
142 }
Dash/DashHome.qml+12−25
@@ -32,9 +32,9 @@ ScopeView {
32 ListModel {
32 ListModel {
33 id: categoryListModel
33 id: categoryListModel
34 // specifies page's content categories, type of delegate and model used in each category
34 // specifies page's content categories, type of delegate and model used in each category
35− ListElement { category: "Frequent Apps"; component: "AppsGrid"; modelName: "AppsModel" }
35+ ListElement { category: "Frequent Apps"; component: "Apps/ApplicationsFilterGrid.qml"; modelName: "AppsModel" }
36− ListElement { category: "Recent Music"; component: "MusicGrid"; modelName: "MusicModel" }
36+ ListElement { category: "Recent Music"; component: "Music/MusicFilterGrid.qml"; modelName: "MusicModel" }
37− ListElement { category: "Videos Popular Online"; component: "VideosGrid"; modelName: "VideosModel" }
37+ ListElement { category: "Videos Popular Online"; component: "Video/VideosFilterGrid.qml"; modelName: "VideosModel" }
38 function getCategory(category1) {
38 function getCategory(category1) {
39 if (category1 === "Frequent Apps") {
39 if (category1 === "Frequent Apps") {
40 return i18n.tr("Frequent Apps");
40 return i18n.tr("Frequent Apps");
@@ -110,26 +110,6 @@ ScopeView {
110 "VideosModel": videosFilter,
110 "VideosModel": videosFilter,
111 }
111 }
112
112
113− /* Workaround for bug: https://bugreports.qt-project.org/browse/QTBUG-28403
114− When using Loader to load external QML file in the list deelgate, the ListView has
115− a bug where it can position the delegate content to overlap the section header
116− of the ListView - a workaround is to use sourceComponent of Loader instead */
117− Component {
118− id: applicationsFilterGrid
119− ApplicationsFilterGrid {
120− objectName: "dashHomeApplicationsGrid"
121− onClicked: shell.activateApplication(data);
122− }
123− }
124−
125− Component { id: musicGrid; MusicFilterGrid {} }
126− Component { id: videosGrid; VideosFilterGrid {} }
127− property var componentModels: {
128− "AppsGrid": applicationsFilterGrid,
129− "MusicGrid": musicGrid,
130− "VideosGrid": videosGrid,
131− }
132−
133 ScopeListView {
113 ScopeListView {
134 id: listView
114 id: listView
135 anchors.fill: parent
115 anchors.fill: parent
@@ -145,13 +125,13 @@ ScopeView {
145
125
146 Loader {
126 Loader {
147 anchors { top: parent.top; left: parent.left; right: parent.right }
127 anchors { top: parent.top; left: parent.left; right: parent.right }
148− sourceComponent: componentModels[component]
128+ source: component
149 onLoaded: {
129 onLoaded: {
150 item.model = categoryModels[modelName]
130 item.model = categoryModels[modelName]
151
131
152 //FIXME: workaround for lack of previews for videos in Home scope.
132 //FIXME: workaround for lack of previews for videos in Home scope.
153 //Need to connect to the clicked() signal here and act upon it here instead.
133 //Need to connect to the clicked() signal here and act upon it here instead.
154− if (component === "VideosGrid") {
134+ if (modelName === "VideosModel") {
155 function playVideo(index, data) {
135 function playVideo(index, data) {
156 if (data.fileUri) {
136 if (data.fileUri) {
157 shell.activateApplication('/usr/share/applications/mediaplayer-app.desktop', "/usr/share/demo-assets/videos/" + data.fileUri);
137 shell.activateApplication('/usr/share/applications/mediaplayer-app.desktop', "/usr/share/demo-assets/videos/" + data.fileUri);
@@ -159,6 +139,13 @@ ScopeView {
159 }
139 }
160
140
161 item.clicked.connect(playVideo);
141 item.clicked.connect(playVideo);
142+ } else if (modelName === "AppsModel") {
143+ function activateApplication(index, data) {
144+ shell.activateApplication(data);
145+ }
146+
147+ item.objectName = "dashHomeApplicationsGrid";
148+ item.clicked.connect(activateApplication);
162 }
149 }
163 }
150 }
164 }
151 }
Dash/DashMusic.qml+3−10
@@ -50,17 +50,10 @@ ScopeView {
50 }
50 }
51 }
51 }
52
52
53− /* Workaround for bug: https://bugreports.qt-project.org/browse/QTBUG-28403
54− When using Loader to load external QML file in the list deelgate, the ListView has
55− a bug where it can position the delegate content to overlap the section header
56− of the ListView - a workaround is to use sourceComponent of Loader instead */
57− Component { id: musicCarousel; MusicCarousel {} }
58− Component { id: musicFilterGrid; MusicFilterGrid {} }
59−
60 function getRenderer(categoryId) {
53 function getRenderer(categoryId) {
61 switch (categoryId) {
54 switch (categoryId) {
62− case 1: return musicCarousel
55+ case 1: return "Music/MusicCarousel.qml"
63− default: return musicFilterGrid
56+ default: return "Music/MusicFilterGrid.qml"
64 }
57 }
65 }
58 }
66
59
@@ -80,7 +73,7 @@ ScopeView {
80
73
81 Loader {
74 Loader {
82 anchors { top: parent.top; left: parent.left; right: parent.right }
75 anchors { top: parent.top; left: parent.left; right: parent.right }
83− sourceComponent: scopeView.getRenderer(base.categoryId)
76+ source: scopeView.getRenderer(base.categoryId)
84 onLoaded: {
77 onLoaded: {
85 item.model = results
78 item.model = results
86 }
79 }
Dash/DashVideos.qml+3−10
@@ -51,17 +51,10 @@ ScopeView {
51 }
51 }
52 }
52 }
53
53
54− /* Workaround for bug: https://bugreports.qt-project.org/browse/QTBUG-28403
55− When using Loader to load external QML file in the list deelgate, the ListView has
56− a bug where it can position the delegate content to overlap the section header
57− of the ListView - a workaround is to use sourceComponent of Loader instead */
58− Component { id: videosFilterGrid; VideosFilterGrid {} }
59− Component { id: videosCarousel; VideosCarousel {} }
60−
61 function getRenderer(categoryId) {
54 function getRenderer(categoryId) {
62 switch (categoryId) {
55 switch (categoryId) {
63− case 1: return videosCarousel
56+ case 1: return "Video/VideosCarousel.qml"
64− default: return videosFilterGrid
57+ default: return "Video/VideosFilterGrid.qml"
65 }
58 }
66 }
59 }
67
60
@@ -115,7 +108,7 @@ ScopeView {
115 Loader {
108 Loader {
116 id: loader
109 id: loader
117 anchors { top: parent.top; left: parent.left; right: parent.right }
110 anchors { top: parent.top; left: parent.left; right: parent.right }
118− sourceComponent: scopeView.getRenderer(base.categoryId)
111+ source: scopeView.getRenderer(base.categoryId)
119 onLoaded: {
112 onLoaded: {
120 item.model = results
113 item.model = results
121 }
114 }
Dash/GenericScopeView.qml+2−2
@@ -72,10 +72,10 @@ ScopeView {
72 delegate: Tile {
72 delegate: Tile {
73 width: filtergrid.cellWidth
73 width: filtergrid.cellWidth
74 height: filtergrid.cellHeight
74 height: filtergrid.cellHeight
75− text: column_5 ? column_5 : "" // FIXME: this shouldn't be necessary
75+ text: title
76 imageWidth: units.gu(11)
76 imageWidth: units.gu(11)
77 imageHeight: units.gu(16)
77 imageHeight: units.gu(16)
78− source: column_1 ? IconUtil.from_gicon(column_1) : "" // FIXME: ditto
78+ source: IconUtil.from_gicon(icon)
79 }
79 }
80 }
80 }
81 }
81 }
Greeter/Infographics.qml+1−1
@@ -81,7 +81,7 @@ Item {
81 var nextCircle = presentCircles.itemAt(presentCircleCounter++)
81 var nextCircle = presentCircles.itemAt(presentCircleCounter++)
82 if (nextCircle !== null) nextCircle.presentCircleGrowAnim.start()
82 if (nextCircle !== null) nextCircle.presentCircleGrowAnim.start()
83 }
83 }
84− if (presentCircleCounter > infographic.model.currentDay) {
84+ if (presentCircleCounter > infographic.model.currentDay && pastCircleCounter >= pastCircles.count) {
85 stop()
85 stop()
86 }
86 }
87 }
87 }
cmake/modules/Plugins.cmakenew file+48
@@ -0,0 +1,48 @@
1+# Creates targets for copying and installing qmlfiles and generating the qmltypes file for a plugin
2+#
3+# export_qmlplugin(plugin version sub_path [TARGETS target1 [target2 ...]])
4+#
5+# TARGETS additional install targets (eg the plugin shared object)
6+#
7+# Two targets will be created:
8+# - plugin-qmlfiles - Copies the qml files (*.qml, *.js, qmldir) into the shadow build folder.
9+# - plugin-qmltypes - Generates the qmltypes file in the shadow build folder.
10+
11+
12+macro(export_qmlplugin PLUGIN VERSION PLUGIN_SUBPATH)
13+ set(multi_value_keywords TARGETS)
14+ cmake_parse_arguments(qmlplugin "" "" "${multi_value_keywords}" ${ARGN})
15+
16+ file(GLOB QMLFILES
17+ *.qml
18+ *.js
19+ qmldir
20+ )
21+
22+ # copy the qmldir file
23+ add_custom_target(${PLUGIN}-qmlfiles ALL
24+ COMMAND cp ${QMLFILES} ${CMAKE_BINARY_DIR}/plugins/${PLUGIN_SUBPATH}
25+ DEPENDS ${QMLFILES}
26+ )
27+
28+ # create the plugin.qmltypes file
29+ add_custom_target(${PLUGIN}-qmltypes ALL
30+ COMMAND qmlplugindump -notrelocatable ${PLUGIN} ${VERSION} ${CMAKE_BINARY_DIR}/plugins > ${CMAKE_BINARY_DIR}/plugins/${PLUGIN_SUBPATH}/plugin.qmltypes
31+ )
32+ add_dependencies(${PLUGIN}-qmltypes ${PLUGIN}-qmlfiles ${qmlplugin_TARGETS})
33+
34+ # install the qmldir file.
35+ install(FILES ${QMLFILES}
36+ DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/${PLUGIN_SUBPATH}
37+ )
38+
39+ # install the qmltypes file.
40+ install(FILES ${CMAKE_BINARY_DIR}/plugins/${PLUGIN_SUBPATH}/plugin.qmltypes
41+ DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/${PLUGIN_SUBPATH}
42+ )
43+
44+ # install the additional targets
45+ install(TARGETS ${qmlplugin_TARGETS}
46+ DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/${PLUGIN_SUBPATH}
47+ )
48+endmacro(export_qmlplugin)
debian/changelog+19
@@ -1,3 +1,22 @@
1+unity8 (7.81.3+13.10.20130708ubuntu.unity.next-0ubuntu1) saucy; urgency=low
2+
3+ [ Michael Terry ]
4+ * Ensure the past circle animations complete Currently, all the
5+ animations stop as soon as the present circles are all visible. This
6+ change ensures that the animations run to completion.
7+
8+ [ Michael Zanetti ]
9+ * improve launcher flicking bahavior - fix initial snapping - improve
10+ foldingAreas behavior - increase clickFlick speed to flick 4 items.
11+
12+ [ Albert Astals ]
13+ * Remove workarounds for Qt bug 28403 . (LP: #28403)
14+
15+ [ Ubuntu daily release ]
16+ * Automatic snapshot from revision 83 (ubuntu-unity/next)
17+
18+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Mon, 08 Jul 2013 02:34:23 +0000
19+
1unity8 (7.81.3+13.10.20130704ubuntu.unity.next-0ubuntu1) saucy; urgency=low
20unity8 (7.81.3+13.10.20130704ubuntu.unity.next-0ubuntu1) saucy; urgency=low
2
21
3 [ Didier Roche ]
22 [ Didier Roche ]
plugins/HudClient/CMakeLists.txt+5−12
@@ -1,3 +1,6 @@
1+# export_qmlplugin macro
2+include(Plugins)
3+
1find_package(Qt5Core REQUIRED)
4find_package(Qt5Core REQUIRED)
2find_package(Qt5Quick REQUIRED)
5find_package(Qt5Quick REQUIRED)
3pkg_search_module(DEE dee-1.0 REQUIRED)
6pkg_search_module(DEE dee-1.0 REQUIRED)
@@ -35,15 +38,5 @@ target_link_libraries(HudClientQml
35
38
36qt5_use_modules(HudClientQml Qml)
39qt5_use_modules(HudClientQml Qml)
37
40
38−# copy qmldir file into build directory for shadow builds
41+# export the qmldir and qmltypes files
39−file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/qmldir"
40− DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
41− )
42−
43−install(TARGETS HudClientQml
42+export_qmlplugin(HudClient 0.1 HudClient TARGETS HudClientQml)
44− DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/HudClient
45− )
46−
47−install(FILES qmldir
48− DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/HudClient
49− )
plugins/HudClient/qmldir+1
@@ -1 +1,2 @@
1plugin HudClientQml
1plugin HudClientQml
2+typeinfo plugin.qmltypes
plugins/LightDM/CMakeLists.txt+5−12
@@ -1,3 +1,6 @@
1+# export_qmlplugin macro
2+include(Plugins)
3+
1# Dependencies
4# Dependencies
2include(FindPkgConfig)
5include(FindPkgConfig)
3pkg_check_modules(LIBUSERMETRICSOUTPUT REQUIRED libusermetricsoutput-1)
6pkg_check_modules(LIBUSERMETRICSOUTPUT REQUIRED libusermetricsoutput-1)
@@ -32,15 +35,5 @@ target_link_libraries(LightDM-qml
32
35
33qt5_use_modules(LightDM-qml Gui Qml)
36qt5_use_modules(LightDM-qml Gui Qml)
34
37
35−# copy qmldir file into build directory for shadow builds
38+# export the qmldir and qmltypes files
36−file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/qmldir"
37− DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
38− )
39−
40−install(TARGETS LightDM-qml
39+export_qmlplugin(LightDM 0.1 LightDM TARGETS LightDM-qml)
41− DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/LightDM
42− )
43−
44−install(FILES qmldir
45− DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/LightDM
46− )
plugins/LightDM/qmldir+1
@@ -1,2 +1,3 @@
1module LightDM
1module LightDM
2plugin LightDM-qml
2plugin LightDM-qml
3+typeinfo plugin.qmltypes
plugins/ListViewWithPageHeader/CMakeLists.txt+5−12
@@ -1,3 +1,6 @@
1+# export_qmlplugin macro
2+include(Plugins)
3+
1# There's no cmake var for v8 include path :-/
4# There's no cmake var for v8 include path :-/
2# so create one
5# so create one
3LIST(GET Qt5Core_INCLUDE_DIRS 0 QtCoreDir0)
6LIST(GET Qt5Core_INCLUDE_DIRS 0 QtCoreDir0)
@@ -30,15 +33,5 @@ target_link_libraries(ListViewWithPageHeader-qml
30
33
31qt5_use_modules(ListViewWithPageHeader-qml Qml Quick)
34qt5_use_modules(ListViewWithPageHeader-qml Qml Quick)
32
35
33−# copy qmldir file into build directory for shadow builds
36+# export the qmldir and qmltypes files
34−file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/qmldir"
35− DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
36− )
37−
38−install(TARGETS ListViewWithPageHeader-qml
37+export_qmlplugin(ListViewWithPageHeader 0.1 ListViewWithPageHeader TARGETS ListViewWithPageHeader-qml)
39− DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/ListViewWithPageHeader
40− )
41−
42−install(FILES qmldir
43− DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/ListViewWithPageHeader
44− )
plugins/ListViewWithPageHeader/qmldir+1
@@ -1,2 +1,3 @@
1module ListViewWithPageHeader
1module ListViewWithPageHeader
2plugin ListViewWithPageHeader-qml
2plugin ListViewWithPageHeader-qml
3+typeinfo plugin.qmltypes
plugins/Ubuntu/Gestures/CMakeLists.txt+5−13
@@ -1,3 +1,6 @@
1+# export_qmlplugin macro
2+include(Plugins)
3+
1set(CMAKE_AUTOMOC ON)
4set(CMAKE_AUTOMOC ON)
2
5
3include(FindPkgConfig)
6include(FindPkgConfig)
@@ -20,16 +23,5 @@ qt5_use_modules(UbuntuGestureQml Core Quick)
20# So that Foo.cpp can #include "Foo.moc"
23# So that Foo.cpp can #include "Foo.moc"
21include_directories(${CMAKE_CURRENT_BINARY_DIR})
24include_directories(${CMAKE_CURRENT_BINARY_DIR})
22
25
23−# copy files into build directory for shadow builds
26+# export the qmldir and qmltypes files
24−add_custom_target(UbuntuGestureQmlDirFile ALL
25− COMMAND cp "${CMAKE_CURRENT_SOURCE_DIR}/qmldir" ${CMAKE_CURRENT_BINARY_DIR}
26− DEPENDS qmldir
27−)
28−
29−install(TARGETS UbuntuGestureQml
27+export_qmlplugin(Ubuntu.Gestures 0.1 Ubuntu/Gestures TARGETS UbuntuGestureQml)
30− DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/Ubuntu/Gestures
31− )
32−
33−install(FILES qmldir
34− DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/Ubuntu/Gestures
35− )
plugins/Ubuntu/Gestures/qmldir+1
@@ -1,2 +1,3 @@
1module Ubuntu.Gestures
1module Ubuntu.Gestures
2plugin UbuntuGestureQml
2plugin UbuntuGestureQml
3+typeinfo plugin.qmltypes
plugins/Unity/CMakeLists.txt+6−17
@@ -1,3 +1,6 @@
1+# export_qmlplugin macro
2+include(Plugins)
3+
1# Dependencies
4# Dependencies
2include(FindPkgConfig)
5include(FindPkgConfig)
3pkg_check_modules(QTDEE REQUIRED libdee-qt5)
6pkg_check_modules(QTDEE REQUIRED libdee-qt5)
@@ -12,11 +15,10 @@ include_directories(
12)
15)
13
16
14set(QMLPLUGIN_SRC
17set(QMLPLUGIN_SRC
15− ../Utils/qsortfilterproxymodelqml.cpp # FIXME evaluate a more generic approach for using other plugins
16 scope.cpp
18 scope.cpp
17 scopes.cpp
19 scopes.cpp
18 categories.cpp
20 categories.cpp
19− categoryfilter.cpp
21+ categoryresults.cpp
20 plugin.cpp
22 plugin.cpp
21 bottombarvisibilitycommunicatorshell.cpp
23 bottombarvisibilitycommunicatorshell.cpp
22 applicationpreview.cpp
24 applicationpreview.cpp
@@ -42,18 +44,5 @@ target_link_libraries(Unity-qml
42
44
43qt5_use_modules(Unity-qml Qml)
45qt5_use_modules(Unity-qml Qml)
44
46
45−# copy qmldir file into build directory for shadow builds
47+# export the qmldir and qmltypes files
46−file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/qmldir"
47− DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
48− )
49−
50−install(TARGETS Unity-qml
48+export_qmlplugin(Unity 0.1 Unity TARGETS Unity-qml)
51− DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/Unity
52− )
53−
54−install(FILES qmldir
55− DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/Unity
56− )
57−
58−
59−add_subdirectory(Launcher)
plugins/Unity/categories.cpp+56−42
@@ -3,6 +3,7 @@
3 *
3 *
4 * Authors:
4 * Authors:
5 * Michał Sawicz <michal.sawicz@canonical.com>
5 * Michał Sawicz <michal.sawicz@canonical.com>
6+ * Michal Hruby <michal.hruby@canonical.com>
6 *
7 *
7 * This program is free software; you can redistribute it and/or modify
8 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * it under the terms of the GNU General Public License as published by
@@ -19,18 +20,25 @@
19
20
20// self
21// self
21#include "categories.h"
22#include "categories.h"
22−#include "categoryfilter.h"
23+#include "categoryresults.h"
24+
25+// TODO: use something from libunity once it's public
26+enum CategoryColumn {
27+ ID,
28+ DISPLAY_NAME,
29+ ICON_HINT,
30+ RENDERER_NAME,
31+ HINTS
32+};
23
33
24Categories::Categories(QObject* parent)
34Categories::Categories(QObject* parent)
25 : DeeListModel(parent)
35 : DeeListModel(parent)
26− , m_resultModel(0)
27{
36{
28− // FIXME: need to clean up unused filters on countChanged
29 m_roles[Categories::RoleId] = "id";
37 m_roles[Categories::RoleId] = "id";
30 m_roles[Categories::RoleName] = "name";
38 m_roles[Categories::RoleName] = "name";
31 m_roles[Categories::RoleIcon] = "icon";
39 m_roles[Categories::RoleIcon] = "icon";
32 m_roles[Categories::RoleRenderer] = "renderer";
40 m_roles[Categories::RoleRenderer] = "renderer";
33− m_roles[Categories::RoleContentType] = "content_type";
41+ m_roles[Categories::RoleContentType] = "contentType";
34 m_roles[Categories::RoleHints] = "hints";
42 m_roles[Categories::RoleHints] = "hints";
35 m_roles[Categories::RoleResults] = "results";
43 m_roles[Categories::RoleResults] = "results";
36 m_roles[Categories::RoleCount] = "count";
44 m_roles[Categories::RoleCount] = "count";
@@ -40,49 +48,57 @@ Categories::Categories(QObject* parent)
40 // change of the search term harder to reproduce
48 // change of the search term harder to reproduce
41 m_timer.setSingleShot(true);
49 m_timer.setSingleShot(true);
42 m_timer.setInterval(50);
50 m_timer.setInterval(50);
43− connect(&m_timer, SIGNAL(timeout()), this, SLOT(onEmitCountChanged()));
51+ connect(&m_timer, &QTimer::timeout, this, &Categories::onEmitCountChanged);
44}
52}
45
53
46−Categories::~Categories()
54+DeeListModel*
55+Categories::getResults(int index) const
47{
56{
48− qDeleteAll(m_filters);
57+ if (!m_results.contains(index)) {
49−}
58+ CategoryResults* results = new CategoryResults(const_cast<Categories*>(this));
59+ results->setCategoryIndex(index);
60+ connect(results, &DeeListModel::countChanged, this, &Categories::onCountChanged);
50
61
51−CategoryFilter*
62+ unsigned categoryIndex = static_cast<unsigned>(index);
52−Categories::getFilter(int index) const
63+ auto unity_results = m_unityScope->GetResultsForCategory(categoryIndex);
53−{
64+ results->setModel(unity_results->model());
54− if (!m_filters.contains(index)) {
55− CategoryFilter* filter = new CategoryFilter();
56− connect(filter, SIGNAL(countChanged()), this, SLOT(onCountChanged()));
57− filter->setModel(m_resultModel);
58− filter->setIndex(index);
59
65
60− m_filters.insert(index, filter);
66+ m_results.insert(index, results);
61 }
67 }
62
68
63− return m_filters[index];
69+ return m_results[index];
70+}
71+
72+void Categories::onCategoriesModelChanged(unity::glib::Object<DeeModel> model)
73+{
74+ m_updatedCategories.clear();
75+ // FIXME: this might destroy the renderer view and re-create it, optimize?
76+ Q_FOREACH(DeeListModel* model, m_results) {
77+ delete model;
78+ }
79+ m_results.clear();
80+ setModel(model);
64}
81}
65
82
66void
83void
67−Categories::setResultModel(DeeListModel* model)
84+Categories::setUnityScope(const unity::dash::Scope::Ptr& scope)
68{
85{
69− if (model != m_resultModel) {
86+ m_unityScope = scope;
70− m_resultModel = model;
71
87
72− Q_FOREACH(CategoryFilter* filter, m_filters) {
88+ // no need to call this, we'll get notified
73− filter->setModel(m_resultModel);
89+ //setModel(m_unityScope->categories()->model());
74− }
75
90
76− Q_EMIT resultModelChanged(m_resultModel);
91+ m_categoriesChangedConnection.disconnect();
77− }
92+ m_categoriesChangedConnection =
93+ m_unityScope->categories()->model.changed.connect(sigc::mem_fun(this, &Categories::onCategoriesModelChanged));
78}
94}
79
95
80void
96void
81Categories::onCountChanged()
97Categories::onCountChanged()
82{
98{
83− CategoryFilter* filter = qobject_cast<CategoryFilter*>(sender());
99+ CategoryResults* results = qobject_cast<CategoryResults*>(sender());
84− if (filter) {
100+ if (results) {
85− m_timerFilters << filter;
101+ m_updatedCategories << results->categoryIndex();
86 m_timer.start();
102 m_timer.start();
87 }
103 }
88}
104}
@@ -92,11 +108,12 @@ Categories::onEmitCountChanged()
92{
108{
93 QVector<int> roles;
109 QVector<int> roles;
94 roles.append(Categories::RoleCount);
110 roles.append(Categories::RoleCount);
95− Q_FOREACH(CategoryFilter* filter, m_timerFilters) {
111+ Q_FOREACH(int categoryIndex, m_updatedCategories) {
112+ if (!m_results.contains(categoryIndex)) continue;
96− QModelIndex changedIndex = index(filter->index());
113+ QModelIndex changedIndex = index(categoryIndex);
97 Q_EMIT dataChanged(changedIndex, changedIndex, roles);
114 Q_EMIT dataChanged(changedIndex, changedIndex, roles);
98 }
115 }
99− m_timerFilters.clear();
116+ m_updatedCategories.clear();
100}
117}
101
118
102QHash<int, QByteArray>
119QHash<int, QByteArray>
@@ -116,25 +133,22 @@ Categories::data(const QModelIndex& index, int role) const
116 case RoleId:
133 case RoleId:
117 return QVariant::fromValue(index.row());
134 return QVariant::fromValue(index.row());
118 case RoleName:
135 case RoleName:
119− return QVariant::fromValue(DeeListModel::data(index, 1)); //DISPLAY_NAME
136+ return DeeListModel::data(index, CategoryColumn::DISPLAY_NAME);
120 case RoleIcon:
137 case RoleIcon:
121− return QVariant::fromValue(DeeListModel::data(index, 2)); //ICON_HINT
138+ return DeeListModel::data(index, CategoryColumn::ICON_HINT);
122 case RoleRenderer:
139 case RoleRenderer:
123− return QVariant::fromValue(DeeListModel::data(index, 3)); //RENDERER_NAME
140+ return DeeListModel::data(index, CategoryColumn::RENDERER_NAME);
124 case RoleContentType:
141 case RoleContentType:
125 {
142 {
126− auto hints = QVariant::fromValue(DeeListModel::data(index, 4)).toHash();
143+ auto hints = DeeListModel::data(index, CategoryColumn::HINTS).toHash();
127 return hints.contains("content-type") ? hints["content-type"] : QVariant(QString("default"));
144 return hints.contains("content-type") ? hints["content-type"] : QVariant(QString("default"));
128 }
145 }
129 case RoleHints:
146 case RoleHints:
130− return QVariant::fromValue(DeeListModel::data(index, 4)); //HINTS
147+ return DeeListModel::data(index, CategoryColumn::HINTS);
131 case RoleResults:
148 case RoleResults:
132− return QVariant::fromValue(getFilter(index.row()));
149+ return QVariant::fromValue(getResults(index.row()));
133 case RoleCount:
150 case RoleCount:
134− {
135− CategoryFilter* filter = getFilter(index.row());
136− return QVariant::fromValue(filter->rowCount());
151+ return QVariant::fromValue(getResults(index.row())->rowCount());
137− }
138 default:
152 default:
139 return QVariant();
153 return QVariant();
140 }
154 }
plugins/Unity/categories.h+13−16
@@ -3,6 +3,7 @@
3 *
3 *
4 * Authors:
4 * Authors:
5 * Michał Sawicz <michal.sawicz@canonical.com>
5 * Michał Sawicz <michal.sawicz@canonical.com>
6+ * Michal Hruby <michal.hruby@canonical.com>
6 *
7 *
7 * This program is free software; you can redistribute it and/or modify
8 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * it under the terms of the GNU General Public License as published by
@@ -21,25 +22,24 @@
21#ifndef CATEGORIES_H
22#ifndef CATEGORIES_H
22#define CATEGORIES_H
23#define CATEGORIES_H
23
24
25+// unity-core
26+#include <UnityCore/Scope.h>
27+
24// dee-qt
28// dee-qt
25#include "deelistmodel.h"
29#include "deelistmodel.h"
26
30
31+#include <QPointer>
27#include <QSet>
32#include <QSet>
28#include <QTimer>
33#include <QTimer>
29
34
30−class CategoryFilter;
31−
32class Categories : public DeeListModel
35class Categories : public DeeListModel
33{
36{
34 Q_OBJECT
37 Q_OBJECT
35
38
36 Q_ENUMS(Roles)
39 Q_ENUMS(Roles)
37
40
38− Q_PROPERTY(DeeListModel* resultModel READ resultModel WRITE setResultModel NOTIFY resultModelChanged)
39−
40public:
41public:
41 explicit Categories(QObject* parent = 0);
42 explicit Categories(QObject* parent = 0);
42− ~Categories();
43
43
44 enum Roles {
44 enum Roles {
45 RoleId,
45 RoleId,
@@ -56,27 +56,24 @@ public:
56
56
57 QHash<int, QByteArray> roleNames() const;
57 QHash<int, QByteArray> roleNames() const;
58
58
59− /* getters */
60− DeeListModel* resultModel() { return m_resultModel; }
61−
62 /* setters */
59 /* setters */
63− void setResultModel(DeeListModel*);
60+ void setUnityScope(const unity::dash::Scope::Ptr& scope);
64−
65−Q_SIGNALS:
66− void resultModelChanged(DeeListModel*);
67
61
68private Q_SLOTS:
62private Q_SLOTS:
69 void onCountChanged();
63 void onCountChanged();
70 void onEmitCountChanged();
64 void onEmitCountChanged();
71
65
72private:
66private:
73− CategoryFilter* getFilter(int index) const;
67+ void onCategoriesModelChanged(unity::glib::Object<DeeModel> model);
68+
69+ DeeListModel* getResults(int index) const;
74
70
71+ unity::dash::Scope::Ptr m_unityScope;
75 QTimer m_timer;
72 QTimer m_timer;
76− QSet<CategoryFilter*> m_timerFilters;
73+ QSet<int> m_updatedCategories;
77 QHash<int, QByteArray> m_roles;
74 QHash<int, QByteArray> m_roles;
78− DeeListModel* m_resultModel;
75+ mutable QMap<int, DeeListModel*> m_results;
79− mutable QMap<int, CategoryFilter*> m_filters;
76+ sigc::connection m_categoriesChangedConnection;
80};
77};
81
78
82#endif // CATEGORIES_H
79#endif // CATEGORIES_H
plugins/Unity/categoryfilter.cppdeleted−45
@@ -1,45 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * Authors:
5− * Michał Sawicz <michal.sawicz@canonical.com>
6− *
7− * This program is free software; you can redistribute it and/or modify
8− * it under the terms of the GNU General Public License as published by
9− * the Free Software Foundation; version 3.
10− *
11− * This program is distributed in the hope that it will be useful,
12− * but WITHOUT ANY WARRANTY; without even the implied warranty of
13− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14− * GNU General Public License for more details.
15− *
16− * You should have received a copy of the GNU General Public License
17− * along with this program. If not, see <http://www.gnu.org/licenses/>.
18− */
19−
20−#include "categoryfilter.h"
21−
22−int const CATEGORY_COLUMN = 2;
23−
24−CategoryFilter::CategoryFilter(QObject* parent)
25− : QSortFilterProxyModelQML(parent)
26− , m_index(-1)
27−{
28− setDynamicSortFilter(true);
29− setFilterRole(CATEGORY_COLUMN);
30− setFilterRegExp(QString("^%1$").arg(m_index));
31−}
32−
33−int CategoryFilter::index() const
34−{
35− return m_index;
36−}
37−
38−void CategoryFilter::setIndex(int index)
39−{
40− if (index != m_index) {
41− m_index = index;
42− setFilterRegExp(QString("^%1$").arg(m_index));
43− Q_EMIT indexChanged(m_index);
44− }
45−}
plugins/Unity/categoryfilter.hdeleted−48
@@ -1,48 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * Authors:
5− * Michał Sawicz <michal.sawicz@canonical.com>
6− *
7− * This program is free software; you can redistribute it and/or modify
8− * it under the terms of the GNU General Public License as published by
9− * the Free Software Foundation; version 3.
10− *
11− * This program is distributed in the hope that it will be useful,
12− * but WITHOUT ANY WARRANTY; without even the implied warranty of
13− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14− * GNU General Public License for more details.
15− *
16− * You should have received a copy of the GNU General Public License
17− * along with this program. If not, see <http://www.gnu.org/licenses/>.
18− */
19−
20−#ifndef CATEGORY_FILTER_H
21−#define CATEGORY_FILTER_H
22−
23−// Utils
24−#include "plugins/Utils/qsortfilterproxymodelqml.h"
25−
26−class CategoryFilter : public QSortFilterProxyModelQML
27−{
28− Q_OBJECT
29−
30− Q_PROPERTY(int index READ index WRITE setIndex NOTIFY indexChanged)
31−
32−public:
33− explicit CategoryFilter(QObject* parent = 0);
34−
35− /* getters */
36− int index() const;
37−
38− /* setters */
39− void setIndex(int index);
40−
41−Q_SIGNALS:
42− void indexChanged(int index);
43−
44−private:
45− int m_index;
46−};
47−
48−#endif // CATEGORY_FILTER_H
plugins/Unity/categoryresults.cppnew file+96
@@ -0,0 +1,96 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Michal Hruby <michal.hruby@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+// self
21+#include "categoryresults.h"
22+
23+// TODO: use something from libunity once it's public
24+enum ResultsColumn {
25+ URI,
26+ ICON_HINT,
27+ CATEGORY,
28+ RESULT_TYPE,
29+ MIMETYPE,
30+ TITLE,
31+ COMMENT,
32+ DND_URI,
33+ METADATA
34+};
35+
36+CategoryResults::CategoryResults(QObject* parent)
37+ : DeeListModel(parent)
38+ , m_categoryIndex(-1)
39+{
40+ m_roles[CategoryResults::RoleUri] = "uri";
41+ m_roles[CategoryResults::RoleIconHint] = "icon";
42+ m_roles[CategoryResults::RoleCategory] = "category";
43+ m_roles[CategoryResults::RoleMimetype] = "mimetype";
44+ m_roles[CategoryResults::RoleTitle] = "title";
45+ m_roles[CategoryResults::RoleComment] = "comment";
46+ m_roles[CategoryResults::RoleDndUri] = "dndUri";
47+ m_roles[CategoryResults::RoleMetadata] = "metadata";
48+}
49+
50+int CategoryResults::categoryIndex() const
51+{
52+ return m_categoryIndex;
53+}
54+
55+void CategoryResults::setCategoryIndex(int index)
56+{
57+ if (m_categoryIndex != index) {
58+ m_categoryIndex = index;
59+ Q_EMIT categoryIndexChanged(m_categoryIndex);
60+ }
61+}
62+
63+QHash<int, QByteArray>
64+CategoryResults::roleNames() const
65+{
66+ return m_roles;
67+}
68+
69+QVariant
70+CategoryResults::data(const QModelIndex& index, int role) const
71+{
72+ if (!index.isValid()) {
73+ return QVariant();
74+ }
75+
76+ switch (role) {
77+ case RoleUri:
78+ return DeeListModel::data(index, ResultsColumn::URI);
79+ case RoleIconHint:
80+ return DeeListModel::data(index, ResultsColumn::ICON_HINT);
81+ case RoleCategory:
82+ return DeeListModel::data(index, ResultsColumn::CATEGORY);
83+ case RoleMimetype:
84+ return DeeListModel::data(index, ResultsColumn::MIMETYPE);
85+ case RoleTitle:
86+ return DeeListModel::data(index, ResultsColumn::TITLE);
87+ case RoleComment:
88+ return DeeListModel::data(index, ResultsColumn::COMMENT);
89+ case RoleDndUri:
90+ return DeeListModel::data(index, ResultsColumn::DND_URI);
91+ case RoleMetadata:
92+ return DeeListModel::data(index, ResultsColumn::METADATA);
93+ default:
94+ return QVariant();
95+ }
96+}
plugins/Unity/categoryresults.hnew file+67
@@ -0,0 +1,67 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Michal Hruby <michal.hruby@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+
21+#ifndef CATEGORY_RESULTS_H
22+#define CATEGORY_RESULTS_H
23+
24+// dee-qt
25+#include "deelistmodel.h"
26+
27+class CategoryResults : public DeeListModel
28+{
29+ Q_OBJECT
30+
31+ Q_ENUMS(Roles)
32+
33+ Q_PROPERTY(int categoryIndex READ categoryIndex WRITE setCategoryIndex NOTIFY categoryIndexChanged)
34+
35+public:
36+ explicit CategoryResults(QObject* parent = 0);
37+
38+ enum Roles {
39+ RoleUri,
40+ RoleIconHint,
41+ RoleCategory,
42+ RoleMimetype,
43+ RoleTitle,
44+ RoleComment,
45+ RoleDndUri,
46+ RoleMetadata
47+ };
48+
49+ QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
50+
51+ QHash<int, QByteArray> roleNames() const;
52+
53+ /* getters */
54+ int categoryIndex() const;
55+
56+ /* setters */
57+ void setCategoryIndex(int index);
58+
59+Q_SIGNALS:
60+ void categoryIndexChanged(int index);
61+
62+private:
63+ QHash<int, QByteArray> m_roles;
64+ int m_categoryIndex;
65+};
66+
67+#endif // CATEGORY_RESULTS_H
plugins/Unity/plugin.cpp+2−2
@@ -30,7 +30,7 @@
30#include "scope.h"
30#include "scope.h"
31#include "scopes.h"
31#include "scopes.h"
32#include "categories.h"
32#include "categories.h"
33−#include "categoryfilter.h"
33+#include "categoryresults.h"
34#include "bottombarvisibilitycommunicatorshell.h"
34#include "bottombarvisibilitycommunicatorshell.h"
35
35
36// libqtdee
36// libqtdee
@@ -48,7 +48,7 @@ void UnityPlugin::registerTypes(const char *uri)
48 qmlRegisterType<Scope>(uri, 0, 1, "Scope");
48 qmlRegisterType<Scope>(uri, 0, 1, "Scope");
49 qmlRegisterType<Scopes>(uri, 0, 1, "Scopes");
49 qmlRegisterType<Scopes>(uri, 0, 1, "Scopes");
50 qmlRegisterType<Categories>(uri, 0, 1, "Categories");
50 qmlRegisterType<Categories>(uri, 0, 1, "Categories");
51− qmlRegisterType<CategoryFilter>(uri, 0, 1, "CategoryFilter");
51+ qmlRegisterUncreatableType<CategoryResults>(uri, 0, 1, "CategoryResults", "Can't create new Category Results in QML. Get them from Categories instance.");
52 qmlRegisterType<DeeListModel>(uri, 0, 1, "DeeListModel");
52 qmlRegisterType<DeeListModel>(uri, 0, 1, "DeeListModel");
53 qmlRegisterUncreatableType<BottomBarVisibilityCommunicatorShell>(uri, 0, 1, "BottomBarVisibilityCommunicatorShell", "Can't create BottomBarVisibilityCommunicatorShell");
53 qmlRegisterUncreatableType<BottomBarVisibilityCommunicatorShell>(uri, 0, 1, "BottomBarVisibilityCommunicatorShell", "Can't create BottomBarVisibilityCommunicatorShell");
54}
54}
plugins/Unity/qmldir+1
@@ -1,2 +1,3 @@
1module Unity
1module Unity
2plugin Unity-qml
2plugin Unity-qml
3+typeinfo plugin.qmltypes
plugins/Unity/scope.cpp+19−57
@@ -3,6 +3,7 @@
3 *
3 *
4 * Authors:
4 * Authors:
5 * Florian Boucault <florian.boucault@canonical.com>
5 * Florian Boucault <florian.boucault@canonical.com>
6+ * Michal Hruby <michal.hruby@canonical.com>
6 *
7 *
7 * This program is free software; you can redistribute it and/or modify
8 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * it under the terms of the GNU General Public License as published by
@@ -38,10 +39,7 @@
38Scope::Scope(QObject *parent) :
39Scope::Scope(QObject *parent) :
39 QObject(parent)
40 QObject(parent)
40{
41{
41− m_results = new DeeListModel(this);
42− m_categories = new Categories(this);
42+ m_categories.reset(new Categories(this));
43−
44− m_categories->setResultModel(m_results);
45}
43}
46
44
47QString Scope::id() const
45QString Scope::id() const
@@ -84,14 +82,9 @@ bool Scope::connected() const
84 return m_unityScope->connected();
82 return m_unityScope->connected();
85}
83}
86
84
87−DeeListModel* Scope::results() const
88−{
89− return m_results;
90−}
91−
92Categories* Scope::categories() const
85Categories* Scope::categories() const
93{
86{
94− return m_categories;
87+ return m_categories.get();
95}
88}
96
89
97QString Scope::searchQuery() const
90QString Scope::searchQuery() const
@@ -104,6 +97,11 @@ QString Scope::noResultsHint() const
104 return m_noResultsHint;
97 return m_noResultsHint;
105}
98}
106
99
100+QString Scope::formFactor() const
101+{
102+ return m_formFactor;
103+}
104+
107void Scope::setSearchQuery(const QString& search_query)
105void Scope::setSearchQuery(const QString& search_query)
108{
106{
109 /* Checking for m_searchQuery.isNull() which returns true only when the string
107 /* Checking for m_searchQuery.isNull() which returns true only when the string
@@ -125,6 +123,15 @@ void Scope::setNoResultsHint(const QString& hint) {
125 }
123 }
126}
124}
127
125
126+void Scope::setFormFactor(const QString& form_factor) {
127+ if (form_factor != m_formFactor) {
128+ m_formFactor = form_factor;
129+ if (m_unityScope) {
130+ m_unityScope->form_factor = m_formFactor.toStdString();
131+ }
132+ Q_EMIT formFactorChanged();
133+ }
134+}
128
135
129unity::dash::LocalResult Scope::createLocalResult(const QVariant &uri, const QVariant &icon_hint,
136unity::dash::LocalResult Scope::createLocalResult(const QVariant &uri, const QVariant &icon_hint,
130 const QVariant &category, const QVariant &result_type,
137 const QVariant &category, const QVariant &result_type,
@@ -237,18 +244,9 @@ void Scope::setUnityScope(const unity::dash::Scope::Ptr& scope)
237{
244{
238 m_unityScope = scope;
245 m_unityScope = scope;
239
246
240− if (QString::fromStdString(m_unityScope->results()->swarm_name) == QString(":local")) {
247+ m_categories->setUnityScope(m_unityScope);
241− m_results->setModel(m_unityScope->results()->model());
242− } else {
243− m_results->setName(QString::fromStdString(m_unityScope->results()->swarm_name));
244− }
245−
246− if (QString::fromStdString(m_unityScope->categories()->swarm_name) == QString(":local")) {
247− m_categories->setModel(m_unityScope->categories()->model());
248− } else {
249− m_categories->setName(QString::fromStdString(m_unityScope->categories()->swarm_name));
250− }
251
248
249+ m_unityScope->form_factor = m_formFactor.toStdString();
252 /* Property change signals */
250 /* Property change signals */
253 m_unityScope->id.changed.connect(sigc::mem_fun(this, &Scope::idChanged));
251 m_unityScope->id.changed.connect(sigc::mem_fun(this, &Scope::idChanged));
254 m_unityScope->name.changed.connect(sigc::mem_fun(this, &Scope::nameChanged));
252 m_unityScope->name.changed.connect(sigc::mem_fun(this, &Scope::nameChanged));
@@ -258,12 +256,6 @@ void Scope::setUnityScope(const unity::dash::Scope::Ptr& scope)
258 m_unityScope->visible.changed.connect(sigc::mem_fun(this, &Scope::visibleChanged));
256 m_unityScope->visible.changed.connect(sigc::mem_fun(this, &Scope::visibleChanged));
259 m_unityScope->shortcut.changed.connect(sigc::mem_fun(this, &Scope::shortcutChanged));
257 m_unityScope->shortcut.changed.connect(sigc::mem_fun(this, &Scope::shortcutChanged));
260 m_unityScope->connected.changed.connect(sigc::mem_fun(this, &Scope::connectedChanged));
258 m_unityScope->connected.changed.connect(sigc::mem_fun(this, &Scope::connectedChanged));
261− m_unityScope->results.changed.connect(sigc::mem_fun(this, &Scope::onResultsChanged));
262− m_unityScope->results()->swarm_name.changed.connect(sigc::mem_fun(this, &Scope::onResultsSwarmNameChanged));
263− m_unityScope->results()->model.changed.connect(sigc::mem_fun(this, &Scope::onResultsModelChanged));
264− m_unityScope->categories()->model.changed.connect(sigc::mem_fun(this, &Scope::onCategoriesModelChanged));
265− m_unityScope->categories.changed.connect(sigc::mem_fun(this, &Scope::onCategoriesChanged));
266− m_unityScope->categories()->swarm_name.changed.connect(sigc::mem_fun(this, &Scope::onCategoriesSwarmNameChanged));
267 /* Signals forwarding */
259 /* Signals forwarding */
268 connect(this, SIGNAL(searchFinished(const std::string &, unity::glib::HintsMap const &, unity::glib::Error const &)), SLOT(onSearchFinished(const std::string &, unity::glib::HintsMap const &)));
260 connect(this, SIGNAL(searchFinished(const std::string &, unity::glib::HintsMap const &, unity::glib::Error const &)), SLOT(onSearchFinished(const std::string &, unity::glib::HintsMap const &)));
269
261
@@ -294,36 +286,6 @@ void Scope::synchronizeStates()
294 }
286 }
295}
287}
296
288
297−void Scope::onResultsSwarmNameChanged(const std::string& /* swarm_name */)
298−{
299− m_results->setName(QString::fromStdString(m_unityScope->results()->swarm_name));
300−}
301−
302−void Scope::onResultsChanged(const unity::dash::Results::Ptr& /* results */)
303−{
304− m_results->setName(QString::fromStdString(m_unityScope->results()->swarm_name));
305−}
306−
307−void Scope::onResultsModelChanged(unity::glib::Object<DeeModel> /* model */)
308−{
309− m_results->setModel(m_unityScope->results()->model());
310−}
311−
312−void Scope::onCategoriesSwarmNameChanged(const std::string& /* swarm_name */)
313−{
314− m_categories->setName(QString::fromStdString(m_unityScope->categories()->swarm_name));
315−}
316−
317−void Scope::onCategoriesChanged(const unity::dash::Categories::Ptr& /* categories */)
318−{
319− m_categories->setName(QString::fromStdString(m_unityScope->categories()->swarm_name));
320−}
321−
322−void Scope::onCategoriesModelChanged(unity::glib::Object<DeeModel> model)
323−{
324− m_categories->setModel(model);
325−}
326−
327void Scope::onSearchFinished(const std::string& /* query */, unity::glib::HintsMap const &hints)
289void Scope::onSearchFinished(const std::string& /* query */, unity::glib::HintsMap const &hints)
328{
290{
329 QString hint;
291 QString hint;
plugins/Unity/scope.h+8−12
@@ -32,7 +32,8 @@
32// dee-qt
32// dee-qt
33#include "deelistmodel.h"
33#include "deelistmodel.h"
34
34
35−class Categories;
35+#include "categories.h"
36+
36class Preview;
37class Preview;
37
38
38class Scope : public QObject
39class Scope : public QObject
@@ -47,11 +48,11 @@ class Scope : public QObject
47 Q_PROPERTY(bool visible READ visible NOTIFY visibleChanged)
48 Q_PROPERTY(bool visible READ visible NOTIFY visibleChanged)
48 Q_PROPERTY(QString shortcut READ shortcut NOTIFY shortcutChanged)
49 Q_PROPERTY(QString shortcut READ shortcut NOTIFY shortcutChanged)
49 Q_PROPERTY(bool connected READ connected NOTIFY connectedChanged)
50 Q_PROPERTY(bool connected READ connected NOTIFY connectedChanged)
50− Q_PROPERTY(DeeListModel* results READ results NOTIFY resultsChanged)
51 Q_PROPERTY(Categories* categories READ categories NOTIFY categoriesChanged)
51 Q_PROPERTY(Categories* categories READ categories NOTIFY categoriesChanged)
52
52
53 Q_PROPERTY(QString searchQuery READ searchQuery WRITE setSearchQuery NOTIFY searchQueryChanged)
53 Q_PROPERTY(QString searchQuery READ searchQuery WRITE setSearchQuery NOTIFY searchQueryChanged)
54 Q_PROPERTY(QString noResultsHint READ noResultsHint WRITE setNoResultsHint NOTIFY noResultsHintChanged)
54 Q_PROPERTY(QString noResultsHint READ noResultsHint WRITE setNoResultsHint NOTIFY noResultsHintChanged)
55+ Q_PROPERTY(QString formFactor READ formFactor WRITE setFormFactor NOTIFY formFactorChanged)
55
56
56public:
57public:
57 explicit Scope(QObject *parent = 0);
58 explicit Scope(QObject *parent = 0);
@@ -65,14 +66,15 @@ public:
65 bool visible() const;
66 bool visible() const;
66 QString shortcut() const;
67 QString shortcut() const;
67 bool connected() const;
68 bool connected() const;
68− DeeListModel* results() const;
69 Categories* categories() const;
69 Categories* categories() const;
70 QString searchQuery() const;
70 QString searchQuery() const;
71 QString noResultsHint() const;
71 QString noResultsHint() const;
72+ QString formFactor() const;
72
73
73 /* setters */
74 /* setters */
74 void setSearchQuery(const QString& search_query);
75 void setSearchQuery(const QString& search_query);
75 void setNoResultsHint(const QString& hint);
76 void setNoResultsHint(const QString& hint);
77+ void setFormFactor(const QString& form_factor);
76
78
77 Q_INVOKABLE void activate(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
79 Q_INVOKABLE void activate(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
78 const QVariant &result_type, const QVariant &mimetype, const QVariant &title,
80 const QVariant &result_type, const QVariant &mimetype, const QVariant &title,
@@ -94,11 +96,11 @@ Q_SIGNALS:
94 void visibleChanged(bool);
96 void visibleChanged(bool);
95 void shortcutChanged(const std::string&);
97 void shortcutChanged(const std::string&);
96 void connectedChanged(bool);
98 void connectedChanged(bool);
97− void resultsChanged();
98 void categoriesChanged();
99 void categoriesChanged();
99 void searchFinished(const std::string&, unity::glib::HintsMap const&, unity::glib::Error const&);
100 void searchFinished(const std::string&, unity::glib::HintsMap const&, unity::glib::Error const&);
100 void searchQueryChanged();
101 void searchQueryChanged();
101 void noResultsHintChanged();
102 void noResultsHintChanged();
103+ void formFactorChanged();
102
104
103 // signals triggered by activate(..) or preview(..) requests.
105 // signals triggered by activate(..) or preview(..) requests.
104 void previewReady(Preview *preview);
106 void previewReady(Preview *preview);
@@ -111,12 +113,6 @@ private Q_SLOTS:
111 void onSearchFinished(const std::string &, unity::glib::HintsMap const &);
113 void onSearchFinished(const std::string &, unity::glib::HintsMap const &);
112
114
113private:
115private:
114− void onResultsSwarmNameChanged(const std::string&);
115− void onResultsChanged(const unity::dash::Results::Ptr&);
116− void onResultsModelChanged(unity::glib::Object<DeeModel>);
117− void onCategoriesSwarmNameChanged(const std::string&);
118− void onCategoriesModelChanged(unity::glib::Object<DeeModel>);
119− void onCategoriesChanged(const unity::dash::Categories::Ptr&);
120 unity::dash::LocalResult createLocalResult(const QVariant &uri, const QVariant &icon_hint,
116 unity::dash::LocalResult createLocalResult(const QVariant &uri, const QVariant &icon_hint,
121 const QVariant &category, const QVariant &result_type,
117 const QVariant &category, const QVariant &result_type,
122 const QVariant &mimetype, const QVariant &title,
118 const QVariant &mimetype, const QVariant &title,
@@ -127,10 +123,10 @@ private:
127 void fallbackActivate(const QString& uri);
123 void fallbackActivate(const QString& uri);
128
124
129 unity::dash::Scope::Ptr m_unityScope;
125 unity::dash::Scope::Ptr m_unityScope;
130− DeeListModel* m_results;
131− Categories* m_categories;
126+ std::unique_ptr<Categories> m_categories;
132 QString m_searchQuery;
127 QString m_searchQuery;
133 QString m_noResultsHint;
128 QString m_noResultsHint;
129+ QString m_formFactor;
134};
130};
135
131
136Q_DECLARE_METATYPE(Scope*)
132Q_DECLARE_METATYPE(Scope*)
plugins/Utils/CMakeLists.txt+2−12
@@ -22,15 +22,5 @@ set_target_properties(Utils-qml PROPERTIES COMPILE_FLAGS -fvisibility=default)
22
22
23qt5_use_modules(Utils-qml Qml Quick)
23qt5_use_modules(Utils-qml Qml Quick)
24
24
25−# copy qmldir file into build directory for shadow builds
25+# export the qmldir and qmltypes files
26−file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/qmldir"
27− DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
28− )
29−
30−install(TARGETS Utils-qml
26+export_qmlplugin(Utils 0.1 Utils TARGETS Utils-qml)
31− DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/Utils
32− )
33−
34−install(FILES qmldir
35− DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/Utils
36− )
plugins/Utils/qmldir+1
@@ -1,2 +1,3 @@
1module Utils
1module Utils
2plugin Utils-qml
2plugin Utils-qml
3+typeinfo plugin.qmltypes
po/sl.po+11−17
@@ -8,14 +8,14 @@ msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2013-06-26 22:58+0200\n"
10"POT-Creation-Date: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-29 10:26+0000\n"
11+"PO-Revision-Date: 2013-07-02 12:59+0000\n"
12"Last-Translator: Damir Jerovšek <Unknown>\n"
12"Last-Translator: Damir Jerovšek <Unknown>\n"
13"Language-Team: Slovenian <sl@li.org>\n"
13"Language-Team: Slovenian <sl@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-30 07:12+0000\n"
17+"X-Launchpad-Export-Date: 2013-07-06 08:44+0000\n"
18−"X-Generator: Launchpad (build 16692)\n"
18+"X-Generator: Launchpad (build 16696)\n"
19
19
20#: Applications/applications.js:23
20#: Applications/applications.js:23
21msgid "Phone"
21msgid "Phone"
@@ -23,7 +23,7 @@ msgstr "Telefon"
23
23
24#: Applications/applications.js:29
24#: Applications/applications.js:29
25msgid "Camera"
25msgid "Camera"
26−msgstr "Fotoaparat"
26+msgstr ""
27
27
28#: Applications/applications.js:35
28#: Applications/applications.js:35
29msgid "Gallery"
29msgid "Gallery"
@@ -111,7 +111,7 @@ msgstr "Programi"
111
111
112#: Dash/DashHome.qml:40
112#: Dash/DashHome.qml:40
113msgid "Frequent Apps"
113msgid "Frequent Apps"
114−msgstr ""
114+msgstr "Pogosto uporabljani programi"
115
115
116#: Dash/DashHome.qml:43
116#: Dash/DashHome.qml:43
117msgid "Recent Music"
117msgid "Recent Music"
@@ -127,7 +127,7 @@ msgstr "Domov"
127
127
128#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
128#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
129msgid "Featured"
129msgid "Featured"
130−msgstr ""
130+msgstr "Predstavljeno"
131
131
132#: Dash/DashMusic.qml:28 Dash/DashVideos.qml:29
132#: Dash/DashMusic.qml:28 Dash/DashVideos.qml:29
133msgid "Recent"
133msgid "Recent"
@@ -139,7 +139,7 @@ msgstr "Nove izdaje"
139
139
140#: Dash/DashMusic.qml:30
140#: Dash/DashMusic.qml:30
141msgid "Top Charting"
141msgid "Top Charting"
142−msgstr ""
142+msgstr "Najvišje na lestvici"
143
143
144#: Dash/DashMusic.qml:99
144#: Dash/DashMusic.qml:99
145msgid "Music"
145msgid "Music"
@@ -147,7 +147,7 @@ msgstr "Glasba"
147
147
148#: Dash/DashVideos.qml:31
148#: Dash/DashVideos.qml:31
149msgid "Popular Online"
149msgid "Popular Online"
150−msgstr ""
150+msgstr "Priljubljeno na spletu"
151
151
152#: Dash/DashVideos.qml:155
152#: Dash/DashVideos.qml:155
153msgid "Videos"
153msgid "Videos"
@@ -163,7 +163,7 @@ msgstr ""
163
163
164#: Dash/Video/VideoPreview.qml:144
164#: Dash/Video/VideoPreview.qml:144
165msgid "Author:"
165msgid "Author:"
166−msgstr "Avtor:"
166+msgstr ""
167
167
168#: Greeter/Lockscreen.qml:133
168#: Greeter/Lockscreen.qml:133
169msgid "Emergency call"
169msgid "Emergency call"
@@ -176,7 +176,7 @@ msgstr "Pozdravljeni, %1"
176
176
177#: Greeter/PassphraseLockscreen.qml:59
177#: Greeter/PassphraseLockscreen.qml:59
178msgid "Hello"
178msgid "Hello"
179−msgstr "Pozdravljeni"
179+msgstr ""
180
180
181#: Hud/HudParametrizedActionsPage.qml:132
181#: Hud/HudParametrizedActionsPage.qml:132
182msgid "Confirm"
182msgid "Confirm"
@@ -217,10 +217,4 @@ msgstr "Nič se ne ujema z vašim iskalnim nizom."
217#: Shell.qml:383
217#: Shell.qml:383
218#, qt-format
218#, qt-format
219msgid "Please enter %1"
219msgid "Please enter %1"
220−msgstr "Vnesite %1"
220+msgstr ""
221−
222−#~ msgid "People"
223−#~ msgstr "Ljudje"
224−
225−#~ msgid "Home screen"
226−#~ msgstr "Domači zaslon"
tests/mocks/Unity/CMakeLists.txt+2−3
@@ -19,11 +19,10 @@ include_directories(
19add_definitions(-DQT_NO_KEYWORDS)
19add_definitions(-DQT_NO_KEYWORDS)
20
20
21set(UnityQML_SOURCES
21set(UnityQML_SOURCES
22− ${CMAKE_SOURCE_DIR}/plugins/Unity/categories.cpp
22+ ${CMAKE_SOURCE_DIR}/plugins/Unity/categoryresults.cpp
23− ${CMAKE_SOURCE_DIR}/plugins/Unity/categoryfilter.cpp
24− ${CMAKE_SOURCE_DIR}/plugins/Utils/qsortfilterproxymodelqml.cpp
25 fake_scope.cpp
23 fake_scope.cpp
26 fake_scopes.cpp
24 fake_scopes.cpp
25+ fake_categories.cpp
27 fake_unity_plugin.cpp
26 fake_unity_plugin.cpp
28)
27)
29
28
tests/mocks/Unity/fake_categories.cppnew file+178
@@ -0,0 +1,178 @@
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+ *
16+ * Author: Nick Dedekind <nick.dedekind@canonical.com>
17+ */
18+
19+// self
20+#include "fake_categories.h"
21+
22+// local
23+#include "categoryresults.h"
24+
25+#define CATEGORY_COLUMN 2
26+
27+Categories::Categories(QObject* parent)
28+ : DeeListModel(parent)
29+{
30+ // FIXME: need to clean up unused filters on countChanged
31+ m_roles[Categories::RoleId] = "id";
32+ m_roles[Categories::RoleName] = "name";
33+ m_roles[Categories::RoleIcon] = "icon";
34+ m_roles[Categories::RoleRenderer] = "renderer";
35+ m_roles[Categories::RoleContentType] = "content_type";
36+ m_roles[Categories::RoleHints] = "hints";
37+ m_roles[Categories::RoleResults] = "results";
38+ m_roles[Categories::RoleCount] = "count";
39+
40+ // TODO This should not be needed but accumulatting the count changes
41+ // makes the visualization more stable and also makes crashes on fast
42+ // change of the search term harder to reproduce
43+ m_timer.setSingleShot(true);
44+ m_timer.setInterval(50);
45+ connect(&m_timer, SIGNAL(timeout()), this, SLOT(onEmitCountChanged()));
46+}
47+
48+DeeListModel*
49+Categories::getFilter(int index) const
50+{
51+ if (!m_filters.contains(index)) {
52+ auto results = new CategoryResults ();
53+ results->setCategoryIndex(index);
54+ connect(results, SIGNAL(countChanged()), this, SLOT(onCountChanged()));
55+
56+ unsigned cat_index = static_cast<unsigned>(index);
57+ auto model = getResultsForCategory(cat_index);
58+ results->setModel(model);
59+
60+ m_filters.insert(index, results);
61+ }
62+
63+ return m_filters[index];
64+}
65+
66+void
67+Categories::onCountChanged()
68+{
69+ DeeListModel* filter = qobject_cast<DeeListModel*>(sender());
70+ if (filter) {
71+ m_timerFilters << filter;
72+ m_timer.start();
73+ }
74+}
75+
76+void
77+Categories::onEmitCountChanged()
78+{
79+ QVector<int> roles;
80+ roles.append(Categories::RoleCount);
81+ Q_FOREACH(DeeListModel* results, m_timerFilters) {
82+ auto cat_results = qobject_cast<CategoryResults*>(results);
83+ QModelIndex changedIndex = index(cat_results->categoryIndex());
84+ Q_EMIT dataChanged(changedIndex, changedIndex, roles);
85+ }
86+ m_timerFilters.clear();
87+}
88+
89+QHash<int, QByteArray>
90+Categories::roleNames() const
91+{
92+ return m_roles;
93+}
94+
95+void Categories::setResultModel(DeeModel* model)
96+{
97+ // FIXME: should ref it
98+ m_dee_results = model;
99+}
100+
101+
102+static void category_filter_map_func (DeeModel* orig_model,
103+ DeeFilterModel* filter_model,
104+ gpointer user_data)
105+{
106+ DeeModelIter* iter;
107+ DeeModelIter* end;
108+ unsigned index = GPOINTER_TO_UINT(user_data);
109+
110+ iter = dee_model_get_first_iter(orig_model);
111+ end = dee_model_get_last_iter(orig_model);
112+ while (iter != end) {
113+ unsigned category_index = dee_model_get_uint32(orig_model, iter, CATEGORY_COLUMN);
114+ if (index == category_index) {
115+ dee_filter_model_append_iter(filter_model, iter);
116+ }
117+ iter = dee_model_next(orig_model, iter);
118+ }
119+}
120+
121+static gboolean category_filter_notify_func (DeeModel* orig_model,
122+ DeeModelIter* orig_iter,
123+ DeeFilterModel* filter_model,
124+ gpointer user_data)
125+{
126+ unsigned index = GPOINTER_TO_UINT(user_data);
127+ unsigned category_index = dee_model_get_uint32(orig_model, orig_iter, CATEGORY_COLUMN);
128+
129+ if (index != category_index)
130+ return FALSE;
131+
132+ dee_filter_model_insert_iter_with_original_order(filter_model, orig_iter);
133+ return TRUE;
134+}
135+
136+DeeModel* Categories::getResultsForCategory(unsigned cat_index) const
137+{
138+ DeeFilter filter;
139+ filter.map_func = category_filter_map_func;
140+ filter.map_notify = category_filter_notify_func;
141+ filter.destroy = nullptr;
142+ filter.userdata = GUINT_TO_POINTER(cat_index);
143+
144+ DeeModel* filtered_model = dee_filter_model_new(m_dee_results, &filter);
145+ return filtered_model;
146+}
147+
148+QVariant
149+Categories::data(const QModelIndex& index, int role) const
150+{
151+ if (!index.isValid()) {
152+ return QVariant();
153+ }
154+
155+ switch (role) {
156+ case RoleId:
157+ return QVariant::fromValue(index.row());
158+ case RoleName:
159+ return DeeListModel::data(index, 1); //DISPLAY_NAME
160+ case RoleIcon:
161+ return DeeListModel::data(index, 2); //ICON_HINT
162+ case RoleRenderer:
163+ return DeeListModel::data(index, 3); //RENDERER_NAME
164+ case RoleContentType:
165+ {
166+ auto hints = DeeListModel::data(index, 4).toHash();
167+ return hints.contains("content-type") ? hints["content-type"] : QVariant(QString("default"));
168+ }
169+ case RoleHints:
170+ return DeeListModel::data(index, 4); //HINTS
171+ case RoleResults:
172+ return QVariant::fromValue(getFilter(index.row()));
173+ case RoleCount:
174+ return QVariant::fromValue(getFilter(index.row())->rowCount());
175+ default:
176+ return QVariant();
177+ }
178+}
tests/mocks/Unity/fake_categories.hnew file+69
@@ -0,0 +1,69 @@
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+ */
16+
17+#ifndef FAKE_CATEGORIES_H
18+#define FAKE_CATEGORIES_H
19+
20+// Qt
21+#include <QObject>
22+#include <QSet>
23+#include <QTimer>
24+
25+#include <dee.h>
26+#include <deelistmodel.h>
27+
28+class Categories : public DeeListModel
29+{
30+ Q_OBJECT
31+
32+ Q_ENUMS(Roles)
33+
34+public:
35+ Categories(QObject* parent = 0);
36+ enum Roles {
37+ RoleId,
38+ RoleName,
39+ RoleIcon,
40+ RoleRenderer,
41+ RoleContentType,
42+ RoleHints,
43+ RoleResults,
44+ RoleCount
45+ };
46+
47+ QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
48+
49+ QHash<int, QByteArray> roleNames() const;
50+
51+ /* setters */
52+ void setResultModel(DeeModel* model);
53+
54+private Q_SLOTS:
55+ void onCountChanged();
56+ void onEmitCountChanged();
57+
58+private:
59+ DeeModel* getResultsForCategory(unsigned index) const;
60+ DeeListModel* getFilter(int index) const;
61+
62+ DeeModel* m_dee_results;
63+ QTimer m_timer;
64+ QSet<DeeListModel*> m_timerFilters;
65+ QHash<int, QByteArray> m_roles;
66+ mutable QMap<int, DeeListModel*> m_filters;
67+};
68+
69+#endif // FAKE_CATEGORIES_H
tests/mocks/Unity/fake_scope.cpp+104−73
@@ -26,32 +26,29 @@ static DeeModel* create_results_model(unsigned category_count, unsigned result_c
26// TODO: Implement remaining pieces
26// TODO: Implement remaining pieces
27
27
28Scope::Scope(QObject* parent)
28Scope::Scope(QObject* parent)
29−: QObject(parent),
29+ : QObject(parent)
30− m_visible(false),
30+ , m_visible(false)
31− m_categories(new Categories(this)),
31+ , m_categories(new Categories(this))
32− m_results(new DeeListModel(this))
32+ , m_results(new DeeListModel(this))
33{
33{
34+ DeeModel* results_model = create_results_model(4, 30);
35+ m_categories->setResultModel(results_model);
34 m_categories->setModel(create_categories_model(4));
36 m_categories->setModel(create_categories_model(4));
35− m_results->setModel(create_results_model(4, 30));
37+ m_results->setModel(results_model);
36−
37− m_categories->setResultModel(m_results);
38}
38}
39
39
40−Scope::Scope(QString const& id,
40+Scope::Scope(QString const& id, QString const& name, bool visible, QObject* parent)
41− QString const& name,
42− bool visible,
43− QObject* parent)
44−: QObject(parent),
41+ : QObject(parent)
45− m_id(id),
42+ , m_id(id)
46− m_name(name),
43+ , m_name(name)
47− m_visible(visible),
44+ , m_visible(visible)
48− m_categories(new Categories(this)),
45+ , m_categories(new Categories(this))
49− m_results(new DeeListModel(this))
46+ , m_results(new DeeListModel(this))
50{
47{
48+ DeeModel* results_model = create_results_model(4, 30);
49+ m_categories->setResultModel(results_model);
51 m_categories->setModel(create_categories_model(4));
50 m_categories->setModel(create_categories_model(4));
52− m_results->setModel(create_results_model(4, 30));
51+ m_results->setModel(results_model);
53−
54− m_categories->setResultModel(m_results);
55}
52}
56
53
57QString Scope::id() const {
54QString Scope::id() const {
@@ -66,6 +63,42 @@ QString Scope::searchQuery() const {
66 return m_searchQuery;
63 return m_searchQuery;
67}
64}
68
65
66+QString Scope::iconHint() const {
67+ return m_iconHint;
68+}
69+
70+QString Scope::description() const {
71+ return m_description;
72+}
73+
74+QString Scope::searchHint() const {
75+ return QString("");
76+}
77+
78+QString Scope::shortcut() const {
79+ return QString("");
80+}
81+
82+bool Scope::connected() const {
83+ return true;
84+}
85+
86+Categories* Scope::categories() const {
87+ return m_categories;
88+}
89+
90+QString Scope::noResultsHint() const {
91+ return m_noResultsHint;
92+}
93+
94+QString Scope::formFactor() const {
95+ return m_formFactor;
96+}
97+
98+bool Scope::visible() const {
99+ return m_visible;
100+}
101+
69void Scope::setName(const QString &str) {
102void Scope::setName(const QString &str) {
70 if (str != m_name) {
103 if (str != m_name) {
71 m_name = str;
104 m_name = str;
@@ -76,45 +109,47 @@ void Scope::setName(const QString &str) {
76void Scope::setSearchQuery(const QString &str) {
109void Scope::setSearchQuery(const QString &str) {
77 if (str != m_searchQuery) {
110 if (str != m_searchQuery) {
78 m_searchQuery = str;
111 m_searchQuery = str;
79− Q_EMIT searchQueryChanged(m_searchQuery);
112+ Q_EMIT searchQueryChanged();
80 }
113 }
81}
114}
82
115
83−bool Scope::visible() const {
116+void Scope::setFormFactor(const QString &str) {
84− return m_visible;
117+ if (str != m_formFactor) {
118+ m_formFactor = str;
119+ Q_EMIT formFactorChanged();
120+ }
85}
121}
86
122
87−Categories* Scope::categories() const {
123+void Scope::setNoResultsHint(const QString& str) {
88− return m_categories;
124+ if (str != m_noResultsHint) {
125+ m_noResultsHint = str;
126+ Q_EMIT noResultsHintChanged();
127+ }
89}
128}
90
129
91static const gchar * categories_model_schema[] = {
130static const gchar * categories_model_schema[] = {
92− "s", //ID
131+ "s", //ID
93− "s", // DISPLAY_NAME
132+ "s", // DISPLAY_NAME
94− "s", // ICON_HINT
133+ "s", // ICON_HINT
95− "s", // RENDERER_NAME
134+ "s", // RENDERER_NAME
96− "a{sv}" // HINTS
135+ "a{sv}" // HINTS
97};
136};
98
137
99
138
100DeeModel* create_categories_model(unsigned category_count) {
139DeeModel* create_categories_model(unsigned category_count) {
101 DeeModel* category_model = dee_sequence_model_new();
140 DeeModel* category_model = dee_sequence_model_new();
102 dee_model_set_schema_full(category_model, categories_model_schema, G_N_ELEMENTS(categories_model_schema));
141 dee_model_set_schema_full(category_model, categories_model_schema, G_N_ELEMENTS(categories_model_schema));
103−
142+ GVariant* hints = g_variant_new_array(g_variant_type_element(G_VARIANT_TYPE_VARDICT), NULL, 0);
104− GVariantBuilder b;
105− g_variant_builder_init(&b, G_VARIANT_TYPE("a{sv}"));
106− GVariant *hints = g_variant_builder_end(&b);
107
143
108 for(unsigned i = 0; i < category_count; ++i)
144 for(unsigned i = 0; i < category_count; ++i)
109 {
145 {
110− dee_model_append(category_model,
146+ dee_model_append(category_model,
111− std::to_string(i).c_str(),
147+ std::to_string(i).c_str(),
112− ("Category "+std::to_string(i)).c_str(),
148+ ("Category "+std::to_string(i)).c_str(),
113− "gtk-apply",
149+ "gtk-apply",
114− "grid",
150+ "grid",
115− hints);
151+ hints);
116 }
152 }
117− g_variant_unref(hints);
118 return category_model;
153 return category_model;
119}
154}
120
155
@@ -122,48 +157,44 @@ DeeModel* create_categories_model(unsigned category_count) {
122/* Schema that is used in the DeeModel representing
157/* Schema that is used in the DeeModel representing
123 the results */
158 the results */
124static const gchar * results_model_schema[] = {
159static const gchar * results_model_schema[] = {
125− "s", // URI
160+ "s", // URI
126− "s", // ICON_HINT
161+ "s", // ICON_HINT
127− "u", // CATEGORY
162+ "u", // CATEGORY
128− "u", // RESULT_TYPE
163+ "u", // RESULT_TYPE
129− "s", // MIMETYPE
164+ "s", // MIMETYPE
130− "s", // TITLE
165+ "s", // TITLE
131− "s", // COMMENT
166+ "s", // COMMENT
132− "s", // DND_URI
167+ "s", // DND_URI
133− "a{sv}" // METADATA
168+ "a{sv}" // METADATA
134};
169};
135
170
136static const gchar * icons[] = {
171static const gchar * icons[] = {
137− "Applications.png",
172+ "Applications.png",
138− "Home.png",
173+ "Home.png",
139− "Music.png",
174+ "Music.png",
140− "People.png",
175+ "People.png",
141− "Videos.png",
176+ "Videos.png",
142};
177};
143
178
144DeeModel* create_results_model(unsigned category_count, unsigned result_count) {
179DeeModel* create_results_model(unsigned category_count, unsigned result_count) {
145 DeeModel* results_model = dee_sequence_model_new();
180 DeeModel* results_model = dee_sequence_model_new();
146 dee_model_set_schema_full(results_model, results_model_schema, G_N_ELEMENTS(results_model_schema));
181 dee_model_set_schema_full(results_model, results_model_schema, G_N_ELEMENTS(results_model_schema));
147−
182+ GVariant* hints = g_variant_new_array(g_variant_type_element(G_VARIANT_TYPE_VARDICT), NULL, 0);
148− GVariantBuilder b;
149− g_variant_builder_init(&b, G_VARIANT_TYPE("a{sv}"));
150− GVariant *hints = g_variant_builder_end(&b);
151
183
152 for(unsigned i = 0; i < result_count; ++i)
184 for(unsigned i = 0; i < result_count; ++i)
153 {
185 {
154− unsigned category = i % category_count;
186+ unsigned category = i % category_count;
155−
187+
156− dee_model_append(results_model,
188+ dee_model_append(results_model,
157− ("uri://result."+std::to_string(i)).c_str(),
189+ ("uri://result."+std::to_string(i)).c_str(),
158− (shellAppDirectory() + "Dash/graphics/scopeIcons/" + (icons[i%G_N_ELEMENTS(icons)])).toLatin1().data(),
190+ (shellAppDirectory() + "Dash/graphics/scopeIcons/" + (icons[i%G_N_ELEMENTS(icons)])).toLatin1().data(),
159− category,
191+ category,
160− 0,
192+ 0,
161− "application/x-desktop",
193+ "application/x-desktop",
162− ("Title."+std::to_string(i)).c_str(),
194+ ("Title."+std::to_string(i)).c_str(),
163− ("Comment."+std::to_string(i)).c_str(),
195+ ("Comment."+std::to_string(i)).c_str(),
164− ("uri://result."+std::to_string(i)).c_str(),
196+ ("uri://result."+std::to_string(i)).c_str(),
165− hints);
197+ hints);
166 }
198 }
167− g_variant_unref(hints);
168 return results_model;
199 return results_model;
169− }
200+}
tests/mocks/Unity/fake_scope.h+43−11
@@ -19,43 +19,75 @@
19
19
20// Qt
20// Qt
21#include <QObject>
21#include <QObject>
22−#include "categories.h"
22+#include "fake_categories.h"
23
23
24class Scope : public QObject
24class Scope : public QObject
25{
25{
26 Q_OBJECT
26 Q_OBJECT
27+
27 Q_PROPERTY(QString id READ id NOTIFY idChanged)
28 Q_PROPERTY(QString id READ id NOTIFY idChanged)
28− Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
29+ Q_PROPERTY(QString name READ name NOTIFY nameChanged)
29− Q_PROPERTY(QString searchQuery READ searchQuery WRITE setSearchQuery NOTIFY searchQueryChanged)
30+ Q_PROPERTY(QString iconHint READ iconHint NOTIFY iconHintChanged)
31+ Q_PROPERTY(QString description READ description NOTIFY descriptionChanged)
32+ Q_PROPERTY(QString searchHint READ searchHint NOTIFY searchHintChanged)
30 Q_PROPERTY(bool visible READ visible NOTIFY visibleChanged)
33 Q_PROPERTY(bool visible READ visible NOTIFY visibleChanged)
34+ Q_PROPERTY(QString shortcut READ shortcut NOTIFY shortcutChanged)
35+ Q_PROPERTY(bool connected READ connected NOTIFY connectedChanged)
31 Q_PROPERTY(Categories* categories READ categories NOTIFY categoriesChanged)
36 Q_PROPERTY(Categories* categories READ categories NOTIFY categoriesChanged)
32
37
38+ Q_PROPERTY(QString searchQuery READ searchQuery WRITE setSearchQuery NOTIFY searchQueryChanged)
39+ Q_PROPERTY(QString noResultsHint READ noResultsHint WRITE setNoResultsHint NOTIFY noResultsHintChanged)
40+ Q_PROPERTY(QString formFactor READ formFactor WRITE setFormFactor NOTIFY formFactorChanged)
41+
33public:
42public:
34 Scope(QObject* parent = 0);
43 Scope(QObject* parent = 0);
35 Scope(QString const& id, QString const& name, bool visible, QObject* parent = 0);
44 Scope(QString const& id, QString const& name, bool visible, QObject* parent = 0);
36
45
46+ /* getters */
37 QString id() const;
47 QString id() const;
38 QString name() const;
48 QString name() const;
39− QString searchQuery() const;
49+ QString iconHint() const;
50+ QString description() const;
51+ QString searchHint() const;
40 bool visible() const;
52 bool visible() const;
41−
53+ QString shortcut() const;
42− void setName(const QString &str);
54+ bool connected() const;
43− void setSearchQuery(const QString &str);
44−
45 Categories* categories() const;
55 Categories* categories() const;
56+ QString searchQuery() const;
57+ QString noResultsHint() const;
58+ QString formFactor() const;
59+
60+ /* setters */
61+ void setName(const QString& name);
62+ void setSearchQuery(const QString& search_query);
63+ void setNoResultsHint(const QString& hint);
64+ void setFormFactor(const QString& form_factor);
46
65
47Q_SIGNALS:
66Q_SIGNALS:
48− void idChanged(QString);
67+ void idChanged(const QString&);
49− void nameChanged(QString);
68+ void nameChanged(const QString&);
50− void searchQueryChanged(QString);
69+ void iconHintChanged(const QString&);
70+ void descriptionChanged(const QString&);
71+ void searchHintChanged(const QString&);
51 void visibleChanged(bool);
72 void visibleChanged(bool);
73+ void shortcutChanged(const QString&);
74+ void connectedChanged(bool);
52 void categoriesChanged();
75 void categoriesChanged();
76+ void searchFinished(const QString&);
77+ void searchQueryChanged();
78+ void noResultsHintChanged();
79+ void formFactorChanged();
53
80
54private:
81private:
55 QString m_id;
82 QString m_id;
83+ QString m_iconHint;
84+ QString m_description;
56 QString m_name;
85 QString m_name;
57 QString m_searchQuery;
86 QString m_searchQuery;
87+ QString m_noResultsHint;
88+ QString m_formFactor;
58 bool m_visible;
89 bool m_visible;
90+
59 Categories* m_categories;
91 Categories* m_categories;
60 DeeListModel* m_results;
92 DeeListModel* m_results;
61};
93};
tests/mocks/Unity/fake_unity_plugin.cpp+3−3
@@ -21,8 +21,8 @@
21
21
22// local
22// local
23#include "fake_scopes.h"
23#include "fake_scopes.h"
24−#include "categories.h"
24+#include "fake_categories.h"
25−#include "categoryfilter.h"
25+#include "categoryresults.h"
26
26
27// External
27// External
28#include <glib-object.h>
28#include <glib-object.h>
@@ -39,5 +39,5 @@ void FakeUnityPlugin::registerTypes(const char *uri)
39 qmlRegisterType<Scopes>(uri, 0, 1, "Scopes");
39 qmlRegisterType<Scopes>(uri, 0, 1, "Scopes");
40 qmlRegisterType<Scope>(uri, 0, 1, "Scope");
40 qmlRegisterType<Scope>(uri, 0, 1, "Scope");
41 qmlRegisterType<Categories>(uri, 0, 1, "Categories");
41 qmlRegisterType<Categories>(uri, 0, 1, "Categories");
42− qmlRegisterType<CategoryFilter>(uri, 0, 1, "CategoryFilter");
42+ qmlRegisterUncreatableType<CategoryResults>(uri, 0, 1, "CategoryResults", "Can't create");
43}
43}
tests/plugins/Unity/CMakeLists.txt+1−1
@@ -21,7 +21,7 @@ macro(run_tests)
21 add_executable(${_test}Exec ${_test}.cpp previewbindingstest.cpp)
21 add_executable(${_test}Exec ${_test}.cpp previewbindingstest.cpp)
22 qt5_use_modules(${_test}Exec Test Core Qml)
22 qt5_use_modules(${_test}Exec Test Core Qml)
23 set_tests_properties(test${CLASSNAME}${_test}
23 set_tests_properties(test${CLASSNAME}${_test}
24− PROPERTIES ENVIRONMENT LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/plugins/Unity:${LIBUNITYPROTO_LIBRARY_DIRS})
24+ PROPERTIES ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/plugins/Unity:${LIBUNITYPROTO_LIBRARY_DIRS}")
25
25
26 target_link_libraries(${_test}Exec
26 target_link_libraries(${_test}Exec
27 Unity-qml
27 Unity-qml
tests/qmltests/Dash/qml/FakeScopeView.qml+2−2
@@ -107,10 +107,10 @@ FocusScope {
107 Image {
107 Image {
108 width: units.gu(5)
108 width: units.gu(5)
109 height: units.gu(5)
109 height: units.gu(5)
110− source: column_1
110+ source: icon
111 anchors.horizontalCenter: parent.horizontalCenter
111 anchors.horizontalCenter: parent.horizontalCenter
112 }
112 }
113− Text { text: column_4; anchors.horizontalCenter: parent.horizontalCenter }
113+ Text { text: title; anchors.horizontalCenter: parent.horizontalCenter }
114 }
114 }
115 }
115 }
116 }
116 }