Merge lp:~fboucault/unity-2d/keyboard_navigation_experimental into lp:~fboucault/unity-2d/icon_provide_better_error_handling
- keyboard_navigation_experimental
- Merge into icon_provide_better_error_...
Proposed by
Florian Boucault
Status: | Superseded |
---|---|
Proposed branch: | lp:~fboucault/unity-2d/keyboard_navigation_experimental |
Merge into: | lp:~fboucault/unity-2d/icon_provide_better_error_handling |
Diff against target: |
2920 lines (+1417/-409) 54 files modified
.bzrignore (+1/-0) CMakeLists.txt (+31/-0) data/com.canonical.Unity2d.gschema.xml (+19/-0) data/unity-2d.convert (+7/-0) debian/20_unity-2d-gconf-default (+0/-4) debian/changelog (+19/-2) debian/control (+3/-1) debian/gconf/schemas/unity-2d.schemas (+0/-56) debian/unity-2d.install (+3/-1) debian/unity-2d.triggers (+1/-1) launcher/app/CMakeLists.txt (+3/-2) launcher/app/launcher.cpp (+13/-28) launcher/app/launcherview.cpp (+12/-3) launcher/app/launcherview.h (+4/-3) launcher/app/visibilitycontroller.cpp (+7/-8) launcher/app/visibilitycontroller.h (+3/-3) libunity-2d-private/Unity2d/CMakeLists.txt (+3/-6) libunity-2d-private/Unity2d/launcherapplicationslist.cpp (+11/-9) libunity-2d-private/Unity2d/launcherapplicationslist.h (+2/-1) libunity-2d-private/Unity2d/plugin.cpp (+3/-0) libunity-2d-private/Unity2d/qsortfilterproxymodelqml.cpp (+114/-6) libunity-2d-private/Unity2d/qsortfilterproxymodelqml.h (+18/-3) libunity-2d-private/Unity2d/workspacesinfo.cpp (+0/-2) libunity-2d-private/src/CMakeLists.txt (+1/-4) libunity-2d-private/src/giodefaultapplication.cpp (+107/-0) libunity-2d-private/src/giodefaultapplication.h (+63/-0) libunity-2d-private/src/unity2dapplication.cpp (+38/-0) libunity-2d-private/src/unity2dapplication.h (+7/-0) libunity-2d-private/tests/CMakeLists.txt (+1/-0) libunity-2d-private/tests/keyboardmodifiersmonitortest.cpp (+1/-0) libunity-2d-private/tests/mouseareademo.cpp (+1/-0) libunity-2d-private/tests/qsortfilterproxymodeltest.cpp (+384/-0) panel/app/main.cpp (+1/-15) panel/applets/CMakeLists.txt (+0/-4) panel/applets/indicator/indicator.c (+15/-0) places/Home.qml (+37/-43) places/HomeButtonDefaultApplication.qml (+48/-0) places/HomeShortcuts.qml (+30/-5) places/ListViewWithHeaders.qml (+277/-0) places/ListViewWithScrollbar.qml (+7/-30) places/PlaceEntryView.qml (+41/-23) places/Renderer.qml (+3/-3) places/RendererGrid.qml (+24/-77) places/Scrollbar.qml (+11/-5) places/SearchEntry.qml (+3/-1) places/SearchRefine.qml (+5/-0) places/SearchRefineOptionType.qml (+6/-2) places/TickBox.qml (+4/-4) places/UnityEmptySearchRenderer.qml (+1/-1) places/app/CMakeLists.txt (+0/-2) places/app/places.cpp (+3/-19) places/dash.qml (+18/-7) spread/app/CMakeLists.txt (+0/-4) spread/app/spread.cpp (+3/-21) |
To merge this branch: | bzr merge lp:~fboucault/unity-2d/keyboard_navigation_experimental |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Gerry Boland | Pending | ||
Review via email: mp+69479@code.launchpad.net |
Commit message
Description of the change
[dash] Implemented keyboard navigation.
To post a comment you must log in.
- 639. By Florian Boucault
-
Remade RendererGrid.
interactive false thus preventing mouse interaction with the individual groups. - 640. By Florian Boucault
-
Prevent the focus to be on the refine search pane when it is folded.
- 641. By Florian Boucault
-
Added FIXME/
- 642. By Florian Boucault
-
Merged colo:proper_grid
Unmerged revisions
- 642. By Florian Boucault
-
Merged colo:proper_grid
- 641. By Florian Boucault
-
Added FIXME/
- 640. By Florian Boucault
-
Prevent the focus to be on the refine search pane when it is folded.
- 639. By Florian Boucault
-
Remade RendererGrid.
interactive false thus preventing mouse interaction with the individual groups. - 638. By Florian Boucault
-
Merged colo:proper_grid
- 637. By Florian Boucault
-
Merged colo:proper_grid
- 636. By Florian Boucault
-
No change.
- 635. By Florian Boucault
-
Merged colo:proper_grid
- 634. By Florian Boucault
-
Merged colo:proper_grid
- 633. By Florian Boucault
-
Merged colo:proper_grid
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file '.bzrignore' |
2 | --- .bzrignore 2011-06-15 14:39:35 +0000 |
3 | +++ .bzrignore 2011-07-27 15:02:42 +0000 |
4 | @@ -78,3 +78,4 @@ |
5 | debian/unity-qt-spread |
6 | debian/libuqpanel-dev |
7 | debian/libuqpanel0 |
8 | +data/gschemas.compiled |
9 | |
10 | === modified file 'CMakeLists.txt' |
11 | --- CMakeLists.txt 2011-06-27 13:40:51 +0000 |
12 | +++ CMakeLists.txt 2011-07-27 15:02:42 +0000 |
13 | @@ -4,6 +4,7 @@ |
14 | # Dirs |
15 | set(UNITY_2D_DIR share/unity-2d) |
16 | set(UNITY_DIR /usr/share/unity/) |
17 | +set(UNITY_2D_DATA_DIR "${CMAKE_SOURCE_DIR}/data") |
18 | |
19 | configure_file(config.h.in config.h) |
20 | |
21 | @@ -23,6 +24,36 @@ |
22 | find_package(Qt4 REQUIRED) |
23 | find_package(X11 REQUIRED) |
24 | find_package(Gettext REQUIRED) |
25 | +pkg_check_modules(GLIB REQUIRED glib-2.0) |
26 | +pkg_check_modules(GDK REQUIRED gdk-2.0) |
27 | +pkg_check_modules(GTK REQUIRED gtk+-2.0) |
28 | +pkg_check_modules(GIO REQUIRED gio-2.0) |
29 | +pkg_check_modules(WNCK REQUIRED libwnck-1.0) |
30 | + |
31 | + |
32 | +# GSettings schemas |
33 | +pkg_check_modules(GLIB REQUIRED glib-2.0) |
34 | +set (UNITY_2D_SCHEMAS "com.canonical.Unity2d.gschema.xml") |
35 | +set (UNITY_2D_GCONF_CONVERT "unity-2d.convert") |
36 | +set (GSETTINGS_DIR "${CMAKE_INSTALL_PREFIX}/share/glib-2.0/schemas/") |
37 | +set (GCONF_CONVERT_DIR "${CMAKE_INSTALL_PREFIX}/share/GConf/gsettings") |
38 | +execute_process (COMMAND ${PKG_CONFIG_EXECUTABLE} gio-2.0 --variable glib_compile_schemas OUTPUT_VARIABLE GLIB_COMPILE_SCHEMAS OUTPUT_STRIP_TRAILING_WHITESPACE) |
39 | + |
40 | +# Run the schemas validator and error if it fails |
41 | +execute_process (COMMAND ${GLIB_COMPILE_SCHEMAS} ${UNITY_2D_DATA_DIR} ERROR_VARIABLE _schemas_invalid OUTPUT_STRIP_TRAILING_WHITESPACE) |
42 | + |
43 | +if (_schemas_invalid) |
44 | + message (SEND_ERROR "Schemas validation error: ${_schemas_invalid}") |
45 | +endif (_schemas_invalid) |
46 | + |
47 | +# Actually install and recompile the schemas |
48 | +message (STATUS "GSettings schemas will be installed into ${GSETTINGS_DIR}") |
49 | +install (FILES ${UNITY_2D_DATA_DIR}/${UNITY_2D_SCHEMAS} DESTINATION ${GSETTINGS_DIR}) |
50 | +install (CODE "message (STATUS \"Compiling GSettings schemas\")") |
51 | +install (CODE "execute_process (COMMAND ${GLIB_COMPILE_SCHEMAS} ${GSETTINGS_DIR})") |
52 | + |
53 | +# Install GConf to GSettings conversion file |
54 | +install (FILES ${UNITY_2D_DATA_DIR}/${UNITY_2D_GCONF_CONVERT} DESTINATION ${GCONF_CONVERT_DIR}) |
55 | |
56 | include_directories( |
57 | ${CMAKE_BINARY_DIR} |
58 | |
59 | === added directory 'data' |
60 | === added file 'data/com.canonical.Unity2d.gschema.xml' |
61 | --- data/com.canonical.Unity2d.gschema.xml 1970-01-01 00:00:00 +0000 |
62 | +++ data/com.canonical.Unity2d.gschema.xml 2011-07-27 15:02:42 +0000 |
63 | @@ -0,0 +1,19 @@ |
64 | +<schemalist> |
65 | + <schema path="/com/canonical/unity-2d/launcher/" id="com.canonical.Unity2d.Launcher" gettext-domain="unity-2d"> |
66 | + <key type="b" name="super-key-enable"> |
67 | + <default>true</default> |
68 | + <summary>Super key activation.</summary> |
69 | + <description>Whether or not the super (also called windows key) key is used.</description> |
70 | + </key> |
71 | + <key name="hide-mode" type="i"> |
72 | + <default>2</default> |
73 | + <summary>Hiding mode of the launcher</summary> |
74 | + <description>Possible values: 0: never hide; the launcher is always visible. Always set /com/canonical/unity-2d/launcher/use-strut to true when using that mode 1: auto hide; the launcher will disappear after a short time if the user is not interacting with it 2: intellihide; the launcher will disappear if a window is placed on top of it and if the user is not interacting with it</description> |
75 | + </key> |
76 | + <key name="use-strut" type="b"> |
77 | + <default>false</default> |
78 | + <summary>Reserve launcher area</summary> |
79 | + <description>Use EWMH standard to reserve an area of the desktop (struts) so that no window can use the launcher's area</description> |
80 | + </key> |
81 | + </schema> |
82 | +</schemalist> |
83 | |
84 | === added file 'data/unity-2d.convert' |
85 | --- data/unity-2d.convert 1970-01-01 00:00:00 +0000 |
86 | +++ data/unity-2d.convert 2011-07-27 15:02:42 +0000 |
87 | @@ -0,0 +1,7 @@ |
88 | +[com.canonical.Unity2d.Launcher] |
89 | +super-key-enable = /desktop/unity-2d/launcher/super_key_enable |
90 | +hide-mode = /desktop/unity-2d/launcher/hide_mode |
91 | +use-strut = /desktop/unity-2d/launcher/use_strut |
92 | + |
93 | +[com.canonical.Unity.Launcher] |
94 | +favorites = /desktop/unity-2d/launcher/favorites |
95 | |
96 | === modified file 'debian/20_unity-2d-gconf-default' |
97 | --- debian/20_unity-2d-gconf-default 2011-06-15 13:05:38 +0000 |
98 | +++ debian/20_unity-2d-gconf-default 2011-07-27 15:02:42 +0000 |
99 | @@ -1,9 +1,5 @@ |
100 | /apps/gnome-power-manager/lock/use_screensaver_settings true |
101 | /apps/gnome-power-manager/general/use_time_for_policy false |
102 | -/desktop/unity-2d/launcher/favorites [ubiquity-gtkui.desktop,nautilus-home.desktop,firefox.desktop,libreoffice-writer.desktop,libreoffice-calc.desktop,libreoffice-impress.desktop,ubuntu-software-center.desktop,ubuntuone-control-panel-gtk.desktop] |
103 | -/desktop/unity-2d/launcher/hide_mode 2 |
104 | -/desktop/unity-2d/launcher/use_strut false |
105 | -/desktop/unity-2d/launcher/super_key_enable true |
106 | /desktop/gnome/applications/window_manager/default /usr/bin/metacity |
107 | /desktop/gnome/applications/window_manager/current /usr/bin/metacity |
108 | /apps/metacity/general/show_maximized_titlebars false |
109 | |
110 | === modified file 'debian/changelog' |
111 | --- debian/changelog 2011-07-13 10:11:55 +0000 |
112 | +++ debian/changelog 2011-07-27 15:02:42 +0000 |
113 | @@ -1,10 +1,27 @@ |
114 | unity-2d (3.8.12-0ubuntu1) UNRELEASED; urgency=low |
115 | |
116 | + [ Florian Boucault ] |
117 | * do not run pkgbinarymangler to convert images to 8bit since this breaks |
118 | the launcher icon background handling. (LP: #809205) |
119 | (QT upstream bug: http://bugreports.qt.nokia.com/browse/QTBUG-4459) |
120 | - |
121 | - -- Florian Boucault <florian.boucault@canonical.com> Wed, 13 Jul 2011 12:11:05 +0200 |
122 | + * debian/unity-2d.install: |
123 | + - install GSettings schemas into usr/share/glib-2.0/schemas |
124 | + - install GConf to GSettings conversion into usr/share/GConf/gsettings |
125 | + * debian/gconf/schemas/unity-2d.schemas: |
126 | + - remove GConf schema for /desktop/unity-2d/launcher/super_key_enable |
127 | + - remove GConf schema for /desktop/unity-2d/launcher/favorites |
128 | + * debian/20_unity-2d-gconf-default: |
129 | + - remove default value for /desktop/unity-2d/launcher/super_key_enable |
130 | + - remove default value for /desktop/unity-2d/launcher/favorites |
131 | + * debian/control: |
132 | + - add dependency on libdconf-qt-dev |
133 | + |
134 | + [ Didier Roche ] |
135 | + * Fix typo in trigger (debian/unity-2d.triggers): (LP: #807358) |
136 | + * Install the apport hook in the right directory so that it's not launched |
137 | + unconditionally (LP: #712343) |
138 | + |
139 | + -- Florian Boucault <florian.boucault@canonical.com> Fri, 22 Jul 2011 18:56:33 +0200 |
140 | |
141 | unity-2d (3.8.10-0ubuntu1) natty; urgency=low |
142 | |
143 | |
144 | === modified file 'debian/control' |
145 | --- debian/control 2011-06-22 21:17:49 +0000 |
146 | +++ debian/control 2011-07-27 15:02:42 +0000 |
147 | @@ -12,6 +12,7 @@ |
148 | libglib2.0-dev, |
149 | libwnck-dev, |
150 | libqtgconf-dev, |
151 | + libdconf-qt-dev, |
152 | libqtbamf-dev, |
153 | libqtdee-dev, |
154 | libdbusmenu-qt-dev, |
155 | @@ -42,7 +43,8 @@ |
156 | Section: libs |
157 | Architecture: any |
158 | Depends: ${shlibs:Depends}, |
159 | - ${misc:Depends} |
160 | + ${misc:Depends}, |
161 | + unity-common, |
162 | Description: Unity 2D shared library |
163 | This library is used to host common code used by several Unity 2D components |
164 | It is only used internally, there is no use case for it outside of the unity-2d |
165 | |
166 | === removed directory 'debian/gconf/schemas' |
167 | === removed file 'debian/gconf/schemas/unity-2d.schemas' |
168 | --- debian/gconf/schemas/unity-2d.schemas 2011-06-15 13:10:14 +0000 |
169 | +++ debian/gconf/schemas/unity-2d.schemas 1970-01-01 00:00:00 +0000 |
170 | @@ -1,56 +0,0 @@ |
171 | -<gconfschemafile> |
172 | -<schemalist> |
173 | - <schema> |
174 | - <key>/schemas/desktop/unity-2d/launcher/favorites</key> |
175 | - <applyto>/desktop/unity-2d/launcher/favorites</applyto> |
176 | - <owner>unity-2d</owner> |
177 | - <type>list</type> |
178 | - <list_type>string</list_type> |
179 | - <default>[ubiquity-gtkui.desktop,nautilus-home.desktop,firefox.desktop,libreoffice-writer.desktop,libreoffice-calc.desktop,libreoffice-impress.desktop,ubuntu-software-center.desktop,ubuntuone-control-panel-gtk.desktop]</default> |
180 | - <locale name="C"> |
181 | - <short>Favorite applications</short> |
182 | - <long>List of desktop files of applications that have been marked as favorites by the user in the launcher</long> |
183 | - </locale> |
184 | - </schema> |
185 | - |
186 | - <schema> |
187 | - <key>/schemas/desktop/unity-2d/launcher/hide_mode</key> |
188 | - <applyto>/desktop/unity-2d/launcher/hide_mode</applyto> |
189 | - <owner>unity-2d</owner> |
190 | - <type>int</type> |
191 | - <default>2</default> |
192 | - <locale name="C"> |
193 | - <short>Hiding mode of the launcher</short> |
194 | - <long>Possible values: |
195 | -0: never hide; the launcher is always visible. Always set /desktop/unity-2d/launcher/use_strut to true when using that mode |
196 | -1: auto hide; the launcher will disappear after a short time if the user is not interacting with it |
197 | -2: intellihide; the launcher will disappear if a window is placed on top of it and if the user is not interacting with it</long> |
198 | - </locale> |
199 | - </schema> |
200 | - |
201 | - <schema> |
202 | - <key>/schemas/desktop/unity-2d/launcher/use_strut</key> |
203 | - <applyto>/desktop/unity-2d/launcher/use_strut</applyto> |
204 | - <owner>unity-2d</owner> |
205 | - <type>bool</type> |
206 | - <default>false</default> |
207 | - <locale name="C"> |
208 | - <short>Reserve launcher area</short> |
209 | - <long>Use EWMH standard to reserve an area of the desktop (struts) so that no window can use the launcher's area</long> |
210 | - </locale> |
211 | - </schema> |
212 | - |
213 | - <schema> |
214 | - <key>/schemas/desktop/unity-2d/launcher/super_key_enable</key> |
215 | - <applyto>/desktop/unity-2d/launcher/super_key_enable</applyto> |
216 | - <owner>unity-2d</owner> |
217 | - <type>bool</type> |
218 | - <default>true</default> |
219 | - <locale name="C"> |
220 | - <short>Super key activation</short> |
221 | - <long>Whether or not the super (also called windows key) key is used</long> |
222 | - </locale> |
223 | - </schema> |
224 | -</schemalist> |
225 | -</gconfschemafile> |
226 | - |
227 | |
228 | === modified file 'debian/unity-2d.install' |
229 | --- debian/unity-2d.install 2011-06-15 13:05:38 +0000 |
230 | +++ debian/unity-2d.install 2011-07-27 15:02:42 +0000 |
231 | @@ -1,7 +1,9 @@ |
232 | -debian/unity-2d.py /usr/share/apport/general-hooks |
233 | +debian/unity-2d.py /usr/share/apport/package-hooks |
234 | debian/gconf/* /usr/share/gconf |
235 | session/unity-2d.desktop /usr/share/xsessions |
236 | session/2d-ubuntu.session /usr/share/gnome-session/sessions |
237 | debian/20_unity-2d-gconf-mandatory /usr/share/gconf/unity-2d/mandatory |
238 | debian/20_unity-2d-gconf-default /usr/share/gconf/unity-2d/default |
239 | usr/share/locale/*/LC_MESSAGES/unity-2d.mo |
240 | +usr/share/glib-2.0/schemas/com.canonical.Unity2d.gschema.xml |
241 | +usr/share/GConf/gsettings |
242 | |
243 | === modified file 'debian/unity-2d.triggers' |
244 | --- debian/unity-2d.triggers 2011-01-26 11:34:38 +0000 |
245 | +++ debian/unity-2d.triggers 2011-07-27 15:02:42 +0000 |
246 | @@ -1,2 +1,2 @@ |
247 | -interest /usr/share/gconf/unity-2d/defaults |
248 | +interest /usr/share/gconf/unity-2d/default |
249 | interest /usr/share/gconf/unity-2d/mandatory |
250 | |
251 | === modified file 'launcher/app/CMakeLists.txt' |
252 | --- launcher/app/CMakeLists.txt 2011-06-11 11:33:52 +0000 |
253 | +++ launcher/app/CMakeLists.txt 2011-07-27 15:02:42 +0000 |
254 | @@ -1,8 +1,7 @@ |
255 | # Dependencies |
256 | -pkg_check_modules(GTK REQUIRED gtk+-2.0) |
257 | -pkg_check_modules(X11 REQUIRED x11) |
258 | pkg_check_modules(GEIS REQUIRED libutouch-geis) |
259 | pkg_check_modules(QTGCONF REQUIRED libqtgconf) |
260 | +pkg_check_modules(DCONFQT REQUIRED dconf-qt) |
261 | |
262 | # Sources |
263 | set(launcher_SRCS |
264 | @@ -38,6 +37,7 @@ |
265 | ${X11_INCLUDE_DIRS} |
266 | ${GEIS_INCLUDE_DIRS} |
267 | ${QTGCONF_INCLUDE_DIRS} |
268 | + ${DCONFQT_INCLUDE_DIRS} |
269 | ${libunity-2d-private_SOURCE_DIR}/src |
270 | ) |
271 | |
272 | @@ -50,6 +50,7 @@ |
273 | ${X11_LDFLAGS} |
274 | ${GEIS_LDFLAGS} |
275 | ${QTGCONF_LDFLAGS} |
276 | + ${DCONFQT_LDFLAGS} |
277 | unity-2d-private |
278 | ) |
279 | |
280 | |
281 | === modified file 'launcher/app/launcher.cpp' |
282 | --- launcher/app/launcher.cpp 2011-06-22 08:33:52 +0000 |
283 | +++ launcher/app/launcher.cpp 2011-07-27 15:02:42 +0000 |
284 | @@ -17,16 +17,14 @@ |
285 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
286 | */ |
287 | |
288 | -#include <gtk/gtk.h> |
289 | - |
290 | // unity-2d |
291 | #include <gnomesessionclient.h> |
292 | #include <launcherclient.h> |
293 | #include <unity2dapplication.h> |
294 | #include <propertybinder.h> |
295 | |
296 | -// libqtgconf |
297 | -#include <gconfitem-qml-wrapper.h> |
298 | +// libdconf-qt |
299 | +#include "qconf.h" |
300 | |
301 | // Qt |
302 | #include <QApplication> |
303 | @@ -44,6 +42,11 @@ |
304 | #include "unity2dpanel.h" |
305 | #include "gesturehandler.h" |
306 | |
307 | +// libc |
308 | +#include <stdlib.h> |
309 | + |
310 | +static const char* LAUNCHER_DCONF_SCHEMA = "com.canonical.Unity2d.Launcher"; |
311 | + |
312 | #if defined(QMLJSDEBUGGER) |
313 | #include <qt_private/qdeclarativedebughelper_p.h> |
314 | #endif |
315 | @@ -73,24 +76,7 @@ |
316 | |
317 | int main(int argc, char *argv[]) |
318 | { |
319 | - /* Unity2d plugin uses GTK APIs to retrieve theme icons |
320 | - (gtk_icon_theme_get_default) and requires a call to gtk_init */ |
321 | - gtk_init(&argc, &argv); |
322 | - |
323 | - Unity2dDebug::installHandlers(); |
324 | - |
325 | - /* When the environment variable QT_GRAPHICSSYSTEM is not set, |
326 | - force graphics system to 'raster' instead of the default 'native' |
327 | - which on X11 is 'XRender'. |
328 | - 'XRender' defaults to using a TrueColor visual. We do _not_ mimick that |
329 | - behaviour with 'raster' by calling QApplication::setColorSpec because |
330 | - of a bug where black rectangular artifacts were appearing randomly: |
331 | - |
332 | - https://bugs.launchpad.net/unity-2d/+bug/734143 |
333 | - */ |
334 | - if(getenv("QT_GRAPHICSSYSTEM") == 0) { |
335 | - QApplication::setGraphicsSystem("raster"); |
336 | - } |
337 | + Unity2dApplication::earlySetup(argc, argv); |
338 | Unity2dApplication application(argc, argv); |
339 | QSet<QString> arguments = QSet<QString>::fromList(QCoreApplication::arguments()); |
340 | |
341 | @@ -132,12 +118,11 @@ |
342 | |
343 | launcherView->setSource(QUrl("./Launcher.qml")); |
344 | |
345 | - /* Synchronise panel's "useStrut" property with its corresponding GConf key */ |
346 | - GConfItemQmlWrapper useStrutGconf; |
347 | - useStrutGconf.setKey("/desktop/unity-2d/launcher/use_strut"); |
348 | - panel.setUseStrut(useStrutGconf.getValue().toBool()); |
349 | + /* Synchronise panel's "useStrut" property with its corresponding DConf key */ |
350 | + QConf dconfLauncher(LAUNCHER_DCONF_SCHEMA); |
351 | + panel.setUseStrut(dconfLauncher.property("useStrut").toBool()); |
352 | PropertyBinder useStrutBinder; |
353 | - useStrutBinder.bind(&useStrutGconf, "value", &panel, "useStrut"); |
354 | + useStrutBinder.bind(&dconfLauncher, "useStrut", &panel, "useStrut"); |
355 | |
356 | /* Composing the QML declarative view inside the panel */ |
357 | panel.addWidget(launcherView); |
358 | @@ -149,7 +134,7 @@ |
359 | the launcher itself was autostarted (which is the common case when |
360 | running installed). |
361 | For a discussion, see https://bugs.launchpad.net/upicek/+bug/684160. */ |
362 | - g_unsetenv("DESKTOP_AUTOSTART_ID"); |
363 | + unsetenv("DESKTOP_AUTOSTART_ID"); |
364 | |
365 | /* Gesture handler instance in charge of listening to gesture events and |
366 | trigger appropriate actions in response. */ |
367 | |
368 | === modified file 'launcher/app/launcherview.cpp' |
369 | --- launcher/app/launcherview.cpp 2011-06-22 08:54:52 +0000 |
370 | +++ launcher/app/launcherview.cpp 2011-07-27 15:02:42 +0000 |
371 | @@ -36,6 +36,9 @@ |
372 | #include <X11/Xlib.h> |
373 | #include <X11/Xatom.h> |
374 | |
375 | +// libdconf-qt |
376 | +#include "qconf.h" |
377 | + |
378 | #include <keyboardmodifiersmonitor.h> |
379 | #include <hotkey.h> |
380 | #include <hotkeymonitor.h> |
381 | @@ -55,6 +58,7 @@ |
382 | static const char* SPREAD_DBUS_METHOD_IS_SHOWN = "IsShown"; |
383 | static const char* APPLICATIONS_PLACE = "/usr/share/unity/places/applications.place"; |
384 | static const char* COMMANDS_PLACE_ENTRY = "Runner"; |
385 | +static const char* LAUNCHER_DCONF_SCHEMA = "com.canonical.Unity2d.Launcher"; |
386 | |
387 | LauncherView::LauncherView(QWidget* parent) : |
388 | Unity2DDeclarativeView(parent), |
389 | @@ -67,8 +71,8 @@ |
390 | connect(&m_superKeyHoldTimer, SIGNAL(timeout()), SLOT(updateSuperKeyHoldState())); |
391 | connect(this, SIGNAL(superKeyTapped()), SLOT(toggleDash())); |
392 | |
393 | - m_enableSuperKey.setKey("/desktop/unity-2d/launcher/super_key_enable"); |
394 | - connect(&m_enableSuperKey, SIGNAL(valueChanged()), SLOT(updateSuperKeyMonitoring())); |
395 | + m_dconf_launcher = new QConf(LAUNCHER_DCONF_SCHEMA); |
396 | + connect(m_dconf_launcher, SIGNAL(superKeyEnableChanged(bool)), SLOT(updateSuperKeyMonitoring())); |
397 | updateSuperKeyMonitoring(); |
398 | |
399 | /* Alt+F1 gives the keyboard focus to the launcher. */ |
400 | @@ -86,6 +90,11 @@ |
401 | } |
402 | } |
403 | |
404 | +LauncherView::~LauncherView() |
405 | +{ |
406 | + delete m_dconf_launcher; |
407 | +} |
408 | + |
409 | void |
410 | LauncherView::activateWindow() |
411 | { |
412 | @@ -111,7 +120,7 @@ |
413 | { |
414 | KeyboardModifiersMonitor *modifiersMonitor = KeyboardModifiersMonitor::instance(); |
415 | |
416 | - QVariant value = m_enableSuperKey.getValue(); |
417 | + QVariant value = m_dconf_launcher->property("superKeyEnable"); |
418 | if (!value.isValid() || value.toBool() == true) { |
419 | QObject::connect(modifiersMonitor, |
420 | SIGNAL(keyboardModifiersChanged(Qt::KeyboardModifiers)), |
421 | |
422 | === modified file 'launcher/app/launcherview.h' |
423 | --- launcher/app/launcherview.h 2011-06-22 08:54:52 +0000 |
424 | +++ launcher/app/launcherview.h 2011-07-27 15:02:42 +0000 |
425 | @@ -24,13 +24,13 @@ |
426 | #include <QList> |
427 | #include <QUrl> |
428 | #include <QTimer> |
429 | - |
430 | -#include "gconfitem-qml-wrapper.h" |
431 | +#include <QVariant> |
432 | |
433 | #include <unity2ddeclarativeview.h> |
434 | |
435 | class DeclarativeDragDropEvent; |
436 | class LauncherDBus; |
437 | +class QConf; |
438 | |
439 | class LauncherView : public Unity2DDeclarativeView |
440 | { |
441 | @@ -40,6 +40,7 @@ |
442 | |
443 | public: |
444 | explicit LauncherView(QWidget* parent = NULL); |
445 | + ~LauncherView(); |
446 | |
447 | bool superKeyHeld() const { return m_superKeyHeld; } |
448 | |
449 | @@ -66,7 +67,7 @@ |
450 | void focusOutEvent(QFocusEvent* event); |
451 | |
452 | private: |
453 | - GConfItemQmlWrapper m_enableSuperKey; |
454 | + QConf* m_dconf_launcher; |
455 | bool m_superKeyPressed; |
456 | bool m_superKeyHeld; |
457 | QTimer m_superKeyHoldTimer; |
458 | |
459 | === modified file 'launcher/app/visibilitycontroller.cpp' |
460 | --- launcher/app/visibilitycontroller.cpp 2011-06-11 11:33:52 +0000 |
461 | +++ launcher/app/visibilitycontroller.cpp 2011-07-27 15:02:42 +0000 |
462 | @@ -30,27 +30,25 @@ |
463 | #include <debug_p.h> |
464 | #include <unity2dpanel.h> |
465 | |
466 | -// libqtgconf |
467 | -#include <gconfitem-qml-wrapper.h> |
468 | +// libdconf-qt |
469 | +#include "qconf.h" |
470 | |
471 | // Qt |
472 | #include <QDBusConnection> |
473 | #include <QDBusServiceWatcher> |
474 | |
475 | -static const char* GCONF_LAUNCHER_HIDEMODE_KEY = "/desktop/unity-2d/launcher/hide_mode"; |
476 | +static const char* LAUNCHER_DCONF_SCHEMA = "com.canonical.Unity2d.Launcher"; |
477 | |
478 | VisibilityController::VisibilityController(Unity2dPanel* panel) |
479 | : QObject(panel) |
480 | , m_panel(panel) |
481 | -, m_hideModeKey(new GConfItemQmlWrapper(this)) |
482 | +, m_dconf_launcher(new QConf(LAUNCHER_DCONF_SCHEMA)) |
483 | , m_dbusWatcher(new QDBusServiceWatcher(this)) |
484 | { |
485 | - m_hideModeKey->setKey(GCONF_LAUNCHER_HIDEMODE_KEY); |
486 | - |
487 | m_dbusWatcher->setConnection(QDBusConnection::sessionBus()); |
488 | m_dbusWatcher->setWatchMode(QDBusServiceWatcher::WatchForUnregistration); |
489 | |
490 | - connect(m_hideModeKey, SIGNAL(valueChanged()), SLOT(update())); |
491 | + connect(m_dconf_launcher, SIGNAL(hideModeChanged(int)), SLOT(update())); |
492 | connect(m_panel, SIGNAL(useStrutChanged(bool)), SLOT(update())); |
493 | connect(m_panel, SIGNAL(manualSlidingChanged(bool)), SLOT(update())); |
494 | connect(m_dbusWatcher, SIGNAL(serviceUnregistered(const QString&)), SLOT(slotServiceUnregistered(const QString&))); |
495 | @@ -59,6 +57,7 @@ |
496 | |
497 | VisibilityController::~VisibilityController() |
498 | { |
499 | + delete m_dconf_launcher; |
500 | } |
501 | |
502 | void VisibilityController::update() |
503 | @@ -66,7 +65,7 @@ |
504 | if (!m_forceVisibleCountHash.isEmpty()) { |
505 | return; |
506 | } |
507 | - AutoHideMode mode = AutoHideMode(m_hideModeKey->getValue().toInt()); |
508 | + AutoHideMode mode = AutoHideMode(m_dconf_launcher->property("hideMode").toInt()); |
509 | |
510 | setBehavior(0); |
511 | |
512 | |
513 | === modified file 'launcher/app/visibilitycontroller.h' |
514 | --- launcher/app/visibilitycontroller.h 2011-06-11 11:33:52 +0000 |
515 | +++ launcher/app/visibilitycontroller.h 2011-07-27 15:02:42 +0000 |
516 | @@ -28,14 +28,14 @@ |
517 | #include <QObject> |
518 | #include <QScopedPointer> |
519 | |
520 | -class GConfItemQmlWrapper; |
521 | +class QConf; |
522 | |
523 | class AbstractVisibilityBehavior; |
524 | class Unity2dPanel; |
525 | class QDBusServiceWatcher; |
526 | |
527 | /** |
528 | - * This class monitors the hide_mode gconf key and set up an instance of |
529 | + * This class monitors the hide_mode dconf key and set up an instance of |
530 | * AbstractVisibilityBehavior depending on its value |
531 | * |
532 | * It also tracks requests for forced visibility: the launcher or another |
533 | @@ -77,7 +77,7 @@ |
534 | }; |
535 | Q_DISABLE_COPY(VisibilityController); |
536 | Unity2dPanel* m_panel; |
537 | - GConfItemQmlWrapper* m_hideModeKey; |
538 | + QConf* m_dconf_launcher; |
539 | QDBusServiceWatcher* m_dbusWatcher; |
540 | QScopedPointer<AbstractVisibilityBehavior> m_behavior; |
541 | |
542 | |
543 | === modified file 'libunity-2d-private/Unity2d/CMakeLists.txt' |
544 | --- libunity-2d-private/Unity2d/CMakeLists.txt 2011-06-22 08:54:52 +0000 |
545 | +++ libunity-2d-private/Unity2d/CMakeLists.txt 2011-07-27 15:02:42 +0000 |
546 | @@ -1,16 +1,11 @@ |
547 | # Dependencies |
548 | -pkg_check_modules(WNCK REQUIRED libwnck-1.0) |
549 | pkg_check_modules(QTBAMF REQUIRED libqtbamf) |
550 | pkg_check_modules(QTGCONF REQUIRED libqtgconf) |
551 | pkg_check_modules(QTDEE REQUIRED libqtdee) |
552 | pkg_check_modules(DBUSMENUQT REQUIRED dbusmenu-qt) |
553 | -pkg_check_modules(GLIB REQUIRED glib-2.0) |
554 | -pkg_check_modules(GDK REQUIRED gdk-2.0) |
555 | -pkg_check_modules(GIO REQUIRED gio-2.0) |
556 | pkg_check_modules(STARTUPNOTIFICATION REQUIRED libstartup-notification-1.0) |
557 | pkg_check_modules(INDICATOR REQUIRED indicator) |
558 | - |
559 | -find_package(X11 REQUIRED) |
560 | +pkg_check_modules(DCONFQT REQUIRED dconf-qt) |
561 | |
562 | # Sources |
563 | set(unity-2d-private-qml_SRCS |
564 | @@ -100,6 +95,7 @@ |
565 | ${STARTUPNOTIFICATION_INCLUDE_DIRS} |
566 | ${INDICATOR_INCLUDE_DIRS} |
567 | ${X11_INCLUDE_DIR} |
568 | + ${DCONFQT_INCLUDE_DIRS} |
569 | ${libunity-2d-private_SOURCE_DIR}/src |
570 | ) |
571 | |
572 | @@ -119,6 +115,7 @@ |
573 | ${GIO_LDFLAGS} |
574 | ${STARTUPNOTIFICATION_LDFLAGS} |
575 | ${INDICATOR_LDFLAGS} |
576 | + ${DCONFQT_LDFLAGS} |
577 | ${X11_Xcomposite_LIB} |
578 | unity-2d-private |
579 | ) |
580 | |
581 | === modified file 'libunity-2d-private/Unity2d/launcherapplicationslist.cpp' |
582 | --- libunity-2d-private/Unity2d/launcherapplicationslist.cpp 2011-07-13 16:04:50 +0000 |
583 | +++ libunity-2d-private/Unity2d/launcherapplicationslist.cpp 2011-07-27 15:02:42 +0000 |
584 | @@ -23,6 +23,9 @@ |
585 | #include "bamf-application.h" |
586 | #include "gconfitem-qml-wrapper.h" |
587 | |
588 | +// libdconf-qt |
589 | +#include "qconf.h" |
590 | + |
591 | // unity-2d |
592 | #include <debug_p.h> |
593 | |
594 | @@ -40,7 +43,8 @@ |
595 | } |
596 | |
597 | |
598 | -#define FAVORITES_KEY QString("/desktop/unity-2d/launcher/favorites") |
599 | +#define LAUNCHER_DCONF_SCHEMA QString("com.canonical.Unity.Launcher") |
600 | +#define LAUNCHER_DCONF_PATH QString("/desktop/unity/launcher") |
601 | #define DBUS_SERVICE_UNITY "com.canonical.Unity" |
602 | #define DBUS_SERVICE_LAUNCHER_ENTRY "com.canonical.Unity.LauncherEntry" |
603 | #define DBUS_SERVICE_LAUNCHER "com.canonical.Unity.Launcher" |
604 | @@ -52,8 +56,7 @@ |
605 | LauncherApplicationsList::LauncherApplicationsList(QObject *parent) : |
606 | QAbstractListModel(parent) |
607 | { |
608 | - m_favorites_list = new GConfItemQmlWrapper(); |
609 | - m_favorites_list->setKey(FAVORITES_KEY); |
610 | + m_dconf_launcher = new QConf(LAUNCHER_DCONF_SCHEMA); |
611 | |
612 | QDBusConnection session = QDBusConnection::sessionBus(); |
613 | /* FIXME: libunity will send out the Update signal for LauncherEntries |
614 | @@ -171,7 +174,7 @@ |
615 | sn_display_unref(m_snDisplay); |
616 | |
617 | qDeleteAll(m_applications); |
618 | - delete m_favorites_list; |
619 | + delete m_dconf_launcher; |
620 | } |
621 | |
622 | QString |
623 | @@ -366,9 +369,8 @@ |
624 | LauncherApplicationsList::load() |
625 | { |
626 | /* Insert favorites */ |
627 | - /* FIXME: migrate to GSettings, like unity. */ |
628 | QString desktop_file; |
629 | - QStringList favorites = m_favorites_list->getValue().toStringList(); |
630 | + QStringList favorites = m_dconf_launcher->property("favorites").toStringList(); |
631 | |
632 | Q_FOREACH(QString favorite, favorites) { |
633 | insertFavoriteApplication(favorite); |
634 | @@ -453,9 +455,9 @@ |
635 | } |
636 | } |
637 | |
638 | - m_favorites_list->blockSignals(true); |
639 | - m_favorites_list->setValue(QVariant(favorites)); |
640 | - m_favorites_list->blockSignals(false); |
641 | + m_dconf_launcher->blockSignals(true); |
642 | + m_dconf_launcher->setProperty("favorites", QVariant(favorites)); |
643 | + m_dconf_launcher->blockSignals(false); |
644 | } |
645 | |
646 | int |
647 | |
648 | === modified file 'libunity-2d-private/Unity2d/launcherapplicationslist.h' |
649 | --- libunity-2d-private/Unity2d/launcherapplicationslist.h 2011-07-13 16:04:50 +0000 |
650 | +++ libunity-2d-private/Unity2d/launcherapplicationslist.h 2011-07-27 15:02:42 +0000 |
651 | @@ -37,6 +37,7 @@ |
652 | class BamfApplication; |
653 | class BamfView; |
654 | class GConfItemQmlWrapper; |
655 | +class QConf; |
656 | |
657 | class LauncherApplicationsList : public QAbstractListModel, protected AbstractX11EventFilter, protected QDBusContext |
658 | { |
659 | @@ -88,7 +89,7 @@ |
660 | displayed (m_applications). |
661 | */ |
662 | QHash<QString, LauncherApplication*> m_applicationForExecutable; |
663 | - GConfItemQmlWrapper* m_favorites_list; |
664 | + QConf* m_dconf_launcher; |
665 | |
666 | /* Startup notification support */ |
667 | SnDisplay *m_snDisplay; |
668 | |
669 | === modified file 'libunity-2d-private/Unity2d/plugin.cpp' |
670 | --- libunity-2d-private/Unity2d/plugin.cpp 2011-07-14 11:17:30 +0000 |
671 | +++ libunity-2d-private/Unity2d/plugin.cpp 2011-07-27 15:02:42 +0000 |
672 | @@ -47,6 +47,7 @@ |
673 | #include "cacheeffect.h" |
674 | #include "iconutilities.h" |
675 | #include "unity2dtr.h" |
676 | +#include "giodefaultapplication.h" |
677 | |
678 | #include "mimedata.h" |
679 | #include "dragdropevent.h" |
680 | @@ -127,6 +128,8 @@ |
681 | qmlRegisterType<ForceVisibleBehavior>(uri, 0, 1, "ForceVisibleBehavior"); |
682 | |
683 | qmlRegisterType<IconUtilities>(); // Register the type as non creatable |
684 | + |
685 | + qmlRegisterType<GioDefaultApplication>(uri, 0, 1, "GioDefaultApplication"); |
686 | } |
687 | |
688 | void Unity2dPlugin::initializeEngine(QDeclarativeEngine *engine, const char *uri) |
689 | |
690 | === modified file 'libunity-2d-private/Unity2d/qsortfilterproxymodelqml.cpp' |
691 | --- libunity-2d-private/Unity2d/qsortfilterproxymodelqml.cpp 2011-04-28 13:09:25 +0000 |
692 | +++ libunity-2d-private/Unity2d/qsortfilterproxymodelqml.cpp 2011-07-27 15:02:42 +0000 |
693 | @@ -18,14 +18,17 @@ |
694 | #include <debug_p.h> |
695 | |
696 | QSortFilterProxyModelQML::QSortFilterProxyModelQML(QObject *parent) : |
697 | - QSortFilterProxyModel(parent) |
698 | + QSortFilterProxyModel(parent), m_limit(-1) |
699 | { |
700 | + connect(this, SIGNAL(modelReset()), SIGNAL(countChanged())); |
701 | + connect(this, SIGNAL(rowsInserted(QModelIndex,int,int)), SIGNAL(countChanged())); |
702 | + connect(this, SIGNAL(rowsRemoved(QModelIndex,int,int)), SIGNAL(countChanged())); |
703 | } |
704 | |
705 | -void |
706 | -QSortFilterProxyModelQML::updateRoleNames() |
707 | +void QSortFilterProxyModelQML::setRoleNames(const QHash<int,QByteArray> &roleNames) |
708 | { |
709 | - setRoleNames(((QAbstractItemModel*)sourceModel())->roleNames()); |
710 | + QSortFilterProxyModel::setRoleNames(roleNames); |
711 | + Q_EMIT roleNamesChanged(roleNames); |
712 | } |
713 | |
714 | QObject* |
715 | @@ -51,10 +54,25 @@ |
716 | sourceModel()->disconnect(this); |
717 | } |
718 | |
719 | + /* Workaround for limitation of QAbstractProxyModel: if sourceModel's |
720 | + roleNames changes, the QAbstractProxyModel's roleNames are not updated |
721 | + to reflect that change. |
722 | + As a consequence it works around Qt bug http://bugreports.qt.nokia.com/browse/QTBUG-20405 |
723 | + */ |
724 | + bool hasRoleNamesChangedSignal; |
725 | + hasRoleNamesChangedSignal = connect(itemModel, SIGNAL(roleNamesChanged(QHash<int,QByteArray>)), SLOT(setRoleNames(QHash<int,QByteArray>))); |
726 | + if (!hasRoleNamesChangedSignal) { |
727 | + UQ_WARNING << "received a sourceModel that does not notify of changes of its roleNames"; |
728 | + } |
729 | + setRoleNames(itemModel->roleNames()); |
730 | + |
731 | setSourceModel(itemModel); |
732 | |
733 | - connect(itemModel, SIGNAL(modelAboutToBeReset()), SLOT(updateRoleNames())); |
734 | - connect(itemModel, SIGNAL(modelReset()), SLOT(updateRoleNames())); |
735 | + connect(itemModel, SIGNAL(modelReset()), SIGNAL(totalCountChanged())); |
736 | + connect(itemModel, SIGNAL(rowsInserted(QModelIndex,int,int)), SIGNAL(totalCountChanged())); |
737 | + connect(itemModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), SIGNAL(totalCountChanged())); |
738 | + Q_EMIT totalCountChanged(); |
739 | + Q_EMIT countChanged(); |
740 | } |
741 | |
742 | QVariantMap |
743 | @@ -76,7 +94,97 @@ |
744 | } |
745 | |
746 | int |
747 | +QSortFilterProxyModelQML::totalCount() const |
748 | +{ |
749 | + if (sourceModel() != NULL) { |
750 | + return sourceModel()->rowCount(); |
751 | + } else { |
752 | + return 0; |
753 | + } |
754 | +} |
755 | + |
756 | +int |
757 | QSortFilterProxyModelQML::count() |
758 | { |
759 | return rowCount(); |
760 | } |
761 | + |
762 | +int |
763 | +QSortFilterProxyModelQML::rowCount(const QModelIndex &parent) const |
764 | +{ |
765 | + int count = QSortFilterProxyModel::rowCount(parent); |
766 | + if (m_limit >= 0) { |
767 | + return qMin(count, m_limit); |
768 | + } else { |
769 | + return count; |
770 | + } |
771 | +} |
772 | + |
773 | +int |
774 | +QSortFilterProxyModelQML::limit() const |
775 | +{ |
776 | + return m_limit; |
777 | +} |
778 | + |
779 | +void |
780 | +QSortFilterProxyModelQML::setLimit(int limit) |
781 | +{ |
782 | + if (limit != m_limit) { |
783 | + int count = QSortFilterProxyModel::rowCount(); |
784 | + int start; |
785 | + int end; |
786 | + bool inserted = false; |
787 | + bool removed = false; |
788 | + |
789 | + if (m_limit == -1) { |
790 | + if (limit < count) { |
791 | + start = qMin(count, limit); |
792 | + end = count-1; |
793 | + removed = true; |
794 | + } |
795 | + } else if (limit == -1) { |
796 | + if (m_limit < count) { |
797 | + start = qMin(count, m_limit); |
798 | + end = count-1; |
799 | + inserted = true; |
800 | + } |
801 | + } else if (m_limit >= count && limit >= count) { |
802 | + // Nothing |
803 | + } else if (m_limit >= count && limit < count) { |
804 | + start = qMin(count, limit); |
805 | + end = count-1; |
806 | + removed = true; |
807 | + } else if (m_limit < count && limit >= count) { |
808 | + start = qMin(count, m_limit); |
809 | + end = count-1; |
810 | + inserted = true; |
811 | + } else if (m_limit < count && limit < count) { |
812 | + if (m_limit < limit) { |
813 | + start = qMin(count, m_limit); |
814 | + end = qMin(count, limit)-1; |
815 | + inserted = true; |
816 | + } else { |
817 | + start = qMin(count, limit); |
818 | + end = qMin(count, m_limit)-1; |
819 | + removed = true; |
820 | + } |
821 | + } |
822 | + |
823 | + if (inserted) { |
824 | + beginInsertRows(QModelIndex(), start, end); |
825 | + } |
826 | + if (removed) { |
827 | + beginRemoveRows(QModelIndex(), start, end); |
828 | + } |
829 | + m_limit = limit; |
830 | + |
831 | + if (inserted) { |
832 | + endInsertRows(); |
833 | + } |
834 | + if (removed) { |
835 | + endRemoveRows(); |
836 | + } |
837 | + |
838 | + Q_EMIT limitChanged(); |
839 | + } |
840 | +} |
841 | |
842 | === modified file 'libunity-2d-private/Unity2d/qsortfilterproxymodelqml.h' |
843 | --- libunity-2d-private/Unity2d/qsortfilterproxymodelqml.h 2011-03-23 14:04:23 +0000 |
844 | +++ libunity-2d-private/Unity2d/qsortfilterproxymodelqml.h 2011-07-27 15:02:42 +0000 |
845 | @@ -24,21 +24,36 @@ |
846 | Q_OBJECT |
847 | |
848 | Q_PROPERTY(QObject* model READ sourceModelQObject WRITE setSourceModelQObject) |
849 | + Q_PROPERTY(int limit READ limit WRITE setLimit NOTIFY limitChanged) |
850 | + Q_PROPERTY(int totalCount READ totalCount NOTIFY totalCountChanged) |
851 | + Q_PROPERTY(int count READ count NOTIFY countChanged) |
852 | |
853 | public: |
854 | explicit QSortFilterProxyModelQML(QObject *parent = 0); |
855 | |
856 | Q_INVOKABLE QVariantMap get(int row); |
857 | Q_INVOKABLE int count(); |
858 | + int rowCount(const QModelIndex &parent = QModelIndex()) const; |
859 | |
860 | /* getters */ |
861 | QObject* sourceModelQObject() const; |
862 | + int limit() const; |
863 | + int totalCount() const; |
864 | |
865 | /* setters */ |
866 | void setSourceModelQObject(QObject *model); |
867 | - |
868 | -private Q_SLOTS: |
869 | - void updateRoleNames(); |
870 | + void setLimit(int limit); |
871 | + |
872 | + Q_SLOT void setRoleNames(const QHash<int,QByteArray> &roleNames); |
873 | + |
874 | +Q_SIGNALS: |
875 | + void limitChanged(); |
876 | + void totalCountChanged(); |
877 | + void countChanged(); |
878 | + void roleNamesChanged(const QHash<int,QByteArray> &); |
879 | + |
880 | +private: |
881 | + int m_limit; |
882 | }; |
883 | |
884 | #endif // QSORTFILTERPROXYMODELQML_H |
885 | |
886 | === modified file 'libunity-2d-private/Unity2d/workspacesinfo.cpp' |
887 | --- libunity-2d-private/Unity2d/workspacesinfo.cpp 2011-06-27 13:43:05 +0000 |
888 | +++ libunity-2d-private/Unity2d/workspacesinfo.cpp 2011-07-27 15:02:42 +0000 |
889 | @@ -9,8 +9,6 @@ |
890 | #include <libwnck/workspace.h> |
891 | } |
892 | |
893 | -#include "gconfitem-qml-wrapper.h" |
894 | - |
895 | #include <QAbstractEventDispatcher> |
896 | #include <QX11Info> |
897 | |
898 | |
899 | === modified file 'libunity-2d-private/src/CMakeLists.txt' |
900 | --- libunity-2d-private/src/CMakeLists.txt 2011-07-12 10:30:50 +0000 |
901 | +++ libunity-2d-private/src/CMakeLists.txt 2011-07-27 15:02:42 +0000 |
902 | @@ -1,7 +1,3 @@ |
903 | -# Dependencies |
904 | -pkg_check_modules(GLIB REQUIRED glib-2.0) |
905 | -pkg_check_modules(WNCK REQUIRED libwnck-1.0) |
906 | - |
907 | # Sources |
908 | set(libunity-2d-private_SRCS |
909 | gconnector.cpp |
910 | @@ -24,6 +20,7 @@ |
911 | edgehitdetector.cpp |
912 | forcevisiblebehavior.cpp |
913 | intellihidebehavior.cpp |
914 | + giodefaultapplication.cpp |
915 | ) |
916 | |
917 | # Build |
918 | |
919 | === added file 'libunity-2d-private/src/giodefaultapplication.cpp' |
920 | --- libunity-2d-private/src/giodefaultapplication.cpp 1970-01-01 00:00:00 +0000 |
921 | +++ libunity-2d-private/src/giodefaultapplication.cpp 2011-07-27 15:02:42 +0000 |
922 | @@ -0,0 +1,107 @@ |
923 | +/* |
924 | + * Copyright (C) 2011 Canonical, Ltd. |
925 | + * |
926 | + * Authors: |
927 | + * Florian Boucault <florian.boucault@canonical.com> |
928 | + * |
929 | + * This program is free software; you can redistribute it and/or modify |
930 | + * it under the terms of the GNU General Public License as published by |
931 | + * the Free Software Foundation; version 3. |
932 | + * |
933 | + * This program is distributed in the hope that it will be useful, |
934 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
935 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
936 | + * GNU General Public License for more details. |
937 | + * |
938 | + * You should have received a copy of the GNU General Public License |
939 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
940 | + */ |
941 | + |
942 | +#include "giodefaultapplication.h" |
943 | + |
944 | +// libunity-2d |
945 | +#include <gscopedpointer.h> |
946 | + |
947 | +// Qt |
948 | +#include <QFileSystemWatcher> |
949 | +#include <QDir> |
950 | +#include <QTimer> |
951 | + |
952 | +// gio |
953 | +#include <gio/gio.h> |
954 | +#include <gio/gdesktopappinfo.h> |
955 | + |
956 | +static const QString MIMEAPPS_FILE = QDir::homePath() + QString("/.local/share/applications/mimeapps.list"); |
957 | + |
958 | +GioDefaultApplication::GioDefaultApplication(QObject* parent) |
959 | + : QObject(parent), |
960 | + m_contentType(""), |
961 | + m_desktopFile(""), |
962 | + m_mimeappsWatcher(new QFileSystemWatcher(this)) |
963 | +{ |
964 | + /* GIO does not have any signal to inform us of changes in default |
965 | + applications to handle a certain content type. Work around that |
966 | + by monitoring file MIMEAPPS_FILE that is overwritten when default |
967 | + applications change. */ |
968 | + m_mimeappsWatcher->addPath(MIMEAPPS_FILE); |
969 | + connect(m_mimeappsWatcher, SIGNAL(fileChanged(const QString&)), |
970 | + SLOT(onMimeappsFileChanged())); |
971 | + |
972 | +} |
973 | + |
974 | +void GioDefaultApplication::onMimeappsFileChanged() |
975 | +{ |
976 | + /* FIXME: wait for 10 seconds before updating the desktop file because |
977 | + of a bug in gio where g_app_info_get_default_for_type will not immediately |
978 | + return the updated result. |
979 | + Ref.: https://bugzilla.gnome.org/show_bug.cgi?id=653999 |
980 | + */ |
981 | + QTimer::singleShot(10000, this, SLOT(updateDesktopFile())); |
982 | + /* If the file is already being monitored, we shouldn’t need to do anything. |
983 | + However it seems that in some cases, a change to the file will stop |
984 | + emiting further fileChanged signals, despite the file still being in the |
985 | + list of monitored files. This is the case when the desktop file is being |
986 | + edited in gedit for example. This may be a bug in QT itself. |
987 | + To work around this issue, remove the path and add it again. */ |
988 | + m_mimeappsWatcher->removePath(MIMEAPPS_FILE); |
989 | + m_mimeappsWatcher->addPath(MIMEAPPS_FILE); |
990 | +} |
991 | + |
992 | +QString GioDefaultApplication::desktopFile() const |
993 | +{ |
994 | + return m_desktopFile; |
995 | +} |
996 | + |
997 | +QString GioDefaultApplication::contentType() const |
998 | +{ |
999 | + return m_contentType; |
1000 | +} |
1001 | + |
1002 | +void GioDefaultApplication::setContentType(const QString& contentType) |
1003 | +{ |
1004 | + if (contentType == m_contentType) { |
1005 | + return; |
1006 | + } |
1007 | + |
1008 | + m_contentType = contentType; |
1009 | + Q_EMIT contentTypeChanged(); |
1010 | + updateDesktopFile(); |
1011 | +} |
1012 | + |
1013 | +void GioDefaultApplication::updateDesktopFile() |
1014 | +{ |
1015 | + GObjectScopedPointer<GAppInfo> app_info; |
1016 | + QByteArray byte_array = m_contentType.toUtf8(); |
1017 | + gchar *content_type = byte_array.data(); |
1018 | + |
1019 | + app_info.reset(g_app_info_get_default_for_type(content_type, false)); |
1020 | + if (!app_info.isNull()) { |
1021 | + m_desktopFile = QString::fromUtf8(g_desktop_app_info_get_filename((GDesktopAppInfo*)app_info.data())); |
1022 | + } else { |
1023 | + m_desktopFile = ""; |
1024 | + } |
1025 | + |
1026 | + Q_EMIT desktopFileChanged(); |
1027 | +} |
1028 | + |
1029 | +#include "giodefaultapplication.moc" |
1030 | |
1031 | === added file 'libunity-2d-private/src/giodefaultapplication.h' |
1032 | --- libunity-2d-private/src/giodefaultapplication.h 1970-01-01 00:00:00 +0000 |
1033 | +++ libunity-2d-private/src/giodefaultapplication.h 2011-07-27 15:02:42 +0000 |
1034 | @@ -0,0 +1,63 @@ |
1035 | +/* |
1036 | + * Copyright (C) 2011 Canonical, Ltd. |
1037 | + * |
1038 | + * Authors: |
1039 | + * Florian Boucault <florian.boucault@canonical.com> |
1040 | + * |
1041 | + * This program is free software; you can redistribute it and/or modify |
1042 | + * it under the terms of the GNU General Public License as published by |
1043 | + * the Free Software Foundation; version 3. |
1044 | + * |
1045 | + * This program is distributed in the hope that it will be useful, |
1046 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1047 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1048 | + * GNU General Public License for more details. |
1049 | + * |
1050 | + * You should have received a copy of the GNU General Public License |
1051 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1052 | + */ |
1053 | + |
1054 | +#ifndef GIODEFAULTAPPLICATION_H |
1055 | +#define GIODEFAULTAPPLICATION_H |
1056 | + |
1057 | +#include <QObject> |
1058 | +#include <QString> |
1059 | + |
1060 | +class QFileSystemWatcher; |
1061 | + |
1062 | +/* Wrapper around GIO's g_app_info_get_default_for_type. |
1063 | + To use it, set the contentType property and the desktopFile will contain the |
1064 | + path to the desktop file of the application handling that kind of content. |
1065 | +*/ |
1066 | +class GioDefaultApplication : public QObject |
1067 | +{ |
1068 | + Q_OBJECT |
1069 | + |
1070 | + Q_PROPERTY(QString desktopFile READ desktopFile NOTIFY desktopFileChanged) |
1071 | + Q_PROPERTY(QString contentType READ contentType WRITE setContentType NOTIFY contentTypeChanged) |
1072 | + |
1073 | +public: |
1074 | + GioDefaultApplication(QObject* parent=0); |
1075 | + |
1076 | + /* getters */ |
1077 | + QString desktopFile() const; |
1078 | + QString contentType() const; |
1079 | + |
1080 | + /* setters */ |
1081 | + void setContentType(const QString& contentType); |
1082 | + |
1083 | +Q_SIGNALS: |
1084 | + void desktopFileChanged(); |
1085 | + void contentTypeChanged(); |
1086 | + |
1087 | +private: |
1088 | + Q_SLOT void updateDesktopFile(); |
1089 | + Q_SLOT void onMimeappsFileChanged(); |
1090 | + |
1091 | + QString m_contentType; |
1092 | + QString m_desktopFile; |
1093 | + QFileSystemWatcher* m_mimeappsWatcher; |
1094 | +}; |
1095 | + |
1096 | +#endif // GIODEFAULTAPPLICATION |
1097 | + |
1098 | |
1099 | === modified file 'libunity-2d-private/src/unity2dapplication.cpp' |
1100 | --- libunity-2d-private/src/unity2dapplication.cpp 2011-06-11 10:50:03 +0000 |
1101 | +++ libunity-2d-private/src/unity2dapplication.cpp 2011-07-27 15:02:42 +0000 |
1102 | @@ -21,8 +21,17 @@ |
1103 | |
1104 | // Self |
1105 | #include "unity2dapplication.h" |
1106 | +#include "config.h" |
1107 | + |
1108 | +// libunity-2d |
1109 | +#include <debug_p.h> |
1110 | +#include <unity2ddebug.h> |
1111 | |
1112 | // Qt |
1113 | +#include <QWindowsStyle> |
1114 | + |
1115 | +// GTK |
1116 | +#include <gtk/gtk.h> |
1117 | |
1118 | AbstractX11EventFilter::~AbstractX11EventFilter() |
1119 | { |
1120 | @@ -32,9 +41,38 @@ |
1121 | } |
1122 | } |
1123 | |
1124 | +void Unity2dApplication::earlySetup(int& argc, char** argv) |
1125 | +{ |
1126 | + // Parts of unity-2d uses GTK so it needs to be initialized |
1127 | + gtk_init(&argc, &argv); |
1128 | + |
1129 | + Unity2dDebug::installHandlers(); |
1130 | + |
1131 | + /* When the environment variable QT_GRAPHICSSYSTEM is not set, force |
1132 | + * graphics system to 'raster' instead of the default 'native' which on X11 |
1133 | + * is 'XRender'. 'XRender' defaults to using a TrueColor visual. We do |
1134 | + * _not_ mimick that behaviour with 'raster' by calling |
1135 | + * QApplication::setColorSpec because of bugs where some pixmaps become |
1136 | + * blueish or black rectangular artifacts were appearing randomly: |
1137 | + * |
1138 | + * https://bugs.launchpad.net/unity-2d/+bug/689877 |
1139 | + * https://bugs.launchpad.net/unity-2d/+bug/734143 |
1140 | + */ |
1141 | + if(getenv("QT_GRAPHICSSYSTEM") == 0) { |
1142 | + QApplication::setGraphicsSystem("raster"); |
1143 | + } |
1144 | +} |
1145 | + |
1146 | Unity2dApplication::Unity2dApplication(int& argc, char** argv) |
1147 | : QApplication(argc, argv) |
1148 | { |
1149 | + /* Allow developers to run Unity 2D uninstalled by telling dconf-qt |
1150 | + where to look for Unity 2D's schemas. |
1151 | + It relies on the fact that the schema is compiled when running cmake. |
1152 | + */ |
1153 | + if (!isRunningInstalled()) { |
1154 | + qputenv("GSETTINGS_SCHEMA_DIR", unity2dDirectory().toLocal8Bit() + "/data"); |
1155 | + } |
1156 | } |
1157 | |
1158 | Unity2dApplication::~Unity2dApplication() |
1159 | |
1160 | === modified file 'libunity-2d-private/src/unity2dapplication.h' |
1161 | --- libunity-2d-private/src/unity2dapplication.h 2011-02-28 17:14:19 +0000 |
1162 | +++ libunity-2d-private/src/unity2dapplication.h 2011-07-27 15:02:42 +0000 |
1163 | @@ -49,6 +49,13 @@ |
1164 | void removeX11EventFilter(AbstractX11EventFilter*); |
1165 | |
1166 | /** |
1167 | + * This method must be called *before* instantiating a Unity2dApplication. |
1168 | + * It inits gtk and adjusts settings like the graphics system and the Qt |
1169 | + * style. |
1170 | + */ |
1171 | + static void earlySetup(int& argc, char** argv); |
1172 | + |
1173 | + /** |
1174 | * Note: This function will return a null pointer if you did not use a Unity2dApplication in your application! |
1175 | */ |
1176 | static Unity2dApplication* instance(); |
1177 | |
1178 | === modified file 'libunity-2d-private/tests/CMakeLists.txt' |
1179 | --- libunity-2d-private/tests/CMakeLists.txt 2011-07-12 10:30:50 +0000 |
1180 | +++ libunity-2d-private/tests/CMakeLists.txt 2011-07-27 15:02:42 +0000 |
1181 | @@ -40,6 +40,7 @@ |
1182 | unity2dtrtest |
1183 | launchermenutest |
1184 | listaggregatormodeltest |
1185 | + qsortfilterproxymodeltest |
1186 | ) |
1187 | |
1188 | add_custom_target(unity2dtr_po COMMAND |
1189 | |
1190 | === modified file 'libunity-2d-private/tests/keyboardmodifiersmonitortest.cpp' |
1191 | --- libunity-2d-private/tests/keyboardmodifiersmonitortest.cpp 2011-01-26 15:50:26 +0000 |
1192 | +++ libunity-2d-private/tests/keyboardmodifiersmonitortest.cpp 2011-07-27 15:02:42 +0000 |
1193 | @@ -39,6 +39,7 @@ |
1194 | #define UQ_TEST_MAIN(TestObject) \ |
1195 | int main(int argc, char *argv[]) \ |
1196 | { \ |
1197 | + Unity2dApplication::earlySetup(argc, argv); \ |
1198 | Unity2dApplication app(argc, argv); \ |
1199 | QTEST_DISABLE_KEYPAD_NAVIGATION \ |
1200 | TestObject tc; \ |
1201 | |
1202 | === modified file 'libunity-2d-private/tests/mouseareademo.cpp' |
1203 | --- libunity-2d-private/tests/mouseareademo.cpp 2011-02-15 18:18:13 +0000 |
1204 | +++ libunity-2d-private/tests/mouseareademo.cpp 2011-07-27 15:02:42 +0000 |
1205 | @@ -29,6 +29,7 @@ |
1206 | |
1207 | int main(int argc, char** argv) |
1208 | { |
1209 | + Unity2dApplication::earlySetup(argc, argv); |
1210 | Unity2dApplication app(argc, argv); |
1211 | QWidget window; |
1212 | QLabel* enteredLabel = new QLabel("Entered"); |
1213 | |
1214 | === added file 'libunity-2d-private/tests/qsortfilterproxymodeltest.cpp' |
1215 | --- libunity-2d-private/tests/qsortfilterproxymodeltest.cpp 1970-01-01 00:00:00 +0000 |
1216 | +++ libunity-2d-private/tests/qsortfilterproxymodeltest.cpp 2011-07-27 15:02:42 +0000 |
1217 | @@ -0,0 +1,384 @@ |
1218 | +/* |
1219 | + * Copyright (C) 2011 Canonical, Ltd. |
1220 | + * |
1221 | + * Authors: |
1222 | + * Florian Boucault <florian.boucault@canonical.com> |
1223 | + * |
1224 | + * This program is free software; you can redistribute it and/or modify |
1225 | + * it under the terms of the GNU General Public License as published by |
1226 | + * the Free Software Foundation; version 3. |
1227 | + * |
1228 | + * This program is distributed in the hope that it will be useful, |
1229 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1230 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1231 | + * GNU General Public License for more details. |
1232 | + * |
1233 | + * You should have received a copy of the GNU General Public License |
1234 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1235 | + */ |
1236 | + |
1237 | +// local |
1238 | +#include "qsortfilterproxymodelqml.h" |
1239 | + |
1240 | +// Qt |
1241 | +#include <QTest> |
1242 | +#include <QSignalSpy> |
1243 | +#include <QModelIndex> |
1244 | +#include <QAbstractListModel> |
1245 | +#include <QDebug> |
1246 | + |
1247 | + |
1248 | +class MockListModel : public QAbstractListModel |
1249 | +{ |
1250 | + Q_OBJECT |
1251 | + |
1252 | +public: |
1253 | + MockListModel(QObject* parent = 0) |
1254 | + : QAbstractListModel(parent) |
1255 | + { |
1256 | + } |
1257 | + |
1258 | + int rowCount(const QModelIndex& parent = QModelIndex()) const |
1259 | + { |
1260 | + return m_list.size(); |
1261 | + } |
1262 | + |
1263 | + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const |
1264 | + { |
1265 | + Q_UNUSED(role) |
1266 | + |
1267 | + if (!index.isValid() || index.row() < 0 || index.row() >= m_list.size()) { |
1268 | + return QVariant(); |
1269 | + } |
1270 | + return QVariant(m_list[index.row()]); |
1271 | + } |
1272 | + |
1273 | + void setRoleNames(const QHash<int,QByteArray> &roleNames) { |
1274 | + QAbstractListModel::setRoleNames(roleNames); |
1275 | + Q_EMIT roleNamesChanged(roleNames); |
1276 | + } |
1277 | + |
1278 | + bool insertRows(int row, int count, const QModelIndex &parent=QModelIndex()) { |
1279 | + beginInsertRows(parent, row, row+count-1); |
1280 | + for (int i=0; i<count; i++) { |
1281 | + m_list.insert(i+row, "test"+i); |
1282 | + } |
1283 | + endInsertRows(); |
1284 | + return true; |
1285 | + } |
1286 | + |
1287 | + bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex()) { |
1288 | + beginRemoveRows(parent, row, row+count-1); |
1289 | + for (int i=0; i<count; i++) { |
1290 | + m_list.removeAt(row); |
1291 | + } |
1292 | + endInsertRows(); |
1293 | + return true; |
1294 | + } |
1295 | + |
1296 | +Q_SIGNALS: |
1297 | + void roleNamesChanged(const QHash<int,QByteArray> &); |
1298 | + |
1299 | +private: |
1300 | + QStringList m_list; |
1301 | +}; |
1302 | + |
1303 | +class QSortFilterProxyModelTest : public QObject |
1304 | +{ |
1305 | + Q_OBJECT |
1306 | + |
1307 | +private Q_SLOTS: |
1308 | + |
1309 | + void initTestCase() { |
1310 | + qRegisterMetaType<QModelIndex>("QModelIndex"); |
1311 | + } |
1312 | + |
1313 | + void testRoleNamesSetAfter() |
1314 | + { |
1315 | + QSortFilterProxyModelQML proxy; |
1316 | + MockListModel model; |
1317 | + QHash<int, QByteArray> roles; |
1318 | + |
1319 | + proxy.setSourceModelQObject(&model); |
1320 | + |
1321 | + roles.clear(); |
1322 | + roles[0] = "role0"; |
1323 | + roles[1] = "role1"; |
1324 | + model.setRoleNames(roles); |
1325 | + QCOMPARE(model.roleNames(), proxy.roleNames()); |
1326 | + } |
1327 | + |
1328 | + void testRoleNamesSetBefore() |
1329 | + { |
1330 | + QSortFilterProxyModelQML proxy; |
1331 | + MockListModel model; |
1332 | + QHash<int, QByteArray> roles; |
1333 | + |
1334 | + roles.clear(); |
1335 | + roles[0] = "role0"; |
1336 | + roles[1] = "role1"; |
1337 | + model.setRoleNames(roles); |
1338 | + |
1339 | + proxy.setSourceModelQObject(&model); |
1340 | + QCOMPARE(model.roleNames(), proxy.roleNames()); |
1341 | + } |
1342 | + |
1343 | + void testCountSetAfter() |
1344 | + { |
1345 | + QSortFilterProxyModelQML proxy; |
1346 | + MockListModel model; |
1347 | + model.insertRows(0, 5); |
1348 | + |
1349 | + QSignalSpy spyOnCountChanged(&proxy, SIGNAL(countChanged())); |
1350 | + |
1351 | + proxy.setSourceModelQObject(&model); |
1352 | + QCOMPARE(proxy.count(), 5); |
1353 | + QVERIFY(spyOnCountChanged.count() >= 1); |
1354 | + } |
1355 | + |
1356 | + void testCountInsert() |
1357 | + { |
1358 | + QSortFilterProxyModelQML proxy; |
1359 | + MockListModel model; |
1360 | + |
1361 | + proxy.setSourceModelQObject(&model); |
1362 | + |
1363 | + QSignalSpy spyOnCountChanged(&proxy, SIGNAL(countChanged())); |
1364 | + |
1365 | + model.insertRows(0, 5); |
1366 | + QCOMPARE(proxy.count(), 5); |
1367 | + QCOMPARE(spyOnCountChanged.count(), 1); |
1368 | + } |
1369 | + |
1370 | + void testCountRemove() |
1371 | + { |
1372 | + QSortFilterProxyModelQML proxy; |
1373 | + MockListModel model; |
1374 | + model.insertRows(0, 5); |
1375 | + |
1376 | + proxy.setSourceModelQObject(&model); |
1377 | + |
1378 | + QSignalSpy spyOnCountChanged(&proxy, SIGNAL(countChanged())); |
1379 | + |
1380 | + model.removeRows(0, 3); |
1381 | + QCOMPARE(proxy.count(), 2); |
1382 | + QCOMPARE(spyOnCountChanged.count(), 1); |
1383 | + } |
1384 | + |
1385 | + void testLimitCount() |
1386 | + { |
1387 | + QSortFilterProxyModelQML proxy; |
1388 | + MockListModel model; |
1389 | + |
1390 | + proxy.setSourceModelQObject(&model); |
1391 | + proxy.setLimit(3); |
1392 | + |
1393 | + QSignalSpy spyOnCountChanged(&proxy, SIGNAL(countChanged())); |
1394 | + |
1395 | + model.insertRows(0, 5); |
1396 | + QCOMPARE(proxy.count(), 3); |
1397 | + QCOMPARE(spyOnCountChanged.count(), 1); |
1398 | + } |
1399 | + |
1400 | + void testLimitLesserThanCount() |
1401 | + { |
1402 | + QSortFilterProxyModelQML proxy; |
1403 | + MockListModel model; |
1404 | + QList<QVariant> arguments; |
1405 | + model.insertRows(0, 10); |
1406 | + |
1407 | + proxy.setSourceModelQObject(&model); |
1408 | + |
1409 | + QSignalSpy spyOnRowsRemoved(&proxy, SIGNAL(rowsRemoved(const QModelIndex &, int, int))); |
1410 | + QSignalSpy spyOnRowsInserted(&proxy, SIGNAL(rowsInserted(const QModelIndex &, int, int))); |
1411 | + QSignalSpy spyOnCountChanged(&proxy, SIGNAL(countChanged())); |
1412 | + |
1413 | + proxy.setLimit(5); |
1414 | + QCOMPARE(spyOnRowsRemoved.count(), 1); |
1415 | + QCOMPARE(spyOnRowsInserted.count(), 0); |
1416 | + QCOMPARE(spyOnCountChanged.count(), 1); |
1417 | + arguments = spyOnRowsRemoved.takeFirst(); |
1418 | + QCOMPARE(arguments.at(1).toInt(), 5); |
1419 | + QCOMPARE(arguments.at(2).toInt(), 9); |
1420 | + QCOMPARE(proxy.count(), 5); |
1421 | + spyOnRowsRemoved.clear(); |
1422 | + spyOnCountChanged.clear(); |
1423 | + |
1424 | + proxy.setLimit(7); |
1425 | + QCOMPARE(spyOnRowsInserted.count(), 1); |
1426 | + QCOMPARE(spyOnRowsRemoved.count(), 0); |
1427 | + QCOMPARE(spyOnCountChanged.count(), 1); |
1428 | + arguments = spyOnRowsInserted.takeFirst(); |
1429 | + QCOMPARE(arguments.at(1).toInt(), 5); |
1430 | + QCOMPARE(arguments.at(2).toInt(), 6); |
1431 | + QCOMPARE(proxy.count(), 7); |
1432 | + spyOnRowsInserted.clear(); |
1433 | + spyOnCountChanged.clear(); |
1434 | + |
1435 | + proxy.setLimit(3); |
1436 | + QCOMPARE(spyOnRowsRemoved.count(), 1); |
1437 | + QCOMPARE(spyOnRowsInserted.count(), 0); |
1438 | + QCOMPARE(spyOnCountChanged.count(), 1); |
1439 | + arguments = spyOnRowsRemoved.takeFirst(); |
1440 | + QCOMPARE(arguments.at(1).toInt(), 3); |
1441 | + QCOMPARE(arguments.at(2).toInt(), 6); |
1442 | + QCOMPARE(proxy.count(), 3); |
1443 | + spyOnRowsRemoved.clear(); |
1444 | + spyOnCountChanged.clear(); |
1445 | + } |
1446 | + |
1447 | + void testLimitGreaterThanCount() |
1448 | + { |
1449 | + QSortFilterProxyModelQML proxy; |
1450 | + MockListModel model; |
1451 | + QList<QVariant> arguments; |
1452 | + model.insertRows(0, 5); |
1453 | + |
1454 | + proxy.setSourceModelQObject(&model); |
1455 | + |
1456 | + QSignalSpy spyOnRowsRemoved(&proxy, SIGNAL(rowsRemoved(const QModelIndex &, int, int))); |
1457 | + QSignalSpy spyOnRowsInserted(&proxy, SIGNAL(rowsInserted(const QModelIndex &, int, int))); |
1458 | + QSignalSpy spyOnCountChanged(&proxy, SIGNAL(countChanged())); |
1459 | + |
1460 | + proxy.setLimit(7); |
1461 | + QCOMPARE(spyOnRowsRemoved.count(), 0); |
1462 | + QCOMPARE(spyOnRowsInserted.count(), 0); |
1463 | + QCOMPARE(spyOnCountChanged.count(), 0); |
1464 | + QCOMPARE(proxy.count(), 5); |
1465 | + |
1466 | + proxy.setLimit(5); |
1467 | + QCOMPARE(spyOnRowsRemoved.count(), 0); |
1468 | + QCOMPARE(spyOnRowsInserted.count(), 0); |
1469 | + QCOMPARE(spyOnCountChanged.count(), 0); |
1470 | + QCOMPARE(proxy.count(), 5); |
1471 | + |
1472 | + proxy.setLimit(3); |
1473 | + QCOMPARE(spyOnRowsInserted.count(), 0); |
1474 | + QCOMPARE(spyOnRowsRemoved.count(), 1); |
1475 | + QCOMPARE(spyOnCountChanged.count(), 1); |
1476 | + arguments = spyOnRowsRemoved.takeFirst(); |
1477 | + QCOMPARE(arguments.at(1).toInt(), 3); |
1478 | + QCOMPARE(arguments.at(2).toInt(), 4); |
1479 | + QCOMPARE(proxy.count(), 3); |
1480 | + spyOnRowsRemoved.clear(); |
1481 | + spyOnCountChanged.clear(); |
1482 | + |
1483 | + proxy.setLimit(4); |
1484 | + QCOMPARE(spyOnRowsRemoved.count(), 0); |
1485 | + QCOMPARE(spyOnRowsInserted.count(), 1); |
1486 | + QCOMPARE(spyOnCountChanged.count(), 1); |
1487 | + arguments = spyOnRowsInserted.takeFirst(); |
1488 | + QCOMPARE(arguments.at(1).toInt(), 3); |
1489 | + QCOMPARE(arguments.at(2).toInt(), 3); |
1490 | + QCOMPARE(proxy.count(), 4); |
1491 | + spyOnRowsInserted.clear(); |
1492 | + spyOnCountChanged.clear(); |
1493 | + |
1494 | + proxy.setLimit(7); |
1495 | + QCOMPARE(spyOnRowsRemoved.count(), 0); |
1496 | + QCOMPARE(spyOnRowsInserted.count(), 1); |
1497 | + QCOMPARE(spyOnCountChanged.count(), 1); |
1498 | + arguments = spyOnRowsInserted.takeFirst(); |
1499 | + QCOMPARE(arguments.at(1).toInt(), 4); |
1500 | + QCOMPARE(arguments.at(2).toInt(), 4); |
1501 | + QCOMPARE(proxy.count(), 5); |
1502 | + spyOnRowsInserted.clear(); |
1503 | + spyOnCountChanged.clear(); |
1504 | + } |
1505 | + |
1506 | + void testLimitMinusOne() |
1507 | + { |
1508 | + QSortFilterProxyModelQML proxy; |
1509 | + MockListModel model; |
1510 | + QList<QVariant> arguments; |
1511 | + model.insertRows(0, 5); |
1512 | + |
1513 | + proxy.setSourceModelQObject(&model); |
1514 | + |
1515 | + QSignalSpy spyOnRowsRemoved(&proxy, SIGNAL(rowsRemoved(const QModelIndex &, int, int))); |
1516 | + QSignalSpy spyOnRowsInserted(&proxy, SIGNAL(rowsInserted(const QModelIndex &, int, int))); |
1517 | + QSignalSpy spyOnCountChanged(&proxy, SIGNAL(countChanged())); |
1518 | + |
1519 | + proxy.setLimit(7); |
1520 | + QCOMPARE(spyOnRowsRemoved.count(), 0); |
1521 | + QCOMPARE(spyOnRowsInserted.count(), 0); |
1522 | + QCOMPARE(spyOnCountChanged.count(), 0); |
1523 | + QCOMPARE(proxy.count(), 5); |
1524 | + |
1525 | + proxy.setLimit(-1); |
1526 | + QCOMPARE(spyOnRowsRemoved.count(), 0); |
1527 | + QCOMPARE(spyOnRowsInserted.count(), 0); |
1528 | + QCOMPARE(spyOnCountChanged.count(), 0); |
1529 | + QCOMPARE(proxy.count(), 5); |
1530 | + |
1531 | + proxy.setLimit(3); |
1532 | + QCOMPARE(spyOnRowsInserted.count(), 0); |
1533 | + QCOMPARE(spyOnRowsRemoved.count(), 1); |
1534 | + QCOMPARE(spyOnCountChanged.count(), 1); |
1535 | + arguments = spyOnRowsRemoved.takeFirst(); |
1536 | + QCOMPARE(arguments.at(1).toInt(), 3); |
1537 | + QCOMPARE(arguments.at(2).toInt(), 4); |
1538 | + QCOMPARE(proxy.count(), 3); |
1539 | + spyOnRowsRemoved.clear(); |
1540 | + spyOnCountChanged.clear(); |
1541 | + |
1542 | + proxy.setLimit(-1); |
1543 | + QCOMPARE(spyOnRowsRemoved.count(), 0); |
1544 | + QCOMPARE(spyOnRowsInserted.count(), 1); |
1545 | + QCOMPARE(spyOnCountChanged.count(), 1); |
1546 | + arguments = spyOnRowsInserted.takeFirst(); |
1547 | + QCOMPARE(arguments.at(1).toInt(), 3); |
1548 | + QCOMPARE(arguments.at(2).toInt(), 4); |
1549 | + QCOMPARE(proxy.count(), 5); |
1550 | + spyOnRowsInserted.clear(); |
1551 | + spyOnCountChanged.clear(); |
1552 | + } |
1553 | + |
1554 | + void testLimitInsert() { |
1555 | + QSortFilterProxyModelQML proxy; |
1556 | + MockListModel model; |
1557 | + QList<QVariant> arguments; |
1558 | + |
1559 | + proxy.setSourceModelQObject(&model); |
1560 | + proxy.setLimit(7); |
1561 | + |
1562 | + QSignalSpy spyOnRowsRemoved(&proxy, SIGNAL(rowsRemoved(const QModelIndex &, int, int))); |
1563 | + QSignalSpy spyOnRowsInserted(&proxy, SIGNAL(rowsInserted(const QModelIndex &, int, int))); |
1564 | + QSignalSpy spyOnCountChanged(&proxy, SIGNAL(countChanged())); |
1565 | + |
1566 | + model.insertRows(0, 5); |
1567 | + QCOMPARE(spyOnRowsRemoved.count(), 0); |
1568 | + QCOMPARE(spyOnRowsInserted.count(), 1); |
1569 | + QCOMPARE(spyOnCountChanged.count(), 1); |
1570 | + arguments = spyOnRowsInserted.takeFirst(); |
1571 | + QCOMPARE(arguments.at(1).toInt(), 0); |
1572 | + QCOMPARE(arguments.at(2).toInt(), 4); |
1573 | + QCOMPARE(proxy.count(), 5); |
1574 | + spyOnRowsInserted.clear(); |
1575 | + spyOnCountChanged.clear(); |
1576 | + |
1577 | + model.insertRows(2, 2); |
1578 | + QCOMPARE(spyOnRowsRemoved.count(), 0); |
1579 | + QCOMPARE(spyOnRowsInserted.count(), 1); |
1580 | + QCOMPARE(spyOnCountChanged.count(), 1); |
1581 | + arguments = spyOnRowsInserted.takeFirst(); |
1582 | + QCOMPARE(arguments.at(1).toInt(), 2); |
1583 | + QCOMPARE(arguments.at(2).toInt(), 3); |
1584 | + QCOMPARE(proxy.count(), 7); |
1585 | + spyOnRowsInserted.clear(); |
1586 | + spyOnCountChanged.clear(); |
1587 | + |
1588 | + /* FIXME: failing case due to QSortFilterProxyModel emitting |
1589 | + rowsInserted/rowsRemoved regardless of the limit */ |
1590 | + //model.insertRows(5, 3); |
1591 | + //QCOMPARE(proxy.count(), 7); |
1592 | + //QCOMPARE(spyOnRowsRemoved.count(), 0); |
1593 | + //QCOMPARE(spyOnRowsInserted.count(), 0); |
1594 | + //QCOMPARE(spyOnCountChanged.count(), 0); |
1595 | + } |
1596 | +}; |
1597 | + |
1598 | +QTEST_MAIN(QSortFilterProxyModelTest) |
1599 | + |
1600 | +#include "qsortfilterproxymodeltest.moc" |
1601 | + |
1602 | |
1603 | === modified file 'panel/app/main.cpp' |
1604 | --- panel/app/main.cpp 2011-06-06 09:23:48 +0000 |
1605 | +++ panel/app/main.cpp 2011-07-27 15:02:42 +0000 |
1606 | @@ -52,21 +52,7 @@ |
1607 | int main(int argc, char** argv) |
1608 | { |
1609 | ThemeEngineHandler handler; |
1610 | - |
1611 | - Unity2dDebug::installHandlers(); |
1612 | - |
1613 | - /* When the environment variable QT_GRAPHICSSYSTEM is not set, |
1614 | - force graphics system to 'raster' instead of the default 'native' |
1615 | - which on X11 is 'XRender'. |
1616 | - 'XRender' defaults to using a TrueColor visual. We do _not_ mimick that |
1617 | - behaviour with 'raster' by calling QApplication::setColorSpec because |
1618 | - of a bug where black rectangular artifacts were appearing randomly: |
1619 | - |
1620 | - https://bugs.launchpad.net/unity-2d/+bug/734143 |
1621 | - */ |
1622 | - if(getenv("QT_GRAPHICSSYSTEM") == 0) { |
1623 | - QApplication::setGraphicsSystem("raster"); |
1624 | - } |
1625 | + Unity2dApplication::earlySetup(argc, argv); |
1626 | Unity2dApplication app(argc, argv); |
1627 | QApplication::setStyle(new Unity2dStyle); |
1628 | |
1629 | |
1630 | === modified file 'panel/applets/CMakeLists.txt' |
1631 | --- panel/applets/CMakeLists.txt 2011-06-22 08:22:14 +0000 |
1632 | +++ panel/applets/CMakeLists.txt 2011-07-27 15:02:42 +0000 |
1633 | @@ -14,11 +14,7 @@ |
1634 | |
1635 | pkg_check_modules(QTBAMF REQUIRED libqtbamf) |
1636 | pkg_check_modules(DBUSMENUQT REQUIRED dbusmenu-qt) |
1637 | -pkg_check_modules(GTK REQUIRED gtk+-2.0) |
1638 | pkg_check_modules(INDICATOR REQUIRED indicator) |
1639 | -pkg_check_modules(WNCK REQUIRED libwnck-1.0) |
1640 | - |
1641 | -find_package(X11 REQUIRED) |
1642 | |
1643 | # Get indicator dirs from pkgconfig |
1644 | read_pkg_variable(INDICATOR_DIR indicator indicatordir) |
1645 | |
1646 | === modified file 'panel/applets/indicator/indicator.c' |
1647 | --- panel/applets/indicator/indicator.c 2011-03-30 14:50:35 +0000 |
1648 | +++ panel/applets/indicator/indicator.c 2011-07-27 15:02:42 +0000 |
1649 | @@ -152,6 +152,20 @@ |
1650 | return; |
1651 | } |
1652 | |
1653 | +static gboolean |
1654 | +entry_scrolled (GtkWidget *menuitem, GdkEventScroll *event, gpointer data) |
1655 | +{ |
1656 | + IndicatorObject *io = g_object_get_data (G_OBJECT (menuitem), MENU_DATA_INDICATOR_OBJECT); |
1657 | + IndicatorObjectEntry *entry = g_object_get_data (G_OBJECT (menuitem), MENU_DATA_INDICATOR_ENTRY); |
1658 | + |
1659 | + g_return_val_if_fail(INDICATOR_IS_OBJECT(io), FALSE); |
1660 | + |
1661 | + g_signal_emit_by_name (io, "scroll", 1, event->direction); |
1662 | + g_signal_emit_by_name (io, "scroll-entry", entry, 1, event->direction); |
1663 | + |
1664 | + return FALSE; |
1665 | +} |
1666 | + |
1667 | static void |
1668 | entry_added (IndicatorObject * io, IndicatorObjectEntry * entry, GtkWidget * menubar) |
1669 | { |
1670 | @@ -233,6 +247,7 @@ |
1671 | |
1672 | g_object_set_data(G_OBJECT(menuitem), MENU_DATA_INDICATOR_ENTRY, entry); |
1673 | g_object_set_data(G_OBJECT(menuitem), MENU_DATA_INDICATOR_OBJECT, io); |
1674 | + g_signal_connect(G_OBJECT (menuitem), "scroll-event", G_CALLBACK(entry_scrolled), NULL); |
1675 | |
1676 | return; |
1677 | } |
1678 | |
1679 | === modified file 'places/Home.qml' |
1680 | --- places/Home.qml 2011-06-23 17:08:53 +0000 |
1681 | +++ places/Home.qml 2011-07-27 15:02:42 +0000 |
1682 | @@ -19,7 +19,7 @@ |
1683 | import QtQuick 1.0 |
1684 | import Unity2d 1.0 /* Necessary for SortFilterProxyModel and for the ImageProvider serving image://icons/theme_name/icon_name */ |
1685 | |
1686 | -Item { |
1687 | +FocusScope { |
1688 | property variant model: PageModel { |
1689 | /* model.entrySearchQuery is copied over to all place entries's globalSearchQuery property */ |
1690 | onEntrySearchQueryChanged: { |
1691 | @@ -36,7 +36,7 @@ |
1692 | var placeEntry, i |
1693 | for (i=0; i<dash.places.rowCount(); i=i+1) { |
1694 | placeEntry = dash.places.get(i) |
1695 | - if (placeEntry.globalResultsModel != null && placeEntry.globalResultsModel.count() != 0) { |
1696 | + if (placeEntry.globalResultsModel != null && placeEntry.globalResultsModel.count != 0) { |
1697 | var firstResult = placeEntry.globalResultsModel.get(0) |
1698 | /* Places give back the uri of the item in 'column_0' per specification */ |
1699 | var uri = firstResult.column_0 |
1700 | @@ -96,50 +96,39 @@ |
1701 | ListViewWithScrollbar { |
1702 | id: globalSearch |
1703 | |
1704 | + focus: globalSearchActive |
1705 | opacity: globalSearchActive ? 1 : 0 |
1706 | anchors.fill: parent |
1707 | |
1708 | - list.model: dash.places |
1709 | - |
1710 | - list.delegate: UnityDefaultRenderer { |
1711 | - width: ListView.view.width |
1712 | - |
1713 | - parentListView: list |
1714 | - placeEntryModel: item |
1715 | - displayName: item.name |
1716 | - iconHint: item.icon |
1717 | - |
1718 | - /* Filter out results for which the corresponding group's renderer |
1719 | - is 'UnityEmptySearchRenderer'. |
1720 | - Each result has a column (the second one) containing the id of |
1721 | - the group it belongs to (groupId). |
1722 | - */ |
1723 | - model: SortFilterProxyModel { |
1724 | - model: item.globalResultsModel |
1725 | - |
1726 | - /* FIXME: we ignore the groupId with renderer 'UnityEmptySearchRenderer' |
1727 | - by hardcoding it instead of looking it up in the Place's |
1728 | - groupsModel as Unity does. |
1729 | - |
1730 | - Two solutions could be envisioned: |
1731 | - 1) Actually looking for the row in the Place's groupsModel |
1732 | - that has in its first column 'UnityEmptySearchRenderer'. |
1733 | - That would require adding an API in libqtdee's DeeListModel. |
1734 | - 2) Changing the behaviour of the place daemons so that the |
1735 | - Place's globalResultsModel is empty when there are no |
1736 | - results. The applications place does that but not the |
1737 | - files place. |
1738 | - */ |
1739 | - property int ignoredGroupId: 5 |
1740 | - filterRole: 2 /* groupId column */ |
1741 | - filterRegExp: RegExp("^[^%1]$".arg(ignoredGroupId)) /* anything but the ignoredGroupId */ |
1742 | - } |
1743 | + model: dash.places |
1744 | + |
1745 | + bodyDelegate: UnityDefaultRenderer { |
1746 | + placeEntryModel: model.item |
1747 | + displayName: model.item.name |
1748 | + iconHint: model.item.icon |
1749 | + |
1750 | + group_model: model.item.globalResultsModel |
1751 | + property bool focusable: group_model != undefined && group_model.count > 0 |
1752 | + } |
1753 | + |
1754 | + headerDelegate: GroupHeader { |
1755 | + visible: body.needHeader && body.focusable |
1756 | + height: visible ? 32 : 0 |
1757 | + |
1758 | + property bool foldable: body.folded != undefined |
1759 | + availableCount: foldable && body.group_model != null ? body.group_model.count - body.cellsPerRow : 0 |
1760 | + folded: foldable ? body.folded : false |
1761 | + onClicked: if(foldable) body.folded = !body.folded |
1762 | + |
1763 | + icon: body.iconHint |
1764 | + label: body.displayName |
1765 | } |
1766 | } |
1767 | |
1768 | - Rectangle { |
1769 | + FocusScope { |
1770 | id: shortcuts |
1771 | |
1772 | + focus: !globalSearchActive |
1773 | opacity: (!globalSearchActive && (shortcutsActive || dashView.dashMode == DashDeclarativeView.FullScreenMode)) ? 1 : 0 |
1774 | anchors.horizontalCenter: parent.horizontalCenter |
1775 | anchors.verticalCenter: parent.verticalCenter |
1776 | @@ -147,11 +136,14 @@ |
1777 | width: 888 |
1778 | height: 466 |
1779 | |
1780 | - radius: 5 |
1781 | - border.width: 1 |
1782 | - /* FIXME: wrong colors */ |
1783 | - border.color: Qt.rgba(1, 1, 1, 0.2) |
1784 | - color: Qt.rgba(0, 0, 0, 0.3) |
1785 | + Rectangle { |
1786 | + anchors.fill: parent |
1787 | + radius: 5 |
1788 | + border.width: 1 |
1789 | + /* FIXME: wrong colors */ |
1790 | + border.color: Qt.rgba(1, 1, 1, 0.2) |
1791 | + color: Qt.rgba(0, 0, 0, 0.3) |
1792 | + } |
1793 | |
1794 | Button { |
1795 | id: closeShortcutsButton |
1796 | @@ -182,11 +174,13 @@ |
1797 | on the default version if a custom one doesn’t exist. */ |
1798 | Loader { |
1799 | id: customShortcutsLoader |
1800 | + focus: status == Loader.Ready |
1801 | anchors.fill: parent |
1802 | source: "HomeShortcutsCustomized.qml" |
1803 | } |
1804 | Loader { |
1805 | id: defaultShortcutsLoader |
1806 | + focus: !customShortcutsLoader.focus |
1807 | anchors.fill: parent |
1808 | source: (customShortcutsLoader.status == Loader.Error) ? "HomeShortcuts.qml" : "" |
1809 | } |
1810 | |
1811 | === added file 'places/HomeButtonDefaultApplication.qml' |
1812 | --- places/HomeButtonDefaultApplication.qml 1970-01-01 00:00:00 +0000 |
1813 | +++ places/HomeButtonDefaultApplication.qml 2011-07-27 15:02:42 +0000 |
1814 | @@ -0,0 +1,48 @@ |
1815 | +/* |
1816 | + * This file is part of unity-2d |
1817 | + * |
1818 | + * Copyright 2011 Canonical Ltd. |
1819 | + * |
1820 | + * This program is free software; you can redistribute it and/or modify |
1821 | + * it under the terms of the GNU General Public License as published by |
1822 | + * the Free Software Foundation; version 3. |
1823 | + * |
1824 | + * This program is distributed in the hope that it will be useful, |
1825 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1826 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1827 | + * GNU General Public License for more details. |
1828 | + * |
1829 | + * You should have received a copy of the GNU General Public License |
1830 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1831 | + */ |
1832 | + |
1833 | +import QtQuick 1.0 |
1834 | +/* Necessary for: |
1835 | + - ImageProvider serving image://icons/theme_name/icon_name |
1836 | + - LauncherApplication |
1837 | +*/ |
1838 | +import Unity2d 1.0 |
1839 | + |
1840 | +HomeButton { |
1841 | + property alias contentType: defaultApplication.contentType |
1842 | + |
1843 | + GioDefaultApplication { |
1844 | + id: defaultApplication |
1845 | + } |
1846 | + |
1847 | + LauncherApplication { |
1848 | + id: application |
1849 | + desktop_file: defaultApplication.desktopFile |
1850 | + } |
1851 | + |
1852 | + visible: application.desktop_file != "" |
1853 | + |
1854 | + onClicked: { |
1855 | + dashView.active = false |
1856 | + application.activate() |
1857 | + } |
1858 | + |
1859 | + icon: "image://icons/" + application.icon |
1860 | + iconSourceSize.width: 128 |
1861 | + iconSourceSize.height: 128 |
1862 | +} |
1863 | |
1864 | === modified file 'places/HomeShortcuts.qml' |
1865 | --- places/HomeShortcuts.qml 2011-06-23 17:08:53 +0000 |
1866 | +++ places/HomeShortcuts.qml 2011-07-27 15:02:42 +0000 |
1867 | @@ -19,16 +19,41 @@ |
1868 | import QtQuick 1.0 |
1869 | import Unity2d 1.0 /* Necessary for the ImageProvider serving image://icons/theme_name/icon_name */ |
1870 | |
1871 | -Flow { |
1872 | +Grid { |
1873 | anchors.fill: parent |
1874 | anchors.topMargin: 26 |
1875 | anchors.bottomMargin: 35 |
1876 | anchors.leftMargin: 32 |
1877 | anchors.rightMargin: 32 |
1878 | spacing: 61 |
1879 | + columns: 4 |
1880 | + rows: 2 |
1881 | + |
1882 | + function selectChild(index) { |
1883 | + if (index < 0 || index >= children.length) return false |
1884 | + currentIndex = index |
1885 | + children[index].focus = true |
1886 | + return true |
1887 | + } |
1888 | + |
1889 | + property int currentIndex: 0 |
1890 | + Keys.onPressed: if (handleKeyPress(event.key)) event.accepted = true |
1891 | + function handleKeyPress(key) { |
1892 | + switch (key) { |
1893 | + case Qt.Key_Right: |
1894 | + return selectChild(currentIndex+1) |
1895 | + case Qt.Key_Left: |
1896 | + return selectChild(currentIndex-1) |
1897 | + case Qt.Key_Up: |
1898 | + return selectChild(currentIndex-columns) |
1899 | + case Qt.Key_Down: |
1900 | + return selectChild(currentIndex+columns) |
1901 | + } |
1902 | + } |
1903 | |
1904 | /* FIXME: dummy icons need to be replaced by design's */ |
1905 | HomeButton { |
1906 | + focus: true |
1907 | label: u2d.tr("Media Apps") |
1908 | icon: "artwork/find_media_apps.png" |
1909 | onClicked: activatePlaceEntry("/usr/share/unity/places/applications.place", "Files", 9) |
1910 | @@ -53,9 +78,9 @@ |
1911 | } |
1912 | |
1913 | /* FIXME: use user's preferred applications instead of hardcoding them */ |
1914 | - HomeButtonApplication { |
1915 | + HomeButtonDefaultApplication { |
1916 | label: u2d.tr("Browse the Web") |
1917 | - key: "/desktop/gnome/applications/browser/exec" |
1918 | + contentType: "x-scheme-handler/http" |
1919 | } |
1920 | |
1921 | HomeButtonApplication { |
1922 | @@ -63,9 +88,9 @@ |
1923 | desktopFile: "shotwell.desktop" |
1924 | } |
1925 | |
1926 | - HomeButtonApplication { |
1927 | + HomeButtonDefaultApplication { |
1928 | label: u2d.tr("Check Email") |
1929 | - key: "/desktop/gnome/url-handlers/mailto/command" |
1930 | + contentType: "x-scheme-handler/mailto" |
1931 | } |
1932 | |
1933 | HomeButtonApplication { |
1934 | |
1935 | === added file 'places/ListViewWithHeaders.qml' |
1936 | --- places/ListViewWithHeaders.qml 1970-01-01 00:00:00 +0000 |
1937 | +++ places/ListViewWithHeaders.qml 2011-07-27 15:02:42 +0000 |
1938 | @@ -0,0 +1,277 @@ |
1939 | +/* |
1940 | + * This file is part of unity-2d |
1941 | + * |
1942 | + * Copyright 2010-2011 Canonical Ltd. |
1943 | + * |
1944 | + * This program is free software; you can redistribute it and/or modify |
1945 | + * it under the terms of the GNU General Public License as published by |
1946 | + * the Free Software Foundation; version 3. |
1947 | + * |
1948 | + * This program is distributed in the hope that it will be useful, |
1949 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1950 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1951 | + * GNU General Public License for more details. |
1952 | + * |
1953 | + * You should have received a copy of the GNU General Public License |
1954 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1955 | + */ |
1956 | + |
1957 | +import QtQuick 1.0 |
1958 | + |
1959 | +/* |
1960 | + List item that behaves similarly to a ListView but supports adding headers |
1961 | + before every delegate. |
1962 | + It works around the lack of flexibility in section headers positioning of |
1963 | + ListView (cf. http://bugreports.qt.nokia.com/browse/QTBUG-12880). It also |
1964 | + supports delegates that are flickable by flicking their content properly |
1965 | + depending on where you are in the list. |
1966 | + |
1967 | + To use it the following properties need to be set: |
1968 | + - bodyDelegate: Component used as a template for each item of the model; it |
1969 | + must have the following properties: |
1970 | + - 'contentY': same definition as a Flickable's |
1971 | + - 'totalHeight': the total height of the content of the body |
1972 | + - 'currentItem': a reference to the item of the body (e.g. a delegate of |
1973 | + a ListView) currently focused by the body |
1974 | + - headerDelegate: Component used as a template for the header preceding each body |
1975 | + |
1976 | + Two behaviours are available for the headers positioning: |
1977 | + - normal: the headers are always positioned just before the body |
1978 | + - accordion: the headers are stacked at the top and bottom of the list |
1979 | + |
1980 | + Currently, it only works in a vertical layout. |
1981 | +*/ |
1982 | +FocusScope { |
1983 | + id: list |
1984 | + |
1985 | + property alias flickable: mouse |
1986 | + property alias model: repeater.model |
1987 | + property bool accordion: false |
1988 | + /* bodyDelegate must be an item that has the following properties: |
1989 | + - 'contentY' |
1990 | + - 'totalHeight' |
1991 | + - 'currentItem' |
1992 | + */ |
1993 | + property Component bodyDelegate |
1994 | + property Component headerDelegate |
1995 | + property int currentIndex: -1 |
1996 | + /* FIXME: Should be read-only but it is not possible to define a read-only property from QML. |
1997 | + Ref.: https://bugreports.qt.nokia.com//browse/QTBUG-15257 |
1998 | + */ |
1999 | + property variant currentItem: items.childFromIndex(currentIndex) |
2000 | + |
2001 | + |
2002 | + clip: true |
2003 | + |
2004 | + /* updateMouseContentY() needs to be called when any of the variable |
2005 | + involved in the computation of the 'y' property of the currentSubItem changes. |
2006 | + |
2007 | + if accordion is false: |
2008 | + - heightFirstChildren(index) |
2009 | + - headerLoader.height |
2010 | + - list.height |
2011 | + |
2012 | + if accordion is true: |
2013 | + - heightFirstChildren(index) |
2014 | + - items.availableHeight |
2015 | + - heightFirstHeaders(index) |
2016 | + |
2017 | + items.contentHeight seems to depend on all of those so it's enough to |
2018 | + depend only on it. |
2019 | + */ |
2020 | + function updateMouseContentY() { |
2021 | + if (currentSubItem != undefined) { |
2022 | + mouse.contentY = Math.max(currentSubItem.mapToItem(mouse.contentItem, 0, 0).y -list.height/2, 0) |
2023 | + } |
2024 | + } |
2025 | + property variant currentSubItem: currentItem != undefined ? currentItem.bodyLoader.item.currentItem : undefined |
2026 | + onCurrentSubItemChanged: updateMouseContentY() |
2027 | + |
2028 | + Connections { |
2029 | + target: items |
2030 | + onContentHeightChanged: updateMouseContentY() |
2031 | + } |
2032 | + |
2033 | + FocusScope { |
2034 | + id: items |
2035 | + |
2036 | + property int availableHeight: list.height - heightFirstHeaders(repeater.count) |
2037 | + property int contentHeight: items.heightFirstChildren(repeater.count) |
2038 | + property real value: mouse.contentY |
2039 | + |
2040 | + anchors.fill: parent |
2041 | + |
2042 | + function heightFirstChildren(n) { |
2043 | + var i |
2044 | + var totalHeight = 0 |
2045 | + /* items.children contains both the repeated items and the repeater |
2046 | + itself. Skip and ignore the repeater. */ |
2047 | + for (i=0; i<n && i<children.length; i++) { |
2048 | + if(children[i] == repeater) {n += 1; continue} |
2049 | + totalHeight += children[i].height |
2050 | + } |
2051 | + return totalHeight |
2052 | + } |
2053 | + |
2054 | + function heightFirstHeaders(n) { |
2055 | + var i |
2056 | + var totalHeight = 0 |
2057 | + /* items.children contains both the repeated items and the repeater |
2058 | + itself. Skip and ignore the repeater. */ |
2059 | + for (i=0; i<n && i<children.length; i++) { |
2060 | + if(children[i] == repeater) {n += 1; continue} |
2061 | + totalHeight += children[i].headerLoader.height |
2062 | + } |
2063 | + return totalHeight |
2064 | + } |
2065 | + |
2066 | + function clamp(x, min, max) { |
2067 | + return Math.max(Math.min(x, max), min) |
2068 | + } |
2069 | + |
2070 | + |
2071 | + /* Keyboard navigation */ |
2072 | + function isIndexValid(index) { |
2073 | + /* Assuming that children contains exactly one item that is not a child (repeater) */ |
2074 | + return index >= 0 && index < children.length-1 |
2075 | + } |
2076 | + |
2077 | + focus: true |
2078 | + Keys.onPressed: if (handleKeyPress(event.key)) event.accepted = true |
2079 | + function handleKeyPress(key) { |
2080 | + switch (key) { |
2081 | + case Qt.Key_Down: |
2082 | + return selectNextEnabled() |
2083 | + case Qt.Key_Up: |
2084 | + return selectPreviousEnabled() |
2085 | + } |
2086 | + } |
2087 | + |
2088 | + function childFromIndex(index) { |
2089 | + var indexInChildren = 0 |
2090 | + for(var i=0; i<children.length; i++) { |
2091 | + if (children[i] != repeater) { |
2092 | + if (indexInChildren == index) return children[i] |
2093 | + indexInChildren++ |
2094 | + } |
2095 | + } |
2096 | + |
2097 | + return undefined |
2098 | + } |
2099 | + |
2100 | + function selectNextEnabled() { |
2101 | + var index = currentIndex |
2102 | + do { |
2103 | + index += 1 |
2104 | + if (!isIndexValid(index)) return false |
2105 | + } while(!childFromIndex(index).focusable) |
2106 | + currentIndex = index |
2107 | + return true |
2108 | + } |
2109 | + |
2110 | + function selectPreviousEnabled() { |
2111 | + var index = currentIndex |
2112 | + do { |
2113 | + index -= 1 |
2114 | + if (!isIndexValid(index)) return false |
2115 | + } while(!childFromIndex(index).focusable) |
2116 | + currentIndex = index |
2117 | + return true |
2118 | + } |
2119 | + |
2120 | + property bool needsFocus: false |
2121 | + onChildrenChanged: { |
2122 | + /* FIXME: this workarounds the fact that list.focus is set to false |
2123 | + when the child with focus is destroyed |
2124 | + */ |
2125 | + if (needsFocus) { |
2126 | + list.focus = true |
2127 | + needsFocus = false |
2128 | + } |
2129 | + /* Assuming that children contains exactly one item that is not a child (repeater) */ |
2130 | + if(children.length <= 1) { |
2131 | + list.currentIndex = -1 |
2132 | + } else { |
2133 | + list.currentIndex = -1 |
2134 | + selectNextEnabled() |
2135 | + } |
2136 | + } |
2137 | + |
2138 | + Repeater { |
2139 | + id: repeater |
2140 | + |
2141 | + FocusScope { |
2142 | + property alias bodyLoader: bodyLoader |
2143 | + property alias headerLoader: headerLoader |
2144 | + |
2145 | + focus: index == list.currentIndex |
2146 | + Component.onDestruction: items.needsFocus = true |
2147 | + |
2148 | + width: list.width |
2149 | + height: headerLoader.height + bodyLoader.item.totalHeight |
2150 | + property bool focusable: bodyLoader.item.focusable |
2151 | + |
2152 | + property int pmin: pmax - (ymax - ymin) |
2153 | + property int pmax: items.heightFirstChildren(index) - ymin |
2154 | + property int ymin: list.accordion ? items.heightFirstHeaders(index) : -headerLoader.height |
2155 | + property int ymax: list.accordion ? ymin + items.availableHeight : list.height |
2156 | + y: items.clamp(-items.value + ymax + pmin, ymin, ymax) |
2157 | + |
2158 | + Loader { |
2159 | + id: headerLoader |
2160 | + |
2161 | + focus: visible |
2162 | + KeyNavigation.down: bodyLoader |
2163 | + sourceComponent: headerDelegate |
2164 | + onLoaded: item.focus = true |
2165 | + width: parent.width |
2166 | + |
2167 | + /* Workaround Qt bug http://bugreports.qt.nokia.com/browse/QTBUG-18857 |
2168 | + More documentation at http://bugreports.qt.nokia.com/browse/QTBUG-18011 |
2169 | + */ |
2170 | + property int index |
2171 | + Binding { target: headerLoader; property: "index"; value: index } |
2172 | + property variant model |
2173 | + Binding { target: headerLoader; property: "model"; value: model } |
2174 | + property variant body |
2175 | + Binding { target: headerLoader; property: "body"; value: bodyLoader.item } |
2176 | + } |
2177 | + |
2178 | + Loader { |
2179 | + id: bodyLoader |
2180 | + |
2181 | + focus: !headerLoader.focus |
2182 | + KeyNavigation.up: headerLoader |
2183 | + sourceComponent: list.bodyDelegate |
2184 | + onLoaded: item.focus = true |
2185 | + width: parent.width |
2186 | + anchors.top: headerLoader.bottom |
2187 | + height: items.clamp(parent.ymax - parent.y, 0, item.totalHeight) |
2188 | + |
2189 | + Binding { |
2190 | + target: bodyLoader.item |
2191 | + property: "contentY" |
2192 | + value: Math.max(items.value - pmax, 0) |
2193 | + } |
2194 | + |
2195 | + /* Workaround Qt bug http://bugreports.qt.nokia.com/browse/QTBUG-18857 |
2196 | + More documentation at http://bugreports.qt.nokia.com/browse/QTBUG-18011 |
2197 | + */ |
2198 | + property int index |
2199 | + Binding { target: bodyLoader; property: "index"; value: index } |
2200 | + property variant model |
2201 | + Binding { target: bodyLoader; property: "model"; value: model } |
2202 | + } |
2203 | + } |
2204 | + } |
2205 | + } |
2206 | + |
2207 | + Flickable { |
2208 | + id: mouse |
2209 | + |
2210 | + z: -1 |
2211 | + anchors.fill: parent |
2212 | + contentWidth: parent.width |
2213 | + contentHeight: items.contentHeight |
2214 | + } |
2215 | +} |
2216 | |
2217 | === modified file 'places/ListViewWithScrollbar.qml' |
2218 | --- places/ListViewWithScrollbar.qml 2011-06-23 17:08:53 +0000 |
2219 | +++ places/ListViewWithScrollbar.qml 2011-07-27 15:02:42 +0000 |
2220 | @@ -18,44 +18,21 @@ |
2221 | |
2222 | import QtQuick 1.0 |
2223 | |
2224 | -Item { |
2225 | - property alias list: list |
2226 | +FocusScope { |
2227 | property alias scrollbar: scrollbar |
2228 | + property alias model: list.model |
2229 | + property alias bodyDelegate: list.bodyDelegate |
2230 | + property alias headerDelegate: list.headerDelegate |
2231 | |
2232 | - ListView { |
2233 | + ListViewWithHeaders { |
2234 | id: list |
2235 | |
2236 | + focus: true |
2237 | anchors.top: parent.top |
2238 | anchors.bottom: parent.bottom |
2239 | anchors.left: parent.left |
2240 | anchors.right: scrollbar.left |
2241 | anchors.rightMargin: 15 |
2242 | - |
2243 | - clip: true |
2244 | - /* FIXME: proper spacing cannot be set because of the hack in Group.qml |
2245 | - whereby empty groups are still in the list but invisible and of |
2246 | - height 0. |
2247 | - */ |
2248 | - //spacing: 31 |
2249 | - |
2250 | - orientation: ListView.Vertical |
2251 | - |
2252 | - /* WARNING - HACK - FIXME |
2253 | - Issue: |
2254 | - User wise annoying jumps in the list are observable if cacheBuffer is |
2255 | - set to 0 (which is the default value). States such as 'folded' are |
2256 | - lost when scrolling a lot. |
2257 | - |
2258 | - Explanation: |
2259 | - The height of the Group delegate depends on its content. However its |
2260 | - content is not known until the delegate is instantiated because it |
2261 | - depends on the number of results displayed by its GridView. |
2262 | - |
2263 | - Resolution: |
2264 | - We set the cacheBuffer to the biggest possible int in order to make |
2265 | - sure all delegates are always instantiated. |
2266 | - */ |
2267 | - cacheBuffer: 2147483647 |
2268 | } |
2269 | |
2270 | Scrollbar { |
2271 | @@ -67,7 +44,7 @@ |
2272 | anchors.bottomMargin: 10 |
2273 | anchors.right: parent.right |
2274 | |
2275 | - targetFlickable: list |
2276 | + targetFlickable: list.flickable |
2277 | |
2278 | /* Hide the scrollbar if there is less than a page of results */ |
2279 | opacity: targetFlickable.visibleArea.heightRatio < 1.0 ? 1.0 : 0.0 |
2280 | |
2281 | === modified file 'places/PlaceEntryView.qml' |
2282 | --- places/PlaceEntryView.qml 2011-06-23 17:08:53 +0000 |
2283 | +++ places/PlaceEntryView.qml 2011-07-27 15:02:42 +0000 |
2284 | @@ -19,7 +19,7 @@ |
2285 | import QtQuick 1.0 |
2286 | import Unity2d 1.0 /* Necessary for SortFilterProxyModel */ |
2287 | |
2288 | -Item { |
2289 | +FocusScope { |
2290 | id: placeEntryView |
2291 | |
2292 | /* An instance of PlaceEntryModel */ |
2293 | @@ -31,9 +31,9 @@ |
2294 | ('firstGroupModel') is used to filter the search results per group. |
2295 | */ |
2296 | var placeEntry, i |
2297 | - for (i=0; i<placeEntryView.model.entryGroupsModel.count(); i=i+1) { |
2298 | + for (i=0; i<placeEntryView.model.entryGroupsModel.count; i=i+1) { |
2299 | firstGroupModel.groupId = i |
2300 | - if (firstGroupModel.count() != 0) { |
2301 | + if (firstGroupModel.count != 0) { |
2302 | var firstResult = firstGroupModel.get(0) |
2303 | /* Places give back the uri of the item in 'column_0' per specification */ |
2304 | var uri = firstResult.column_0 |
2305 | @@ -62,6 +62,7 @@ |
2306 | ListViewWithScrollbar { |
2307 | id: results |
2308 | |
2309 | + focus: true |
2310 | anchors.fill: parent |
2311 | |
2312 | /* The group's delegate is chosen dynamically depending on what |
2313 | @@ -74,10 +75,10 @@ |
2314 | If groupRenderer == 'UnityShowcaseRenderer' then it will look for |
2315 | the file 'UnityShowcaseRenderer.qml' and use it to render the group. |
2316 | */ |
2317 | - list.delegate: Loader { |
2318 | - property string groupRenderer: column_0 |
2319 | - property string displayName: column_1 |
2320 | - property string iconHint: column_2 |
2321 | + bodyDelegate: Loader { |
2322 | + property string groupRenderer: model.column_0 |
2323 | + property string displayName: model.column_1 |
2324 | + property string iconHint: model.column_2 |
2325 | property int groupId: index |
2326 | |
2327 | source: groupRenderer ? groupRenderer+".qml" : "" |
2328 | @@ -86,12 +87,8 @@ |
2329 | console.log("Failed to load renderer", groupRenderer) |
2330 | } |
2331 | |
2332 | - width: ListView.view.width |
2333 | - |
2334 | /* Model that will be used by the group's delegate */ |
2335 | - SortFilterProxyModel { |
2336 | - id: group_model |
2337 | - |
2338 | + property variant group_model: SortFilterProxyModel { |
2339 | model: placeEntryView.model.entryResultsModel |
2340 | |
2341 | /* resultsModel contains data for all the groups of a given Place. |
2342 | @@ -102,16 +99,37 @@ |
2343 | filterRegExp: RegExp("^%1$".arg(groupId)) /* exact match */ |
2344 | } |
2345 | |
2346 | - onLoaded: { |
2347 | - item.parentListView = results.list |
2348 | - item.displayName = displayName |
2349 | - item.iconHint = iconHint |
2350 | - item.groupId = groupId |
2351 | - item.model = group_model |
2352 | - item.placeEntryModel = placeEntryView.model |
2353 | - } |
2354 | - } |
2355 | - |
2356 | - list.model: placeEntryView.model != undefined ? placeEntryView.model.entryGroupsModel : undefined |
2357 | + /* Required by ListViewWithHeaders when the loaded Renderer is a Flickable. |
2358 | + In that case the list view scrolls the Flickable appropriately. |
2359 | + */ |
2360 | + property int totalHeight: item.totalHeight != undefined ? item.totalHeight : 0 |
2361 | + property int contentY |
2362 | + Binding { target: item; property: "contentY"; value: contentY } |
2363 | + property bool focusable: group_model.count > 0 |
2364 | + property variant currentItem: item.currentItem |
2365 | + |
2366 | + Binding { target: item; property: "displayName"; value: displayName } |
2367 | + Binding { target: item; property: "iconHint"; value: iconHint } |
2368 | + Binding { target: item; property: "groupId"; value: groupId } |
2369 | + Binding { target: item; property: "group_model"; value: group_model } |
2370 | + Binding { target: item; property: "placeEntryModel"; value: placeEntryView.model } |
2371 | + |
2372 | + onLoaded: item.focus = true |
2373 | + } |
2374 | + |
2375 | + headerDelegate: GroupHeader { |
2376 | + visible: body.item.needHeader && body.focusable |
2377 | + height: visible ? 32 : 0 |
2378 | + |
2379 | + property bool foldable: body.item.folded != undefined |
2380 | + availableCount: foldable ? body.group_model.count - body.item.cellsPerRow : 0 |
2381 | + folded: foldable ? body.item.folded : false |
2382 | + onClicked: if(foldable) body.item.folded = !body.item.folded |
2383 | + |
2384 | + icon: body.iconHint |
2385 | + label: body.displayName |
2386 | + } |
2387 | + |
2388 | + model: placeEntryView.model != undefined ? placeEntryView.model.entryGroupsModel : undefined |
2389 | } |
2390 | } |
2391 | |
2392 | === modified file 'places/Renderer.qml' |
2393 | --- places/Renderer.qml 2011-06-23 17:08:53 +0000 |
2394 | +++ places/Renderer.qml 2011-07-27 15:02:42 +0000 |
2395 | @@ -26,11 +26,11 @@ |
2396 | itself. A typical renderer is the UnityDefaultRender that lays out the items |
2397 | in a grid of icons with the item's title underneath it. |
2398 | */ |
2399 | -Item { |
2400 | +FocusScope { |
2401 | property string displayName /* Name of the group typically displayed in the header */ |
2402 | property string iconHint /* Icon id of the group */ |
2403 | property int groupId /* Index of the group */ |
2404 | - property variant model /* List model containing the items to be displayed by the renderer */ |
2405 | + property variant group_model /* List model containing the items to be displayed by the renderer */ |
2406 | property variant placeEntryModel /* Reference to the place entry the group belongs to */ |
2407 | - property variant parentListView /* Reference to the ListView the renderer is nested into */ |
2408 | + property bool needHeader: false /* Whether or not the renderer requires a header to be displayed */ |
2409 | } |
2410 | |
2411 | === modified file 'places/RendererGrid.qml' |
2412 | --- places/RendererGrid.qml 2011-06-23 17:08:53 +0000 |
2413 | +++ places/RendererGrid.qml 2011-07-27 15:02:42 +0000 |
2414 | @@ -28,6 +28,11 @@ |
2415 | Renderer { |
2416 | id: renderer |
2417 | |
2418 | + needHeader: true |
2419 | + property alias cellsPerRow: results.cellsPerRow |
2420 | + property alias contentY: results.contentY |
2421 | + property alias currentItem: results.currentItem |
2422 | + |
2423 | property variant cellRenderer |
2424 | property bool folded |
2425 | folded: { |
2426 | @@ -44,99 +49,35 @@ |
2427 | property int horizontalSpacing: 26 |
2428 | property int verticalSpacing: 26 |
2429 | |
2430 | - /* Using results.contentHeight produces binding loop warnings and potential |
2431 | - rendering issues. We compute the height manually. |
2432 | - */ |
2433 | - /* FIXME: tricking the system by making the delegate of height 0 and with |
2434 | - an invisible header is no good: the item in the model still |
2435 | - exists and some things such as keyboard selection break. |
2436 | - */ |
2437 | - height: results.count > 0 ? header.height + results_layout.anchors.topMargin + results.totalHeight : 0 |
2438 | - //Behavior on height {NumberAnimation {duration: 200}} |
2439 | - |
2440 | - GroupHeader { |
2441 | - id: header |
2442 | - |
2443 | - visible: results.count > 0 |
2444 | - availableCount: results.count - results.cellsPerRow |
2445 | - folded: parent.folded |
2446 | - anchors.top: parent.top |
2447 | - anchors.left: parent.left |
2448 | - anchors.right: parent.right |
2449 | - height: 32 |
2450 | - icon: parent.iconHint |
2451 | - label: parent.displayName |
2452 | - |
2453 | - onClicked: parent.folded = !parent.folded |
2454 | - } |
2455 | + /* FIXME: using results_layout.anchors.topMargin in the following expression |
2456 | + causes QML to think they might be an anchor loop. */ |
2457 | + property int totalHeight: results.count > 0 ? results_layout.anchors.topMargin + results.totalHeight : 0 |
2458 | |
2459 | Item { |
2460 | id: results_layout |
2461 | |
2462 | - anchors.top: header.bottom |
2463 | - anchors.topMargin: 22 |
2464 | - anchors.left: parent.left |
2465 | + anchors.fill: parent |
2466 | + anchors.topMargin: 12 |
2467 | anchors.leftMargin: 2 |
2468 | - anchors.right: parent.right |
2469 | - anchors.bottom: parent.bottom |
2470 | |
2471 | CenteredGridView { |
2472 | id: results |
2473 | |
2474 | - /* FIXME: this is a gross hack compensating for the lack of sections |
2475 | - in GridView (see ListView.section). |
2476 | - |
2477 | - We nest GridViews inside a ListView and add headers manually |
2478 | - (GroupHeader). The total height of each Group is computed |
2479 | - manually and given back to the ListView. However that size cannot |
2480 | - be used by the individual GridViews because it would make them |
2481 | - load all of their delegates at once using far too much memory and |
2482 | - processing power. Instead we constrain the height of the GridViews |
2483 | - and compute their position manually to compensate for the position |
2484 | - changes when flicking the ListView. |
2485 | - |
2486 | - We assume that renderer.parentListView is the ListView we nest our |
2487 | - GridView into. |
2488 | - */ |
2489 | - property variant flickable: renderer.parentListView.contentItem |
2490 | - |
2491 | - /* flickable.contentY*0 is equal to 0 but is necessary in order to |
2492 | - have the entire expression being evaluated at the right moment. |
2493 | - */ |
2494 | - property int inFlickableY: flickable.contentY*0+parent.mapToItem(flickable, 0, 0).y |
2495 | - /* note: testing for flickable.height < 0 is probably useless since it is |
2496 | - unlikely flickable.height will ever be negative. |
2497 | - */ |
2498 | - property int compensateY: inFlickableY > 0 || flickable.height < 0 || totalHeight < flickable.height ? 0 : -inFlickableY |
2499 | - |
2500 | - /* Synchronise the position and content's position of the GridView |
2501 | - with the current position of flickable's visibleArea */ |
2502 | - function synchronisePosition() { |
2503 | - y = compensateY |
2504 | - contentY = compensateY |
2505 | - } |
2506 | - |
2507 | - onCompensateYChanged: synchronisePosition() |
2508 | - /* Any change in content needs to trigger a synchronisation */ |
2509 | - onCountChanged: synchronisePosition() |
2510 | - onModelChanged: synchronisePosition() |
2511 | - |
2512 | - width: flickable.width |
2513 | - height: Math.min(totalHeight, flickable.height) |
2514 | - |
2515 | - /* Only display one line of items when folded */ |
2516 | - property int displayedCount: folded ? cellsPerRow : count |
2517 | - property int totalHeight: results.cellHeight*Math.ceil(displayedCount/cellsPerRow) |
2518 | + focus: true |
2519 | + |
2520 | + anchors.fill: parent |
2521 | + |
2522 | + property int totalHeight: results.cellHeight*Math.ceil(count/cellsPerRow) |
2523 | |
2524 | minHorizontalSpacing: renderer.horizontalSpacing |
2525 | minVerticalSpacing: renderer.verticalSpacing |
2526 | delegateWidth: renderer.cellWidth |
2527 | delegateHeight: renderer.cellHeight |
2528 | |
2529 | - interactive: false |
2530 | +// interactive: false |
2531 | clip: true |
2532 | |
2533 | - delegate: Item { |
2534 | + delegate: FocusScope { |
2535 | |
2536 | width: results.cellWidth |
2537 | height: results.cellHeight |
2538 | @@ -157,6 +98,7 @@ |
2539 | height: results.delegateHeight |
2540 | anchors.horizontalCenter: parent.horizontalCenter |
2541 | |
2542 | + focus: true |
2543 | sourceComponent: cellRenderer |
2544 | onLoaded: { |
2545 | item.uri = uri |
2546 | @@ -164,11 +106,16 @@ |
2547 | item.mimetype = mimetype |
2548 | item.displayName = displayName |
2549 | item.comment = comment |
2550 | + item.focus = true |
2551 | } |
2552 | } |
2553 | } |
2554 | |
2555 | - model: renderer.model |
2556 | + /* Only display one line of items when folded */ |
2557 | + model: SortFilterProxyModel { |
2558 | + model: renderer.group_model != undefined ? renderer.group_model : null |
2559 | + limit: folded ? results.cellsPerRow : -1 |
2560 | + } |
2561 | } |
2562 | } |
2563 | } |
2564 | |
2565 | === modified file 'places/Scrollbar.qml' |
2566 | --- places/Scrollbar.qml 2011-06-23 17:08:53 +0000 |
2567 | +++ places/Scrollbar.qml 2011-07-27 15:02:42 +0000 |
2568 | @@ -72,12 +72,18 @@ |
2569 | anchors.left: parent.left |
2570 | anchors.right: parent.right |
2571 | |
2572 | - y: { |
2573 | - var clampedYPosition = Math.max(0, Math.min(1-targetFlickable.visibleArea.heightRatio, |
2574 | - targetFlickable.visibleArea.yPosition)) |
2575 | - return clampedYPosition * scrollbar.height |
2576 | + Binding { |
2577 | + target: slider |
2578 | + property: "y" |
2579 | + value: { |
2580 | + var clampedYPosition = Math.max(0, Math.min(1-targetFlickable.visibleArea.heightRatio, |
2581 | + targetFlickable.visibleArea.yPosition)) |
2582 | + return clampedYPosition * scrollbar.height |
2583 | + } |
2584 | + when: !dragMouseArea.drag.active |
2585 | } |
2586 | - height: Math.max(minimalHeight, targetFlickable.visibleArea.heightRatio * scrollbar.height) |
2587 | + |
2588 | + height: Math.min(scrollbar.height, Math.max(minimalHeight, targetFlickable.visibleArea.heightRatio * scrollbar.height)) |
2589 | |
2590 | Behavior on height {NumberAnimation {duration: 200; easing.type: Easing.InOutQuad}} |
2591 | |
2592 | |
2593 | === modified file 'places/SearchEntry.qml' |
2594 | --- places/SearchEntry.qml 2011-06-23 17:08:53 +0000 |
2595 | +++ places/SearchEntry.qml 2011-07-27 15:02:42 +0000 |
2596 | @@ -19,7 +19,7 @@ |
2597 | import QtQuick 1.0 |
2598 | import Effects 1.0 |
2599 | |
2600 | -FocusScope { |
2601 | +AbstractButton { |
2602 | property string searchQuery |
2603 | |
2604 | /* Cancels current search when the dash becomes invisible */ |
2605 | @@ -37,6 +37,8 @@ |
2606 | /* Keys forwarded to the search entry are forwarded to the text input. */ |
2607 | Keys.forwardTo: [search_input] |
2608 | |
2609 | + opacity: state == "selected" ? 1.0 : 0.7 |
2610 | + |
2611 | BorderImage { |
2612 | anchors.fill: parent |
2613 | source: "artwork/search_background.sci" |
2614 | |
2615 | === modified file 'places/SearchRefine.qml' |
2616 | --- places/SearchRefine.qml 2011-06-23 17:08:53 +0000 |
2617 | +++ places/SearchRefine.qml 2011-07-27 15:02:42 +0000 |
2618 | @@ -49,6 +49,8 @@ |
2619 | |
2620 | focus: true |
2621 | |
2622 | + KeyNavigation.down: options |
2623 | + |
2624 | anchors.left: parent.left |
2625 | anchors.right: parent.right |
2626 | anchors.top: parent.top |
2627 | @@ -61,6 +63,7 @@ |
2628 | text: u2d.tr("Refine search") |
2629 | font.bold: true |
2630 | font.pixelSize: 16 |
2631 | + font.underline: parent.state == "selected" |
2632 | |
2633 | anchors.top: parent.top |
2634 | anchors.left: parent.left |
2635 | @@ -92,6 +95,8 @@ |
2636 | opacity: folded ? 0.0 : 1.0 |
2637 | Behavior on opacity {NumberAnimation {duration: 100; easing.type: Easing.InOutQuad}} |
2638 | |
2639 | + KeyNavigation.up: header |
2640 | + |
2641 | anchors.left: parent.left |
2642 | anchors.right: parent.right |
2643 | anchors.top: header.bottom |
2644 | |
2645 | === modified file 'places/SearchRefineOptionType.qml' |
2646 | --- places/SearchRefineOptionType.qml 2011-06-23 17:08:53 +0000 |
2647 | +++ places/SearchRefineOptionType.qml 2011-07-27 15:02:42 +0000 |
2648 | @@ -21,9 +21,11 @@ |
2649 | SearchRefineOption { |
2650 | id: searchRefineOption |
2651 | |
2652 | - AbstractButton { |
2653 | + Item { |
2654 | id: header |
2655 | |
2656 | + KeyNavigation.down: filters |
2657 | + |
2658 | focus: true |
2659 | anchors.top: parent.top |
2660 | anchors.left: parent.left |
2661 | @@ -39,6 +41,7 @@ |
2662 | text: searchRefineOption.title |
2663 | font.pixelSize: 16 |
2664 | font.bold: true |
2665 | + font.underline: parent.state == "selected" |
2666 | } |
2667 | } |
2668 | |
2669 | @@ -63,6 +66,7 @@ |
2670 | |
2671 | /* Make sure the first item is selected when getting the focus for the first time */ |
2672 | currentIndex: 0 |
2673 | + KeyNavigation.up: header |
2674 | |
2675 | delegate: TickBox { |
2676 | height: filters.cellHeight |
2677 | @@ -70,7 +74,7 @@ |
2678 | /* Not checking for placeEntryModel != undefined leads to a segfault |
2679 | when switching places */ |
2680 | text: placeEntryModel != undefined ? column_0 : "" |
2681 | - ticked: dash.currentPage.model.activeSection == model.index |
2682 | + checked: dash.currentPage.model.activeSection == model.index |
2683 | |
2684 | onClicked: placeEntryModel.activeSection = model.index |
2685 | } |
2686 | |
2687 | === modified file 'places/TickBox.qml' |
2688 | --- places/TickBox.qml 2011-06-23 17:08:53 +0000 |
2689 | +++ places/TickBox.qml 2011-07-27 15:02:42 +0000 |
2690 | @@ -22,8 +22,8 @@ |
2691 | id: tickBox |
2692 | |
2693 | property string text |
2694 | - property bool ticked: false |
2695 | - property bool canUntick: true |
2696 | + property bool checked: false |
2697 | + property bool canUncheck: true |
2698 | |
2699 | width: childrenRect.width |
2700 | height: childrenRect.height |
2701 | @@ -43,7 +43,7 @@ |
2702 | Image { |
2703 | id: box |
2704 | |
2705 | - opacity: !canUntick && ticked ? 0 : 1 |
2706 | + opacity: !canUncheck && checked ? 0 : 1 |
2707 | anchors.top: parent.top |
2708 | anchors.left: parent.left |
2709 | source: "artwork/tick_box.png" |
2710 | @@ -58,7 +58,7 @@ |
2711 | anchors.topMargin: 2 |
2712 | anchors.left: box.left |
2713 | anchors.leftMargin: 3 |
2714 | - opacity: ticked ? 1.0 : parent.state == "selected" ? 0.4 : 0.0 |
2715 | + opacity: checked ? 1.0 : parent.state == "selected" ? 0.4 : 0.0 |
2716 | source: "artwork/tick.png" |
2717 | width: sourceSize.width |
2718 | height: sourceSize.height |
2719 | |
2720 | === modified file 'places/UnityEmptySearchRenderer.qml' |
2721 | --- places/UnityEmptySearchRenderer.qml 2011-06-23 17:08:53 +0000 |
2722 | +++ places/UnityEmptySearchRenderer.qml 2011-07-27 15:02:42 +0000 |
2723 | @@ -40,7 +40,7 @@ |
2724 | boundsBehavior: ListView.StopAtBounds |
2725 | orientation: ListView.Vertical |
2726 | |
2727 | - model: renderer.model |
2728 | + model: renderer.group_model |
2729 | delegate: Button { |
2730 | property string uri: column_0 |
2731 | property string iconHint: column_1 |
2732 | |
2733 | === modified file 'places/app/CMakeLists.txt' |
2734 | --- places/app/CMakeLists.txt 2011-03-08 09:20:02 +0000 |
2735 | +++ places/app/CMakeLists.txt 2011-07-27 15:02:42 +0000 |
2736 | @@ -1,7 +1,5 @@ |
2737 | # Dependencies |
2738 | -find_package(X11 REQUIRED) |
2739 | pkg_check_modules(QTGCONF REQUIRED libqtgconf) |
2740 | -pkg_check_modules(GTK REQUIRED gtk+-2.0) |
2741 | |
2742 | # Sources |
2743 | set(places_SRCS |
2744 | |
2745 | === modified file 'places/app/places.cpp' |
2746 | --- places/app/places.cpp 2011-06-27 13:43:05 +0000 |
2747 | +++ places/app/places.cpp 2011-07-27 15:02:42 +0000 |
2748 | @@ -31,9 +31,8 @@ |
2749 | |
2750 | #include <X11/Xlib.h> |
2751 | |
2752 | -#include <gtk/gtk.h> |
2753 | - |
2754 | // unity-2d |
2755 | +#include <unity2dapplication.h> |
2756 | #include <unity2ddebug.h> |
2757 | |
2758 | #include "dashdeclarativeview.h" |
2759 | @@ -41,23 +40,8 @@ |
2760 | |
2761 | int main(int argc, char *argv[]) |
2762 | { |
2763 | - /* gtk needs to be inited, otherwise we get an assert failure in gdk */ |
2764 | - gtk_init(&argc, &argv); |
2765 | - Unity2dDebug::installHandlers(); |
2766 | - |
2767 | - /* When the environment variable QT_GRAPHICSSYSTEM is not set, |
2768 | - force graphics system to 'raster' instead of the default 'native' |
2769 | - which on X11 is 'XRender'. |
2770 | - 'XRender' defaults to using a TrueColor visual. We do _not_ mimick that |
2771 | - behaviour with 'raster' by calling QApplication::setColorSpec because |
2772 | - of a bug where some pixmaps become blueish: |
2773 | - |
2774 | - https://bugs.launchpad.net/unity-2d/+bug/689877 |
2775 | - */ |
2776 | - if(getenv("QT_GRAPHICSSYSTEM") == 0) { |
2777 | - QApplication::setGraphicsSystem("raster"); |
2778 | - } |
2779 | - QApplication application(argc, argv); |
2780 | + Unity2dApplication::earlySetup(argc, argv); |
2781 | + Unity2dApplication application(argc, argv); |
2782 | QSet<QString> arguments = QSet<QString>::fromList(QCoreApplication::arguments()); |
2783 | |
2784 | qmlRegisterType<DashDeclarativeView>("Unity2d", 1, 0, "DashDeclarativeView"); |
2785 | |
2786 | === modified file 'places/dash.qml' |
2787 | --- places/dash.qml 2011-07-05 19:01:18 +0000 |
2788 | +++ places/dash.qml 2011-07-27 15:02:42 +0000 |
2789 | @@ -31,6 +31,9 @@ |
2790 | } |
2791 | |
2792 | function activatePage(page) { |
2793 | + /* Always give the focus to the search entry when switching pages */ |
2794 | + search_entry.focus = true |
2795 | + |
2796 | if (page == currentPage) { |
2797 | return |
2798 | } |
2799 | @@ -40,12 +43,6 @@ |
2800 | } |
2801 | currentPage = page |
2802 | currentPage.visible = true |
2803 | - /* FIXME: For some reason currentPage gets the focus when it becomes |
2804 | - visible. Reset the focus to the search_bar instead. |
2805 | - It could be due to Qt bug QTBUG-13380: |
2806 | - "Listview gets focus when it becomes visible" |
2807 | - */ |
2808 | - search_entry.focus = true |
2809 | } |
2810 | |
2811 | function activatePlaceEntry(fileName, groupName, section) { |
2812 | @@ -121,13 +118,18 @@ |
2813 | /* Unhandled keys will always be forwarded to the search bar. That way |
2814 | the user can type and search from anywhere in the interface without |
2815 | necessarily focusing the search bar first. */ |
2816 | - Keys.forwardTo: [search_entry] |
2817 | + //Keys.forwardTo: [search_entry] |
2818 | |
2819 | |
2820 | SearchEntry { |
2821 | id: search_entry |
2822 | |
2823 | focus: true |
2824 | + /* FIXME: check on visible necessary; fixed in Qt Quick 1.1 |
2825 | + ref: http://bugreports.qt.nokia.com/browse/QTBUG-15862 |
2826 | + */ |
2827 | + KeyNavigation.right: refine_search.visible ? refine_search : search_entry |
2828 | + KeyNavigation.down: pageLoader |
2829 | |
2830 | anchors.top: parent.top |
2831 | anchors.topMargin: 10 |
2832 | @@ -142,6 +144,8 @@ |
2833 | SearchRefine { |
2834 | id: refine_search |
2835 | |
2836 | + KeyNavigation.left: search_entry |
2837 | + |
2838 | /* SearchRefine is only to be displayed for places, not in the home page */ |
2839 | visible: dashView.activePlaceEntry != "" |
2840 | placeEntryModel: visible && currentPage != undefined ? currentPage.model : undefined |
2841 | @@ -158,6 +162,12 @@ |
2842 | Loader { |
2843 | id: pageLoader |
2844 | |
2845 | + /* FIXME: check on visible necessary; fixed in Qt Quick 1.1 |
2846 | + ref: http://bugreports.qt.nokia.com/browse/QTBUG-15862 |
2847 | + */ |
2848 | + KeyNavigation.right: refine_search.visible && !refine_search.folded ? refine_search : pageLoader |
2849 | + KeyNavigation.up: search_entry |
2850 | + |
2851 | anchors.top: search_entry.bottom |
2852 | anchors.topMargin: 2 |
2853 | anchors.bottom: parent.bottom |
2854 | @@ -165,6 +175,7 @@ |
2855 | anchors.leftMargin: 20 |
2856 | anchors.right: !refine_search.visible || refine_search.folded ? parent.right : refine_search.left |
2857 | anchors.rightMargin: !refine_search.visible || refine_search.folded ? 0 : 15 |
2858 | + onLoaded: item.focus = true |
2859 | } |
2860 | } |
2861 | |
2862 | |
2863 | === modified file 'spread/app/CMakeLists.txt' |
2864 | --- spread/app/CMakeLists.txt 2011-03-07 14:52:11 +0000 |
2865 | +++ spread/app/CMakeLists.txt 2011-07-27 15:02:42 +0000 |
2866 | @@ -1,7 +1,3 @@ |
2867 | -# Dependencies |
2868 | -pkg_check_modules(GTK REQUIRED gtk+-2.0) |
2869 | -find_package(X11 REQUIRED) |
2870 | - |
2871 | # Sources |
2872 | set(spread_SRCS |
2873 | spread.cpp |
2874 | |
2875 | === modified file 'spread/app/spread.cpp' |
2876 | --- spread/app/spread.cpp 2011-06-22 08:33:52 +0000 |
2877 | +++ spread/app/spread.cpp 2011-07-27 15:02:42 +0000 |
2878 | @@ -18,7 +18,6 @@ |
2879 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2880 | */ |
2881 | |
2882 | -#include <gtk/gtk.h> |
2883 | #include <QApplication> |
2884 | #include <QDesktopWidget> |
2885 | #include <QDeclarativeEngine> |
2886 | @@ -28,31 +27,14 @@ |
2887 | #include "spreadcontrol.h" |
2888 | #include "launcherclient.h" |
2889 | |
2890 | -#include <unity2ddebug.h> |
2891 | +#include <unity2dapplication.h> |
2892 | |
2893 | #include "config.h" |
2894 | |
2895 | int main(int argc, char *argv[]) |
2896 | { |
2897 | - /* Unity2d plugin uses GTK APIs to retrieve theme icons |
2898 | - (gtk_icon_theme_get_default) and requires a call to gtk_init */ |
2899 | - gtk_init(&argc, &argv); |
2900 | - |
2901 | - Unity2dDebug::installHandlers(); |
2902 | - |
2903 | - /* When the environment variable QT_GRAPHICSSYSTEM is not set, |
2904 | - force graphics system to 'raster' instead of the default 'native' |
2905 | - which on X11 is 'XRender'. |
2906 | - 'XRender' defaults to using a TrueColor visual. We do _not_ mimick that |
2907 | - behaviour with 'raster' by calling QApplication::setColorSpec because |
2908 | - of a bug where some pixmaps become blueish: |
2909 | - |
2910 | - https://bugs.launchpad.net/unity-2d/+bug/689877 |
2911 | - */ |
2912 | - if(getenv("QT_GRAPHICSSYSTEM") == 0) { |
2913 | - QApplication::setGraphicsSystem("raster"); |
2914 | - } |
2915 | - QApplication application(argc, argv); |
2916 | + Unity2dApplication::earlySetup(argc, argv); |
2917 | + Unity2dApplication application(argc, argv); |
2918 | QSet<QString> arguments = QSet<QString>::fromList(QCoreApplication::arguments()); |
2919 | |
2920 | SpreadView view; |