70
70
def error(parent_window, summary, msg):
71
" show a error dialog "
72
dialog = Gtk.MessageDialog(parent=parent_window,
73
flags=Gtk.DialogFlags.MODAL,
74
type=Gtk.MessageType.ERROR,
75
buttons=Gtk.ButtonsType.OK,
77
dialog.set_markup("<big><b>%s</b></big>\n\n%s" % (summary, msg))
71
""" show a error dialog """
72
dialog = Gtk.MessageDialog(parent=parent_window,
73
flags=Gtk.DialogFlags.MODAL,
74
type=Gtk.MessageType.ERROR,
75
buttons=Gtk.ButtonsType.OK,
77
dialog.set_markup("<big><b>%s</b></big>\n\n%s" % (summary, msg))
82
82
class SoftwarePropertiesGtk(SoftwareProperties,SimpleGtkbuilderApp):
83
84
def __init__(self, datadir=None, options=None, file=None, parent=None):
84
85
""" Provide a GTK based graphical user interface to configure
85
86
the used software repositories, corresponding authentication keys
115
117
if options and options.open_tab:
116
118
self.notebook_main.set_current_page(int(options.open_tab))
121
self.settings = Gio.Settings("com.ubuntu.update-notifier")
122
# we need this for reverting
123
self.initial_auto_launch = self.settings.get_int("regular-auto-launch-interval")
125
# get the dbus backend
126
bus = dbus.SystemBus()
127
proxy = bus.get_object("com.ubuntu.SoftwareProperties", "/")
128
self.backend = dbus.Interface(proxy, "com.ubuntu.SoftwareProperties")
129
self.backend.connect_to_signal(
130
"SourcesListModified", self.on_sources_list_modified)
131
self.backend.connect_to_signal(
132
"ConfigModified", self.on_config_modified)
133
self.backend.connect_to_signal(
134
"KeysModified", self.on_keys_modified)
135
self.backend.connect_to_signal(
136
"AuthFailed", self.on_auth_failed)
118
138
# Show what we have early
119
139
self.window_main.show()
167
188
" setup the widgets that allow configuring the release upgrades "
168
189
i = self.get_release_upgrades_policy()
169
190
self.combobox_release_upgrades.set_active(i)
170
self.combobox_release_upgrades.connect('changed', self.on_combobox_release_upgrades_changed)
191
self.combobox_release_upgrades.connect(
192
'changed', self.on_combobox_release_upgrades_changed)
172
194
def init_auto_update(self):
173
195
""" Set up the widgets that allow to configure the update automation """
174
self.combobox_update_interval = Gtk.ComboBoxText.new_with_entry()
175
self.hbox_check_for_updates.pack_start(self.combobox_update_interval, True, True, 0)
176
196
self.combobox_update_interval.show()
178
199
# this maps the key (combo-box-index) to the auto-update-interval value
179
# where (-1) means, no key
180
self.combobox_interval_mapping = { 0 : 1,
184
self.combobox_update_interval.set_active(0)
186
#update_days = apt_pkg.Config.FindI(softwareproperties.CONF_MAP["autoupdate"])
187
self.combobox_update_interval.append_text(_("Daily"))
188
self.combobox_update_interval.append_text(_("Every two days"))
189
self.combobox_update_interval.append_text(_("Weekly"))
190
self.combobox_update_interval.append_text(_("Every two weeks"))
192
model_check_interval = Gtk.ListStore(gobject.TYPE_STRING,
200
# we build it dynamically from the model
201
model = self.combobox_update_interval.get_model()
202
self.combobox_interval_mapping = {}
203
for (i, row) in enumerate(model):
204
# column 1 is the update interval in days
205
value = model.get_value(row.iter, 1)
206
self.combobox_interval_mapping[i] = value
194
209
update_days = self.get_update_interval()
196
211
# If a custom period is defined add a corresponding entry
198
213
if update_days > 0:
199
214
self.combobox_update_interval.append_text(_("Every %s days")
201
self.combobox_interval_mapping[4] = update_days
216
self.combobox_interval_mapping[-1] = update_days
203
218
for key in self.combobox_interval_mapping:
204
219
if self.combobox_interval_mapping[key] == update_days:
205
220
self.combobox_update_interval.set_active(key)
209
self.checkbutton_auto_update.set_active(True)
210
self.combobox_update_interval.set_sensitive(True)
211
self.vbox_auto_updates.set_sensitive(True)
213
self.checkbutton_auto_update.set_active(False)
214
self.combobox_update_interval.set_sensitive(False)
215
self.vbox_auto_updates.set_sensitive(False)
217
self.handlers.append(
218
(self.checkbutton_auto_update,
219
self.checkbutton_auto_update.connect("toggled",
220
self.on_auto_update_toggled)))
221
223
self.handlers.append(
222
224
(self.combobox_update_interval,
223
225
self.combobox_update_interval.connect("changed",
224
226
self.on_combobox_update_interval_changed)))
225
self.handlers.append(
226
(self.radiobutton_updates_download,
227
self.radiobutton_updates_download.connect("toggled",
228
self.set_update_automation_level,
229
softwareproperties.UPDATE_DOWNLOAD)))
230
self.handlers.append(
231
(self.radiobutton_updates_inst_sec,
232
self.radiobutton_updates_inst_sec.connect("toggled",
233
self.set_update_automation_level,
234
softwareproperties.UPDATE_INST_SEC)))
235
self.handlers.append(
236
(self.radiobutton_updates_notify,
237
self.radiobutton_updates_notify.connect("toggled",
238
self.set_update_automation_level,
239
softwareproperties.UPDATE_NOTIFY)))
228
self.handlers.append(
229
(self.combobox_security_updates,
230
self.combobox_security_updates.connect("changed",
231
self.set_sec_update_automation_level)))
233
self.handlers.append(
234
(self.combobox_security_updates,
235
self.combobox_other_updates.connect("changed",
236
self.set_other_update_automation_level)))
241
238
def show_auto_update_level(self):
242
239
"""Represent the level of update automation in the user interface"""
243
level = self.get_update_automation_level()
244
self.block_handlers()
246
self.radiobutton_updates_inst_sec.set_inconsistent(True)
247
self.radiobutton_updates_download.set_inconsistent(True)
248
self.radiobutton_updates_notify.set_inconsistent(True)
242
level_sec = self.get_update_automation_level()
243
if level_sec == None:
244
self.combobox_security_updates.set_sensitive(False)
250
self.radiobutton_updates_inst_sec.set_inconsistent(False)
251
self.radiobutton_updates_download.set_inconsistent(False)
252
self.radiobutton_updates_notify.set_inconsistent(False)
253
if level == softwareproperties.UPDATE_MANUAL or \
254
level == softwareproperties.UPDATE_NOTIFY:
255
self.radiobutton_updates_notify.set_active(True)
256
elif level == softwareproperties.UPDATE_DOWNLOAD:
257
self.radiobutton_updates_download.set_active(True)
258
elif level == softwareproperties.UPDATE_INST_SEC:
259
self.radiobutton_updates_inst_sec.set_active(True)
260
# Unblock the toggle handlers
261
self.unblock_handlers()
246
self.combobox_security_updates.set_sensitive(True)
248
if (level_sec == softwareproperties.UPDATE_MANUAL or
249
level_sec == softwareproperties.UPDATE_NOTIFY):
250
self.combobox_security_updates.set_active(0) # Display immediately
251
elif level_sec == softwareproperties.UPDATE_DOWNLOAD:
252
self.combobox_security_updates.set_active(1) # Download automatically
253
elif level_sec == softwareproperties.UPDATE_INST_SEC:
254
self.combobox_security_updates.set_active(2) # Download and install automatically
257
level_other = self.settings.get_int("regular-auto-launch-interval")
258
model = self.combobox_other_updates.get_model()
259
for (i, row) in enumerate(model):
260
level = model.get_value(row.iter, 1)
261
if level_other == level:
262
self.combobox_other_updates.set_active(i)
263
265
def init_distro(self):
264
266
"""Setup the user interface elements to represent the distro"""
266
268
# TRANS: %s stands for the distribution name e.g. Debian or Ubuntu
267
self.label_updates.set_label("<b>%s</b>" % (_("%s updates") %\
268
self.distro.id.encode('UTF-8')))
269
# TRANS: %s stands for the distribution name e.g. Debian or Ubuntu
270
self.label_dist_name.set_label(_("%s Software") % self.distro.id.encode('UTF-8'))
269
self.label_dist_name.set_label(_("%s Software") % self.distro.id)
273
271
self.handlers.append((self.checkbutton_source_code,
274
272
self.checkbutton_source_code.connect("toggled",
425
424
for source in self.sourceslist_visible:
426
425
self.print_source_entry(source)
428
def set_update_automation_level(self, widget, state):
429
'''Call the backend to set the update automation level to the given
431
if widget.get_active() == True:
432
self.vbox_auto_updates.foreach(lambda b, d: b.set_inconsistent(False), None)
433
SoftwareProperties.set_update_automation_level(self, state)
434
self.set_modified_config()
427
def set_sec_update_automation_level(self, widget):
428
"""Call the backend to set the security update automation level to the given
430
index = widget.get_active()
432
if index == 0: # Display immediately
433
state = softwareproperties.UPDATE_NOTIFY
434
elif index == 1: # Download automatically
435
state = softwareproperties.UPDATE_DOWNLOAD
436
elif index == 2: # Download and install automatically
437
state = softwareproperties.UPDATE_INST_SEC
438
# only set if something actually changed
439
if state != self.get_update_automation_level():
440
self.backend.SetUpdateAutomationLevel(state)
442
def set_other_update_automation_level(self, widget):
443
"""Set the other update automation level to the given value via gconf"""
444
index = widget.get_active()
445
model = self.combobox_other_updates.get_model()
446
# the second column is the update interval days
447
days = model[index][1]
448
self.settings.set_int("regular-auto-launch-interval", days)
436
450
def is_row_separator(self, model, iter, column=0):
437
451
''' Check if a given row is a separator '''
461
475
self.custom_mirrors)
462
476
res = dialog.run()
464
self.distro.change_server(res)
465
self.set_modified_sourceslist()
478
self.backend.ChangeMainDownloadServer(res)
467
480
combobox.set_active(self.active_server)
468
481
elif uri != None and len(self.distro.used_servers) > 0:
469
482
self.active_server = combobox.get_active()
470
self.distro.change_server(uri)
471
self.distro.default_server = uri
472
self.set_modified_sourceslist()
474
self.distro.default_server = uri
483
self.backend.ChangeMainDownloadServer(uri)
484
# mvo: is this still needed?
486
# self.distro.default_server = uri
476
488
def on_component_toggled(self, checkbutton, comp):
479
491
child sources and source code sources
481
493
if checkbutton.get_active() == True:
482
self.enable_component(comp)
494
self.backend.EnableComponent(comp)
484
self.disable_component(comp)
485
self.set_modified_sourceslist()
496
self.backend.DisableComponent(comp)
487
498
def on_checkbutton_child_toggled(self, checkbutton, template):
489
500
Enable or disable a child repo of the distribution main repository
491
502
if checkbutton.get_active() == False:
492
self.disable_child_source(template)
503
self.backend.DisableChildSource(template)
494
self.enable_child_source(template)
505
self.backend.EnableChildSource(template)
496
507
def on_checkbutton_source_code_toggled(self, checkbutton):
497
508
""" Disable or enable the source code for all sources """
498
509
if checkbutton.get_active() == True:
499
self.enable_source_code_sources()
510
self.backend.EnableSourceCodeSources()
501
self.disable_source_code_sources()
512
self.backend.DisableSourceCodeSources()
503
514
def on_checkbutton_popcon_toggled(self, widget):
504
515
""" The user clicked on the popcon paritipcation button """
505
self.set_popcon_pariticipation(widget.get_active())
516
# only trigger the backend if something actually changed
517
do_popcon = self.get_popcon_participation()
518
if widget.get_active() != do_popcon:
519
self.backend.SetPopconPariticipation(widget.get_active())
507
521
def open_file(self, file):
508
522
"""Show a confirmation for adding the channels of the specified file"""
682
691
"or it might be corrupt."))
685
#FIXME revert automation settings too
686
694
def on_button_revert_clicked(self, button):
687
"""Restore the source list from the startup of the dialog"""
688
SoftwareProperties.revert(self)
689
self.set_modified_sourceslist()
690
self.show_auto_update_level()
691
self.button_revert.set_sensitive(False)
692
self.modified_sourceslist = False
695
"""Restore the source list from the startup of the dialog"""
696
self.backend.Revert()
697
self.settings.set_int("regular-auto-launch-interval", self.initial_auto_launch)
698
self.show_auto_update_level()
699
self.button_revert.set_sensitive(False)
700
self.modified_sourceslist = False
694
def set_modified_config(self):
703
def on_config_modified(self):
695
704
"""The config was changed and now needs to be saved and reloaded"""
696
SoftwareProperties.set_modified_config(self)
705
apt.apt_pkg.init_config()
697
706
self.button_revert.set_sensitive(True)
699
def set_modified_sourceslist(self):
708
def on_keys_modified(self):
709
""" The apt keys have changed and need to be redisplayed """
712
def on_sources_list_modified(self):
700
713
"""The sources list was changed and now needs to be saved and reloaded"""
701
SoftwareProperties.set_modified_sourceslist(self)
714
self.reload_sourceslist()
702
715
self.show_distro()
703
716
self.show_isv_sources()
704
717
self.show_cdrom_sources()
705
718
self.button_revert.set_sensitive(True)
720
def on_auth_failed(self):
721
""" send when the authentication failed """
722
# reread the current config
723
self.on_sources_list_modified()
724
self.on_config_modified()
725
self.on_keys_modified()
707
728
def show_isv_sources(self):
708
729
""" Show the repositories of independent software vendors in the
709
730
third-party software tree view """
748
769
value = self.combobox_interval_mapping[i]
749
770
self.set_update_interval(value)
751
def on_auto_update_toggled(self, widget):
752
"""Enable or disable automatic updates and modify the user interface
754
if self.checkbutton_auto_update.get_active():
755
self.combobox_update_interval.set_sensitive(True)
756
self.vbox_auto_updates.set_sensitive(True)
757
# if no frequency was specified use daily
758
i = self.combobox_update_interval.get_active()
761
self.combobox_update_interval.set_active(i)
762
value = self.combobox_interval_mapping[i]
763
# A little hack to re-set the former selected update automation level
764
self.vbox_auto_updates.foreach(lambda b, d: b.toggled(), None)
766
self.combobox_update_interval.set_sensitive(False)
767
self.vbox_auto_updates.set_sensitive(False)
768
SoftwareProperties.set_update_automation_level(self, None)
770
self.set_update_interval(str(value))
772
772
def on_add_clicked(self, widget):
773
773
"""Show a dialog that allows to enter the apt line of a to be used repo"""
774
774
dialog = DialogAdd(self.window_main, self.sourceslist,
775
775
self.datadir, self.distro)
776
776
line = dialog.run()
778
self.add_source_from_line(line)
779
self.set_modified_sourceslist()
778
self.backend.AddSourceFromLine(line)
781
780
def on_edit_clicked(self, widget):
782
781
"""Show a dialog to edit an ISV source"""
784
783
(model, iter) = sel.get_selected()
787
source_entry = model.get_value(iter, LIST_ENTRY_OBJ)
786
old_source_entry = model.get_value(iter, LIST_ENTRY_OBJ)
788
787
dialog = DialogEdit(self.window_main, self.sourceslist,
789
source_entry, self.datadir)
788
old_source_entry, self.datadir)
790
789
if dialog.run() == Gtk.ResponseType.OK:
791
self.set_modified_sourceslist()
790
self.backend.ReplaceSourceEntry(str(old_source_entry),
791
str(dialog.new_source_entry))
793
793
# FIXME:outstanding from merge
794
794
def on_isv_source_activated(self, treeview, path, column):