Merge lp:~mvo/software-center/purchaseviewspinner2 into lp:software-center

Proposed by Michael Vogt
Status: Merged
Merged at revision: 2602
Proposed branch: lp:~mvo/software-center/purchaseviewspinner2
Merge into: lp:software-center
Diff against target: 325 lines (+155/-7) (has conflicts)
6 files modified
softwarecenter/ui/gtk3/panes/availablepane.py (+5/-0)
softwarecenter/ui/gtk3/panes/globalpane.py (+7/-0)
softwarecenter/ui/gtk3/session/viewmanager.py (+18/-0)
softwarecenter/ui/gtk3/views/purchaseview.py (+77/-5)
test/gtk3/test_globalpane.py (+30/-0)
test/gtk3/test_purchase.py (+18/-2)
Text conflict in softwarecenter/ui/gtk3/views/purchaseview.py
To merge this branch: bzr merge lp:~mvo/software-center/purchaseviewspinner2
Reviewer Review Type Date Requested Status
Gary Lasker (community) Approve
Michael Vogt Pending
Review via email: mp+85653@code.launchpad.net

Description of the change

This adds a spinner to the purchaseview both when new windows are opened and in the global toolbar.

To post a comment you must log in.
Revision history for this message
Gary Lasker (gary-lasker) wrote :

This is awesome! Thanks mvo!

review: Approve

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 2011-11-29 21:50:55 +0000
3+++ softwarecenter/ui/gtk3/panes/availablepane.py 2011-12-14 13:06:26 +0000
4@@ -138,6 +138,7 @@
5 self.purchase_view.connect("purchase-succeeded", self.on_purchase_succeeded)
6 self.purchase_view.connect("purchase-failed", self.on_purchase_failed)
7 self.purchase_view.connect("purchase-cancelled-by-user", self.on_purchase_cancelled_by_user)
8+ self.purchase_view.connect("purchase-needs-spinner", self.on_purchase_needs_spinner)
9 # categories, appview and details into the notebook in the bottom
10 self.scroll_categories = Gtk.ScrolledWindow()
11 self.scroll_categories.set_policy(Gtk.PolicyType.AUTOMATIC,
12@@ -226,6 +227,10 @@
13 self.display_purchase)
14 return
15
16+ def on_purchase_needs_spinner(self, appmanager, active):
17+ vm = get_viewmanager()
18+ vm.set_spinner_active(active)
19+
20 def on_purchase_succeeded(self, widget):
21 # switch to the details page to display the transaction is in progress
22 self._return_to_appdetails_view()
23
24=== modified file 'softwarecenter/ui/gtk3/panes/globalpane.py'
25--- softwarecenter/ui/gtk3/panes/globalpane.py 2011-09-15 09:36:39 +0000
26+++ softwarecenter/ui/gtk3/panes/globalpane.py 2011-12-14 13:06:26 +0000
27@@ -47,6 +47,12 @@
28 #~ self.init_atk_name(self.searchentry, "searchentry")
29 self.searchentry = vm.get_global_searchentry()
30 self._insert_as_tool_item(self.searchentry, -1)
31+
32+ # spinner
33+ self.spinner = vm.get_global_spinner()
34+ self.spinner.set_size_request(StockEms.XLARGE, StockEms.XLARGE)
35+ self._insert_as_tool_item(self.spinner, -1)
36+
37 if self.get_direction() != Gtk.TextDirection.RTL:
38 _widget_set_margins(self.searchentry, right=StockEms.MEDIUM)
39 else:
40@@ -77,6 +83,7 @@
41 p = GlobalPane(vm, datadir, db, cache, icons)
42
43 win = Gtk.Window()
44+ win.set_data("pane", p)
45 win.connect("destroy", Gtk.main_quit)
46 win.add(p)
47 win.show_all()
48
49=== modified file 'softwarecenter/ui/gtk3/session/viewmanager.py'
50--- softwarecenter/ui/gtk3/session/viewmanager.py 2011-11-09 09:49:39 +0000
51+++ softwarecenter/ui/gtk3/session/viewmanager.py 2011-12-14 13:06:26 +0000
52@@ -49,6 +49,7 @@
53 "right-clicked", self.on_nav_forward_clicked)
54
55 self.navhistory = NavigationHistory(self.back_forward, options)
56+ self.spinner = Gtk.Spinner()
57
58 self.all_views = {}
59 self.view_to_pane = {}
60@@ -95,9 +96,22 @@
61 if page_id == v:
62 return k
63
64+ def set_spinner_active(self, active):
65+ if active:
66+ self.spinner.show()
67+ self.spinner.start()
68+ else:
69+ self.spinner.stop()
70+ self.spinner.hide()
71+
72 def set_active_view(self, view_id):
73+ # no views yet
74 if not self.all_views:
75 return
76+ # if the view switches, ensure that the global spinner is hidden
77+ self.spinner.hide()
78+
79+ # emit signal
80 self.emit('view-changed', view_id)
81 page_id = self.all_views[view_id]
82 view_widget = self.get_view_widget(view_id)
83@@ -178,6 +192,7 @@
84 self.search_entry.hide()
85 else:
86 self.search_entry.show()
87+ self.spinner.hide()
88 return
89
90 def nav_back(self):
91@@ -194,3 +209,6 @@
92
93 def get_global_backforward(self):
94 return self.back_forward
95+
96+ def get_global_spinner(self):
97+ return self.spinner
98
99=== modified file 'softwarecenter/ui/gtk3/views/purchaseview.py'
100--- softwarecenter/ui/gtk3/views/purchaseview.py 2011-12-12 09:15:52 +0000
101+++ softwarecenter/ui/gtk3/views/purchaseview.py 2011-12-14 13:06:26 +0000
102@@ -20,11 +20,13 @@
103 from gi.repository import GObject
104 from gi.repository import Gtk
105 from gi.repository import Gdk
106+from gi.repository import Pango
107 import logging
108 import os
109 import json
110 import sys
111 import urllib
112+import urlparse
113 from gi.repository import WebKit as webkit
114 session = webkit.get_default_session()
115 session.set_property("ssl-ca-file", "/etc/ssl/certs/ca-certificates.crt")
116@@ -55,17 +57,70 @@
117 #headers.foreach(_show_header, None)
118
119
120-class ScrolledWebkitWindow(Gtk.ScrolledWindow):
121+class ScrolledWebkitWindow(Gtk.VBox):
122
123- def __init__(self):
124+ def __init__(self, include_progress_ui=False):
125 super(ScrolledWebkitWindow, self).__init__()
126+ # get webkit
127 self.webkit = LocaleAwareWebView()
128 settings = self.webkit.get_settings()
129 settings.set_property("enable-plugins", False)
130- self.webkit.show()
131+ # add progress UI if needed
132+ if include_progress_ui:
133+ self._add_progress_ui()
134+ # create main webkitview
135+ self.scroll = Gtk.ScrolledWindow()
136+ self.scroll.set_policy(Gtk.PolicyType.AUTOMATIC,
137+ Gtk.PolicyType.AUTOMATIC)
138+ self.pack_start(self.scroll, True, True, 0)
139 # embed the webkit view in a scrolled window
140- self.add(self.webkit)
141- self.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
142+ self.scroll.add(self.webkit)
143+ self.show_all()
144+ def _add_progress_ui(self):
145+ # create toolbar box
146+ self.header = Gtk.HBox()
147+ # add spinner
148+ self.spinner = Gtk.Spinner()
149+ self.header.pack_start(self.spinner, False, False, 6)
150+ # add a url to the toolbar
151+ self.url = Gtk.Label()
152+ self.url.set_ellipsize(Pango.EllipsizeMode.END)
153+ self.url.set_alignment(0.0, 0.5)
154+ self.url.set_text("")
155+ self.header.pack_start(self.url, True, True, 0)
156+ # frame around the box
157+ self.frame = Gtk.Frame()
158+ self.frame.set_border_width(3)
159+ self.frame.add(self.header)
160+ self.pack_start(self.frame, False, False, 6)
161+ # connect the webkit stuff
162+ self.webkit.connect("notify::uri", self._on_uri_changed)
163+ self.webkit.connect("notify::load-status", self._on_load_status_changed)
164+ def _on_uri_changed(self, view, pspec):
165+ prop = pspec.name
166+ uri = view.get_property(prop)
167+ # the full uri is irellevant for the purchase view, but it is
168+ # interessting to know what protocol/netloc is in use so that the
169+ # user can verify its https on sites he is expecting
170+ scheme, netloc, path, params, query, frag = urlparse.urlparse(uri)
171+ if scheme == "file" and netloc == "":
172+ self.url.set_text("")
173+ else:
174+ self.url.set_text("%s://%s" % (scheme, netloc))
175+ # start spinner when the uri changes
176+ #self.spinner.start()
177+ def _on_load_status_changed(self, view, pspec):
178+ prop = pspec.name
179+ status = view.get_property(prop)
180+ #print status
181+ if status == webkit.LoadStatus.PROVISIONAL:
182+ self.spinner.start()
183+ self.spinner.show()
184+ if (status == webkit.LoadStatus.FINISHED or
185+ status == webkit.LoadStatus.FAILED):
186+ self.spinner.stop()
187+ self.spinner.hide()
188+
189
190
191 class PurchaseView(Gtk.VBox):
192@@ -119,6 +174,10 @@
193 'purchase-cancelled-by-user' : (GObject.SignalFlags.RUN_LAST,
194 None,
195 ()),
196+ 'purchase-needs-spinner' : (GObject.SignalFlags.RUN_LAST,
197+ None,
198+ (bool, )),
199+
200 }
201
202 def __init__(self):
203@@ -179,6 +238,7 @@
204
205 def _on_create_web_view(self, view, frame):
206 win = Gtk.Window()
207+<<<<<<< TREE
208 win.set_size_request(500, 400)
209 # set transient parent
210 parent = self
211@@ -187,11 +247,20 @@
212 win.set_transient_for(parent)
213 # and add the webkit view
214 wk = ScrolledWebkitWindow()
215+=======
216+ win.set_size_request(400, 400)
217+ wk = ScrolledWebkitWindow(include_progress_ui=True)
218+>>>>>>> MERGE-SOURCE
219 wk.webkit.connect("close-web-view", self._on_close_web_view)
220 win.add(wk)
221 win.show_all()
222 # make sure close will work later
223 wk.webkit.set_data("win", win)
224+ # find and set parent
225+ w = self.wk.get_parent()
226+ while w.get_parent():
227+ w = w.get_parent()
228+ win.set_transient_for(w)
229 return wk.webkit
230
231 def _on_console_message(self, view, message, line, source_id):
232@@ -224,10 +293,13 @@
233 prop = view.get_property(property_spec.name)
234 window = self.get_window()
235 if prop == webkit.LoadStatus.PROVISIONAL:
236+ self.emit("purchase-needs-spinner", True)
237 if window:
238 window.set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH))
239 elif (prop == webkit.LoadStatus.FIRST_VISUALLY_NON_EMPTY_LAYOUT or
240+ prop == webkit.LoadStatus.FAILED or
241 prop == webkit.LoadStatus.FINISHED):
242+ self.emit("purchase-needs-spinner", False)
243 if window:
244 window.set_cursor(None)
245
246
247=== added file 'test/gtk3/test_globalpane.py'
248--- test/gtk3/test_globalpane.py 1970-01-01 00:00:00 +0000
249+++ test/gtk3/test_globalpane.py 2011-12-14 13:06:26 +0000
250@@ -0,0 +1,30 @@
251+#!/usr/bin/python
252+
253+from gi.repository import Gtk, GObject
254+import sys
255+import unittest
256+
257+sys.path.insert(0,"../..")
258+sys.path.insert(0,"..")
259+
260+#from mock import Mock
261+
262+TIMEOUT=300
263+
264+import softwarecenter.paths
265+softwarecenter.paths.datadir = "../data"
266+
267+from softwarecenter.testutils import do_events
268+
269+class TestGlobalPane(unittest.TestCase):
270+
271+ def test_spinner_available(self):
272+ from softwarecenter.ui.gtk3.panes.globalpane import get_test_window
273+ win = get_test_window()
274+ pane = win.get_data("pane")
275+ self.assertNotEqual(pane.spinner, None)
276+ do_events()
277+
278+
279+if __name__ == "__main__":
280+ unittest.main()
281
282=== modified file 'test/gtk3/test_purchase.py'
283--- test/gtk3/test_purchase.py 2011-09-20 09:50:30 +0000
284+++ test/gtk3/test_purchase.py 2011-12-14 13:06:26 +0000
285@@ -20,6 +20,7 @@
286 SoftwareCenterAppGtk3)
287 from softwarecenter.ui.gtk3.panes.availablepane import (
288 AvailablePane)
289+from softwarecenter.testutils import do_events
290
291 class TestPurchase(unittest.TestCase):
292
293@@ -47,6 +48,22 @@
294 # run another one
295 win.destroy()
296
297+ def test_spinner_emits_signals(self):
298+ import softwarecenter.ui.gtk3.views.purchaseview
299+ from softwarecenter.ui.gtk3.views.purchaseview import get_test_window_purchaseview
300+ win = get_test_window_purchaseview()
301+ self._p()
302+ # get the view
303+ view = win.get_data("view")
304+ # ensure "purchase-needs-spinner" signals are send
305+ signal_mock = Mock()
306+ view.connect("purchase-needs-spinner", signal_mock)
307+ view.wk.webkit.load_uri("http://www.ubuntu.com/")
308+ self._p()
309+ self.assertTrue(signal_mock.called)
310+ # run another one
311+ win.destroy()
312+
313
314 def test_reinstall_previous_purchase_display(self):
315 os.environ["PYTHONPATH"]=".."
316@@ -74,8 +91,7 @@
317 context = GObject.main_context_default()
318 for i in range(5):
319 time.sleep(0.1)
320- while context.pending():
321- context.iteration()
322+ do_events()
323
324 if __name__ == "__main__":
325 import logging

Subscribers

People subscribed via source and target branches