예제 #1
0
 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()
예제 #2
0
 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)
예제 #3
0
 def check_line(self, *args):
     """
 Check for a valid apt line and set the sensitiveness of the
 button 'add' accordingly
 """
     line = self.entry.get_text() + "\n"
     source_entry = aptsources.SourceEntry(line)
     if source_entry.invalid == True or source_entry.disabled == True:
         self.button_add.set_sensitive(False)
     else:
         self.button_add.set_sensitive(True)
예제 #4
0
 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
예제 #5
0
 def check_line(self, *args):
   """Check for a valid apt line and set the sensitiveness of the
      button 'add' accordingly"""
   line = self.get_line()
   if line == False:
     self.button_edit_ok.set_sensitive(False)
     return
   source_entry = aptsources.SourceEntry(line)
   if (source_entry.invalid == True or source_entry.disabled == True):
     self.button_edit_ok.set_sensitive(False)
   else:
     self.button_edit_ok.set_sensitive(True)
예제 #6
0
  def run(self):
      res = self.main.run()
      if res == gtk.RESPONSE_OK:
        line = self.get_line()

        # change repository
        index = self.sourceslist.list.index(self.source_entry)
        file = self.sourceslist.list[index].file
        self.sourceslist.list[index] = aptsources.SourceEntry(line,file)
        #self.sourceslist.add(self.selected.type,
        #                     self.selected.uri,
        #                     self.selected.dist,
        #                     self.selected_comps)
      self.main.hide()
      return res
예제 #7
0
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