29
29
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
32
from __future__ import absolute_import, print_function
34
35
gi.require_version("Gtk", "3.0")
35
36
from gi.repository import GLib
36
37
from gi.repository import Gtk
75
74
# - screen reader does not say "Downloaded" for downloaded updates
77
(LIST_NAME, LIST_UPDATE_DATA, LIST_SIZE, LIST_TOGGLE_ACTIVE,
78
LIST_SENSITIVE) = range(5)
86
80
# NetworkManager enums
87
81
from .Core.roam import NetworkManagerHelper
91
85
def __init__(self, groups, group, item):
92
86
self.groups = groups if groups else []
97
91
class CellAreaPackage(Gtk.CellAreaBox):
98
92
"""This CellArea lays our package cells side by side, without allocating
99
width for a cell if it isn't present (like icons for header labels).
100
We assume that the last cell should be expanded to fill remaining space,
101
and other cells have a fixed width.
93
width for a cell if it isn't present (like icons for header labels).
94
We assume that the last cell should be expanded to fill remaining space,
95
and other cells have a fixed width.
104
98
def __init__(self, indent_toplevel=False):
107
101
self.column = None
108
102
self.cached_cell_size = {}
110
def do_foreach_alloc(
111
self, context, widget, cell_area_in, bg_area_in, callback
104
def do_foreach_alloc(self, context, widget, cell_area_in, bg_area_in,
115
108
def gather(cell, data):
190
183
cell_start = self.get_cell_start(widget)
191
184
cell_area.width = cell_area.width + cell_area.x - cell_start
192
185
cell_area.x = cell_start
193
return Gtk.CellAreaBox.do_event(
194
self, context, widget, event, cell_area, flags
186
return Gtk.CellAreaBox.do_event(self, context, widget, event,
197
189
def get_cell_start(self, widget):
198
190
if not self.column:
216
208
class UpdatesAvailable(InternalDialog):
217
209
APP_INSTALL_ICONS_PATH = "/usr/share/app-install/icons"
219
def __init__(self, window_main, header=None, desc=None, need_reboot=False):
211
def __init__(self, window_main, header=None, desc=None,
220
213
InternalDialog.__init__(self, window_main)
222
215
self.window_main = window_main
227
220
self.custom_desc = desc
228
221
self.need_reboot = need_reboot
230
content_ui_path = os.path.join(
231
self.datadir, "gtkbuilder/UpdateManager.ui"
223
content_ui_path = os.path.join(self.datadir,
224
"gtkbuilder/UpdateManager.ui")
233
225
self._load_ui(content_ui_path, "pane_updates_available")
234
226
self.set_content_widget(self.pane_updates_available)
252
244
# setup the help viewer and disable the help button if there
253
245
# is no viewer available
254
# self.help_viewer = HelpViewer("update-manager")
255
# if self.help_viewer.check() == False:
246
#self.help_viewer = HelpViewer("update-manager")
247
#if self.help_viewer.check() == False:
256
248
# self.button_help.set_sensitive(False)
258
250
self.add_settings_button()
259
self.button_close = self.add_button(
260
Gtk.STOCK_CANCEL, self.window_main.close
262
self.button_install = self.add_button(
263
_("Install Now"), self.on_button_install_clicked
251
self.button_close = self.add_button(Gtk.STOCK_CANCEL,
252
self.window_main.close)
253
self.button_install = self.add_button(_("Install Now"),
254
self.on_button_install_clicked)
265
255
self.focus_button = self.button_install
267
257
# create text view
275
265
self.store = Gtk.TreeStore(str, GObject.TYPE_PYOBJECT, str, bool, bool)
276
266
self.treeview_update.set_model(None)
278
self.image_restart.set_from_gicon(
279
self.get_restart_icon(), Gtk.IconSize.BUTTON
268
self.image_restart.set_from_gicon(self.get_restart_icon(),
282
271
restart_icon_renderer = Gtk.CellRendererPixbuf()
283
272
restart_icon_renderer.set_property("xpad", 4)
288
277
restart_column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
289
278
restart_column.set_fixed_width(20)
290
279
self.treeview_update.append_column(restart_column)
291
restart_column.set_cell_data_func(
292
restart_icon_renderer, self.restart_icon_renderer_data_func
280
restart_column.set_cell_data_func(restart_icon_renderer,
281
self.restart_icon_renderer_data_func)
295
283
self.pkg_cell_area = CellAreaPackage(False)
296
284
pkg_column = Gtk.TreeViewColumn.new_with_area(self.pkg_cell_area)
304
292
pkg_toggle_renderer.set_property("ypad", 2)
305
293
pkg_toggle_renderer.connect("toggled", self.on_update_toggled)
306
294
pkg_column.pack_start(pkg_toggle_renderer, False)
307
pkg_column.add_attribute(
308
pkg_toggle_renderer, "active", LIST_TOGGLE_ACTIVE
310
pkg_column.add_attribute(
311
pkg_toggle_renderer, "sensitive", LIST_SENSITIVE
313
pkg_column.set_cell_data_func(
314
pkg_toggle_renderer, self.pkg_toggle_renderer_data_func
295
pkg_column.add_attribute(pkg_toggle_renderer,
296
'active', LIST_TOGGLE_ACTIVE)
297
pkg_column.add_attribute(pkg_toggle_renderer,
298
'sensitive', LIST_SENSITIVE)
299
pkg_column.set_cell_data_func(pkg_toggle_renderer,
300
self.pkg_toggle_renderer_data_func)
317
302
pkg_icon_renderer = Gtk.CellRendererPixbuf()
318
303
pkg_icon_renderer.set_property("ypad", 2)
319
304
pkg_icon_renderer.set_property("stock-size", Gtk.IconSize.MENU)
320
305
pkg_column.pack_start(pkg_icon_renderer, False)
321
pkg_column.set_cell_data_func(
322
pkg_icon_renderer, self.pkg_icon_renderer_data_func
306
pkg_column.set_cell_data_func(pkg_icon_renderer,
307
self.pkg_icon_renderer_data_func)
325
309
pkg_label_renderer = Gtk.CellRendererText()
326
310
pkg_label_renderer.set_property("ypad", 2)
327
311
pkg_label_renderer.set_property("ellipsize", Pango.EllipsizeMode.END)
328
312
pkg_column.pack_start(pkg_label_renderer, True)
329
pkg_column.set_cell_data_func(
330
pkg_label_renderer, self.pkg_label_renderer_data_func
313
pkg_column.set_cell_data_func(pkg_label_renderer,
314
self.pkg_label_renderer_data_func)
333
316
size_renderer = Gtk.CellRendererText()
334
317
size_renderer.set_property("xpad", 6)
336
319
size_renderer.set_property("xalign", 1)
337
320
# 1.0/1.2 == PANGO.Scale.SMALL. Constant is not (yet) introspected.
338
321
size_renderer.set_property("scale", 1.0 / 1.2)
339
size_column = Gtk.TreeViewColumn(
340
_("Download"), size_renderer, text=LIST_SIZE
322
size_column = Gtk.TreeViewColumn(_("Download"), size_renderer,
342
324
size_column.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
343
size_column.add_attribute(size_renderer, "sensitive", LIST_SENSITIVE)
325
size_column.add_attribute(size_renderer,
326
'sensitive', LIST_SENSITIVE)
344
327
self.treeview_update.append_column(size_column)
346
329
self.treeview_update.set_headers_visible(True)
349
332
self.treeview_update.set_fixed_height_mode(False)
350
333
self.treeview_update.set_expander_column(pkg_column)
351
334
self.treeview_update.set_search_column(LIST_NAME)
352
self.treeview_update.connect(
353
"button-press-event", self.on_treeview_button_press
335
self.treeview_update.connect("button-press-event",
336
self.on_treeview_button_press)
356
338
# init show version
357
339
self.show_versions = self.settings.get_boolean("show-versions")
358
340
# init summary_before_name
359
341
self.summary_before_name = self.settings.get_boolean(
360
"summary-before-name"
342
"summary-before-name")
364
345
self.expander_details.set_expanded(
365
self.settings.get_boolean("show-details")
346
self.settings.get_boolean("show-details"))
367
347
self.expander_details.connect("activate", self.pre_activate_details)
368
self.expander_details.connect(
369
"notify::expanded", self.activate_details
348
self.expander_details.connect("notify::expanded",
349
self.activate_details)
371
350
self.expander_desc.connect("notify::expanded", self.activate_desc)
373
352
# If auto-updates are on, change cancel label
374
353
self.notifier_settings = Gio.Settings.new("com.ubuntu.update-notifier")
375
354
self.notifier_settings.connect(
376
"changed::auto-launch", lambda s, p: self.update_close_button()
355
"changed::auto-launch",
356
lambda s, p: self.update_close_button())
378
357
self.update_close_button()
381
360
self.alert_watcher = AlertWatcher()
382
361
self.alert_watcher.connect("network-alert", self._on_network_alert)
383
362
self.alert_watcher.connect("battery-alert", self._on_battery_alert)
384
self.alert_watcher.connect(
385
"network-3g-alert", self._on_network_3g_alert
363
self.alert_watcher.connect("network-3g-alert",
364
self._on_network_3g_alert)
389
367
InternalDialog.stop(self)
418
395
def pkg_requires_restart(self, pkg):
419
396
if pkg is None or pkg.candidate is None:
421
restart_condition = pkg.candidate.record.get("Restart-Required")
422
return restart_condition == "system"
398
restart_condition = pkg.candidate.record.get('Restart-Required')
399
return restart_condition == 'system'
424
401
def get_restart_icon(self):
425
402
# FIXME: Non-standard, incorrect icon name (from app category).
426
403
# Theme support for what we want seems to be lacking.
427
restart_icon_names = [
428
"view-refresh-symbolic",
404
restart_icon_names = ['view-refresh-symbolic',
432
407
return Gio.ThemedIcon.new_from_names(restart_icon_names)
434
def restart_icon_renderer_data_func(
435
self, cell_layout, renderer, model, iter, user_data
409
def restart_icon_renderer_data_func(self, cell_layout, renderer, model,
437
411
data = model.get_value(iter, LIST_UPDATE_DATA)
438
412
sensitive = model.get_value(iter, LIST_SENSITIVE)
439
413
path = model.get_path(iter)
460
433
renderer.set_property("gicon", gicon)
462
def pkg_toggle_renderer_data_func(
463
self, cell_layout, renderer, model, iter, user_data
435
def pkg_toggle_renderer_data_func(self, cell_layout, renderer, model,
465
437
data = model.get_value(iter, LIST_UPDATE_DATA)
467
439
activatable = False
492
464
renderer.set_property("activatable", activatable)
493
465
renderer.set_property("inconsistent", inconsistent)
495
def pkg_icon_renderer_data_func(
496
self, cell_layout, renderer, model, iter, user_data
467
def pkg_icon_renderer_data_func(self, cell_layout, renderer, model,
498
469
data = model.get_value(iter, LIST_UPDATE_DATA)
508
479
def get_app_install_icon(self, icon):
509
480
"""Any application icon is coming from app-install-data's desktop
510
files, which refer to icons from app-install-data's icon directory.
511
So we look them up here."""
481
files, which refer to icons from app-install-data's icon directory.
482
So we look them up here."""
513
484
if not isinstance(icon, Gio.ThemedIcon):
514
485
return icon # shouldn't happen
516
info = self.app_icons.choose_icon(
517
icon.get_names(), 16, Gtk.IconLookupFlags.FORCE_SIZE
487
info = self.app_icons.choose_icon(icon.get_names(), 16,
488
Gtk.IconLookupFlags.FORCE_SIZE)
519
489
if info is not None:
520
490
return Gio.FileIcon.new(Gio.File.new_for_path(info.get_filename()))
522
492
return icon # Assume it's in one of the user's themes
524
def pkg_label_renderer_data_func(
525
self, cell_layout, renderer, model, iter, user_data
494
def pkg_label_renderer_data_func(self, cell_layout, renderer, model,
527
496
data = model.get_value(iter, LIST_UPDATE_DATA)
528
497
sensitive = model.get_value(iter, LIST_SENSITIVE)
529
498
name = GLib.markup_escape_text(model.get_value(iter, LIST_NAME))
549
518
for line in lines:
550
519
end_iter = changes_buffer.get_end_iter()
551
520
version_match = re.match(
552
r"^%s \((.*)\)(.*)\;.*$" % re.escape(srcpkg), line
554
# bullet_match = re.match("^.*[\*-]", line)
521
r'^%s \((.*)\)(.*)\;.*$' % re.escape(srcpkg), line)
522
#bullet_match = re.match("^.*[\*-]", line)
555
523
author_match = re.match("^.*--.*<.*@.*>.*$", line)
556
524
if version_match:
557
525
version = version_match.group(1)
558
# upload_archive = version_match.group(2).strip()
526
#upload_archive = version_match.group(2).strip()
559
527
version_text = _("Version %s: \n") % version
560
changes_buffer.insert_with_tags_by_name(
561
end_iter, version_text, "versiontag"
528
changes_buffer.insert_with_tags_by_name(end_iter, version_text,
566
533
changes_buffer.insert(end_iter, line + "\n")
577
544
data = model.get_value(iter, LIST_UPDATE_DATA)
581
and data.group is not None
582
and data.group.core_item is not None
546
if (item is None and data.group is not None
547
and data.group.core_item is not None):
584
548
item = data.group.core_item
588
or item.pkg.candidate is None
589
or item.pkg.candidate.description is None
549
if (item is None or item.pkg is None
550
or item.pkg.candidate is None
551
or item.pkg.candidate.description is None):
591
552
changes_buffer = self.textview_changes.get_buffer()
592
553
changes_buffer.set_text("")
593
554
desc_buffer = self.textview_descr.get_buffer()
598
559
self.notebook_details.set_sensitive(True)
599
560
# do some regular expression magic on the description
600
561
# Add a newline before each bullet
601
p = re.compile(r"^(\s|\t)*(\*|0|-)", re.MULTILINE)
602
long_desc = p.sub("\n*", long_desc)
562
p = re.compile(r'^(\s|\t)*(\*|0|-)', re.MULTILINE)
563
long_desc = p.sub('\n*', long_desc)
603
564
# replace all newlines by spaces
604
p = re.compile(r"\n", re.MULTILINE)
565
p = re.compile(r'\n', re.MULTILINE)
605
566
long_desc = p.sub(" ", long_desc)
606
567
# replace all multiple spaces by newlines
607
p = re.compile(r"\s\s+", re.MULTILINE)
568
p = re.compile(r'\s\s+', re.MULTILINE)
608
569
long_desc = p.sub("\n", long_desc)
609
long_desc = "Package: %s\n%s" % (item.pkg.name, long_desc)
570
long_desc = ("Package: %s\n%s" %
571
(item.pkg.name, long_desc))
611
573
desc_buffer = self.textview_descr.get_buffer()
612
574
desc_buffer.set_text(long_desc)
627
589
# if not connected, do not even attempt to get the changes
628
590
elif not self.connected:
629
591
changes_buffer.set_text(
631
"No network connection detected, you can not download "
632
"changelog information."
592
_("No network connection detected, you can not download "
593
"changelog information."))
635
594
# else, get it from the entwork
636
595
elif self.expander_details.get_expanded():
637
596
lock = threading.Lock()
639
598
changelog_thread = threading.Thread(
640
target=self.cache.get_news_and_changelog, args=(name, lock)
599
target=self.cache.get_news_and_changelog, args=(name, lock))
642
600
changelog_thread.start()
643
changes_buffer.set_text(
644
"%s\n" % _("Downloading list of changes...")
601
changes_buffer.set_text("%s\n" %
602
_("Downloading list of changes..."))
646
603
iter = changes_buffer.get_iter_at_line(1)
647
604
anchor = changes_buffer.create_child_anchor(iter)
648
605
button = Gtk.Button(stock="gtk-cancel")
649
606
self.textview_changes.add_child_at_anchor(button, anchor)
652
"clicked", lambda w, lock: lock.release(), lock
608
id = button.connect("clicked",
609
lambda w, lock: lock.release(), lock)
654
610
# wait for the dl-thread
655
611
while lock.locked():
686
642
# deleted when it goes out of scope and no menu is visible
688
644
self.menu = menu = Gtk.Menu()
689
item_select_none = Gtk.MenuItem.new_with_mnemonic(
646
Gtk.MenuItem.new_with_mnemonic(_("_Deselect All"))
692
647
item_select_none.connect("activate", self.select_none_upgrades)
693
648
menu.append(item_select_none)
694
649
num_updates = self.cache.install_count + self.cache.del_count
699
654
menu.append(item_select_all)
701
656
menu.popup_for_device(
702
None, None, None, None, None, event.button, event.time
657
None, None, None, None, None, event.button, event.time)
707
661
# we need this for select all/unselect all
708
662
def _toggle_group_headers(self, new_selection_value):
709
"""small helper that will set/unset the group headers"""
663
""" small helper that will set/unset the group headers
710
665
model = self.treeview_update.get_model()
711
666
for row in model:
712
667
data = model.get_value(row.iter, LIST_UPDATE_DATA)
713
668
if data.groups is not None or data.group is not None:
715
row.iter, LIST_TOGGLE_ACTIVE, new_selection_value
669
model.set_value(row.iter, LIST_TOGGLE_ACTIVE,
718
672
def select_all_upgrades(self, widget):
738
692
self.setBusy(False)
740
694
def setBusy(self, flag):
741
"""Show a watch cursor if the app is busy for more than 0.3 sec.
742
Furthermore provide a loop to handle user interface events"""
695
""" Show a watch cursor if the app is busy for more than 0.3 sec.
696
Furthermore provide a loop to handle user interface events """
743
697
if self.window_main.get_window() is None:
746
700
self.window_main.get_window().set_cursor(
747
Gdk.Cursor.new(Gdk.CursorType.WATCH)
701
Gdk.Cursor.new(Gdk.CursorType.WATCH))
750
703
self.window_main.get_window().set_cursor(None)
751
704
while Gtk.events_pending():
786
738
self.hbox_restart.set_visible(requires_restart)
788
740
def _refresh_updates_count(self):
789
self.button_install.set_sensitive(
790
self.cache.install_count + self.cache.del_count
741
self.button_install.set_sensitive(self.cache.install_count
742
+ self.cache.del_count)
793
744
inst_count = self.cache.install_count + self.cache.del_count
794
745
self.dl_size = self.cache.required_download
795
746
download_str = ""
796
747
if self.dl_size != 0:
797
748
download_str = _("%s will be downloaded.") % (
798
humanize_size(self.dl_size)
749
humanize_size(self.dl_size))
800
750
self.image_downsize.set_sensitive(True)
801
751
# do not set the buttons to sensitive/insensitive until NM
802
752
# can deal with dialup connections properly
803
# if self.alert_watcher.network_state != NM_STATE_CONNECTED:
753
#if self.alert_watcher.network_state != NM_STATE_CONNECTED:
804
754
# self.button_install.set_sensitive(False)
806
756
# self.button_install.set_sensitive(True)
807
757
self.button_install.set_sensitive(True)
808
758
self.unity.set_install_menuitem_visible(True)
852
801
elif self.settings.get_boolean("first-run"):
853
802
flavor = self.window_main.meta_release.flavor_name
854
803
version = self.window_main.meta_release.current_dist_version
856
"Updated software has been issued since %s %s "
857
"was released. Do you want to install it now?"
858
) % (flavor, version)
804
text_header = _("Updated software has been issued since %s %s "
805
"was released. Do you want to install "
806
"it now?") % (flavor, version)
859
807
self.settings.set_boolean("first-run", False)
862
"Updated software is available for this "
863
"computer. Do you want to install it now?"
809
text_header = _("Updated software is available for this "
810
"computer. Do you want to install it now?")
865
811
if not self.hbox_restart.get_visible() and self.need_reboot:
867
"The computer also needs to restart "
868
"to finish installing previous updates."
812
text_desc = _("The computer also needs to restart "
813
"to finish installing previous updates.")
871
815
self.notebook_details.set_sensitive(True)
872
816
self.treeview_update.set_sensitive(True)
896
840
self.unity.set_install_menuitem_visible(False)
897
841
# print("on_button_install_clicked")
898
842
err_sum = _("Not enough free disk space")
900
"The upgrade needs a total of %s free space on disk '%s'. "
901
"Please free at least an additional %s of disk space on '%s'. %s"
843
err_msg = _("The upgrade needs a total of %s free space on "
845
"Please free at least an additional %s of disk "
903
847
# specific ways to resolve lack of free space
904
remedy_archivedir = _(
905
"Remove temporary packages of former "
906
"installations using 'sudo apt clean'."
909
"You can remove old kernels using 'sudo apt autoremove', and you "
910
"could also set COMPRESS=xz in /etc/initramfs-tools/initramfs.conf"
911
" to reduce the size of your initramfs."
914
"Empty your trash and remove temporary packages "
915
"of former installations using 'sudo apt clean'."
848
remedy_archivedir = _("Remove temporary packages of former "
849
"installations using 'sudo apt clean'.")
850
remedy_boot = _("You can remove old kernels using "
851
"'sudo apt autoremove', and you could also "
852
"set COMPRESS=xz in "
853
"/etc/initramfs-tools/initramfs.conf to "
854
"reduce the size of your initramfs.")
855
remedy_root = _("Empty your trash and remove temporary "
856
"packages of former installations using "
917
858
remedy_tmp = _("Reboot to clean up files in /tmp.")
918
859
remedy_usr = _("")
919
860
# check free space and error if its not enough
927
868
if err_long != "":
929
870
if req.dir == archivedir:
930
err_long += err_msg % (
871
err_long += err_msg % (req.size_total, req.dir,
872
req.size_needed, req.dir,
937
874
elif req.dir == "/boot":
938
err_long += err_msg % (
875
err_long += err_msg % (req.size_total, req.dir,
876
req.size_needed, req.dir,
945
878
elif req.dir == "/":
946
err_long += err_msg % (
879
err_long += err_msg % (req.size_total, req.dir,
880
req.size_needed, req.dir,
953
882
elif req.dir == "/tmp":
954
err_long += err_msg % (
883
err_long += err_msg % (req.size_total, req.dir,
884
req.size_needed, req.dir,
961
886
elif req.dir == "/usr":
962
err_long += err_msg % (
887
err_long += err_msg % (req.size_total, req.dir,
888
req.size_needed, req.dir,
969
890
self.window_main.start_error(False, err_sum, err_long)
971
892
except SystemError:
982
903
self.vbox_alerts.show()
983
904
self.connected = False
984
905
# in doubt (STATE_UNKNOWN), assume connected
986
state in NetworkManagerHelper.NM_STATE_CONNECTED_LIST
987
or state == NetworkManagerHelper.NM_STATE_UNKNOWN
906
elif (state in NetworkManagerHelper.NM_STATE_CONNECTED_LIST
907
or state == NetworkManagerHelper.NM_STATE_UNKNOWN):
989
908
self.updates_changed()
990
909
self.hbox_offline.hide()
991
910
self.connected = True
994
913
self.on_treeview_update_cursor_changed(self.treeview_update)
996
915
self.connected = False
997
self.label_offline.set_text(
999
"You may not be able to check for "
1000
"updates or download new updates."
916
self.label_offline.set_text(_("You may not be able to check for "
917
"updates or download new updates."))
1003
918
self.updates_changed()
1004
919
self.hbox_offline.show()
1005
920
self.vbox_alerts.show()
1024
939
self.hbox_roaming.hide()
1026
941
def on_update_toggled(self, renderer, path):
1027
"""a toggle button in the listview was toggled"""
942
""" a toggle button in the listview was toggled """
1028
943
iter = self.store.get_iter(path)
1029
944
data = self.store.get_value(iter, LIST_UPDATE_DATA)
1030
945
# make sure that we don't allow to toggle deactivated updates
1031
946
# this is needed for the call by the row activation callback
1033
self.toggle_from_items(
1034
[item for group in data.groups for item in group.items]
948
self.toggle_from_items([item for group in data.groups
949
for item in group.items])
1036
950
elif data.group:
1037
951
self.toggle_from_items(data.group.items)
1073
987
self.setBusy(False)
1075
989
def _save_state(self):
1076
"""save the state (window-size for now)"""
990
""" save the state (window-size for now) """
1077
991
if self.expander_details.get_expanded():
1078
992
(w, h) = self.window_main.get_size()
1079
993
self.settings.set_int("window-width", w)
1080
994
self.settings.set_int("window-height", h)
1082
996
def _restore_state(self):
1083
"""restore the state (window-size for now)"""
997
""" restore the state (window-size for now) """
1084
998
w = self.settings.get_int("window-width")
1085
999
h = self.settings.get_int("window-height")
1086
1000
expanded = self.expander_details.get_expanded()
1090
1004
self.window_main.end_user_resizable()
1093
def _add_header(self, name, groups, sensitive=True):
1007
def _add_header(self, name, groups):
1095
1009
for group in groups:
1096
1010
total_size = total_size + group.get_total_size()
1137
1049
UpdateData(None, None, item),
1138
1050
humanize_size(getattr(item.pkg.candidate, "size", 0)),
1142
1054
self.store.append(group_iter, item_row)
1157
1069
# add security and update groups to self.store
1158
1070
if self.list.oem_groups:
1160
_("Improved hardware support"), self.list.oem_groups
1071
self._add_header(_("Improved hardware support"),
1072
self.list.oem_groups)
1162
1073
self._add_groups(self.list.oem_groups)
1163
1074
if self.list.security_groups:
1164
1075
self._add_header(_("Security updates"), self.list.security_groups)
1165
1076
self._add_groups(self.list.security_groups)
1167
self.list.security_groups or self.list.oem_groups
1168
) and self.list.update_groups:
1077
if ((self.list.security_groups or self.list.oem_groups)
1078
and self.list.update_groups):
1169
1079
self._add_header(_("Other updates"), self.list.update_groups)
1170
elif self.list.update_groups and (
1171
self.list.kernel_autoremove_groups or self.list.duplicate_groups
1080
elif self.list.update_groups and (self.list.kernel_autoremove_groups
1081
or self.list.duplicate_groups):
1173
1082
self._add_header(_("Updates"), self.list.update_groups)
1174
1083
if self.list.update_groups:
1175
1084
self._add_groups(self.list.update_groups)
1176
1085
if self.list.kernel_autoremove_groups:
1177
1086
self._add_header(
1178
1087
_("Unused kernel updates to be removed"),
1179
self.list.kernel_autoremove_groups,
1088
self.list.kernel_autoremove_groups)
1181
1089
self._add_groups(self.list.kernel_autoremove_groups)
1182
1090
if self.list.duplicate_groups:
1183
1091
self._add_header(
1184
1092
_("Duplicate packages to be removed"),
1185
self.list.duplicate_groups,
1093
self.list.duplicate_groups)
1187
1094
self._add_groups(self.list.duplicate_groups)
1188
1095
if self.list.ubuntu_pro_groups:
1190
_("Ubuntu Pro (enable in Settings…)"),
1191
self.list.ubuntu_pro_groups,
1194
1096
self._add_groups(self.list.ubuntu_pro_groups)
1196
1098
self.treeview_update.set_model(self.store)
1197
1099
self.pkg_cell_area.indent_toplevel = (
1198
1100
bool(self.list.security_groups)
1199
1101
or bool(self.list.kernel_autoremove_groups)
1200
or bool(self.list.duplicate_groups)
1102
or bool(self.list.duplicate_groups))
1202
1103
self.update_close_button()
1203
1104
self.update_count()
1204
1105
self.setBusy(False)