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
=== modified file 'softwarecenter/ui/gtk3/panes/availablepane.py'
--- softwarecenter/ui/gtk3/panes/availablepane.py 2011-11-29 21:50:55 +0000
+++ softwarecenter/ui/gtk3/panes/availablepane.py 2011-12-14 13:06:26 +0000
@@ -138,6 +138,7 @@
138 self.purchase_view.connect("purchase-succeeded", self.on_purchase_succeeded)138 self.purchase_view.connect("purchase-succeeded", self.on_purchase_succeeded)
139 self.purchase_view.connect("purchase-failed", self.on_purchase_failed)139 self.purchase_view.connect("purchase-failed", self.on_purchase_failed)
140 self.purchase_view.connect("purchase-cancelled-by-user", self.on_purchase_cancelled_by_user)140 self.purchase_view.connect("purchase-cancelled-by-user", self.on_purchase_cancelled_by_user)
141 self.purchase_view.connect("purchase-needs-spinner", self.on_purchase_needs_spinner)
141 # categories, appview and details into the notebook in the bottom142 # categories, appview and details into the notebook in the bottom
142 self.scroll_categories = Gtk.ScrolledWindow()143 self.scroll_categories = Gtk.ScrolledWindow()
143 self.scroll_categories.set_policy(Gtk.PolicyType.AUTOMATIC, 144 self.scroll_categories.set_policy(Gtk.PolicyType.AUTOMATIC,
@@ -226,6 +227,10 @@
226 self.display_purchase)227 self.display_purchase)
227 return228 return
228229
230 def on_purchase_needs_spinner(self, appmanager, active):
231 vm = get_viewmanager()
232 vm.set_spinner_active(active)
233
229 def on_purchase_succeeded(self, widget):234 def on_purchase_succeeded(self, widget):
230 # switch to the details page to display the transaction is in progress235 # switch to the details page to display the transaction is in progress
231 self._return_to_appdetails_view()236 self._return_to_appdetails_view()
232237
=== modified file 'softwarecenter/ui/gtk3/panes/globalpane.py'
--- softwarecenter/ui/gtk3/panes/globalpane.py 2011-09-15 09:36:39 +0000
+++ softwarecenter/ui/gtk3/panes/globalpane.py 2011-12-14 13:06:26 +0000
@@ -47,6 +47,12 @@
47 #~ self.init_atk_name(self.searchentry, "searchentry")47 #~ self.init_atk_name(self.searchentry, "searchentry")
48 self.searchentry = vm.get_global_searchentry()48 self.searchentry = vm.get_global_searchentry()
49 self._insert_as_tool_item(self.searchentry, -1)49 self._insert_as_tool_item(self.searchentry, -1)
50
51 # spinner
52 self.spinner = vm.get_global_spinner()
53 self.spinner.set_size_request(StockEms.XLARGE, StockEms.XLARGE)
54 self._insert_as_tool_item(self.spinner, -1)
55
50 if self.get_direction() != Gtk.TextDirection.RTL:56 if self.get_direction() != Gtk.TextDirection.RTL:
51 _widget_set_margins(self.searchentry, right=StockEms.MEDIUM)57 _widget_set_margins(self.searchentry, right=StockEms.MEDIUM)
52 else:58 else:
@@ -77,6 +83,7 @@
77 p = GlobalPane(vm, datadir, db, cache, icons)83 p = GlobalPane(vm, datadir, db, cache, icons)
7884
79 win = Gtk.Window()85 win = Gtk.Window()
86 win.set_data("pane", p)
80 win.connect("destroy", Gtk.main_quit)87 win.connect("destroy", Gtk.main_quit)
81 win.add(p)88 win.add(p)
82 win.show_all()89 win.show_all()
8390
=== modified file 'softwarecenter/ui/gtk3/session/viewmanager.py'
--- softwarecenter/ui/gtk3/session/viewmanager.py 2011-11-09 09:49:39 +0000
+++ softwarecenter/ui/gtk3/session/viewmanager.py 2011-12-14 13:06:26 +0000
@@ -49,6 +49,7 @@
49 "right-clicked", self.on_nav_forward_clicked)49 "right-clicked", self.on_nav_forward_clicked)
5050
51 self.navhistory = NavigationHistory(self.back_forward, options)51 self.navhistory = NavigationHistory(self.back_forward, options)
52 self.spinner = Gtk.Spinner()
5253
53 self.all_views = {}54 self.all_views = {}
54 self.view_to_pane = {}55 self.view_to_pane = {}
@@ -95,9 +96,22 @@
95 if page_id == v:96 if page_id == v:
96 return k97 return k
9798
99 def set_spinner_active(self, active):
100 if active:
101 self.spinner.show()
102 self.spinner.start()
103 else:
104 self.spinner.stop()
105 self.spinner.hide()
106
98 def set_active_view(self, view_id):107 def set_active_view(self, view_id):
108 # no views yet
99 if not self.all_views: 109 if not self.all_views:
100 return110 return
111 # if the view switches, ensure that the global spinner is hidden
112 self.spinner.hide()
113
114 # emit signal
101 self.emit('view-changed', view_id)115 self.emit('view-changed', view_id)
102 page_id = self.all_views[view_id]116 page_id = self.all_views[view_id]
103 view_widget = self.get_view_widget(view_id)117 view_widget = self.get_view_widget(view_id)
@@ -178,6 +192,7 @@
178 self.search_entry.hide()192 self.search_entry.hide()
179 else:193 else:
180 self.search_entry.show()194 self.search_entry.show()
195 self.spinner.hide()
181 return196 return
182197
183 def nav_back(self):198 def nav_back(self):
@@ -194,3 +209,6 @@
194209
195 def get_global_backforward(self):210 def get_global_backforward(self):
196 return self.back_forward211 return self.back_forward
212
213 def get_global_spinner(self):
214 return self.spinner
197215
=== modified file 'softwarecenter/ui/gtk3/views/purchaseview.py'
--- softwarecenter/ui/gtk3/views/purchaseview.py 2011-12-12 09:15:52 +0000
+++ softwarecenter/ui/gtk3/views/purchaseview.py 2011-12-14 13:06:26 +0000
@@ -20,11 +20,13 @@
20from gi.repository import GObject20from gi.repository import GObject
21from gi.repository import Gtk21from gi.repository import Gtk
22from gi.repository import Gdk22from gi.repository import Gdk
23from gi.repository import Pango
23import logging24import logging
24import os25import os
25import json26import json
26import sys27import sys
27import urllib28import urllib
29import urlparse
28from gi.repository import WebKit as webkit30from gi.repository import WebKit as webkit
29session = webkit.get_default_session()31session = webkit.get_default_session()
30session.set_property("ssl-ca-file", "/etc/ssl/certs/ca-certificates.crt")32session.set_property("ssl-ca-file", "/etc/ssl/certs/ca-certificates.crt")
@@ -55,17 +57,70 @@
55 #headers.foreach(_show_header, None)57 #headers.foreach(_show_header, None)
5658
5759
58class ScrolledWebkitWindow(Gtk.ScrolledWindow):60class ScrolledWebkitWindow(Gtk.VBox):
5961
60 def __init__(self):62 def __init__(self, include_progress_ui=False):
61 super(ScrolledWebkitWindow, self).__init__()63 super(ScrolledWebkitWindow, self).__init__()
64 # get webkit
62 self.webkit = LocaleAwareWebView()65 self.webkit = LocaleAwareWebView()
63 settings = self.webkit.get_settings()66 settings = self.webkit.get_settings()
64 settings.set_property("enable-plugins", False)67 settings.set_property("enable-plugins", False)
65 self.webkit.show()68 # add progress UI if needed
69 if include_progress_ui:
70 self._add_progress_ui()
71 # create main webkitview
72 self.scroll = Gtk.ScrolledWindow()
73 self.scroll.set_policy(Gtk.PolicyType.AUTOMATIC,
74 Gtk.PolicyType.AUTOMATIC)
75 self.pack_start(self.scroll, True, True, 0)
66 # embed the webkit view in a scrolled window76 # embed the webkit view in a scrolled window
67 self.add(self.webkit)77 self.scroll.add(self.webkit)
68 self.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)78 self.show_all()
79 def _add_progress_ui(self):
80 # create toolbar box
81 self.header = Gtk.HBox()
82 # add spinner
83 self.spinner = Gtk.Spinner()
84 self.header.pack_start(self.spinner, False, False, 6)
85 # add a url to the toolbar
86 self.url = Gtk.Label()
87 self.url.set_ellipsize(Pango.EllipsizeMode.END)
88 self.url.set_alignment(0.0, 0.5)
89 self.url.set_text("")
90 self.header.pack_start(self.url, True, True, 0)
91 # frame around the box
92 self.frame = Gtk.Frame()
93 self.frame.set_border_width(3)
94 self.frame.add(self.header)
95 self.pack_start(self.frame, False, False, 6)
96 # connect the webkit stuff
97 self.webkit.connect("notify::uri", self._on_uri_changed)
98 self.webkit.connect("notify::load-status", self._on_load_status_changed)
99 def _on_uri_changed(self, view, pspec):
100 prop = pspec.name
101 uri = view.get_property(prop)
102 # the full uri is irellevant for the purchase view, but it is
103 # interessting to know what protocol/netloc is in use so that the
104 # user can verify its https on sites he is expecting
105 scheme, netloc, path, params, query, frag = urlparse.urlparse(uri)
106 if scheme == "file" and netloc == "":
107 self.url.set_text("")
108 else:
109 self.url.set_text("%s://%s" % (scheme, netloc))
110 # start spinner when the uri changes
111 #self.spinner.start()
112 def _on_load_status_changed(self, view, pspec):
113 prop = pspec.name
114 status = view.get_property(prop)
115 #print status
116 if status == webkit.LoadStatus.PROVISIONAL:
117 self.spinner.start()
118 self.spinner.show()
119 if (status == webkit.LoadStatus.FINISHED or
120 status == webkit.LoadStatus.FAILED):
121 self.spinner.stop()
122 self.spinner.hide()
123
69124
70125
71class PurchaseView(Gtk.VBox):126class PurchaseView(Gtk.VBox):
@@ -119,6 +174,10 @@
119 'purchase-cancelled-by-user' : (GObject.SignalFlags.RUN_LAST,174 'purchase-cancelled-by-user' : (GObject.SignalFlags.RUN_LAST,
120 None,175 None,
121 ()),176 ()),
177 'purchase-needs-spinner' : (GObject.SignalFlags.RUN_LAST,
178 None,
179 (bool, )),
180
122 }181 }
123182
124 def __init__(self):183 def __init__(self):
@@ -179,6 +238,7 @@
179 238
180 def _on_create_web_view(self, view, frame):239 def _on_create_web_view(self, view, frame):
181 win = Gtk.Window()240 win = Gtk.Window()
241<<<<<<< TREE
182 win.set_size_request(500, 400)242 win.set_size_request(500, 400)
183 # set transient parent243 # set transient parent
184 parent = self244 parent = self
@@ -187,11 +247,20 @@
187 win.set_transient_for(parent)247 win.set_transient_for(parent)
188 # and add the webkit view248 # and add the webkit view
189 wk = ScrolledWebkitWindow()249 wk = ScrolledWebkitWindow()
250=======
251 win.set_size_request(400, 400)
252 wk = ScrolledWebkitWindow(include_progress_ui=True)
253>>>>>>> MERGE-SOURCE
190 wk.webkit.connect("close-web-view", self._on_close_web_view)254 wk.webkit.connect("close-web-view", self._on_close_web_view)
191 win.add(wk)255 win.add(wk)
192 win.show_all()256 win.show_all()
193 # make sure close will work later257 # make sure close will work later
194 wk.webkit.set_data("win", win)258 wk.webkit.set_data("win", win)
259 # find and set parent
260 w = self.wk.get_parent()
261 while w.get_parent():
262 w = w.get_parent()
263 win.set_transient_for(w)
195 return wk.webkit264 return wk.webkit
196265
197 def _on_console_message(self, view, message, line, source_id):266 def _on_console_message(self, view, message, line, source_id):
@@ -224,10 +293,13 @@
224 prop = view.get_property(property_spec.name)293 prop = view.get_property(property_spec.name)
225 window = self.get_window()294 window = self.get_window()
226 if prop == webkit.LoadStatus.PROVISIONAL:295 if prop == webkit.LoadStatus.PROVISIONAL:
296 self.emit("purchase-needs-spinner", True)
227 if window:297 if window:
228 window.set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH))298 window.set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH))
229 elif (prop == webkit.LoadStatus.FIRST_VISUALLY_NON_EMPTY_LAYOUT or299 elif (prop == webkit.LoadStatus.FIRST_VISUALLY_NON_EMPTY_LAYOUT or
300 prop == webkit.LoadStatus.FAILED or
230 prop == webkit.LoadStatus.FINISHED):301 prop == webkit.LoadStatus.FINISHED):
302 self.emit("purchase-needs-spinner", False)
231 if window:303 if window:
232 window.set_cursor(None)304 window.set_cursor(None)
233305
234306
=== added file 'test/gtk3/test_globalpane.py'
--- test/gtk3/test_globalpane.py 1970-01-01 00:00:00 +0000
+++ test/gtk3/test_globalpane.py 2011-12-14 13:06:26 +0000
@@ -0,0 +1,30 @@
1#!/usr/bin/python
2
3from gi.repository import Gtk, GObject
4import sys
5import unittest
6
7sys.path.insert(0,"../..")
8sys.path.insert(0,"..")
9
10#from mock import Mock
11
12TIMEOUT=300
13
14import softwarecenter.paths
15softwarecenter.paths.datadir = "../data"
16
17from softwarecenter.testutils import do_events
18
19class TestGlobalPane(unittest.TestCase):
20
21 def test_spinner_available(self):
22 from softwarecenter.ui.gtk3.panes.globalpane import get_test_window
23 win = get_test_window()
24 pane = win.get_data("pane")
25 self.assertNotEqual(pane.spinner, None)
26 do_events()
27
28
29if __name__ == "__main__":
30 unittest.main()
031
=== modified file 'test/gtk3/test_purchase.py'
--- test/gtk3/test_purchase.py 2011-09-20 09:50:30 +0000
+++ test/gtk3/test_purchase.py 2011-12-14 13:06:26 +0000
@@ -20,6 +20,7 @@
20 SoftwareCenterAppGtk3)20 SoftwareCenterAppGtk3)
21from softwarecenter.ui.gtk3.panes.availablepane import (21from softwarecenter.ui.gtk3.panes.availablepane import (
22 AvailablePane)22 AvailablePane)
23from softwarecenter.testutils import do_events
2324
24class TestPurchase(unittest.TestCase):25class TestPurchase(unittest.TestCase):
2526
@@ -47,6 +48,22 @@
47 # run another one48 # run another one
48 win.destroy()49 win.destroy()
4950
51 def test_spinner_emits_signals(self):
52 import softwarecenter.ui.gtk3.views.purchaseview
53 from softwarecenter.ui.gtk3.views.purchaseview import get_test_window_purchaseview
54 win = get_test_window_purchaseview()
55 self._p()
56 # get the view
57 view = win.get_data("view")
58 # ensure "purchase-needs-spinner" signals are send
59 signal_mock = Mock()
60 view.connect("purchase-needs-spinner", signal_mock)
61 view.wk.webkit.load_uri("http://www.ubuntu.com/")
62 self._p()
63 self.assertTrue(signal_mock.called)
64 # run another one
65 win.destroy()
66
5067
51 def test_reinstall_previous_purchase_display(self):68 def test_reinstall_previous_purchase_display(self):
52 os.environ["PYTHONPATH"]=".."69 os.environ["PYTHONPATH"]=".."
@@ -74,8 +91,7 @@
74 context = GObject.main_context_default()91 context = GObject.main_context_default()
75 for i in range(5):92 for i in range(5):
76 time.sleep(0.1)93 time.sleep(0.1)
77 while context.pending():94 do_events()
78 context.iteration()
7995
80if __name__ == "__main__":96if __name__ == "__main__":
81 import logging97 import logging

Subscribers

People subscribed via source and target branches