Merge lp:~gary-lasker/software-center/list-view-icon-coordinates-lp947624 into lp:software-center

Proposed by Gary Lasker
Status: Merged
Merged at revision: 2815
Proposed branch: lp:~gary-lasker/software-center/list-view-icon-coordinates-lp947624
Merge into: lp:software-center
Diff against target: 255 lines (+116/-17)
5 files modified
softwarecenter/ui/gtk3/panes/availablepane.py (+3/-1)
softwarecenter/ui/gtk3/views/appview.py (+37/-1)
softwarecenter/ui/gtk3/widgets/apptreeview.py (+8/-0)
softwarecenter/ui/gtk3/widgets/cellrenderers.py (+10/-5)
test/gtk3/test_unity_launcher_integration.py (+58/-10)
To merge this branch: bzr merge lp:~gary-lasker/software-center/list-view-icon-coordinates-lp947624
Reviewer Review Type Date Requested Status
Michael Vogt Approve
Review via email: mp+96298@code.launchpad.net

Description of the change

This branch adds support for providing the correct icon size and on-screen coordinates values in the Unity launcher integration dbus call when an installation is initiated via the list view. Previously this was only correct for installations from the details view.

Please see the associated bug 947624 for further details.

A new unit test has been added in test_unity_launcher_integration.py.

Thanks!

To post a comment you must log in.
Michael Vogt (mvo) wrote :

Thanks Gary. This is excellent work!

I'm sure that was not a easy one. Great to see the test addition too (and the RED/GREEN approach in use!).

review: Approve
Gary Lasker (gary-lasker) wrote :

Thank you, mvo! That main tricky part was getting the coordinates via Cairo, but the other bits weren't too bad as it was already partially stubbed out from the original work in anticipation of needing this.

And yeah, the RED/GREEN dance would normally be more finely grained, but it was a kinda big RED (the full feature working) and needed a few interim steps before I finally reached GREEN. ;)

Thanks again!

Michael Vogt (mvo) wrote :

On Wed, Mar 07, 2012 at 05:24:19PM -0000, Gary Lasker wrote:
> Thank you, mvo! That main tricky part was getting the coordinates via Cairo, but the other bits weren't too bad as it was already partially stubbed out from the original work in anticipation of needing this.
>
> And yeah, the RED/GREEN dance would normally be more finely grained, but it was a kinda big RED (the full feature working) and needed a few interim steps before I finally reached GREEN. ;)

Yeah, I think that is toally appropriate to have some steps in between
if there is just too much work to make it green in one go :)

Cheers,
 Michael

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'softwarecenter/ui/gtk3/panes/availablepane.py'
2--- softwarecenter/ui/gtk3/panes/availablepane.py 2012-02-28 13:14:06 +0000
3+++ softwarecenter/ui/gtk3/panes/availablepane.py 2012-03-07 06:19:19 +0000
4@@ -407,8 +407,10 @@
5 def _get_onscreen_icon_details_for_launcher_service(self, app):
6 if self.is_app_details_view_showing():
7 return self.app_details_view.get_app_icon_details()
8+ elif self.is_applist_view_showing():
9+ return self.app_view.get_app_icon_details()
10 else:
11- # TODO: implement the app list view case once it has been specified
12+ # set a default, even though we cannot install from the other panes
13 return (0, 0, 0)
14
15 def on_app_list_changed(self, pane, length):
16
17=== modified file 'softwarecenter/ui/gtk3/views/appview.py'
18--- softwarecenter/ui/gtk3/views/appview.py 2012-02-16 14:14:01 +0000
19+++ softwarecenter/ui/gtk3/views/appview.py 2012-03-07 06:19:19 +0000
20@@ -18,7 +18,7 @@
21
22 #~ from __future__ import with_statement
23
24-
25+import logging
26
27 from gi.repository import Gtk, GObject
28 from gettext import gettext as _
29@@ -31,6 +31,7 @@
30 from softwarecenter.ui.gtk3.models.appstore2 import AppPropertiesHelper
31 #~ from softwarecenter.ui.gtk3.widgets.containers import FlowableGrid
32
33+LOG=logging.getLogger(__name__)
34
35 class AppView(Gtk.VBox):
36
37@@ -219,6 +220,41 @@
38 def get_sort_mode(self):
39 active_index = self.sort_methods_combobox.get_active()
40 return self._SORT_METHOD_INDEX[active_index]
41+
42+ def get_app_icon_details(self):
43+ """ helper for unity dbus support to provide details about the
44+ application icon as it is displayed on-screen
45+ """
46+ icon_size = self._get_app_icon_size_on_screen()
47+ (icon_x, icon_y) = self._get_app_icon_xy_position_on_screen()
48+ return (icon_size, icon_x, icon_y)
49+
50+ def _get_app_icon_size_on_screen(self):
51+ """ helper for unity dbus support to get the size of the maximum side
52+ for the application icon as it is displayed on-screen
53+ """
54+ icon_size = 32
55+ if self.tree_view.selected_row_renderer.icon:
56+ pb = self.tree_view.selected_row_renderer.icon
57+ if pb.get_width() > pb.get_height():
58+ icon_size = pb.get_width()
59+ else:
60+ icon_size = pb.get_height()
61+ return icon_size
62+
63+ def _get_app_icon_xy_position_on_screen(self):
64+ """ helper for unity dbus support to get the x,y position of
65+ the application icon as it is displayed on-screen
66+ """
67+ # find toplevel parent
68+ parent = self
69+ while parent.get_parent():
70+ parent = parent.get_parent()
71+ # get toplevel window position
72+ (px, py) = parent.get_position()
73+ # and return the coordinate values
74+ return (px+self.tree_view.selected_row_renderer.icon_x_offset,
75+ py+self.tree_view.selected_row_renderer.icon_y_offset)
76
77
78 def get_test_window():
79
80=== modified file 'softwarecenter/ui/gtk3/widgets/apptreeview.py'
81--- softwarecenter/ui/gtk3/widgets/apptreeview.py 2011-12-02 14:56:14 +0000
82+++ softwarecenter/ui/gtk3/widgets/apptreeview.py 2012-03-07 06:19:19 +0000
83@@ -45,6 +45,9 @@
84 self._action_block_list = []
85 self._needs_collapse = []
86 self.expanded_path = None
87+
88+ # pixbuf for the icon that is displayed in the selected row
89+ self.selected_row_icon = None
90
91 #~ # if this hacked mode is available everything will be fast
92 #~ # and we can set fixed_height mode and still have growing rows
93@@ -267,6 +270,11 @@
94 return
95
96 def _update_selected_row(self, view, tr, path=None):
97+ # keep track of the currently selected row renderer for use when
98+ # calculating icon size and coordinate values for the Unity
99+ # launcher integration feature
100+ self.selected_row_renderer = tr
101+ ##
102 sel = view.get_selection()
103 if not sel:
104 return False
105
106=== modified file 'softwarecenter/ui/gtk3/widgets/cellrenderers.py'
107--- softwarecenter/ui/gtk3/widgets/cellrenderers.py 2011-10-31 16:23:43 +0000
108+++ softwarecenter/ui/gtk3/widgets/cellrenderers.py 2012-03-07 06:19:19 +0000
109@@ -56,6 +56,9 @@
110
111 def __init__(self, icons, layout, show_ratings, overlay_icon_name):
112 GObject.GObject.__init__(self)
113+
114+ # the icon pixbuf to be displayed in the row
115+ self.icon = None
116
117 # geometry-state values
118 self.pixbuf_width = 0
119@@ -126,9 +129,11 @@
120
121 def _render_icon(self, cr, app, cell_area, xpad, ypad, is_rtl):
122 # calc offsets so icon is nicely centered
123- icon = self.model.get_icon(app)
124- xo = (self.pixbuf_width - icon.get_width())/2
125-
126+ self.icon = self.model.get_icon(app)
127+ self.icon_x_offset = xpad + cell_area.x
128+ self.icon_y_offset = ypad + cell_area.y
129+ xo = (self.pixbuf_width - self.icon.get_width())/2
130+
131 if not is_rtl:
132 x = cell_area.x + xo + xpad
133 else:
134@@ -136,9 +141,9 @@
135 y = cell_area.y + ypad
136
137 # draw appicon pixbuf
138- Gdk.cairo_set_source_pixbuf(cr, icon, x, y)
139+ Gdk.cairo_set_source_pixbuf(cr, self.icon, x, y)
140 cr.paint()
141-
142+
143 # draw overlay if application is installed
144 if self.model.is_installed(app):
145 if not is_rtl:
146
147=== modified file 'test/gtk3/test_unity_launcher_integration.py'
148--- test/gtk3/test_unity_launcher_integration.py 2012-01-27 00:08:22 +0000
149+++ test/gtk3/test_unity_launcher_integration.py 2012-03-07 06:19:19 +0000
150@@ -16,14 +16,19 @@
151 from softwarecenter.ui.gtk3.panes.availablepane import get_test_window
152 from softwarecenter.backend.unitylauncher import UnityLauncherInfo
153
154+# Tests for Ubuntu Software Center's integration with the Unity launcher,
155+# see https://wiki.ubuntu.com/SoftwareCenter#Learning%20how%20to%20launch%20an%20application
156+
157 # we can only have one instance of availablepane, so create it here
158 win = get_test_window()
159 available_pane = win.get_data("pane")
160
161-# see https://wiki.ubuntu.com/SoftwareCenter#Learning%20how%20to%20launch%20an%20application
162-
163 class TestUnityLauncherIntegration(unittest.TestCase):
164-
165+
166+ def setUp(self):
167+ # monkey patch is_unity_running
168+ softwarecenter.utils.is_unity_running = lambda: True
169+
170 def _zzz(self):
171 for i in range(10):
172 time.sleep(0.1)
173@@ -33,9 +38,28 @@
174 while Gtk.events_pending():
175 Gtk.main_iteration()
176
177- def setUp(self):
178- # monkey patch is_unity_running
179- softwarecenter.utils.is_unity_running = lambda: True
180+ def _install_from_list_view(self, pkgname):
181+ from softwarecenter.ui.gtk3.panes.availablepane import AvailablePane
182+ available_pane.notebook.set_current_page(AvailablePane.Pages.LIST)
183+
184+ self._p()
185+ available_pane.on_search_terms_changed(None, "ark,artha,software-center")
186+ self._p()
187+
188+ # select the first item in the list
189+ available_pane.app_view.tree_view.set_cursor(Gtk.TreePath(0),
190+ None, False)
191+ # ok to just use the test app here
192+ app = Application("", pkgname)
193+ self._p()
194+
195+ # pretend we started an install
196+ available_pane.backend.emit("transaction-started",
197+ app.pkgname, app.appname,
198+ "testid101",
199+ TransactionTypes.INSTALL)
200+ # wait a wee bit
201+ self._zzz()
202
203 def _navigate_to_appdetails_and_install(self, pkgname):
204 app = Application("", pkgname)
205@@ -59,14 +83,38 @@
206 self.expected_launcher_info.icon_name)
207 self.assertTrue(launcher_info.icon_x > 5)
208 self.assertTrue(launcher_info.icon_y > 5)
209- self.assertEqual(launcher_info.icon_size, 96)
210+ # check that the icon size is one of either 32 pixels (for the
211+ # list view case) or 96 pixels (for the details view case)
212+ self.assertTrue(launcher_info.icon_size == 32 or
213+ launcher_info.icon_size == 96)
214 self.assertEqual(launcher_info.app_install_desktop_file_path,
215 self.expected_launcher_info.app_install_desktop_file_path)
216 self.assertEqual(launcher_info.trans_id,
217 self.expected_launcher_info.trans_id)
218+
219+ def test_unity_launcher_integration_list_view(self):
220+ # test the automatic add to launcher enabled functionality when
221+ # installing an app form the list view
222+ available_pane.add_to_launcher_enabled = True
223+ test_pkgname = "lincity-ng"
224+ # now pretend
225+ # for testing, we substitute a fake version of UnityLauncher's
226+ # send_application_to_launcher method that lets us check for the
227+ # correct values and also avoids firing the actual dbus signal
228+ # to the unity launcher service
229+ self.expected_pkgname = test_pkgname
230+ self.expected_launcher_info = UnityLauncherInfo("lincity-ng",
231+ "lincity-ng",
232+ 0, 0, 0, 0, # these values are set in availablepane
233+ "/usr/share/app-install/desktop/lincity-ng:lincity-ng.desktop",
234+ "testid101")
235+ available_pane.unity_launcher.send_application_to_launcher = (
236+ self._fake_send_application_to_launcher_and_check)
237+ self._install_from_list_view(test_pkgname)
238
239- def test_unity_launcher_integration(self):
240- # test the automatic add to launcher enabled functionality
241+ def test_unity_launcher_integration_details_view(self):
242+ # test the automatic add to launcher enabled functionality when
243+ # installing an app from the details view
244 available_pane.add_to_launcher_enabled = True
245 test_pkgname = "lincity-ng"
246 # now pretend
247@@ -134,7 +182,7 @@
248 # FIXME: this will only work if update-manager is installed
249 self.assertEqual(installed_desktop_path,
250 "/usr/share/applications/update-manager.desktop")
251-
252+
253
254 if __name__ == "__main__":
255 unittest.main()

Subscribers

People subscribed via source and target branches