Merge lp:~ilidrissi.amine/update-manager/window-main-alerts into lp:update-manager

Proposed by Mohamed Amine Ilidrissi
Status: Merged
Merged at revision: 1881
Proposed branch: lp:~ilidrissi.amine/update-manager/window-main-alerts
Merge into: lp:update-manager
Diff against target: 413 lines (+249/-18)
4 files modified
UpdateManager/Core/AlertWatcher.py (+73/-0)
UpdateManager/UpdateManager.py (+69/-6)
data/glade/UpdateManager.ui (+100/-12)
debian/changelog (+7/-0)
To merge this branch: bzr merge lp:~ilidrissi.amine/update-manager/window-main-alerts
Reviewer Review Type Date Requested Status
Michael Vogt (community) Needs Fixing
Review via email: mp+31091@code.launchpad.net

Description of the change

This branch introduces alerts handling for the update manager, as described in https://wiki.ubuntu.com/SoftwareUpdateHandling#alert.

To post a comment you must log in.
1879. By Mohamed Amine Ilidrissi

merge with trunk

1880. By Mohamed Amine Ilidrissi

modified debian/changelog

1881. By Mohamed Amine Ilidrissi

included another bug in debian/changelog

Revision history for this message
Michael Vogt (mvo) wrote :

Thanks a lot for the branch.

I looked over it and discovered some small issues. If I start update-manager and
I'm not on AC power then I don't get a battery warning. This is because there is
no "change" signal emit (nothing in the power state has changed). So we need to
add a additional check for this on startup.

There is also the lines:
137 if inst_count > 1:
138 + t = _("The updates have already been downloaded, but not installed")
139 + self.button_install.set_sensitive(True)
140 + elif inst_count == 1:
141 + t = _("The update has already been downloaded, but not installed")
142 + self.button_install.set_sensitive(True)
143 + else:
144 + t = _("There is no updates to install")

Those are better written with ngettext, so:
t = ngettext("The update has already been downloaded, but not installed",
             "The updates have already been downloaded, but not installed",
             inst_count)
This will ensure the text can be translated into languages with different plural forms
(there are eg languages that have a different on for one, below 10, more than 10).

I also like the display "Nr items selected" :) I guess its not very important, but it
would be cool to have it back.

All minor nitpicks, if you could address them, that would be very nice.

Thanks,
 Michael

Revision history for this message
Michael Vogt (mvo) :
review: Needs Fixing
1882. By Mohamed Amine IL Idrissi <devildante@devildante-laptop>

merge with trunk

1883. By Mohamed Amine IL Idrissi <devildante@devildante-laptop>

Fixed a bunch of things at mvo's request.

1884. By Mohamed Amine IL Idrissi <devildante@devildante-laptop>

Enums. I like enums.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'UpdateManager/Core/AlertWatcher.py'
2--- UpdateManager/Core/AlertWatcher.py 1970-01-01 00:00:00 +0000
3+++ UpdateManager/Core/AlertWatcher.py 2010-08-10 10:01:00 +0000
4@@ -0,0 +1,73 @@
5+# AlertWatcher.py
6+#
7+# Copyright (c) 2010 Mohamed Amine IL Idrissi
8+#
9+# Author: Mohamed Amine IL Idrissi <ilidrissiamine@gmail.com>
10+#
11+# This program is free software; you can redistribute it and/or
12+# modify it under the terms of the GNU General Public License as
13+# published by the Free Software Foundation; either version 2 of the
14+# License, or (at your option) any later version.
15+#
16+# This program is distributed in the hope that it will be useful,
17+# but WITHOUT ANY WARRANTY; without even the implied warranty of
18+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19+# GNU General Public License for more details.
20+#
21+# You should have received a copy of the GNU General Public License
22+# along with this program; if not, write to the Free Software
23+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
24+# USA
25+
26+import gobject
27+import dbus
28+from dbus.mainloop.glib import DBusGMainLoop
29+
30+class AlertWatcher(gobject.GObject):
31+ """ a class that checks for alerts and reports them, like a battery
32+ or network warning """
33+
34+ __gsignals__ = {"network-alert": (gobject.SIGNAL_RUN_FIRST,
35+ gobject.TYPE_NONE,
36+ (gobject.TYPE_INT,)),
37+ "battery-alert": (gobject.SIGNAL_RUN_FIRST,
38+ gobject.TYPE_NONE,
39+ (gobject.TYPE_BOOLEAN,))
40+ }
41+
42+ def __init__(self):
43+ gobject.GObject.__init__(self)
44+ DBusGMainLoop(set_as_default=True)
45+ self.bus = dbus.Bus(dbus.Bus.TYPE_SYSTEM)
46+ self.network_state = 3 # make it always connected if NM isn't available
47+
48+ def check_alert_state(self):
49+ try:
50+ obj = self.bus.get_object("org.freedesktop.NetworkManager", \
51+ "/org/freedesktop/NetworkManager")
52+ obj.connect_to_signal("StateChanged", self._network_alert, \
53+ dbus_interface="org.freedesktop.NetworkManager")
54+ interface = dbus.Interface(obj, "org.freedesktop.DBus.Properties")
55+ self.network_state = interface.Get("org.freedesktop.NetworkManager", "State")
56+ self._network_alert(self.network_state)
57+
58+ obj = self.bus.get_object('org.freedesktop.UPower',
59+ '/org/freedesktop/UPower')
60+ obj.connect_to_signal("Changed", self._power_changed,
61+ dbus_interface="org.freedesktop.UPower")
62+ self._power_changed()
63+ except dbus.exceptions.DBusException, e:
64+ pass
65+
66+ def _network_alert(self, state):
67+ self.network_state = state
68+ self.emit("network-alert", state)
69+
70+ def _power_changed(self):
71+ obj = self.bus.get_object("org.freedesktop.UPower", \
72+ "/org/freedesktop/UPower")
73+ interface = dbus.Interface(obj, "org.freedesktop.DBus.Properties")
74+ on_battery = interface.Get("org.freedesktop.UPower", "OnBattery")
75+ self.emit("battery-alert", on_battery)
76+
77+
78
79=== modified file 'UpdateManager/UpdateManager.py'
80--- UpdateManager/UpdateManager.py 2010-07-28 13:57:54 +0000
81+++ UpdateManager/UpdateManager.py 2010-08-10 10:01:00 +0000
82@@ -3,10 +3,12 @@
83 # Copyright (c) 2004-2008 Canonical
84 # 2004 Michiel Sikkes
85 # 2005 Martin Willemoes Hansen
86+# 2010 Mohamed Amine IL Idrissi
87 #
88 # Author: Michiel Sikkes <michiel@eyesopened.nl>
89 # Michael Vogt <mvo@debian.org>
90 # Martin Willemoes Hansen <mwh@sysrq.dk>
91+# Mohamed Amine IL Idrissi <ilidrissiamine@gmail.com>
92 #
93 # This program is free software; you can redistribute it and/or
94 # modify it under the terms of the GNU General Public License as
95@@ -73,6 +75,7 @@
96 from Core.UpdateList import UpdateList
97 from Core.MyCache import MyCache, NotEnoughFreeSpaceError
98 from Core.MetaRelease import Dist
99+from Core.AlertWatcher import AlertWatcher
100 from SafeGConfClient import SafeGConfClient
101
102 from DistUpgradeFetcher import DistUpgradeFetcherGtk
103@@ -95,6 +98,13 @@
104 # file that signals if we need to reboot
105 REBOOT_REQUIRED_FILE = "/var/run/reboot-required"
106
107+# NetworkManager enums
108+NM_STATE_UNKNOWN = 0
109+NM_STATE_ASLEEP = 1
110+NM_STATE_CONNECTING = 2
111+NM_STATE_CONNECTED = 3
112+NM_STATE_DISCONNECTED = 4
113+
114 class UpdateManagerDbusControler(dbus.service.Object):
115 """ this is a helper to provide the UpdateManagerIFace """
116 def __init__(self, parent, bus_name,
117@@ -224,15 +234,17 @@
118 self.window_main.set_urgency_hint(True)
119 self.initial_focus_id = self.window_main.connect(
120 "focus-in-event", self.on_initial_focus_in)
121- else:
122- self.warn_on_battery()
123+
124+ # Alert watcher
125+ self.alert_watcher = AlertWatcher()
126+ self.alert_watcher.connect("network-alert", self._on_network_alert)
127+ self.alert_watcher.connect("battery-alert", self._on_battery_alert)
128
129 def on_initial_focus_in(self, widget, event):
130 """callback run on initial focus-in (if started unmapped)"""
131 widget.unstick()
132 widget.set_urgency_hint(False)
133 self.window_main.disconnect(self.initial_focus_id)
134- self.warn_on_battery()
135 return False
136
137 def warn_on_battery(self):
138@@ -458,12 +470,36 @@
139 try:
140 inst_count = self.cache.installCount
141 self.dl_size = self.cache.requiredDownload
142- t = _("Download size: %s\n%s selected.") % (
143- humanize_size(self.dl_size),inst_count)
144+ t = ""
145+ if inst_count >= 1:
146+ t = ngettext("One update has been selected. ",
147+ "%s updates have been selected. " % inst_count,
148+ inst_count)
149+ if self.dl_size != 0:
150+ t += _("%s will be downloaded.") % (humanize_size(self.dl_size))
151+ self.image_downsize.set_sensitive(True)
152+ if self.alert_watcher.network_state != NM_STATE_CONNECTED:
153+ self.button_install.set_sensitive(False)
154+ else:
155+ self.button_install.set_sensitive(True)
156+ else:
157+ if inst_count >= 1:
158+ t += ngettext("The update has already been downloaded, but not installed",
159+ "The updates have already been downloaded, but not installed", inst_count)
160+ self.button_install.set_sensitive(True)
161+ else:
162+ t += _("There is no updates to install")
163+ self.button_install.set_sensitive(False)
164+ self.image_downsize.set_sensitive(False)
165 self.label_downsize.set_text(t)
166+ self.hbox_downsize.show()
167+ self.vbox_alerts.show()
168 except SystemError, e:
169 print "requiredDownload could not be calculated: %s" % e
170- self.label_downsize.set_markup(_("Unknown download size"))
171+ self.label_downsize.set_markup(_("Unknown download size."))
172+ self.image_downsize.set_sensitive(False)
173+ self.hbox_downsize.show()
174+ self.vbox_alerts.show()
175
176 def _get_last_apt_get_update_text(self):
177 """
178@@ -666,6 +702,31 @@
179 self.window_main.set_sensitive(True)
180 self.window_main.window.set_cursor(None)
181
182+ def _on_network_alert(self, watcher, state):
183+ if state == NM_STATE_CONNECTING:
184+ self.label_offline.set_text(_("Connecting..."))
185+ self.button_reload.set_sensitive(False)
186+ self.refresh_updates_count()
187+ self.hbox_offline.show()
188+ self.vbox_alerts.show()
189+ elif state == NM_STATE_CONNECTED:
190+ self.button_reload.set_sensitive(True)
191+ self.refresh_updates_count()
192+ self.hbox_offline.hide()
193+ else:
194+ self.label_offline.set_text(_("You may not be able to check for updates or download new updates."))
195+ self.button_reload.set_sensitive(False)
196+ self.refresh_updates_count()
197+ self.hbox_offline.show()
198+ self.vbox_alerts.show()
199+
200+ def _on_battery_alert(self, watcher, on_battery):
201+ if on_battery:
202+ self.hbox_battery.show()
203+ self.vbox_alerts.show()
204+ else:
205+ self.hbox_battery.hide()
206+
207 def row_activated(self, treeview, path, column):
208 iter = self.store.get_iter(path)
209 pkg = self.store.get_value(iter, LIST_PKG)
210@@ -842,6 +903,7 @@
211 self.update_count()
212 self.setBusy(False)
213 self.check_all_updates_installable()
214+ self.refresh_updates_count()
215 return False
216
217 def dist_no_longer_supported(self, meta_release):
218@@ -999,4 +1061,5 @@
219
220 self.fillstore()
221 self.check_auto_update()
222+ self.alert_watcher.check_alert_state()
223 gtk.main()
224
225=== modified file 'data/glade/UpdateManager.ui'
226--- data/glade/UpdateManager.ui 2010-06-10 14:42:23 +0000
227+++ data/glade/UpdateManager.ui 2010-08-10 10:01:00 +0000
228@@ -48,7 +48,7 @@
229 <property name="wrap">True</property>
230 <attributes>
231 <attribute name="weight" value="bold"/>
232- <attribute name="scale" value="1,000000"/>
233+ <attribute name="scale" value="1.000000"/>
234 </attributes>
235 </object>
236 <packing>
237@@ -179,7 +179,6 @@
238 <child>
239 <object class="GtkVBox" id="vbox12">
240 <property name="visible">True</property>
241- <property name="spacing">6</property>
242 <child>
243 <object class="GtkScrolledWindow" id="scrolledwindow_update">
244 <property name="visible">True</property>
245@@ -208,15 +207,106 @@
246 </packing>
247 </child>
248 <child>
249+ <object class="GtkVBox" id="vbox_alerts">
250+ <property name="spacing">3</property>
251+ <child>
252+ <object class="GtkHBox" id="hbox_downsize">
253+ <property name="spacing">12</property>
254+ <child>
255+ <object class="GtkImage" id="image_downsize">
256+ <property name="visible">True</property>
257+ <property name="icon_name">aptdaemon-download</property>
258+ </object>
259+ <packing>
260+ <property name="expand">False</property>
261+ <property name="position">0</property>
262+ </packing>
263+ </child>
264+ <child>
265+ <object class="GtkLabel" id="label_downsize">
266+ <property name="visible">True</property>
267+ <property name="xalign">0</property>
268+ <property name="label">
269+</property>
270+ </object>
271+ <packing>
272+ <property name="position">1</property>
273+ </packing>
274+ </child>
275+ </object>
276+ <packing>
277+ <property name="position">0</property>
278+ </packing>
279+ </child>
280+ <child>
281+ <object class="GtkHBox" id="hbox_battery">
282+ <property name="spacing">12</property>
283+ <child>
284+ <object class="GtkImage" id="image_battery">
285+ <property name="visible">True</property>
286+ <property name="icon_name">battery</property>
287+ </object>
288+ <packing>
289+ <property name="expand">False</property>
290+ <property name="position">0</property>
291+ </packing>
292+ </child>
293+ <child>
294+ <object class="GtkLabel" id="label_battery">
295+ <property name="visible">True</property>
296+ <property name="label" translatable="yes">It&#x2019;s safer to connect the computer to AC power before updating.</property>
297+ </object>
298+ <packing>
299+ <property name="expand">False</property>
300+ <property name="position">1</property>
301+ </packing>
302+ </child>
303+ </object>
304+ <packing>
305+ <property name="position">1</property>
306+ </packing>
307+ </child>
308+ <child>
309+ <object class="GtkHBox" id="hbox_offline">
310+ <property name="spacing">12</property>
311+ <child>
312+ <object class="GtkImage" id="image_offline">
313+ <property name="visible">True</property>
314+ <property name="icon_name">network-offline</property>
315+ </object>
316+ <packing>
317+ <property name="expand">False</property>
318+ <property name="position">0</property>
319+ </packing>
320+ </child>
321+ <child>
322+ <object class="GtkLabel" id="label_offline">
323+ <property name="visible">True</property>
324+ </object>
325+ <packing>
326+ <property name="expand">False</property>
327+ <property name="position">1</property>
328+ </packing>
329+ </child>
330+ </object>
331+ <packing>
332+ <property name="position">2</property>
333+ </packing>
334+ </child>
335+ </object>
336+ <packing>
337+ <property name="expand">False</property>
338+ <property name="fill">False</property>
339+ <property name="position">1</property>
340+ </packing>
341+ </child>
342+ <child>
343 <object class="GtkHBox" id="hbox15">
344 <property name="visible">True</property>
345 <property name="spacing">12</property>
346 <child>
347- <object class="GtkLabel" id="label_downsize">
348+ <object class="GtkLabel" id="label_placeholder">
349 <property name="visible">True</property>
350- <property name="xalign">0</property>
351- <property name="label">
352-</property>
353 </object>
354 <packing>
355 <property name="position">0</property>
356@@ -228,7 +318,7 @@
357 <property name="spacing">6</property>
358 <property name="homogeneous">True</property>
359 <child>
360- <object class="GtkButton" id="button1">
361+ <object class="GtkButton" id="button_reload">
362 <property name="visible">True</property>
363 <property name="can_focus">True</property>
364 <property name="can_default">True</property>
365@@ -326,9 +416,6 @@
366 <property name="position">1</property>
367 </packing>
368 </child>
369- <child>
370- <placeholder/>
371- </child>
372 </object>
373 <packing>
374 <property name="expand">False</property>
375@@ -338,11 +425,12 @@
376 </object>
377 <packing>
378 <property name="expand">False</property>
379- <property name="position">1</property>
380+ <property name="position">2</property>
381 </packing>
382 </child>
383 </object>
384 <packing>
385+ <property name="padding">6</property>
386 <property name="position">3</property>
387 </packing>
388 </child>
389@@ -508,8 +596,8 @@
390 <property name="can_default">True</property>
391 <property name="receives_default">False</property>
392 <property name="use_stock">True</property>
393+ <accelerator key="Q" signal="clicked" modifiers="GDK_CONTROL_MASK"/>
394 <accelerator key="W" signal="clicked" modifiers="GDK_CONTROL_MASK"/>
395- <accelerator key="Q" signal="clicked" modifiers="GDK_CONTROL_MASK"/>
396 </object>
397 <packing>
398 <property name="expand">False</property>
399
400=== modified file 'debian/changelog'
401--- debian/changelog 2010-08-05 20:55:55 +0000
402+++ debian/changelog 2010-08-10 10:01:00 +0000
403@@ -1,3 +1,10 @@
404+update-manager (1:0.142.6) UNRELEASED; urgency=low
405+
406+ * Implemented battery and network alerts directly in the main window.
407+ LP: #484249, #426708, #426710, #494772
408+
409+ -- Michael Vogt <michael.vogt@ubuntu.com> Wed, 28 Jul 2010 15:18:20 +0200
410+
411 update-manager (1:0.142.5) maverick; urgency=low
412
413 * more python-apt 0.8 porting

Subscribers

People subscribed via source and target branches

to status/vote changes: