Merge lp:~fboucault/unity-2d/keyboard_navigation_experimental into lp:~fboucault/unity-2d/icon_provide_better_error_handling

Proposed by Florian Boucault on 2011-07-27
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
Reviewer Review Type Date Requested Status
Gerry Boland 2011-07-27 Pending
Review via email: mp+69479@code.launchpad.net

Description of the change

[dash] Implemented keyboard navigation.

To post a comment you must log in.
639. By Florian Boucault on 2011-07-27

Remade RendererGrid.interactive false thus preventing mouse interaction with the individual groups.

640. By Florian Boucault on 2011-07-27

Prevent the focus to be on the refine search pane when it is folded.

641. By Florian Boucault on 2011-07-27

Added FIXME/

642. By Florian Boucault on 2011-07-27

Merged colo:proper_grid

Unmerged revisions

642. By Florian Boucault on 2011-07-27

Merged colo:proper_grid

641. By Florian Boucault on 2011-07-27

Added FIXME/

640. By Florian Boucault on 2011-07-27

Prevent the focus to be on the refine search pane when it is folded.

639. By Florian Boucault on 2011-07-27

Remade RendererGrid.interactive false thus preventing mouse interaction with the individual groups.

638. By Florian Boucault on 2011-07-27

Merged colo:proper_grid

637. By Florian Boucault on 2011-07-27

Merged colo:proper_grid

636. By Florian Boucault on 2011-07-26

No change.

635. By Florian Boucault on 2011-07-26

Merged colo:proper_grid

634. By Florian Boucault on 2011-07-26

Merged colo:proper_grid

633. By Florian Boucault on 2011-07-26

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;

Subscribers

People subscribed via source and target branches

to all changes: