summaryrefslogtreecommitdiff
path: root/SoftwareProperties
diff options
context:
space:
mode:
Diffstat (limited to 'SoftwareProperties')
-rw-r--r--SoftwareProperties/SoftwareProperties.py646
-rw-r--r--SoftwareProperties/aptsources.py573
-rw-r--r--SoftwareProperties/dialog_add.py187
-rw-r--r--SoftwareProperties/dialog_add_sources_list.py127
-rw-r--r--SoftwareProperties/dialog_edit.py2
5 files changed, 724 insertions, 811 deletions
diff --git a/SoftwareProperties/SoftwareProperties.py b/SoftwareProperties/SoftwareProperties.py
index 65b72cda..18e5d260 100644
--- a/SoftwareProperties/SoftwareProperties.py
+++ b/SoftwareProperties/SoftwareProperties.py
@@ -21,6 +21,7 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
# USA
+#import pdb
import sys
import apt
import apt_pkg
@@ -30,15 +31,18 @@ import gettext
import tempfile
from gettext import gettext as _
import os
+import string
+import re
#sys.path.append("@prefix/share/update-manager/python")
from UpdateManager.Common.SimpleGladeApp import SimpleGladeApp
from UpdateManager.Common.HelpViewer import HelpViewer
-import aptsources
+import UpdateManager.Common.aptsources as aptsources
import dialog_add
import dialog_edit
import dialog_cache_outdated
+import dialog_add_sources_list
from dialog_apt_key import apt_key
from utils import *
@@ -53,10 +57,27 @@ CONF_MAP = {
"max_age" : "APT::Archives::MaxAge"
}
+(
+ COLUMN_ACTIVE,
+ COLUMN_DESC
+) = range(2)
+
+RESPONSE_REPLACE = 1
+RESPONSE_ADD = 2
+
+# columns of the source_store
+(
+ STORE_ACTIVE,
+ STORE_DESCRIPTION,
+ STORE_SOURCE,
+ STORE_SEPARATOR,
+ STORE_VISIBLE
+) = range(5)
+
class SoftwareProperties(SimpleGladeApp):
- def __init__(self, datadir=None, options=None, parent=None):
+ def __init__(self, datadir=None, options=None, parent=None, file=None):
gtk.window_set_default_icon_name("software-properties")
# FIXME: some saner way is needed here
@@ -67,8 +88,20 @@ class SoftwareProperties(SimpleGladeApp):
None, domain="update-manager")
self.modified = False
- #self.gnome_program = gnome.init("Software Properties", "0.41")
- #self.gconfclient = gconf.client_get_default()
+ 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)
@@ -83,13 +116,12 @@ class SoftwareProperties(SimpleGladeApp):
toplevel = gtk.gdk.window_foreign_new(int(options.toplevel))
self.window_main.window.set_transient_for(toplevel)
- self.window_main.show()
-
self.init_sourceslist()
self.reload_sourceslist()
+ self.backup_sourceslist()
+
+ self.window_main.show()
- # internet update setings
-
# this maps the key (combo-box-index) to the auto-update-interval value
# where (-1) means, no key
self.combobox_interval_mapping = { 0 : 1,
@@ -184,30 +216,396 @@ class SoftwareProperties(SimpleGladeApp):
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)
+
+ # 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():
+ checkbox = gtk.CheckButton(label=self.distro.source_template.components[comp][2])
+ # 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: an ubuntu hack
+ i = server.find("http://")
+ l = server.find(".archive.ubuntu.com")
+ if i != -1 and l != -1:
+ country = server[i+7: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)
+
+ 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)
+ 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 """
+ popcon = "/etc/popularity-contest.conf"
+ if widget.get_active():
+ new_value = "yes"
+ else:
+ new_value = "no"
+ if os.path.exists(popcon):
+ # read it
+ lines = open(popcon).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(popcon,"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):
- self.source_store = gtk.ListStore(str, bool, gobject.TYPE_PYOBJECT)
+ """
+ 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)
-
- tr = gtk.CellRendererText()
- tr.set_property("xpad", 10)
- tr.set_property("ypad", 10)
-
- source_col = gtk.TreeViewColumn("Description", tr, markup=LIST_MARKUP)
- #source_col.set_max_width(500)
+ self.treeview_sources.set_row_separator_func(self.is_separator,
+ STORE_SEPARATOR)
- toggle = gtk.CellRendererToggle()
- toggle.connect("toggled", self.on_channel_toggled)
- toggle_col = gtk.TreeViewColumn("Active", toggle, active=LIST_ENABLED)
+ 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.treeview_sources.append_column(toggle_col)
- self.treeview_sources.append_column(source_col)
-
self.sourceslist = aptsources.SourcesList()
- self.matcher = aptsources.SourceEntryMatcher()
-
+
+ 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)
@@ -217,29 +615,122 @@ class SoftwareProperties(SimpleGladeApp):
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"""
+ 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>" % 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, enabled, 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 source.invalid:
- continue
- (a_type, dist, comps) = self.matcher.match(source)
-
- contents = ""
- if source.comment != "":
- contents += "<i>%s</i>\n\n" % (source.comment)
- contents +="<big><b>%s </b></big> (%s) <small>\n%s</small>" % (dist,a_type, comps)
-
- self.source_store.append([contents, not source.disabled, source])
- # try to reselect the latest selected channel or if it fails the first
- # one
- if len(self.source_store) > 0 and \
- (path_x == None or self.treeview_sources.set_cursor(path_x)):
- self.treeview_sources.set_cursor(0)
- else:
- # call the cursor_changed signal if no channel is selected
- self.treeview_sources.emit("cursor_changed")
+ 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])
+
+ if len(self.source_store) < 1:
+ self.button_remove.set_sensitive(False)
+ self.button_edit.set_sensitive(False)
+ else:
+ self.treeview_sources.set_cursor(0)
+ 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():
@@ -357,20 +848,14 @@ class SoftwareProperties(SimpleGladeApp):
#shutil.copy(location, location + ".save")
self.sourceslist.backup(".save")
self.sourceslist.save()
- # 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()
def on_add_clicked(self, widget):
dialog = dialog_add.dialog_add(self.window_main, self.sourceslist,
self.datadir)
- if dialog.run() == gtk.RESPONSE_OK:
- self.reload_sourceslist()
- self.modified = True
+ 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()
@@ -378,28 +863,19 @@ class SoftwareProperties(SimpleGladeApp):
if not iter:
return
source_entry = model.get_value(iter, LIST_ENTRY_OBJ)
- # see if we know what this thing should look like
- found_matcher = False
- for item in aptsources.SourceEntryTemplates(self.datadir).templates:
- if item.matches(source_entry):
- found_matcher = True
- break
- if found_matcher:
- dialog = dialog_add.dialog_add(self.window_main, self.sourceslist,
- self.datadir, source_entry)
- else:
- dialog = dialog_edit.dialog_edit(self.window_main, self.sourceslist,
- source_entry, self.datadir)
+ dialog = dialog_edit.dialog_edit(self.window_main, self.sourceslist,
+ source_entry, self.datadir)
if dialog.run() == gtk.RESPONSE_OK:
- self.reload_sourceslist()
- self.modified = True
+ 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"""
@@ -420,14 +896,14 @@ class SoftwareProperties(SimpleGladeApp):
self.button_edit.set_sensitive(True)
def on_remove_clicked(self, widget):
- sel = self.treeview_sources.get_selection()
- (model, iter) = sel.get_selected()
+ 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.reload_sourceslist()
- self.modified = True
-
+ self.modified_sourceslist()
+
def add_key_clicked(self, widget):
chooser = gtk.FileChooserDialog(title=_("Import key"),
parent=self.window_main,
@@ -462,11 +938,16 @@ class SoftwareProperties(SimpleGladeApp):
self.reload_keyslist()
def on_delete_event(self, widget, args):
- self.save_sourceslist()
- self.quit()
-
+ self.on_close_button(widget)
+
def on_close_button(self, widget):
- self.save_sourceslist()
+ # 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):
@@ -512,13 +993,13 @@ class SoftwareProperties(SimpleGladeApp):
self.reload_sourceslist()
self.modified = True
- def on_channel_toggled(self, cell_toggle, path):
- """Enable or disable the selected channel"""
- iter = self.source_store.get_iter((int(path),))
- source_entry = self.source_store.get_value(iter, LIST_ENTRY_OBJ)
- source_entry.disabled = not source_entry.disabled
- self.reload_sourceslist()
- self.modified = True
+ # def on_channel_toggled(self, cell_toggle, path, store):
+ # """Enable or disable the selected channel"""
+ # iter = store.get_iter((int(path),))
+ # source_entry = store.get_value(iter, LIST_ENTRY_OBJ)
+ # source_entry.disabled = not source_entry.disabled
+ # self.reload_sourceslist()
+ # self.modified = True
# FIXME: move this into a different file
class GtkCdromProgress(apt.progress.CdromProgress, SimpleGladeApp):
@@ -574,3 +1055,4 @@ class GtkCdromProgress(apt.progress.CdromProgress, SimpleGladeApp):
return True
return False
+
diff --git a/SoftwareProperties/aptsources.py b/SoftwareProperties/aptsources.py
deleted file mode 100644
index 74ef2f4a..00000000
--- a/SoftwareProperties/aptsources.py
+++ /dev/null
@@ -1,573 +0,0 @@
-# aptsource.py.in - parse sources.list
-#
-# Copyright (c) 2004,2005 Canonical
-# 2004 Michiel Sikkes
-#
-# Author: Michiel Sikkes <michiel@eyesopened.nl>
-# Michael Vogt <mvo@debian.org>
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License as
-# published by the Free Software Foundation; either version 2 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-# USA
-
-import string
-import gettext
-import re
-import apt_pkg
-import glob
-import shutil
-import time
-import os.path
-
-from UpdateManager.Common.DistInfo import DistInfo
-
-
-# some global helpers
-def is_mirror(master_uri, compare_uri):
- """check if the given add_url is idential or a mirror of orig_uri
- e.g. master_uri = archive.ubuntu.com
- compare_uri = de.archive.ubuntu.com
- -> True
- """
- # remove traling spaces and "/"
- compare_uri = compare_uri.rstrip("/ ")
- master_uri = master_uri.rstrip("/ ")
- # uri is identical
- if compare_uri == master_uri:
- #print "Identical"
- return True
- # add uri is a master site and orig_uri has the from "XX.mastersite"
- # (e.g. de.archive.ubuntu.com)
- try:
- compare_srv = compare_uri.split("//")[1]
- master_srv = master_uri.split("//")[1]
- #print "%s == %s " % (add_srv, orig_srv)
- except IndexError: # ok, somethings wrong here
- #print "IndexError"
- return False
- # remove the leading "<country>." (if any) and see if that helps
- if "." in compare_srv and \
- compare_srv[compare_srv.index(".")+1:] == master_srv:
- #print "Mirror"
- return True
- return False
-
-def uniq(s):
- """ simple (and not efficient) way to return uniq list """
- u = []
- for x in s:
- if x not in u:
- u.append(x)
- return u
-
-
-
-# actual source.list entries
-class SourceEntry:
-
- def __init__(self, line,file=None):
- self.invalid = False
- self.disabled = False
- self.type = ""
- self.uri = ""
- self.dist = ""
- self.comps = []
- self.comment = ""
- self.line = line
- if file == None:
- file = apt_pkg.Config.FindDir("Dir::Etc")+apt_pkg.Config.Find("Dir::Etc::sourcelist")
- self.file = file
- self.parse(line)
-
- # works mostely like split but takes [] into account
- def mysplit(self, line):
- line = string.strip(line)
- pieces = []
- tmp = ""
- # we are inside a [..] block
- p_found = False
- space_found = False
- for i in range(len(line)):
- if line[i] == "[":
- p_found=True
- tmp += line[i]
- elif line[i] == "]":
- p_found=False
- tmp += line[i]
- elif space_found and not line[i].isspace(): # we skip one or more space
- space_found = False
- pieces.append(tmp)
- tmp = line[i]
- elif line[i].isspace() and not p_found: # found a whitespace
- space_found = True
- else:
- tmp += line[i]
- # append last piece
- if len(tmp) > 0:
- pieces.append(tmp)
- return pieces
-
-
- # parse a given source line and split it into the fields we need
- def parse(self,line):
- line = string.strip(self.line)
- #print line
- # check if the source is enabled/disabled
- if line == "" or line == "#": # empty line
- self.invalid = True
- return
- if line[0] == "#":
- self.disabled = True
- pieces = string.split(line[1:])
- # if it looks not like a disabled deb line return
- if not (pieces[0] == "deb" or pieces[0] == "deb-src"):
- self.invalid = True
- return
- else:
- line = line[1:]
- # check for another "#" in the line (this is treated as a comment)
- i = line.find("#")
- if i > 0:
- self.comment = line[i+1:]
- line = line[:i]
- # source is ok, split it and see what we have
- pieces = self.mysplit(line)
- # Sanity check
- if len(pieces) < 3:
- self.invalid = True
- return
- # Type, deb or deb-src
- self.type = string.strip(pieces[0])
- # Sanity check
- if self.type not in ("deb", "deb-src"):
- self.invalid = True
- return
- # URI
- self.uri = string.strip(pieces[1])
- if len(self.uri) < 1:
- self.invalid = True
- # distro and components (optional)
- # Directory or distro
- self.dist = string.strip(pieces[2])
- if len(pieces) > 3:
- # List of components
- self.comps = pieces[3:]
- else:
- self.comps = []
-
- #print self.__dict__
-
-
- # set enabled/disabled
- def set_enabled(self, new_value):
- self.disabled = not new_value
- # enable, remove all "#" from the start of the line
- if new_value == True:
- i=0
- self.line = string.lstrip(self.line)
- while self.line[i] == "#":
- i += 1
- self.line = self.line[i:]
- else:
- # disabled, add a "#"
- if string.strip(self.line)[0] != "#":
- self.line = "#" + self.line
-
- def __str__(self):
- """ debug helper """
- return self.str().strip()
-
- def str(self):
- """ return the current line as string """
- if self.invalid:
- return self.line
- line = ""
- if self.disabled:
- line = "# "
- line += "%s %s %s" % (self.type, self.uri, self.dist)
- if len(self.comps) > 0:
- line += " " + " ".join(self.comps)
- if self.comment != "":
- line += " #"+self.comment
- line += "\n"
- return line
-
-# the SourceList file as a class
-class SourcesList:
- def __init__(self):
- self.list = [] # of Type SourceEntries
- self.refresh()
-
- def refresh(self):
- self.list = []
- # read sources.list
- dir = apt_pkg.Config.FindDir("Dir::Etc")
- file = apt_pkg.Config.Find("Dir::Etc::sourcelist")
- self.load(dir+file)
- # read sources.list.d
- partsdir = apt_pkg.Config.FindDir("Dir::Etc::sourceparts")
- for file in glob.glob("%s/*.list" % partsdir):
- self.load(file)
-
- def __iter__(self):
- for entry in self.list:
- yield entry
- raise StopIteration
-
- def add(self, type, uri, dist, comps, comment="", pos=-1):
- # if there is a repo with the same (type, uri, dist) just add the
- # components
- for i in self.list:
- if i.type == type and is_mirror(uri,i.uri) and i.dist == dist:
- comps = uniq(i.comps + comps)
- # set to the old position and preserve comment
- comment = i.comment
- pos = self.list.index(i)
- self.list.remove(i)
- line = "%s %s %s" % (type,uri,dist)
- for c in comps:
- line = line + " " + c;
- if comment != "":
- line = "%s #%s\n" %(line,comment)
- line = line + "\n"
- self.list.insert(pos, SourceEntry(line))
-
- def remove(self, source_entry):
- self.list.remove(source_entry)
-
- def restoreBackup(self, backup_ext):
- " restore sources.list files based on the backup extension "
- dir = apt_pkg.Config.FindDir("Dir::Etc")
- file = apt_pkg.Config.Find("Dir::Etc::sourcelist")
- if os.path.exists(dir+file+backup_ext):
- shutil.copy(dir+file+backup_ext,dir+file)
- # now sources.list.d
- partsdir = apt_pkg.Config.FindDir("Dir::Etc::sourceparts")
- for file in glob.glob("%s/*.list" % partsdir):
- if os.path.exists(file+backup_ext):
- shutil.copy(file+backup_ext,file)
-
- def backup(self, backup_ext=None):
- """ make a backup of the current source files, if no backup extension
- is given, the current date/time is used (and returned) """
- already_backuped = set()
- if backup_ext == None:
- backup_ext = time.strftime("%y%m%d.%H%M")
- for source in self.list:
- if not source.file in already_backuped:
- shutil.copy(source.file,"%s%s" % (source.file,backup_ext))
- return backup_ext
-
- def load(self,file):
- """ (re)load the current sources """
- f = open(file, "r")
- lines = f.readlines()
- for line in lines:
- source = SourceEntry(line,file)
- self.list.append(source)
- f.close()
-
- def save(self):
- """ save the current sources """
- files = {}
- for source in self.list:
- if not files.has_key(source.file):
- files[source.file]=open(source.file,"w")
- files[source.file].write(source.str())
- for f in files:
- files[f].close()
-
-# templates for the add dialog
-class SourceEntryTemplate(SourceEntry):
- def __init__(self,a_type,uri,dist,description,comps):
- self.comps_descriptions = []
- self.type = a_type
- self.uri = uri
- self.dist = dist
- self.description = description
- self.comps = comps
-
- def matches(self,source_entry):
- """ check if a given source_entry matches this one """
- if (self.type != source_entry.type):
- return False
- if (self.dist != source_entry.dist):
- return False
- if not is_mirror(self.uri,source_entry.uri):
- return False
- for e_comp in source_entry.comps:
- for t_comp in self.comps:
- if e_comp == t_comp.name: break
- else:
- return False
- return True
-
-class SourceCompTemplate:
- def __init__(self, name, description, on_by_default):
- self.name = name
- self.description = description
- self.on_by_default = on_by_default
-
-class SourceEntryTemplates:
- def __init__(self,datadir):
- _ = gettext.gettext
- self.templates = []
-
- dinfo = DistInfo (base_dir=datadir+"channels/")
-
- for suite in dinfo.suites:
- comps = []
- for comp in suite.components:
- comps.append(SourceCompTemplate(comp.name, _(comp.description),
- comp.enabled))
- self.templates.append (SourceEntryTemplate(suite.repository_type,
- suite.base_uri,
- suite.name,
- suite.description,
- comps))
-
-# matcher class to make a source entry look nice
-# lots of predefined matchers to make it i18n/gettext friendly
-class SourceEntryMatcher:
- class MatchType:
- def __init__(self, a_type,a_descr):
- self.type = a_type
- self.description = a_descr
-
- class MatchDist:
- def __init__(self,a_uri,a_dist, a_descr,l_comps, l_comps_descr):
- self.uri = a_uri
- self.dist = a_dist
- self.description = a_descr
- self.comps = l_comps
- self.comps_descriptions = l_comps_descr
-
- def __init__(self):
- _ = gettext.gettext
- self.type_list = []
- self.type_list.append(self.MatchType("^deb$",_("Binary")))
- self.type_list.append(self.MatchType("^deb-src$",_("Source")))
-
- self.dist_list = []
-
- ubuntu_comps = ["^main$","^restricted$","^universe$","^multiverse$"]
- ubuntu_comps_descr = [_("Officially supported"),
- _("Restricted copyright"),
- _("Community maintained (Universe)"),
- _("Non-free (Multiverse)")]
- # CDs
- self.dist_list.append(self.MatchDist("cdrom:\[Ubuntu.*6.06",
- ".*",
- _("CD disk with Ubuntu 6.06 LTS"),
- ubuntu_comps, ubuntu_comps_descr))
- self.dist_list.append(self.MatchDist("cdrom:\[Ubuntu.*5.10",
- ".*",
- _("CD disk with Ubuntu 5.10"),
- ubuntu_comps, ubuntu_comps_descr))
- self.dist_list.append(self.MatchDist("cdrom:\[Ubuntu.*5.04",
- ".*",
- _("CD disk with Ubuntu 5.04"),
- ubuntu_comps, ubuntu_comps_descr))
- self.dist_list.append(self.MatchDist("cdrom:\[Ubuntu.*4.10",
- ".*",
- _("CD disk with Ubuntu 4.10"),
- ubuntu_comps, ubuntu_comps_descr))
- # URIs
- # Warty
- self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
- "^warty$",
- "Ubuntu 4.10",
- ubuntu_comps, ubuntu_comps_descr))
- self.dist_list.append(self.MatchDist(".*security.ubuntu.com/ubuntu",
- "^warty-security$",
- _("Ubuntu 4.10 Security Updates"),
- ubuntu_comps, ubuntu_comps_descr))
- self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
- "^warty-security$",
- _("Ubuntu 4.10 Security Updates"),
- ubuntu_comps, ubuntu_comps_descr))
- self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
- "^warty-updates$",
- _("Ubuntu 4.10 Updates"),
- ubuntu_comps, ubuntu_comps_descr))
- self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
- "^warty-backports$",
- _("Ubuntu 4.10 Backports"),
- ubuntu_comps, ubuntu_comps_descr))
- # Hoary
- self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
- "^hoary-security$",
- _("Ubuntu 5.04 Security Updates"),
- ubuntu_comps, ubuntu_comps_descr))
- self.dist_list.append(self.MatchDist(".*security.ubuntu.com/ubuntu",
- "^hoary-security$",
- _("Ubuntu 5.04 Security Updates"),
- ubuntu_comps, ubuntu_comps_descr))
- self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
- "^hoary$",
- "Ubuntu 5.04",
- ubuntu_comps, ubuntu_comps_descr))
- self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
- "^hoary-updates$",
- _("Ubuntu 5.04 Updates"),
- ubuntu_comps, ubuntu_comps_descr))
- self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
- "^hoary-backports$",
- _("Ubuntu 5.04 Backports"),
- ubuntu_comps, ubuntu_comps_descr))
- # Breezy
- self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
- "^breezy-security$",
- _("Ubuntu 5.10 Security Updates"),
- ubuntu_comps, ubuntu_comps_descr))
- self.dist_list.append(self.MatchDist(".*security.ubuntu.com/ubuntu",
- "^breezy-security$",
- _("Ubuntu 5.10 Security Updates"),
- ubuntu_comps, ubuntu_comps_descr))
- self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
- "^breezy$",
- "Ubuntu 5.10",
- ubuntu_comps, ubuntu_comps_descr))
- self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
- "^breezy-backports$",
- _("Ubuntu 5.10 Backports"),
- ubuntu_comps, ubuntu_comps_descr))
- self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
- "^breezy-updates$",
- _("Ubuntu 5.10 Updates"),
- ubuntu_comps, ubuntu_comps_descr))
- # dapper
- self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
- "^dapper-security$",
- _("Ubuntu 6.06 LTS Security Updates"),
- ubuntu_comps, ubuntu_comps_descr))
- self.dist_list.append(self.MatchDist(".*security.ubuntu.com/ubuntu",
- "^dapper-security$",
- _("Ubuntu 6.06 LTS Security Updates"),
- ubuntu_comps, ubuntu_comps_descr))
- self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
- "^dapper$",
- "Ubuntu 6.06 LTS",
- ubuntu_comps, ubuntu_comps_descr))
- self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
- "^dapper-backports$",
- _("Ubuntu 6.06 LTS Backports"),
- ubuntu_comps, ubuntu_comps_descr))
- self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
- "^dapper-updates$",
- _("Ubuntu 6.06 LTS Updates"),
- ubuntu_comps, ubuntu_comps_descr))
-
-
- # DEBIAN
- debian_comps = ["^main$","^contrib$","^non-free$","^non-US$"]
- debian_comps_descr = [_("Officially supported"),
- _("Contributed software"),
- _("Non-free software"),
- _("US export restricted software")
- ]
-
- # dists by name
- self.dist_list.append(self.MatchDist(".*debian.org/debian",
- "^sarge$",
- _("Debian 3.1 \"Sarge\""),
- debian_comps, debian_comps_descr))
- self.dist_list.append(self.MatchDist(".*debian.org/debian",
- "^woody$",
- _("Debian 3.0 \"Woody\""),
- debian_comps, debian_comps_descr))
- # securtiy
- self.dist_list.append(self.MatchDist(".*security.debian.org",
- "^stable.*$",
- _("Debian Stable Security Updates"),
- debian_comps, debian_comps_descr))
- # dists by status
- self.dist_list.append(self.MatchDist(".*debian.org/debian",
- "^stable$",
- _("Debian Stable"),
- debian_comps, debian_comps_descr))
- self.dist_list.append(self.MatchDist(".*debian.org/debian",
- "^testing$",
- _("Debian Testing"),
- debian_comps, debian_comps_descr))
- self.dist_list.append(self.MatchDist(".*debian.org/debian",
- "^unstable$",
- _("Debian Unstable \"Sid\""),
- debian_comps, debian_comps_descr))
-
- # non-us
- self.dist_list.append(self.MatchDist(".*debian.org/debian-non-US",
- "^stable.*$",
- _("Debian Non-US (Stable)"),
- debian_comps, debian_comps_descr))
- self.dist_list.append(self.MatchDist(".*debian.org/debian-non-US",
- "^testing.*$",
- _("Debian Non-US (Testing)"),
- debian_comps, debian_comps_descr))
- self.dist_list.append(self.MatchDist(".*debian.org/debian-non-US",
- "^unstable.*$",
- _("Debian Non-US (Unstable)"),
- debian_comps, debian_comps_descr))
-
-
-
-
- def match(self,source):
- _ = gettext.gettext
- # some sane defaults first
- type_description = source.type
- dist_description = source.uri + " " + source.dist
- comp_description = ""
- for c in source.comps:
- comp_description = comp_description + " " + c
-
- for t in self.type_list:
- if re.match(t.type, source.type):
- type_description = _(t.description)
- break
-
- for d in self.dist_list:
- #print "'%s'" %source.uri
- if re.match(d.uri, source.uri) and re.match(d.dist,source.dist):
- dist_description = d.description
- comp_description = ""
- for c in source.comps:
- found = False
- for i in range(len(d.comps)):
- if re.match(d.comps[i], c):
- comp_description = comp_description+"\n"+d.comps_descriptions[i]
- found = True
- if found == False:
- comp_description = comp_description+" "+c
- break
-
-
- return (type_description,dist_description,comp_description)
-
-
-# some simple tests
-if __name__ == "__main__":
- apt_pkg.InitConfig()
- sources = SourcesList()
-
- for entry in sources:
- print entry.str()
- #print entry.uri
-
- mirror = is_mirror("http://archive.ubuntu.com/ubuntu/",
- "http://de.archive.ubuntu.com/ubuntu/")
- print "is_mirror(): %s" % mirror
-
- print is_mirror("http://archive.ubuntu.com/ubuntu",
- "http://de.archive.ubuntu.com/ubuntu/")
diff --git a/SoftwareProperties/dialog_add.py b/SoftwareProperties/dialog_add.py
index b5fbe07f..cf9e22c2 100644
--- a/SoftwareProperties/dialog_add.py
+++ b/SoftwareProperties/dialog_add.py
@@ -6,7 +6,8 @@
# Authors:
# Michael Vogt <mvo@debian.org>
# Michiel Sikkes <michiels@gnome.org>
-#
+# Sebastian Heinlein <glatzor@ubuntu.com>
+#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of the
@@ -28,168 +29,44 @@ import gtk
import gtk.glade
from gettext import gettext as _
-import aptsources
-import dialog_edit
+import UpdateManager.Common.aptsources as aptsources
class dialog_add:
- def __init__(self, parent, sourceslist, datadir, source_entry = None):
+ def __init__(self, parent, sourceslist, datadir):
+ """
+ Initialize the dialog that allows to add a new source entering the
+ raw apt line
+ """
self.sourceslist = sourceslist
self.parent = parent
self.datadir = datadir
- self.custom = False
- # we have a source_entry that we want to modify
- self.source_entry = source_entry
- if source_entry:
- self.source_entry_index = sourceslist.list.index(source_entry)
- else:
- self.source_entry_index = None
-
- # templates
- self.templatelist = aptsources.SourceEntryTemplates(datadir)
-
- # FIXME: simple-glade-app should be able to do all this!
-
# gtk stuff
- self.gladexml = gtk.glade.XML("%s/glade/SoftwarePropertiesDialogs.glade" % datadir)
-
- self.main = widget = self.gladexml.get_widget("dialog_add")
- self.main.set_transient_for(self.parent)
-
- combo = self.gladexml.get_widget("combobox_what")
- self.gladexml.signal_connect("on_combobox_what_changed", self.on_combobox_what_changed, None)
- # combox box needs
- cell = gtk.CellRendererText()
- combo.pack_start(cell, True)
- combo.add_attribute(cell, 'text', 0)
- self.fill_combo(combo)
- if source_entry:
- self.main.set_title(_("Edit Channel"))
- self.gladexml.get_widget("button_add").set_label("gtk-ok")
- self.gladexml.signal_connect("on_button_custom_clicked",
- self.on_button_custom_clicked, None)
-
+ self.gladexml = gtk.glade.XML("%s/glade/SoftwarePropertiesDialogs.glade" %\
+ datadir)
+ self.dialog = self.gladexml.get_widget("dialog_add_custom")
+ self.dialog.set_transient_for(self.parent)
+ self.entry = self.gladexml.get_widget("entry_source_line")
+ self.button_add = self.gladexml.get_widget("button_add_source")
+ self.entry.connect("changed", self.check_line)
- def fill_combo(self,combo):
- liststore = gtk.ListStore(gobject.TYPE_STRING,gobject.TYPE_PYOBJECT)
- matched_template = None
- for item in self.templatelist.templates:
- liststore.append((item.description, item))
- if self.source_entry and item.matches(self.source_entry):
- matched_template = item
- combo.set_model(liststore)
- if matched_template:
- try:
- combo.set_active(self.templatelist.templates.index(matched_template))
- vbox = self.gladexml.get_widget("vbox_comps")
- for c in vbox.get_children():
- c.set_active(c.get_data("name") in self.source_entry.comps)
- except ValueError:
- pass
+ def run(self):
+ res = self.dialog.run()
+ self.dialog.hide()
+ if res == gtk.RESPONSE_OK:
+ line = self.entry.get_text() + "\n"
else:
- combo.set_active(0)
-
- def on_combobox_what_changed(self, combobox, user):
- #print "on_combobox_what_changed"
- vbox = self.gladexml.get_widget("vbox_comps")
- vbox.foreach(lambda widget,vbox: vbox.remove(widget), vbox)
- liststore = combobox.get_model()
- a_iter = liststore.iter_nth_child(None, combobox.get_active())
- (name, template) = liststore.get(a_iter, 0,1)
- self.selected = template
- comps = template.comps
- for c in comps:
- checkbox = gtk.CheckButton(c.description)
- checkbox.set_active(c.on_by_default)
- checkbox.set_data("name",c.name)
- vbox.pack_start(checkbox)
- checkbox.show()
+ line = None
+ return line
- def on_button_custom_clicked(self, widget, data):
- #print "on_button_custom_clicked()"
- # this hide here is ugly :/
- self.main.hide()
- # check if we are in add or edit-matched mode
- if self.source_entry:
- # we are in "edit" mode
- # get the SourceEntry as it is now (with local changes)
- # and display the "old" edit dialog
- self.selected_comps = []
- vbox = self.gladexml.get_widget("vbox_comps")
- vbox.foreach(self.get_enabled_comps)
- source_entry = self._make_source_entry()
- # since we're passing the SourceEntry as it is now,
- # this SourceEntry needs to be in the sourceslist,
- # so temporarily swap the original for the current
- if source_entry:
- self.sourceslist.list[self.source_entry_index] = source_entry
- dialog = dialog_edit.dialog_edit(self.parent, self.sourceslist,
- source_entry, self.datadir)
- res = dialog.run()
- if res == gtk.RESPONSE_CANCEL:
- # restore original SourceEntry
- self.sourceslist.list[self.source_entry_index] = self.source_entry
- elif res == gtk.RESPONSE_OK:
- # the sourceslist is allready updated, but we'll overwrite it
- # in self.run if we're not carefull
- self.custom = True
+ 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:
- # we are in "add" mode
- dialog = self.gladexml.get_widget("dialog_add_custom")
- dialog.set_transient_for(self.parent)
- res = dialog.run()
- dialog.hide()
- entry = self.gladexml.get_widget("entry_source_line")
- line = entry.get_text() + "\n"
- self.sourceslist.list.append(aptsources.SourceEntry(line))
- self.main.response(res)
+ self.button_add.set_sensitive(True)
- def get_enabled_comps(self, checkbutton):
- if checkbutton.get_active():
- self.selected_comps.append(checkbutton.get_data("name"))
-
- def _make_source_entry(self):
- " helper for the 'edit' mode "
- # we use "selected" for pretty much everything *but* we use
- # self.source_entry.uri to make sure that the mirror information is
- # preserved
-
- line = "%s %s %s" % (self.selected.type, self.source_entry.uri, self.selected.dist)
- if self.source_entry.disabled:
- line = "#" + line
- if len(self.selected.comps) > 0 and len(self.selected_comps) == 0:
- line = "#" + line
- elif len(self.selected_comps) > 0:
- line += " " + " ".join(self.selected_comps)
- if self.selected.matches(self.source_entry) and self.source_entry.comment != "":
- line += " #"+self.source_entry.comment
- line += "\n"
- return aptsources.SourceEntry(line,self.source_entry.file)
-
- def run(self):
- res = self.main.run()
- if res == gtk.RESPONSE_OK:
- # add repository
- self.selected_comps = []
- vbox = self.gladexml.get_widget("vbox_comps")
- vbox.foreach(self.get_enabled_comps)
-
- # check if we are in 'add' or 'edit' mode
- if self.source_entry:
- # 'edit' - ode
- # check if there are no selected components
- if len(self.selected_comps) < 1:
- # remove the source
- self.sourceslist.remove(self.source_entry)
- else:
- if not self.custom:
- entry = self._make_source_entry()
- if entry:
- self.sourceslist.list[self.source_entry_index] = entry
- else:
- # 'add' mode
- self.sourceslist.add(self.selected.type,
- self.selected.uri,
- self.selected.dist,
- self.selected_comps)
- self.main.hide()
- return res
diff --git a/SoftwareProperties/dialog_add_sources_list.py b/SoftwareProperties/dialog_add_sources_list.py
new file mode 100644
index 00000000..3b581c6c
--- /dev/null
+++ b/SoftwareProperties/dialog_add_sources_list.py
@@ -0,0 +1,127 @@
+#!/usr/bin/env python
+import pygtk
+import gtk
+import gtk.glade
+import gobject
+import os
+from optparse import OptionParser
+from gettext import gettext as _
+import gettext
+import urllib
+from utils import *
+
+from UpdateManager.Common.aptsources import SourcesList, SourceEntryMatcher
+
+
+class AddSourcesList:
+ def __init__(self, parent, sourceslist, source_renderer,
+ get_comparable, datadir, file):
+ print file
+ self.parent = parent
+ self.source_renderer = source_renderer
+ self.sourceslist = sourceslist
+ self.get_comparable = get_comparable
+ self.file = self.format_uri(file)
+ self.glade = gtk.glade.XML(os.path.join(datadir,
+ "glade/SoftwarePropertiesDialogs.glade"))
+ self.glade.signal_autoconnect(self)
+ self.dialog = self.glade.get_widget("dialog_add_sources_list")
+ self.label = self.glade.get_widget("label_sources")
+ self.button_add = self.glade.get_widget("button_add")
+ self.button_cancel = self.glade.get_widget("button_cancel")
+ self.button_replace = self.glade.get_widget("button_replace")
+ self.treeview = self.glade.get_widget("treeview_sources")
+ self.scrolled = self.glade.get_widget("scrolled_window")
+ self.image = self.glade.get_widget("image_sources_list")
+
+ self.dialog.realize()
+ if self.parent != None:
+ self.dialog.set_transient_for(parent)
+ else:
+ self.dialog.set_title(_("Add Software Channels"))
+ self.dialog.window.set_functions(gtk.gdk.FUNC_MOVE)
+
+ # Setup the treeview
+ self.store = gtk.ListStore(gobject.TYPE_STRING)
+ self.treeview.set_model(self.store)
+ cell = gtk.CellRendererText()
+ cell.set_property("xpad", 2)
+ cell.set_property("ypad", 2)
+ column = gtk.TreeViewColumn("Software Channel", cell, markup=0)
+ column.set_max_width(500)
+ self.treeview.append_column(column)
+
+ # Parse the source.list file
+ try:
+ self.new_sources = SingleSourcesList(self.file)
+ except:
+ self.error()
+ return
+
+ # show the found channels or an error message
+ if len(self.new_sources.list) > 0:
+ counter = 0
+
+ for source in self.new_sources.list:
+ if source.invalid or source.disabled:
+ continue
+ self.new_sources.matcher.match(source)
+ # sort the list
+ self.new_sources.list.sort(key=self.get_comparable)
+
+ for source in self.new_sources.list:
+ if source.invalid or source.disabled:
+ continue
+ counter = counter +1
+ line = self.source_renderer(source)
+ self.store.append([line])
+ if counter == 0:
+ self.error()
+ return
+
+ header = gettext.ngettext("Install software additionally or "
+ "only from this source?",
+ "Install software additionally or "
+ "only from these sources?",
+ counter)
+ body = _("You can either add the following sources or replace your "
+ "current sources by them. Only install software from "
+ "trusted sources.")
+ self.label.set_markup("<big><b>%s</b></big>\n\n%s" % (header, body))
+ else:
+ self.error()
+ return
+
+ def error(self):
+ self.button_add.hide()
+ self.button_cancel.set_use_stock(True)
+ self.button_cancel.set_label("gtk-close")
+ self.button_replace.hide()
+ self.scrolled.hide()
+ self.image.set_from_stock(gtk.STOCK_DIALOG_ERROR, gtk.ICON_SIZE_DIALOG)
+ header = _("There are no sources to install software from")
+ body = _("The file '%s' does not contain any valid "
+ "software sources." % self.file)
+ self.label.set_markup("<big><b>%s</b></big>\n\n%s" % (header, body))
+
+ def run(self):
+ res = self.dialog.run()
+ self.dialog.destroy()
+ return res, self.new_sources
+
+ def format_uri(self, uri):
+ path = urllib.url2pathname(uri) # escape special chars
+ path = path.strip('\r\n\x00') # remove \r\n and NULL
+ if path.startswith('file:\\\\\\'): # windows
+ path = path[8:] # 8 is len('file:///')
+ elif path.startswith('file://'): #nautilus, rox
+ path = path[7:] # 7 is len('file://')
+ elif path.startswith('file:'): # xffm
+ path = path[5:] # 5 is len('file:')
+ return path
+
+class SingleSourcesList(SourcesList):
+ def __init__(self, file):
+ self.matcher = SourceEntryMatcher()
+ self.list = []
+ self.load(file)
diff --git a/SoftwareProperties/dialog_edit.py b/SoftwareProperties/dialog_edit.py
index 59788915..0eedd3b8 100644
--- a/SoftwareProperties/dialog_edit.py
+++ b/SoftwareProperties/dialog_edit.py
@@ -27,7 +27,7 @@ import gobject
import gtk
import gtk.glade
-import aptsources
+import UpdateManager.Common.aptsources as aptsources
class dialog_edit:
def __init__(self, parent, sourceslist, source_entry, datadir):