def __init__(self, datadir=None, options=None, parent=None, file=None): gtk.window_set_default_icon_name("software-properties") self.popconfile = "/etc/popularity-contest.conf" # FIXME: some saner way is needed here if datadir == None: datadir = "/usr/share/update-manager/" self.datadir = datadir SimpleGladeApp.__init__(self, datadir+"glade/SoftwareProperties.glade", None, domain="update-manager") self.modified = False self.file = file self.distro = aptsources.Distribution() cell = gtk.CellRendererText() self.combobox_server.pack_start(cell, True) self.combobox_server.add_attribute(cell, 'text', 0) # set up the handler id for the callbacks self.handler_server_changed = self.combobox_server.connect("changed", self.on_combobox_server_changed) self.handler_source_code_changed = self.checkbutton_source_code.connect( "toggled", self.on_checkbutton_source_code_toggled ) if parent: self.window_main.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG) self.window_main.show() self.window_main.set_transient_for(parent) # If externally called, reparent to external application. self.options = options if options and options.toplevel != None: self.window_main.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG) self.window_main.show() toplevel = gtk.gdk.window_foreign_new(int(options.toplevel)) self.window_main.window.set_transient_for(toplevel) self.init_sourceslist() self.reload_sourceslist() self.backup_sourceslist() self.window_main.show() # this maps the key (combo-box-index) to the auto-update-interval value # where (-1) means, no key self.combobox_interval_mapping = { 0 : 1, 1 : 2, 2 : 7, 3 : 14 } self.combobox_update_interval.set_active(0) update_days = apt_pkg.Config.FindI(CONF_MAP["autoupdate"]) self.combobox_update_interval.append_text(_("Daily")) self.combobox_update_interval.append_text(_("Every two days")) self.combobox_update_interval.append_text(_("Weekly")) self.combobox_update_interval.append_text(_("Every two weeks")) # If a custom period is defined add an corresponding entry if not update_days in self.combobox_interval_mapping.values(): if update_days > 0: self.combobox_update_interval.append_text(_("Every %s days") % update_days) self.combobox_interval_mapping[4] = update_days for key in self.combobox_interval_mapping: if self.combobox_interval_mapping[key] == update_days: self.combobox_update_interval.set_active(key) break if update_days >= 1: self.checkbutton_auto_update.set_active(True) self.combobox_update_interval.set_sensitive(True) else: self.checkbutton_auto_update.set_active(False) self.combobox_update_interval.set_sensitive(False) # Automatic removal of cached packages by age self.combobox_delete_interval_mapping = { 0 : 7, 1 : 14, 2 : 30 } delete_days = apt_pkg.Config.FindI(CONF_MAP["max_age"]) self.combobox_delete_interval.append_text(_("After one week")) self.combobox_delete_interval.append_text(_("After two weeks")) self.combobox_delete_interval.append_text(_("After one month")) # If a custom period is defined add an corresponding entry if not delete_days in self.combobox_delete_interval_mapping.values(): if delete_days > 0 and CONF_MAP["autoclean"] != 0: self.combobox_delete_interval.append_text(_("After %s days") % delete_days) self.combobox_delete_interval_mapping[3] = delete_days for key in self.combobox_delete_interval_mapping: if self.combobox_delete_interval_mapping[key] == delete_days: self.combobox_delete_interval.set_active(key) break if delete_days >= 1 and apt_pkg.Config.FindI(CONF_MAP["autoclean"]) != 0: self.checkbutton_auto_delete.set_active(True) self.combobox_delete_interval.set_sensitive(True) else: self.checkbutton_auto_delete.set_active(False) self.combobox_delete_interval.set_sensitive(False) # Autodownload if apt_pkg.Config.FindI(CONF_MAP["autodownload"]) == 1: self.checkbutton_auto_download.set_active(True) else: self.checkbutton_auto_download.set_active(False) # Unattended updates if os.path.exists("/usr/bin/unattended-upgrade"): # FIXME: we should always show the option. if unattended-upgrades is # not installed a dialog should popup and allow the user to install # unattended-upgrade #self.checkbutton_unattended.set_sensitive(True) self.checkbutton_unattended.show() else: #self.checkbutton_unattended.set_sensitive(False) self.checkbutton_unattended.hide() if apt_pkg.Config.FindI(CONF_MAP["unattended"]) == 1: self.checkbutton_unattended.set_active(True) else: self.checkbutton_unattended.set_active(False) self.help_viewer = HelpViewer("update-manager#setting-preferences") if self.help_viewer.check() == False: self.button_help.set_sensitive(False) # apt-key stuff self.apt_key = apt_key() self.init_keyslist() self.reload_keyslist() # drag and drop support for sources.list self.treeview_sources.drag_dest_set(gtk.DEST_DEFAULT_ALL, \ [('text/uri-list',0, 0)], \ gtk.gdk.ACTION_COPY) self.treeview_sources.connect("drag_data_received",\ self.on_sources_drag_data_received) # popcon if os.path.exists(self.popconfile): # read it lines = open(self.popconfile).read().split("\n") active = False for line in lines: try: (key,value) = line.split("=") if key == "PARTICIPATE": if value.strip('"').lower() == "yes": active = True except ValueError: continue self.checkbutton_popcon.set_active(active) # call the add sources.list dialog if we got a file from the cli if self.file != None: self.open_file(file)
def __init__(self, datadir=None, options=None, parent=None, file=None): gtk.window_set_default_icon_name("software-properties") self.popconfile = "/etc/popularity-contest.conf" # FIXME: some saner way is needed here if datadir == None: datadir = "/usr/share/update-manager/" self.datadir = datadir SimpleGladeApp.__init__(self, datadir + "glade/SoftwareProperties.glade", None, domain="update-manager") self.modified = False self.file = file self.distro = aptsources.Distribution() cell = gtk.CellRendererText() self.combobox_server.pack_start(cell, True) self.combobox_server.add_attribute(cell, 'text', 0) # set up the handler id for the callbacks self.handler_server_changed = self.combobox_server.connect( "changed", self.on_combobox_server_changed) self.handler_source_code_changed = self.checkbutton_source_code.connect( "toggled", self.on_checkbutton_source_code_toggled) if parent: self.window_main.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG) self.window_main.show() self.window_main.set_transient_for(parent) # If externally called, reparent to external application. self.options = options if options and options.toplevel != None: self.window_main.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG) self.window_main.show() toplevel = gtk.gdk.window_foreign_new(int(options.toplevel)) self.window_main.window.set_transient_for(toplevel) self.init_sourceslist() self.reload_sourceslist() self.backup_sourceslist() self.window_main.show() # this maps the key (combo-box-index) to the auto-update-interval value # where (-1) means, no key self.combobox_interval_mapping = {0: 1, 1: 2, 2: 7, 3: 14} self.combobox_update_interval.set_active(0) update_days = apt_pkg.Config.FindI(CONF_MAP["autoupdate"]) self.combobox_update_interval.append_text(_("Daily")) self.combobox_update_interval.append_text(_("Every two days")) self.combobox_update_interval.append_text(_("Weekly")) self.combobox_update_interval.append_text(_("Every two weeks")) # If a custom period is defined add an corresponding entry if not update_days in self.combobox_interval_mapping.values(): if update_days > 0: self.combobox_update_interval.append_text( _("Every %s days") % update_days) self.combobox_interval_mapping[4] = update_days for key in self.combobox_interval_mapping: if self.combobox_interval_mapping[key] == update_days: self.combobox_update_interval.set_active(key) break if update_days >= 1: self.checkbutton_auto_update.set_active(True) self.combobox_update_interval.set_sensitive(True) else: self.checkbutton_auto_update.set_active(False) self.combobox_update_interval.set_sensitive(False) # Automatic removal of cached packages by age self.combobox_delete_interval_mapping = {0: 7, 1: 14, 2: 30} delete_days = apt_pkg.Config.FindI(CONF_MAP["max_age"]) self.combobox_delete_interval.append_text(_("After one week")) self.combobox_delete_interval.append_text(_("After two weeks")) self.combobox_delete_interval.append_text(_("After one month")) # If a custom period is defined add an corresponding entry if not delete_days in self.combobox_delete_interval_mapping.values(): if delete_days > 0 and CONF_MAP["autoclean"] != 0: self.combobox_delete_interval.append_text( _("After %s days") % delete_days) self.combobox_delete_interval_mapping[3] = delete_days for key in self.combobox_delete_interval_mapping: if self.combobox_delete_interval_mapping[key] == delete_days: self.combobox_delete_interval.set_active(key) break if delete_days >= 1 and apt_pkg.Config.FindI( CONF_MAP["autoclean"]) != 0: self.checkbutton_auto_delete.set_active(True) self.combobox_delete_interval.set_sensitive(True) else: self.checkbutton_auto_delete.set_active(False) self.combobox_delete_interval.set_sensitive(False) # Autodownload if apt_pkg.Config.FindI(CONF_MAP["autodownload"]) == 1: self.checkbutton_auto_download.set_active(True) else: self.checkbutton_auto_download.set_active(False) # Unattended updates if os.path.exists("/usr/bin/unattended-upgrade"): # FIXME: we should always show the option. if unattended-upgrades is # not installed a dialog should popup and allow the user to install # unattended-upgrade #self.checkbutton_unattended.set_sensitive(True) self.checkbutton_unattended.show() else: #self.checkbutton_unattended.set_sensitive(False) self.checkbutton_unattended.hide() if apt_pkg.Config.FindI(CONF_MAP["unattended"]) == 1: self.checkbutton_unattended.set_active(True) else: self.checkbutton_unattended.set_active(False) self.help_viewer = HelpViewer("update-manager#setting-preferences") if self.help_viewer.check() == False: self.button_help.set_sensitive(False) # apt-key stuff self.apt_key = apt_key() self.init_keyslist() self.reload_keyslist() # drag and drop support for sources.list self.treeview_sources.drag_dest_set(gtk.DEST_DEFAULT_ALL, \ [('text/uri-list',0, 0)], \ gtk.gdk.ACTION_COPY) self.treeview_sources.connect("drag_data_received",\ self.on_sources_drag_data_received) # popcon if os.path.exists(self.popconfile): # read it lines = open(self.popconfile).read().split("\n") active = False for line in lines: try: (key, value) = line.split("=") if key == "PARTICIPATE": if value.strip('"').lower() == "yes": active = True except ValueError: continue self.checkbutton_popcon.set_active(active) # call the add sources.list dialog if we got a file from the cli if self.file != None: self.open_file(file)
class SoftwareProperties(SimpleGladeApp): def __init__(self, datadir=None, options=None, parent=None, file=None): gtk.window_set_default_icon_name("software-properties") self.popconfile = "/etc/popularity-contest.conf" # FIXME: some saner way is needed here if datadir == None: datadir = "/usr/share/update-manager/" self.datadir = datadir SimpleGladeApp.__init__(self, datadir+"glade/SoftwareProperties.glade", None, domain="update-manager") self.modified = False self.file = file self.distro = aptsources.Distribution() cell = gtk.CellRendererText() self.combobox_server.pack_start(cell, True) self.combobox_server.add_attribute(cell, 'text', 0) # set up the handler id for the callbacks self.handler_server_changed = self.combobox_server.connect("changed", self.on_combobox_server_changed) self.handler_source_code_changed = self.checkbutton_source_code.connect( "toggled", self.on_checkbutton_source_code_toggled ) if parent: self.window_main.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG) self.window_main.show() self.window_main.set_transient_for(parent) # If externally called, reparent to external application. self.options = options if options and options.toplevel != None: self.window_main.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG) self.window_main.show() toplevel = gtk.gdk.window_foreign_new(int(options.toplevel)) self.window_main.window.set_transient_for(toplevel) self.init_sourceslist() self.reload_sourceslist() self.backup_sourceslist() self.window_main.show() # this maps the key (combo-box-index) to the auto-update-interval value # where (-1) means, no key self.combobox_interval_mapping = { 0 : 1, 1 : 2, 2 : 7, 3 : 14 } self.combobox_update_interval.set_active(0) update_days = apt_pkg.Config.FindI(CONF_MAP["autoupdate"]) self.combobox_update_interval.append_text(_("Daily")) self.combobox_update_interval.append_text(_("Every two days")) self.combobox_update_interval.append_text(_("Weekly")) self.combobox_update_interval.append_text(_("Every two weeks")) # If a custom period is defined add an corresponding entry if not update_days in self.combobox_interval_mapping.values(): if update_days > 0: self.combobox_update_interval.append_text(_("Every %s days") % update_days) self.combobox_interval_mapping[4] = update_days for key in self.combobox_interval_mapping: if self.combobox_interval_mapping[key] == update_days: self.combobox_update_interval.set_active(key) break if update_days >= 1: self.checkbutton_auto_update.set_active(True) self.combobox_update_interval.set_sensitive(True) else: self.checkbutton_auto_update.set_active(False) self.combobox_update_interval.set_sensitive(False) # Automatic removal of cached packages by age self.combobox_delete_interval_mapping = { 0 : 7, 1 : 14, 2 : 30 } delete_days = apt_pkg.Config.FindI(CONF_MAP["max_age"]) self.combobox_delete_interval.append_text(_("After one week")) self.combobox_delete_interval.append_text(_("After two weeks")) self.combobox_delete_interval.append_text(_("After one month")) # If a custom period is defined add an corresponding entry if not delete_days in self.combobox_delete_interval_mapping.values(): if delete_days > 0 and CONF_MAP["autoclean"] != 0: self.combobox_delete_interval.append_text(_("After %s days") % delete_days) self.combobox_delete_interval_mapping[3] = delete_days for key in self.combobox_delete_interval_mapping: if self.combobox_delete_interval_mapping[key] == delete_days: self.combobox_delete_interval.set_active(key) break if delete_days >= 1 and apt_pkg.Config.FindI(CONF_MAP["autoclean"]) != 0: self.checkbutton_auto_delete.set_active(True) self.combobox_delete_interval.set_sensitive(True) else: self.checkbutton_auto_delete.set_active(False) self.combobox_delete_interval.set_sensitive(False) # Autodownload if apt_pkg.Config.FindI(CONF_MAP["autodownload"]) == 1: self.checkbutton_auto_download.set_active(True) else: self.checkbutton_auto_download.set_active(False) # Unattended updates if os.path.exists("/usr/bin/unattended-upgrade"): # FIXME: we should always show the option. if unattended-upgrades is # not installed a dialog should popup and allow the user to install # unattended-upgrade #self.checkbutton_unattended.set_sensitive(True) self.checkbutton_unattended.show() else: #self.checkbutton_unattended.set_sensitive(False) self.checkbutton_unattended.hide() if apt_pkg.Config.FindI(CONF_MAP["unattended"]) == 1: self.checkbutton_unattended.set_active(True) else: self.checkbutton_unattended.set_active(False) self.help_viewer = HelpViewer("update-manager#setting-preferences") if self.help_viewer.check() == False: self.button_help.set_sensitive(False) # apt-key stuff self.apt_key = apt_key() self.init_keyslist() self.reload_keyslist() # drag and drop support for sources.list self.treeview_sources.drag_dest_set(gtk.DEST_DEFAULT_ALL, \ [('text/uri-list',0, 0)], \ gtk.gdk.ACTION_COPY) self.treeview_sources.connect("drag_data_received",\ self.on_sources_drag_data_received) # popcon if os.path.exists(self.popconfile): # read it lines = open(self.popconfile).read().split("\n") active = False for line in lines: try: (key,value) = line.split("=") if key == "PARTICIPATE": if value.strip('"').lower() == "yes": active = True except ValueError: continue self.checkbutton_popcon.set_active(active) # call the add sources.list dialog if we got a file from the cli if self.file != None: self.open_file(file) def distro_to_widgets(self): """ Represent the distro information in the user interface """ # TRANS: %s stands for the distribution name e.g. Debian or Ubuntu self.label_updates.set_label("<b>%s</b>" % (_("%s updates") %\ self.distro.id)) # TRANS: %s stands for the distribution name e.g. Debian or Ubuntu self.label_dist_name.set_label("%s" % self.distro.description) # Setup the checkbuttons for the components for checkbutton in self.vbox_dist_comps.get_children(): self.vbox_dist_comps.remove(checkbutton) for comp in self.distro.source_template.components.keys(): # TRANSLATORS: Label for the components in the Internet section # first %s is the description of the component # second %s is the code name of the comp, eg main, universe label = _("%s (%s)") % (self.distro.source_template.components[comp][1], comp) checkbox = gtk.CheckButton(label) # check if the comp is enabled # FIXME: use inconsistence if there are main sources with not all comps if comp in self.distro.download_comps: checkbox.set_active(True) # setup the callback and show the checkbutton checkbox.connect("toggled", self.on_component_toggled, comp) self.vbox_dist_comps.add(checkbox) checkbox.show() # Setup the checkbuttons for the child repos / updates for checkbutton in self.vbox_updates.get_children(): self.vbox_updates.remove(checkbutton) for template in self.distro.source_template.children: checkbox = gtk.CheckButton(label=template.description) comps = [] for child in self.distro.child_sources: if child.template == template: comps.extend(child.comps) # check if all comps of the main source are also enabled # for the corresponding child sources if len(comps) > 0 and \ len(self.distro.enabled_comps ^ set(comps)) == 0: # the cild source covers all components checkbox.set_active(True) elif len(comps) > 0 and\ len(self.distro.enabled_comps ^ set(comps)) != 0: # the cild is enabled, but doesn't cover # all components checkbox.set_active(False) checkbox.set_inconsistent(True) else: # there is no corresponding child source at all checkbox.set_active(False) # setup the callback and show the checkbutton checkbox.connect("toggled", self.on_checkbutton_child_toggled, template) self.vbox_updates.add(checkbox) checkbox.show() if len(self.distro.enabled_comps) < 1: self.vbox_updates.set_sensitive(False) else: self.vbox_updates.set_sensitive(True) # Intiate the combobox which allows do specify a server for all # distro related sources self.combobox_server.handler_block(self.handler_server_changed) server_store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING) self.combobox_server.set_model(server_store) server_store.append([_("Main server"), self.distro.main_server]) if self.distro.country != None: # TRANSLATORS: %s is a country server_store.append([_("Server for %s") % gettext.dgettext("iso-3166", self.distro.country).rstrip(), self.distro.nearest_server]) else: server_store.append([_("Nearest server"), self.distro.nearest_server]) if len(self.distro.used_servers) > 0: for server in self.distro.used_servers: if not re.match(server, self.distro.main_server) and \ not re.match(server, self.distro.nearest_server): # FIXME: use regexp here instead of this country = "" i = server.find("://") l = server.find(".archive.ubuntu.com") if i != -1 and l != -1: country = server[i+len("://"):l] if self.distro.countries.has_key(country): # TRANSLATORS: %s is a country server_store.append([_("Server for %s") % \ gettext.dgettext("iso-3166", self.distro.countries[country].rstrip()), server]) else: server_store.append(["%s" % server, server]) if len(self.distro.used_servers) > 1: server_store.append([_("Custom servers"), None]) self.combobox_server.set_active(2) elif self.distro.used_servers[0] == self.distro.main_server: self.combobox_server.set_active(0) elif self.distro.used_servers[0] == self.distro.nearest_server: self.combobox_server.set_active(1) elif len(self.distro.used_servers) == 1: self.combobox_server.set_active(2) else: self.combobox_server.set_active(0) self.combobox_server.handler_unblock(self.handler_server_changed) # Check for source code sources self.checkbutton_source_code.handler_block(self.handler_source_code_changed) self.checkbutton_source_code.set_inconsistent(False) if len(self.distro.source_code_sources) < 1: # we don't have any source code sources, so # uncheck the button self.checkbutton_source_code.set_active(False) self.distro.get_source_code = False else: # there are source code sources, so we check the button self.checkbutton_source_code.set_active(True) self.distro.get_source_code = True # check if there is a corresponding source code source for # every binary source. if not set the checkbutton to inconsistent templates = {} sources = [] sources.extend(self.distro.main_sources) sources.extend(self.distro.child_sources) for source in sources: if templates.has_key(source.template): for comp in source.comps: templates[source.template].add(comp) else: templates[source.template] = set(source.comps) # add fake http sources for the cdrom, since the sources # for the cdrom are only available in the internet if len(self.distro.cdrom_sources) > 0: templates[self.distro.source_template] = self.distro.cdrom_comps for source in self.distro.source_code_sources: if not templates.has_key(source.template) or \ (templates.has_key(source.template) and not \ (len(set(templates[source.template]) ^ set(source.comps)) == 0\ or (len(set(source.comps) ^ self.distro.enabled_comps) == 0))): self.checkbutton_source_code.set_inconsistent(True) self.distro.get_source_code = False break self.checkbutton_source_code.handler_unblock(self.handler_source_code_changed) if len(self.cdrom_store) == 0: self.treeview_cdroms.set_sensitive(False) else: self.treeview_cdroms.set_sensitive(True) if self.options.debug == True or self.options.massive_debug == True: print "ENABLED COMPS: %s" % self.distro.enabled_comps print "INTERNET COMPS: %s" % self.distro.download_comps print "MAIN SOURCES" for source in self.distro.main_sources: self.print_source_entry(source) print "CHILD SOURCES" for source in self.distro.child_sources: self.print_source_entry(source) print "CDROM SOURCES" for source in self.distro.cdrom_sources: self.print_source_entry(source) print "SOURCE CODE SOURCES" for source in self.distro.source_code_sources: self.print_source_entry(source) print "DISABLED SOURCES" for source in self.distro.disabled_sources: self.print_source_entry(source) print "ISV" for source in self.sourceslist_visible: self.print_source_entry(source) def print_source_entry(self, source): """Print the data of a source entry to the command line""" print source.dist for (label, value) in [("URI:", source.uri), ("Comps:", source.comps), ("Enabled:", not source.disabled), ("Valid:", not source.invalid)]: print " %s %s" % (label, value) if source.template: for (label, value) in [("MatchURI:", source.template.match_uri), ("BaseURI:", source.template.base_uri)]: print " %s %s" % (label, value) print "\n" def on_combobox_server_changed(self, combobox): """ Replace the servers used by the main and update sources with the selected one """ server_store = combobox.get_model() iter = combobox.get_active_iter() uri_selected = server_store.get_value(iter, 1) sources = [] sources.extend(self.distro.main_sources) sources.extend(self.distro.child_sources) sources.extend(self.distro.source_code_sources) for source in sources: # FIXME: ugly if not "security.ubuntu.com" in source.uri: source.uri = uri_selected self.distro.ddefault_server = uri_selected self.modified_sourceslist() def on_component_toggled(self, checkbutton, comp): """ Sync the components of all main sources (excluding cdroms), child sources and source code sources """ if checkbutton.get_active() == True: self.distro.enable_component(self.sourceslist, comp) else: self.distro.disable_component(self.sourceslist, comp) self.modified_sourceslist() def massive_debug_output(self): """ do not write our changes yet - just print them to std_out """ print "START SOURCES.LIST:" for source in self.sourceslist: print source.str() print "END SOURCES.LIST\n" def on_checkbutton_child_toggled(self, checkbutton, template): """ Enable or disable a child repo of the distribution main repository """ if checkbutton.get_active() == False: for source in self.distro.child_sources: if source.template == template: self.sourceslist.remove(source) for source in self.distro.source_code_sources: if source.template == template: self.sourceslist.remove(source) else: self.distro.add_source(self.sourceslist, uri=template.base_uri, dist=template.name) self.modified_sourceslist() def on_checkbutton_source_code_toggled(self, checkbutton): """ Disable or enable the source code for all sources """ self.distro.get_source_code = checkbutton.get_active() sources = [] sources.extend(self.distro.main_sources) sources.extend(self.distro.child_sources) # remove all exisiting sources for source in self.distro.source_code_sources: self.sourceslist.remove(source) if checkbutton.get_active() == True: for source in sources: self.sourceslist.add("deb-src", source.uri, source.dist, source.comps, "Added by software-properties", self.sourceslist.list.index(source)+1, source.file) for source in self.distro.cdrom_sources: self.sourceslist.add("deb-src", self.distro.source_template.base_uri, self.distro.source_template.name, source.comps, "Added by software-properties", self.sourceslist.list.index(source)+1, source.file) self.modified_sourceslist() def on_checkbutton_popcon_toggled(self, widget): """ The user clicked on the popcon paritipcation button """ if widget.get_active(): new_value = "yes" else: new_value = "no" if os.path.exists(self.popconfile): # read it lines = open(self.popconfile).read().split("\n") for line in lines: try: (key,value) = line.split("=") if key == "PARTICIPATE": lines[lines.index(line)] = 'PARTICIPATE=\"%s"' % new_value except ValueError: continue # write it open(self.popconfile,"w").write("\n".join(lines)) def open_file(self, file): """Show an confirmation for adding the channels of the specified file""" dialog = dialog_add_sources_list.AddSourcesList(self.window_main, self.sourceslist, self.render_source, self.get_comparable, self.datadir, file) (res, new_sources) = dialog.run() if res == RESPONSE_REPLACE: self.sourceslist.list = [] if res in (RESPONSE_ADD, RESPONSE_REPLACE): for source in new_sources: self.sourceslist.add(source.type, source.uri, source.dist, source.comps, source.comment) self.modified_sourceslist() def on_sources_drag_data_received(self, widget, context, x, y, selection, target_type, timestamp): """Extract the dropped file pathes and open the first file, only""" uri = selection.data.strip() uri_splitted = uri.split() if len(uri_splitted)>0: self.open_file(uri_splitted[0]) def hide(self): self.window_main.hide() def init_sourceslist(self): """ Read all valid sources into our ListStore """ # STORE_ACTIVE - is the source enabled or disabled # STORE_DESCRIPTION - description of the source entry # STORE_SOURCE - the source entry object # STORE_SEPARATOR - if the entry is a separator # STORE_VISIBLE - if the entry is shown or hidden self.cdrom_store = gtk.ListStore(gobject.TYPE_BOOLEAN, gobject.TYPE_STRING, gobject.TYPE_PYOBJECT, gobject.TYPE_BOOLEAN, gobject.TYPE_BOOLEAN) self.treeview_cdroms.set_model(self.cdrom_store) self.source_store = gtk.ListStore(gobject.TYPE_BOOLEAN, gobject.TYPE_STRING, gobject.TYPE_PYOBJECT, gobject.TYPE_BOOLEAN, gobject.TYPE_BOOLEAN) self.treeview_sources.set_model(self.source_store) self.treeview_sources.set_row_separator_func(self.is_separator, STORE_SEPARATOR) cell_desc = gtk.CellRendererText() cell_desc.set_property("xpad", 2) cell_desc.set_property("ypad", 2) col_desc = gtk.TreeViewColumn(_("Software Channel"), cell_desc, markup=COLUMN_DESC) col_desc.set_max_width(1000) cell_toggle = gtk.CellRendererToggle() cell_toggle.set_property("xpad", 2) cell_toggle.set_property("ypad", 2) cell_toggle.connect('toggled', self.on_channel_toggled, self.cdrom_store) col_active = gtk.TreeViewColumn(_("Active"), cell_toggle, active=COLUMN_ACTIVE) self.treeview_cdroms.append_column(col_active) self.treeview_cdroms.append_column(col_desc) cell_desc = gtk.CellRendererText() cell_desc.set_property("xpad", 2) cell_desc.set_property("ypad", 2) col_desc = gtk.TreeViewColumn(_("Software Channel"), cell_desc, markup=COLUMN_DESC) col_desc.set_max_width(1000) cell_toggle = gtk.CellRendererToggle() cell_toggle.set_property("xpad", 2) cell_toggle.set_property("ypad", 2) cell_toggle.connect('toggled', self.on_channel_toggled, self.source_store) col_active = gtk.TreeViewColumn(_("Active"), cell_toggle, active=COLUMN_ACTIVE) self.treeview_sources.append_column(col_active) self.treeview_sources.append_column(col_desc) self.sourceslist = aptsources.SourcesList() def backup_sourceslist(self): """ Duplicate the list of sources """ self.sourceslist_backup = [] for source in self.sourceslist.list: source_bkp = aptsources.SourceEntry(line=source.line,file=source.file) self.sourceslist_backup.append(source_bkp) def on_channel_activate(self, treeview, path, column): """Open the edit dialog if a channel was double clicked""" self.on_edit_clicked(treeview) def on_treeview_sources_cursor_changed(self, treeview): """Enable the buttons remove and edit if a channel is selected""" sel = self.treeview_sources.get_selection() (model, iter) = sel.get_selected() if iter: self.button_edit.set_sensitive(True) self.button_remove.set_sensitive(True) else: self.button_edit.set_sensitive(False) self.button_remove.set_sensitive(False) def on_channel_toggled(self, cell_toggle, path, store): """Enable or disable the selected channel""" #FIXME cdroms need to disable the comps in the childs and sources iter = store.get_iter((int(path),)) source_entry = store.get_value(iter, STORE_SOURCE) source_entry.disabled = not source_entry.disabled store.set_value(iter, STORE_ACTIVE, not source_entry.disabled) self.modified_sourceslist() def init_keyslist(self): self.keys_store = gtk.ListStore(str) self.treeview2.set_model(self.keys_store) tr = gtk.CellRendererText() keys_col = gtk.TreeViewColumn("Key", tr, text=0) self.treeview2.append_column(keys_col) def on_button_revert_clicked(self, button): """Restore the source list from the startup of the dialog""" self.sourceslist.list = [] for source in self.sourceslist_backup: source_reset = aptsources.SourceEntry(line=source.line,file=source.file) self.sourceslist.list.append(source_reset) self.save_sourceslist() self.reload_sourceslist() self.button_revert.set_sensitive(False) self.modified = False def modified_sourceslist(self): """The sources list was changed and now needs to be saved and reloaded""" if self.options.massive_debug == True: self.massive_debug_output() self.modified = True self.button_revert.set_sensitive(True) self.save_sourceslist() self.reload_sourceslist() def render_source(self, source): """Render a nice output to show the source in a treeview""" if source.template == None: if source.comment: contents = "<b>%s</b>" % escape(source.comment) # Only show the components if there are more than one if len(source.comps) > 1: for c in source.comps: contents += " %s" % c else: contents = "<b>%s %s</b>" % (source.uri, source.dist) for c in source.comps: contents += " %s" % c if source.type in ("deb-src", "rpm-src"): contents += " %s" % _("(Source Code)") return contents else: # try to make use of an corresponding template contents = "<b>%s</b>" % source.template.description if source.type in ("deb-src", "rpm-src"): contents += " (%s)" % _("Source Code") if source.comment: contents +=" %s" % source.comment if source.template.child == False: for comp in source.comps: if source.template.components.has_key(comp): print source.template.components[comp] (desc, desc_long) = source.template.components[comp] contents += "\n%s" % desc else: contents += "\n%s" % comp return contents def get_comparable(self, source): """extract attributes to sort the sources""" cur_sys = 1 has_template = 1 has_comment = 1 is_source = 1 revert_numbers = string.maketrans("0123456789", "9876543210") if source.template: has_template = 0 desc = source.template.description if source.template.distribution == self.distro: cur_sys = 0 else: desc = "%s %s %s" % (source.uri, source.dist, source.comps) if source.comment: has_comment = 0 if source.type.find("src"): is_source = 0 return (cur_sys, has_template, has_comment, is_source, desc.translate(revert_numbers)) def reload_sourceslist(self): (path_x, path_y) = self.treeview_sources.get_cursor() self.source_store.clear() self.cdrom_store.clear() self.sourceslist.refresh() self.sourceslist_visible=[] self.distro.get_sources(self.sourceslist) # Only show sources that are no binary or source code repos for # the current distribution, but show cdrom based repos for source in self.sourceslist.list: if not source.invalid and\ (source not in self.distro.main_sources and\ source not in self.distro.cdrom_sources and\ source not in self.distro.child_sources and\ source not in self.distro.disabled_sources) and\ source not in self.distro.source_code_sources: self.sourceslist_visible.append(source) elif not source.invalid and source in self.distro.cdrom_sources: contents = self.render_source(source) self.cdrom_store.append([not source.disabled, contents, source, False, True]) # Sort the sources list self.sourceslist_visible.sort(key=self.get_comparable) for source in self.sourceslist_visible: contents = self.render_source(source) self.source_store.append([not source.disabled, contents, source, False, True]) (path_x, path_y) = self.treeview_sources.get_cursor() if len(self.source_store) < 1 or path_x <0: self.button_remove.set_sensitive(False) self.button_edit.set_sensitive(False) self.distro.get_sources(self.sourceslist) self.distro_to_widgets() def is_separator(self, model, iter, column): return model.get_value(iter, column) def reload_keyslist(self): self.keys_store.clear() for key in self.apt_key.list(): self.keys_store.append([key]) def on_combobox_update_interval_changed(self, widget): i = self.combobox_update_interval.get_active() if i != -1: value = self.combobox_interval_mapping[i] # Only write the key if it has changed if not value == apt_pkg.Config.FindI(CONF_MAP["autoupdate"]): apt_pkg.Config.Set(CONF_MAP["autoupdate"], str(value)) self.write_config() def on_opt_autoupdate_toggled(self, widget): if self.checkbutton_auto_update.get_active(): self.combobox_update_interval.set_sensitive(True) # if no frequency was specified use daily i = self.combobox_update_interval.get_active() if i == -1: i = 0 self.combobox_update_interval.set_active(i) value = self.combobox_interval_mapping[i] else: self.combobox_update_interval.set_sensitive(False) value = 0 apt_pkg.Config.Set(CONF_MAP["autoupdate"], str(value)) # FIXME: Write config options, apt_pkg should be able to do this. self.write_config() def on_opt_unattended_toggled(self, widget): if self.checkbutton_unattended.get_active(): self.checkbutton_unattended.set_active(True) apt_pkg.Config.Set(CONF_MAP["unattended"], str(1)) else: self.checkbutton_unattended.set_active(False) apt_pkg.Config.Set(CONF_MAP["unattended"], str(0)) # FIXME: Write config options, apt_pkg should be able to do this. self.write_config() def on_opt_autodownload_toggled(self, widget): if self.checkbutton_auto_download.get_active(): self.checkbutton_auto_download.set_active(True) apt_pkg.Config.Set(CONF_MAP["autodownload"], str(1)) else: self.checkbutton_auto_download.set_active(False) apt_pkg.Config.Set(CONF_MAP["autodownload"], str(0)) # FIXME: Write config options, apt_pkg should be able to do this. self.write_config() def on_combobox_delete_interval_changed(self, widget): i = self.combobox_delete_interval.get_active() if i != -1: value = self.combobox_delete_interval_mapping[i] # Only write the key if it has changed if not value == apt_pkg.Config.FindI(CONF_MAP["max_age"]): apt_pkg.Config.Set(CONF_MAP["max_age"], str(value)) self.write_config() def on_opt_autodelete_toggled(self, widget): if self.checkbutton_auto_delete.get_active(): self.combobox_delete_interval.set_sensitive(True) # if no frequency was specified use the first default value i = self.combobox_delete_interval.get_active() if i == -1: i = 0 self.combobox_delete_interval.set_active(i) value_maxage = self.combobox_delete_interval_mapping[i] value_clean = 1 apt_pkg.Config.Set(CONF_MAP["max_age"], str(value_maxage)) else: self.combobox_delete_interval.set_sensitive(False) value_clean = 0 apt_pkg.Config.Set(CONF_MAP["autoclean"], str(value_clean)) # FIXME: Write config options, apt_pkg should be able to do this. self.write_config() def write_config(self): # update the adept file as well if it is there conffiles = ["/etc/apt/apt.conf.d/10periodic", "/etc/apt/apt.conf.d/15adept-periodic-update"] # check (beforehand) if one exists, if not create one for f in conffiles: if os.path.isfile(f): break else: print "No config found, creating one" open(conffiles[0], "w") # now update them for periodic in conffiles: # read the old content first content = [] if os.path.isfile(periodic): content = open(periodic, "r").readlines() cnf = apt_pkg.Config.SubTree("APT::Periodic") # then write a new file without the updated keys f = open(periodic, "w") for line in content: for key in cnf.List(): if line.find("APT::Periodic::%s" % (key)) >= 0: break else: f.write(line) # and append the updated keys for i in cnf.List(): f.write("APT::Periodic::%s \"%s\";\n" % (i, cnf.FindI(i))) f.close() def save_sourceslist(self): #location = "/etc/apt/sources.list" #shutil.copy(location, location + ".save") self.sourceslist.backup(".save") self.sourceslist.save() def on_add_clicked(self, widget): dialog = dialog_add.dialog_add(self.window_main, self.sourceslist, self.datadir) line = dialog.run() if line != None: self.sourceslist.list.append(aptsources.SourceEntry(line)) self.modified_sourceslist() def on_edit_clicked(self, widget): sel = self.treeview_sources.get_selection() (model, iter) = sel.get_selected() if not iter: return source_entry = model.get_value(iter, LIST_ENTRY_OBJ) dialog = dialog_edit.dialog_edit(self.window_main, self.sourceslist, source_entry, self.datadir) if dialog.run() == gtk.RESPONSE_OK: self.modified_sourceslist() # FIXME:outstanding from merge def on_channel_activated(self, treeview, path, column): """Open the edit dialog if a channel was double clicked""" # check if the channel can be edited if self.button_edit.get_property("sensitive") == True: self.on_edit_clicked(treeview) # FIXME:outstanding from merge def on_treeview_sources_cursor_changed(self, treeview): """set the sensitiveness of the edit and remove button corresponding to the selected channel""" sel = self.treeview_sources.get_selection() (model, iter) = sel.get_selected() if not iter: # No channel is selected, so disable edit and remove self.button_edit.set_sensitive(False) self.button_remove.set_sensitive(False) return # allow to remove the selected channel self.button_remove.set_sensitive(True) # disable editing of cdrom sources source_entry = model.get_value(iter, LIST_ENTRY_OBJ) if source_entry.uri.startswith("cdrom:"): self.button_edit.set_sensitive(False) else: self.button_edit.set_sensitive(True) def on_remove_clicked(self, widget): model = self.treeview_sources.get_model() (path, column) = self.treeview_sources.get_cursor() iter = model.get_iter(path) if iter: source = model.get_value(iter, LIST_ENTRY_OBJ) self.sourceslist.remove(source) self.modified_sourceslist() def add_key_clicked(self, widget): chooser = gtk.FileChooserDialog(title=_("Import key"), parent=self.window_main, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK,gtk.RESPONSE_ACCEPT)) res = chooser.run() chooser.hide() if res == gtk.RESPONSE_ACCEPT: if not self.apt_key.add(chooser.get_filename()): error(self.window_main, _("Error importing selected file"), _("The selected file may not be a GPG key file " \ "or it might be corrupt.")) self.reload_keyslist() def remove_key_clicked(self, widget): selection = self.treeview2.get_selection() (model,a_iter) = selection.get_selected() if a_iter == None: return key = model.get_value(a_iter,0) if not self.apt_key.rm(key[:8]): error(self.main, _("Error removing the key"), _("The key you selected could not be removed. " "Please report this as a bug.")) self.reload_keyslist() def on_restore_clicked(self, widget): self.apt_key.update() self.reload_keyslist() def on_delete_event(self, widget, args): self.on_close_button(widget) def on_close_button(self, widget): # show a dialog that a reload of the channel information is required # only if there is no parent defined if self.modified == True and \ self.options.toplevel == None: d = dialog_cache_outdated.DialogCacheOutdated(self.window_main, self.datadir) res = d.run() self.quit() def on_help_button(self, widget): self.help_viewer.run() def on_button_add_cdrom_clicked(self, widget): #print "on_button_add_cdrom_clicked()" # testing #apt_pkg.Config.Set("APT::CDROM::Rename","true") saved_entry = apt_pkg.Config.Find("Dir::Etc::sourcelist") tmp = tempfile.NamedTemporaryFile() apt_pkg.Config.Set("Dir::Etc::sourcelist",tmp.name) progress = GtkCdromProgress(self.datadir,self.window_main) cdrom = apt_pkg.GetCdrom() # if nothing was found just return try: res = cdrom.Add(progress) except SystemError, msg: #print "aiiiieeee, exception from cdrom.Add() [%s]" % msg progress.close() dialog = gtk.MessageDialog(parent=self.window_main, flags=gtk.DIALOG_MODAL, type=gtk.MESSAGE_ERROR, buttons=gtk.BUTTONS_OK, message_format=None) dialog.set_markup(_("<big><b>Error scanning the CD</b></big>\n\n%s"%msg)) res = dialog.run() dialog.destroy() return apt_pkg.Config.Set("Dir::Etc::sourcelist",saved_entry) if res == False: progress.close() return # read tmp file with source name (read only last line) line = "" for x in open(tmp.name): line = x if line != "": full_path = "%s%s" % (apt_pkg.Config.FindDir("Dir::Etc"),saved_entry) self.sourceslist.list.append(aptsources.SourceEntry(line,full_path)) self.reload_sourceslist() self.modified = True
class SoftwareProperties(SimpleGladeApp): def __init__(self, datadir=None, options=None, parent=None, file=None): gtk.window_set_default_icon_name("software-properties") self.popconfile = "/etc/popularity-contest.conf" # FIXME: some saner way is needed here if datadir == None: datadir = "/usr/share/update-manager/" self.datadir = datadir SimpleGladeApp.__init__(self, datadir + "glade/SoftwareProperties.glade", None, domain="update-manager") self.modified = False self.file = file self.distro = aptsources.Distribution() cell = gtk.CellRendererText() self.combobox_server.pack_start(cell, True) self.combobox_server.add_attribute(cell, 'text', 0) # set up the handler id for the callbacks self.handler_server_changed = self.combobox_server.connect( "changed", self.on_combobox_server_changed) self.handler_source_code_changed = self.checkbutton_source_code.connect( "toggled", self.on_checkbutton_source_code_toggled) if parent: self.window_main.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG) self.window_main.show() self.window_main.set_transient_for(parent) # If externally called, reparent to external application. self.options = options if options and options.toplevel != None: self.window_main.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG) self.window_main.show() toplevel = gtk.gdk.window_foreign_new(int(options.toplevel)) self.window_main.window.set_transient_for(toplevel) self.init_sourceslist() self.reload_sourceslist() self.backup_sourceslist() self.window_main.show() # this maps the key (combo-box-index) to the auto-update-interval value # where (-1) means, no key self.combobox_interval_mapping = {0: 1, 1: 2, 2: 7, 3: 14} self.combobox_update_interval.set_active(0) update_days = apt_pkg.Config.FindI(CONF_MAP["autoupdate"]) self.combobox_update_interval.append_text(_("Daily")) self.combobox_update_interval.append_text(_("Every two days")) self.combobox_update_interval.append_text(_("Weekly")) self.combobox_update_interval.append_text(_("Every two weeks")) # If a custom period is defined add an corresponding entry if not update_days in self.combobox_interval_mapping.values(): if update_days > 0: self.combobox_update_interval.append_text( _("Every %s days") % update_days) self.combobox_interval_mapping[4] = update_days for key in self.combobox_interval_mapping: if self.combobox_interval_mapping[key] == update_days: self.combobox_update_interval.set_active(key) break if update_days >= 1: self.checkbutton_auto_update.set_active(True) self.combobox_update_interval.set_sensitive(True) else: self.checkbutton_auto_update.set_active(False) self.combobox_update_interval.set_sensitive(False) # Automatic removal of cached packages by age self.combobox_delete_interval_mapping = {0: 7, 1: 14, 2: 30} delete_days = apt_pkg.Config.FindI(CONF_MAP["max_age"]) self.combobox_delete_interval.append_text(_("After one week")) self.combobox_delete_interval.append_text(_("After two weeks")) self.combobox_delete_interval.append_text(_("After one month")) # If a custom period is defined add an corresponding entry if not delete_days in self.combobox_delete_interval_mapping.values(): if delete_days > 0 and CONF_MAP["autoclean"] != 0: self.combobox_delete_interval.append_text( _("After %s days") % delete_days) self.combobox_delete_interval_mapping[3] = delete_days for key in self.combobox_delete_interval_mapping: if self.combobox_delete_interval_mapping[key] == delete_days: self.combobox_delete_interval.set_active(key) break if delete_days >= 1 and apt_pkg.Config.FindI( CONF_MAP["autoclean"]) != 0: self.checkbutton_auto_delete.set_active(True) self.combobox_delete_interval.set_sensitive(True) else: self.checkbutton_auto_delete.set_active(False) self.combobox_delete_interval.set_sensitive(False) # Autodownload if apt_pkg.Config.FindI(CONF_MAP["autodownload"]) == 1: self.checkbutton_auto_download.set_active(True) else: self.checkbutton_auto_download.set_active(False) # Unattended updates if os.path.exists("/usr/bin/unattended-upgrade"): # FIXME: we should always show the option. if unattended-upgrades is # not installed a dialog should popup and allow the user to install # unattended-upgrade #self.checkbutton_unattended.set_sensitive(True) self.checkbutton_unattended.show() else: #self.checkbutton_unattended.set_sensitive(False) self.checkbutton_unattended.hide() if apt_pkg.Config.FindI(CONF_MAP["unattended"]) == 1: self.checkbutton_unattended.set_active(True) else: self.checkbutton_unattended.set_active(False) self.help_viewer = HelpViewer("update-manager#setting-preferences") if self.help_viewer.check() == False: self.button_help.set_sensitive(False) # apt-key stuff self.apt_key = apt_key() self.init_keyslist() self.reload_keyslist() # drag and drop support for sources.list self.treeview_sources.drag_dest_set(gtk.DEST_DEFAULT_ALL, \ [('text/uri-list',0, 0)], \ gtk.gdk.ACTION_COPY) self.treeview_sources.connect("drag_data_received",\ self.on_sources_drag_data_received) # popcon if os.path.exists(self.popconfile): # read it lines = open(self.popconfile).read().split("\n") active = False for line in lines: try: (key, value) = line.split("=") if key == "PARTICIPATE": if value.strip('"').lower() == "yes": active = True except ValueError: continue self.checkbutton_popcon.set_active(active) # call the add sources.list dialog if we got a file from the cli if self.file != None: self.open_file(file) def distro_to_widgets(self): """ Represent the distro information in the user interface """ # TRANS: %s stands for the distribution name e.g. Debian or Ubuntu self.label_updates.set_label("<b>%s</b>" % (_("%s updates") %\ self.distro.id)) # TRANS: %s stands for the distribution name e.g. Debian or Ubuntu self.label_dist_name.set_label("%s" % self.distro.description) # Setup the checkbuttons for the components for checkbutton in self.vbox_dist_comps.get_children(): self.vbox_dist_comps.remove(checkbutton) for comp in self.distro.source_template.components.keys(): # TRANSLATORS: Label for the components in the Internet section # first %s is the description of the component # second %s is the code name of the comp, eg main, universe label = _("%s (%s)") % ( self.distro.source_template.components[comp][1], comp) checkbox = gtk.CheckButton(label) # check if the comp is enabled # FIXME: use inconsistence if there are main sources with not all comps if comp in self.distro.download_comps: checkbox.set_active(True) # setup the callback and show the checkbutton checkbox.connect("toggled", self.on_component_toggled, comp) self.vbox_dist_comps.add(checkbox) checkbox.show() # Setup the checkbuttons for the child repos / updates for checkbutton in self.vbox_updates.get_children(): self.vbox_updates.remove(checkbutton) for template in self.distro.source_template.children: checkbox = gtk.CheckButton(label=template.description) comps = [] for child in self.distro.child_sources: if child.template == template: comps.extend(child.comps) # check if all comps of the main source are also enabled # for the corresponding child sources if len(comps) > 0 and \ len(self.distro.enabled_comps ^ set(comps)) == 0: # the cild source covers all components checkbox.set_active(True) elif len(comps) > 0 and\ len(self.distro.enabled_comps ^ set(comps)) != 0: # the cild is enabled, but doesn't cover # all components checkbox.set_active(False) checkbox.set_inconsistent(True) else: # there is no corresponding child source at all checkbox.set_active(False) # setup the callback and show the checkbutton checkbox.connect("toggled", self.on_checkbutton_child_toggled, template) self.vbox_updates.add(checkbox) checkbox.show() if len(self.distro.enabled_comps) < 1: self.vbox_updates.set_sensitive(False) else: self.vbox_updates.set_sensitive(True) # Intiate the combobox which allows do specify a server for all # distro related sources self.combobox_server.handler_block(self.handler_server_changed) server_store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING) self.combobox_server.set_model(server_store) server_store.append([_("Main server"), self.distro.main_server]) if self.distro.country != None: # TRANSLATORS: %s is a country server_store.append([ _("Server for %s") % gettext.dgettext("iso-3166", self.distro.country).rstrip(), self.distro.nearest_server ]) else: server_store.append( [_("Nearest server"), self.distro.nearest_server]) if len(self.distro.used_servers) > 0: for server in self.distro.used_servers: if not re.match(server, self.distro.main_server) and \ not re.match(server, self.distro.nearest_server): # FIXME: use regexp here instead of this country = "" i = server.find("://") l = server.find(".archive.ubuntu.com") if i != -1 and l != -1: country = server[i + len("://"):l] if self.distro.countries.has_key(country): # TRANSLATORS: %s is a country server_store.append([_("Server for %s") % \ gettext.dgettext("iso-3166", self.distro.countries[country].rstrip()), server]) else: server_store.append(["%s" % server, server]) if len(self.distro.used_servers) > 1: server_store.append([_("Custom servers"), None]) self.combobox_server.set_active(2) elif self.distro.used_servers[0] == self.distro.main_server: self.combobox_server.set_active(0) elif self.distro.used_servers[0] == self.distro.nearest_server: self.combobox_server.set_active(1) elif len(self.distro.used_servers) == 1: self.combobox_server.set_active(2) else: self.combobox_server.set_active(0) self.combobox_server.handler_unblock(self.handler_server_changed) # Check for source code sources self.checkbutton_source_code.handler_block( self.handler_source_code_changed) self.checkbutton_source_code.set_inconsistent(False) if len(self.distro.source_code_sources) < 1: # we don't have any source code sources, so # uncheck the button self.checkbutton_source_code.set_active(False) self.distro.get_source_code = False else: # there are source code sources, so we check the button self.checkbutton_source_code.set_active(True) self.distro.get_source_code = True # check if there is a corresponding source code source for # every binary source. if not set the checkbutton to inconsistent templates = {} sources = [] sources.extend(self.distro.main_sources) sources.extend(self.distro.child_sources) for source in sources: if templates.has_key(source.template): for comp in source.comps: templates[source.template].add(comp) else: templates[source.template] = set(source.comps) # add fake http sources for the cdrom, since the sources # for the cdrom are only available in the internet if len(self.distro.cdrom_sources) > 0: templates[ self.distro.source_template] = self.distro.cdrom_comps for source in self.distro.source_code_sources: if not templates.has_key(source.template) or \ (templates.has_key(source.template) and not \ (len(set(templates[source.template]) ^ set(source.comps)) == 0\ or (len(set(source.comps) ^ self.distro.enabled_comps) == 0))): self.checkbutton_source_code.set_inconsistent(True) self.distro.get_source_code = False break self.checkbutton_source_code.handler_unblock( self.handler_source_code_changed) if len(self.cdrom_store) == 0: self.treeview_cdroms.set_sensitive(False) else: self.treeview_cdroms.set_sensitive(True) if self.options.debug == True or self.options.massive_debug == True: print "ENABLED COMPS: %s" % self.distro.enabled_comps print "INTERNET COMPS: %s" % self.distro.download_comps print "MAIN SOURCES" for source in self.distro.main_sources: self.print_source_entry(source) print "CHILD SOURCES" for source in self.distro.child_sources: self.print_source_entry(source) print "CDROM SOURCES" for source in self.distro.cdrom_sources: self.print_source_entry(source) print "SOURCE CODE SOURCES" for source in self.distro.source_code_sources: self.print_source_entry(source) print "DISABLED SOURCES" for source in self.distro.disabled_sources: self.print_source_entry(source) print "ISV" for source in self.sourceslist_visible: self.print_source_entry(source) def print_source_entry(self, source): """Print the data of a source entry to the command line""" print source.dist for (label, value) in [("URI:", source.uri), ("Comps:", source.comps), ("Enabled:", not source.disabled), ("Valid:", not source.invalid)]: print " %s %s" % (label, value) if source.template: for (label, value) in [("MatchURI:", source.template.match_uri), ("BaseURI:", source.template.base_uri)]: print " %s %s" % (label, value) print "\n" def on_combobox_server_changed(self, combobox): """ Replace the servers used by the main and update sources with the selected one """ server_store = combobox.get_model() iter = combobox.get_active_iter() uri_selected = server_store.get_value(iter, 1) sources = [] sources.extend(self.distro.main_sources) sources.extend(self.distro.child_sources) sources.extend(self.distro.source_code_sources) for source in sources: # FIXME: ugly if not "security.ubuntu.com" in source.uri: source.uri = uri_selected self.distro.ddefault_server = uri_selected self.modified_sourceslist() def on_component_toggled(self, checkbutton, comp): """ Sync the components of all main sources (excluding cdroms), child sources and source code sources """ if checkbutton.get_active() == True: self.distro.enable_component(self.sourceslist, comp) else: self.distro.disable_component(self.sourceslist, comp) self.modified_sourceslist() def massive_debug_output(self): """ do not write our changes yet - just print them to std_out """ print "START SOURCES.LIST:" for source in self.sourceslist: print source.str() print "END SOURCES.LIST\n" def on_checkbutton_child_toggled(self, checkbutton, template): """ Enable or disable a child repo of the distribution main repository """ if checkbutton.get_active() == False: for source in self.distro.child_sources: if source.template == template: self.sourceslist.remove(source) for source in self.distro.source_code_sources: if source.template == template: self.sourceslist.remove(source) else: self.distro.add_source(self.sourceslist, uri=template.base_uri, dist=template.name) self.modified_sourceslist() def on_checkbutton_source_code_toggled(self, checkbutton): """ Disable or enable the source code for all sources """ self.distro.get_source_code = checkbutton.get_active() sources = [] sources.extend(self.distro.main_sources) sources.extend(self.distro.child_sources) # remove all exisiting sources for source in self.distro.source_code_sources: self.sourceslist.remove(source) if checkbutton.get_active() == True: for source in sources: self.sourceslist.add("deb-src", source.uri, source.dist, source.comps, "Added by software-properties", self.sourceslist.list.index(source) + 1, source.file) for source in self.distro.cdrom_sources: self.sourceslist.add("deb-src", self.distro.source_template.base_uri, self.distro.source_template.name, source.comps, "Added by software-properties", self.sourceslist.list.index(source) + 1, source.file) self.modified_sourceslist() def on_checkbutton_popcon_toggled(self, widget): """ The user clicked on the popcon paritipcation button """ if widget.get_active(): new_value = "yes" else: new_value = "no" if os.path.exists(self.popconfile): # read it lines = open(self.popconfile).read().split("\n") for line in lines: try: (key, value) = line.split("=") if key == "PARTICIPATE": lines[lines.index( line)] = 'PARTICIPATE=\"%s"' % new_value except ValueError: continue # write it open(self.popconfile, "w").write("\n".join(lines)) def open_file(self, file): """Show an confirmation for adding the channels of the specified file""" dialog = dialog_add_sources_list.AddSourcesList( self.window_main, self.sourceslist, self.render_source, self.get_comparable, self.datadir, file) (res, new_sources) = dialog.run() if res == RESPONSE_REPLACE: self.sourceslist.list = [] if res in (RESPONSE_ADD, RESPONSE_REPLACE): for source in new_sources: self.sourceslist.add(source.type, source.uri, source.dist, source.comps, source.comment) self.modified_sourceslist() def on_sources_drag_data_received(self, widget, context, x, y, selection, target_type, timestamp): """Extract the dropped file pathes and open the first file, only""" uri = selection.data.strip() uri_splitted = uri.split() if len(uri_splitted) > 0: self.open_file(uri_splitted[0]) def hide(self): self.window_main.hide() def init_sourceslist(self): """ Read all valid sources into our ListStore """ # STORE_ACTIVE - is the source enabled or disabled # STORE_DESCRIPTION - description of the source entry # STORE_SOURCE - the source entry object # STORE_SEPARATOR - if the entry is a separator # STORE_VISIBLE - if the entry is shown or hidden self.cdrom_store = gtk.ListStore(gobject.TYPE_BOOLEAN, gobject.TYPE_STRING, gobject.TYPE_PYOBJECT, gobject.TYPE_BOOLEAN, gobject.TYPE_BOOLEAN) self.treeview_cdroms.set_model(self.cdrom_store) self.source_store = gtk.ListStore(gobject.TYPE_BOOLEAN, gobject.TYPE_STRING, gobject.TYPE_PYOBJECT, gobject.TYPE_BOOLEAN, gobject.TYPE_BOOLEAN) self.treeview_sources.set_model(self.source_store) self.treeview_sources.set_row_separator_func(self.is_separator, STORE_SEPARATOR) cell_desc = gtk.CellRendererText() cell_desc.set_property("xpad", 2) cell_desc.set_property("ypad", 2) col_desc = gtk.TreeViewColumn(_("Software Channel"), cell_desc, markup=COLUMN_DESC) col_desc.set_max_width(1000) cell_toggle = gtk.CellRendererToggle() cell_toggle.set_property("xpad", 2) cell_toggle.set_property("ypad", 2) cell_toggle.connect('toggled', self.on_channel_toggled, self.cdrom_store) col_active = gtk.TreeViewColumn(_("Active"), cell_toggle, active=COLUMN_ACTIVE) self.treeview_cdroms.append_column(col_active) self.treeview_cdroms.append_column(col_desc) cell_desc = gtk.CellRendererText() cell_desc.set_property("xpad", 2) cell_desc.set_property("ypad", 2) col_desc = gtk.TreeViewColumn(_("Software Channel"), cell_desc, markup=COLUMN_DESC) col_desc.set_max_width(1000) cell_toggle = gtk.CellRendererToggle() cell_toggle.set_property("xpad", 2) cell_toggle.set_property("ypad", 2) cell_toggle.connect('toggled', self.on_channel_toggled, self.source_store) col_active = gtk.TreeViewColumn(_("Active"), cell_toggle, active=COLUMN_ACTIVE) self.treeview_sources.append_column(col_active) self.treeview_sources.append_column(col_desc) self.sourceslist = aptsources.SourcesList() def backup_sourceslist(self): """ Duplicate the list of sources """ self.sourceslist_backup = [] for source in self.sourceslist.list: source_bkp = aptsources.SourceEntry(line=source.line, file=source.file) self.sourceslist_backup.append(source_bkp) def on_channel_activate(self, treeview, path, column): """Open the edit dialog if a channel was double clicked""" self.on_edit_clicked(treeview) def on_treeview_sources_cursor_changed(self, treeview): """Enable the buttons remove and edit if a channel is selected""" sel = self.treeview_sources.get_selection() (model, iter) = sel.get_selected() if iter: self.button_edit.set_sensitive(True) self.button_remove.set_sensitive(True) else: self.button_edit.set_sensitive(False) self.button_remove.set_sensitive(False) def on_channel_toggled(self, cell_toggle, path, store): """Enable or disable the selected channel""" #FIXME cdroms need to disable the comps in the childs and sources iter = store.get_iter((int(path), )) source_entry = store.get_value(iter, STORE_SOURCE) source_entry.disabled = not source_entry.disabled store.set_value(iter, STORE_ACTIVE, not source_entry.disabled) self.modified_sourceslist() def init_keyslist(self): self.keys_store = gtk.ListStore(str) self.treeview2.set_model(self.keys_store) tr = gtk.CellRendererText() keys_col = gtk.TreeViewColumn("Key", tr, text=0) self.treeview2.append_column(keys_col) def on_button_revert_clicked(self, button): """Restore the source list from the startup of the dialog""" self.sourceslist.list = [] for source in self.sourceslist_backup: source_reset = aptsources.SourceEntry(line=source.line, file=source.file) self.sourceslist.list.append(source_reset) self.save_sourceslist() self.reload_sourceslist() self.button_revert.set_sensitive(False) self.modified = False def modified_sourceslist(self): """The sources list was changed and now needs to be saved and reloaded""" if self.options.massive_debug == True: self.massive_debug_output() self.modified = True self.button_revert.set_sensitive(True) self.save_sourceslist() self.reload_sourceslist() def render_source(self, source): """Render a nice output to show the source in a treeview""" if source.template == None: if source.comment: contents = "<b>%s</b>" % escape(source.comment) # Only show the components if there are more than one if len(source.comps) > 1: for c in source.comps: contents += " %s" % c else: contents = "<b>%s %s</b>" % (source.uri, source.dist) for c in source.comps: contents += " %s" % c if source.type in ("deb-src", "rpm-src"): contents += " %s" % _("(Source Code)") return contents else: # try to make use of an corresponding template contents = "<b>%s</b>" % source.template.description if source.type in ("deb-src", "rpm-src"): contents += " (%s)" % _("Source Code") if source.comment: contents += " %s" % source.comment if source.template.child == False: for comp in source.comps: if source.template.components.has_key(comp): print source.template.components[comp] (desc, desc_long) = source.template.components[comp] contents += "\n%s" % desc else: contents += "\n%s" % comp return contents def get_comparable(self, source): """extract attributes to sort the sources""" cur_sys = 1 has_template = 1 has_comment = 1 is_source = 1 revert_numbers = string.maketrans("0123456789", "9876543210") if source.template: has_template = 0 desc = source.template.description if source.template.distribution == self.distro: cur_sys = 0 else: desc = "%s %s %s" % (source.uri, source.dist, source.comps) if source.comment: has_comment = 0 if source.type.find("src"): is_source = 0 return (cur_sys, has_template, has_comment, is_source, desc.translate(revert_numbers)) def reload_sourceslist(self): (path_x, path_y) = self.treeview_sources.get_cursor() self.source_store.clear() self.cdrom_store.clear() self.sourceslist.refresh() self.sourceslist_visible = [] self.distro.get_sources(self.sourceslist) # Only show sources that are no binary or source code repos for # the current distribution, but show cdrom based repos for source in self.sourceslist.list: if not source.invalid and\ (source not in self.distro.main_sources and\ source not in self.distro.cdrom_sources and\ source not in self.distro.child_sources and\ source not in self.distro.disabled_sources) and\ source not in self.distro.source_code_sources: self.sourceslist_visible.append(source) elif not source.invalid and source in self.distro.cdrom_sources: contents = self.render_source(source) self.cdrom_store.append( [not source.disabled, contents, source, False, True]) # Sort the sources list self.sourceslist_visible.sort(key=self.get_comparable) for source in self.sourceslist_visible: contents = self.render_source(source) self.source_store.append( [not source.disabled, contents, source, False, True]) (path_x, path_y) = self.treeview_sources.get_cursor() if len(self.source_store) < 1 or path_x < 0: self.button_remove.set_sensitive(False) self.button_edit.set_sensitive(False) self.distro.get_sources(self.sourceslist) self.distro_to_widgets() def is_separator(self, model, iter, column): return model.get_value(iter, column) def reload_keyslist(self): self.keys_store.clear() for key in self.apt_key.list(): self.keys_store.append([key]) def on_combobox_update_interval_changed(self, widget): i = self.combobox_update_interval.get_active() if i != -1: value = self.combobox_interval_mapping[i] # Only write the key if it has changed if not value == apt_pkg.Config.FindI(CONF_MAP["autoupdate"]): apt_pkg.Config.Set(CONF_MAP["autoupdate"], str(value)) self.write_config() def on_opt_autoupdate_toggled(self, widget): if self.checkbutton_auto_update.get_active(): self.combobox_update_interval.set_sensitive(True) # if no frequency was specified use daily i = self.combobox_update_interval.get_active() if i == -1: i = 0 self.combobox_update_interval.set_active(i) value = self.combobox_interval_mapping[i] else: self.combobox_update_interval.set_sensitive(False) value = 0 apt_pkg.Config.Set(CONF_MAP["autoupdate"], str(value)) # FIXME: Write config options, apt_pkg should be able to do this. self.write_config() def on_opt_unattended_toggled(self, widget): if self.checkbutton_unattended.get_active(): self.checkbutton_unattended.set_active(True) apt_pkg.Config.Set(CONF_MAP["unattended"], str(1)) else: self.checkbutton_unattended.set_active(False) apt_pkg.Config.Set(CONF_MAP["unattended"], str(0)) # FIXME: Write config options, apt_pkg should be able to do this. self.write_config() def on_opt_autodownload_toggled(self, widget): if self.checkbutton_auto_download.get_active(): self.checkbutton_auto_download.set_active(True) apt_pkg.Config.Set(CONF_MAP["autodownload"], str(1)) else: self.checkbutton_auto_download.set_active(False) apt_pkg.Config.Set(CONF_MAP["autodownload"], str(0)) # FIXME: Write config options, apt_pkg should be able to do this. self.write_config() def on_combobox_delete_interval_changed(self, widget): i = self.combobox_delete_interval.get_active() if i != -1: value = self.combobox_delete_interval_mapping[i] # Only write the key if it has changed if not value == apt_pkg.Config.FindI(CONF_MAP["max_age"]): apt_pkg.Config.Set(CONF_MAP["max_age"], str(value)) self.write_config() def on_opt_autodelete_toggled(self, widget): if self.checkbutton_auto_delete.get_active(): self.combobox_delete_interval.set_sensitive(True) # if no frequency was specified use the first default value i = self.combobox_delete_interval.get_active() if i == -1: i = 0 self.combobox_delete_interval.set_active(i) value_maxage = self.combobox_delete_interval_mapping[i] value_clean = 1 apt_pkg.Config.Set(CONF_MAP["max_age"], str(value_maxage)) else: self.combobox_delete_interval.set_sensitive(False) value_clean = 0 apt_pkg.Config.Set(CONF_MAP["autoclean"], str(value_clean)) # FIXME: Write config options, apt_pkg should be able to do this. self.write_config() def write_config(self): # update the adept file as well if it is there conffiles = [ "/etc/apt/apt.conf.d/10periodic", "/etc/apt/apt.conf.d/15adept-periodic-update" ] # check (beforehand) if one exists, if not create one for f in conffiles: if os.path.isfile(f): break else: print "No config found, creating one" open(conffiles[0], "w") # now update them for periodic in conffiles: # read the old content first content = [] if os.path.isfile(periodic): content = open(periodic, "r").readlines() cnf = apt_pkg.Config.SubTree("APT::Periodic") # then write a new file without the updated keys f = open(periodic, "w") for line in content: for key in cnf.List(): if line.find("APT::Periodic::%s" % (key)) >= 0: break else: f.write(line) # and append the updated keys for i in cnf.List(): f.write("APT::Periodic::%s \"%s\";\n" % (i, cnf.FindI(i))) f.close() def save_sourceslist(self): #location = "/etc/apt/sources.list" #shutil.copy(location, location + ".save") self.sourceslist.backup(".save") self.sourceslist.save() def on_add_clicked(self, widget): dialog = dialog_add.dialog_add(self.window_main, self.sourceslist, self.datadir) line = dialog.run() if line != None: self.sourceslist.list.append(aptsources.SourceEntry(line)) self.modified_sourceslist() def on_edit_clicked(self, widget): sel = self.treeview_sources.get_selection() (model, iter) = sel.get_selected() if not iter: return source_entry = model.get_value(iter, LIST_ENTRY_OBJ) dialog = dialog_edit.dialog_edit(self.window_main, self.sourceslist, source_entry, self.datadir) if dialog.run() == gtk.RESPONSE_OK: self.modified_sourceslist() # FIXME:outstanding from merge def on_channel_activated(self, treeview, path, column): """Open the edit dialog if a channel was double clicked""" # check if the channel can be edited if self.button_edit.get_property("sensitive") == True: self.on_edit_clicked(treeview) # FIXME:outstanding from merge def on_treeview_sources_cursor_changed(self, treeview): """set the sensitiveness of the edit and remove button corresponding to the selected channel""" sel = self.treeview_sources.get_selection() (model, iter) = sel.get_selected() if not iter: # No channel is selected, so disable edit and remove self.button_edit.set_sensitive(False) self.button_remove.set_sensitive(False) return # allow to remove the selected channel self.button_remove.set_sensitive(True) # disable editing of cdrom sources source_entry = model.get_value(iter, LIST_ENTRY_OBJ) if source_entry.uri.startswith("cdrom:"): self.button_edit.set_sensitive(False) else: self.button_edit.set_sensitive(True) def on_remove_clicked(self, widget): model = self.treeview_sources.get_model() (path, column) = self.treeview_sources.get_cursor() iter = model.get_iter(path) if iter: source = model.get_value(iter, LIST_ENTRY_OBJ) self.sourceslist.remove(source) self.modified_sourceslist() def add_key_clicked(self, widget): chooser = gtk.FileChooserDialog( title=_("Import key"), parent=self.window_main, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)) res = chooser.run() chooser.hide() if res == gtk.RESPONSE_ACCEPT: if not self.apt_key.add(chooser.get_filename()): error(self.window_main, _("Error importing selected file"), _("The selected file may not be a GPG key file " \ "or it might be corrupt.")) self.reload_keyslist() def remove_key_clicked(self, widget): selection = self.treeview2.get_selection() (model, a_iter) = selection.get_selected() if a_iter == None: return key = model.get_value(a_iter, 0) if not self.apt_key.rm(key[:8]): error( self.main, _("Error removing the key"), _("The key you selected could not be removed. " "Please report this as a bug.")) self.reload_keyslist() def on_restore_clicked(self, widget): self.apt_key.update() self.reload_keyslist() def on_delete_event(self, widget, args): self.on_close_button(widget) def on_close_button(self, widget): # show a dialog that a reload of the channel information is required # only if there is no parent defined if self.modified == True and \ self.options.toplevel == None: d = dialog_cache_outdated.DialogCacheOutdated( self.window_main, self.datadir) res = d.run() self.quit() def on_help_button(self, widget): self.help_viewer.run() def on_button_add_cdrom_clicked(self, widget): #print "on_button_add_cdrom_clicked()" # testing #apt_pkg.Config.Set("APT::CDROM::Rename","true") saved_entry = apt_pkg.Config.Find("Dir::Etc::sourcelist") tmp = tempfile.NamedTemporaryFile() apt_pkg.Config.Set("Dir::Etc::sourcelist", tmp.name) progress = GtkCdromProgress(self.datadir, self.window_main) cdrom = apt_pkg.GetCdrom() # if nothing was found just return try: res = cdrom.Add(progress) except SystemError, msg: #print "aiiiieeee, exception from cdrom.Add() [%s]" % msg progress.close() dialog = gtk.MessageDialog(parent=self.window_main, flags=gtk.DIALOG_MODAL, type=gtk.MESSAGE_ERROR, buttons=gtk.BUTTONS_OK, message_format=None) dialog.set_markup( _("<big><b>Error scanning the CD</b></big>\n\n%s" % msg)) res = dialog.run() dialog.destroy() return apt_pkg.Config.Set("Dir::Etc::sourcelist", saved_entry) if res == False: progress.close() return # read tmp file with source name (read only last line) line = "" for x in open(tmp.name): line = x if line != "": full_path = "%s%s" % (apt_pkg.Config.FindDir("Dir::Etc"), saved_entry) self.sourceslist.list.append( aptsources.SourceEntry(line, full_path)) self.reload_sourceslist() self.modified = True