summaryrefslogtreecommitdiff
path: root/SoftwareProperties
diff options
context:
space:
mode:
Diffstat (limited to 'SoftwareProperties')
-rw-r--r--SoftwareProperties/SoftwareProperties.py81
-rw-r--r--SoftwareProperties/aptsources.py314
-rw-r--r--SoftwareProperties/dialog_add.py30
-rw-r--r--SoftwareProperties/dialog_sources_list.py19
4 files changed, 360 insertions, 84 deletions
diff --git a/SoftwareProperties/SoftwareProperties.py b/SoftwareProperties/SoftwareProperties.py
index 0e9a0f0d..f7f7f6f2 100644
--- a/SoftwareProperties/SoftwareProperties.py
+++ b/SoftwareProperties/SoftwareProperties.py
@@ -91,6 +91,7 @@ class SoftwareProperties(SimpleGladeApp):
self.init_sourceslist()
self.reload_sourceslist()
+ self.button_revert.set_sensitive(False)
# internet update setings
@@ -179,6 +180,10 @@ class SoftwareProperties(SimpleGladeApp):
else:
self.checkbutton_unattended.set_active(False)
+ # Backup the source list
+ self.sourceslist.clearBackup(".save")
+ self.sourceslist.backup(".save")
+
# apt-key stuff
self.apt_key = apt_key()
self.init_keyslist()
@@ -204,8 +209,7 @@ class SoftwareProperties(SimpleGladeApp):
file)
res = dialog.run()
if res == gtk.RESPONSE_OK:
- self.reload_sourceslist()
- self.modified = True
+ self.modified_sourceslist()
def on_sources_drag_data_received(self, widget, context, x, y,
selection, target_type, timestamp):
@@ -225,13 +229,15 @@ class SoftwareProperties(SimpleGladeApp):
self.treeview_sources.set_model(self.source_store)
cell_desc = gtk.CellRendererText()
- #cell_desc.set_property("xpad", 10)
- #cell_desc.set_property("ypad", 10)
+ 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(500)
+ 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)
col_active = gtk.TreeViewColumn(_("Active"), cell_toggle,
active=COLUMN_ACTIVE)
@@ -242,13 +248,27 @@ class SoftwareProperties(SimpleGladeApp):
self.sourceslist = aptsources.SourcesList()
self.matcher = aptsources.SourceEntryMatcher()
+ 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):
"""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
+ self.modified_sourceslist()
def init_keyslist(self):
self.keys_store = gtk.ListStore(str)
@@ -259,18 +279,30 @@ 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.restoreBackup(".save")
+ self.sourceslist.clearBackup(".save")
+ self.sourceslist.backup(".save")
+ self.sourceslist.refresh()
+ self.reload_sourceslist()
+ self.button_revert.set_sensitive(False)
+
+ def modified_sourceslist(self):
+ """The sources list was changed and now needs to be saved and reloaded"""
+ self.button_revert.set_sensitive(True)
+ self.save_sourceslist()
+ self.reload_sourceslist()
+
def reload_sourceslist(self):
self.source_store.clear()
+ self.sourceslist.check_for_endangered_dists()
for source in self.sourceslist.list:
if source.invalid:
continue
- (nice_type, nice_dist, nice_comps) = self.matcher.match(source)
-
- contents = "<b>%s</b>%s" % (nice_dist, nice_comps)
- if source.type == "deb-src":
- contents = "<b>%s</b> - %s %s" % (nice_dist, nice_type, nice_comps)
+ contents = self.sourceslist.render_source(source)
self.source_store.append([not source.disabled, contents, source])
-
+
def reload_keyslist(self):
self.keys_store.clear()
for key in self.apt_key.list():
@@ -378,17 +410,17 @@ class SoftwareProperties(SimpleGladeApp):
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):
+ """Open a dialog to add new channels"""
dialog = dialog_add.dialog_add(self.window_main, self.sourceslist,
self.datadir)
if dialog.run() == gtk.RESPONSE_OK:
- self.reload_sourceslist()
- self.modified = True
-
+ self.modified_sourceslist()
+
def on_edit_clicked(self, widget):
+ """Open a dialog to edit the currently selected dialog"""
sel = self.treeview_sources.get_selection()
(model, iter) = sel.get_selected()
if not iter:
@@ -397,17 +429,17 @@ class SoftwareProperties(SimpleGladeApp):
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()
+
def on_remove_clicked(self, widget):
sel = self.treeview_sources.get_selection()
(model, iter) = sel.get_selected()
if iter:
source = model.get_value(iter, LIST_ENTRY_OBJ)
self.sourceslist.remove(source)
- self.reload_sourceslist()
- self.modified = True
+ self.modified_sourceslist()
+ self.button_edit.set_sensitive(False)
+ self.button_remove.set_sensitive(False)
def add_key_clicked(self, widget):
chooser = gtk.FileChooserDialog(title=_("Import key"),
@@ -492,8 +524,7 @@ class SoftwareProperties(SimpleGladeApp):
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
+ self.modified_sourceslist()
# FIXME: move this into a different file
diff --git a/SoftwareProperties/aptsources.py b/SoftwareProperties/aptsources.py
index f751cf7c..532600fd 100644
--- a/SoftwareProperties/aptsources.py
+++ b/SoftwareProperties/aptsources.py
@@ -32,6 +32,8 @@ import os.path
from UpdateManager.Common.DistInfo import DistInfo
+(SOURCE_SECURITY, SOURCE_UPDATES, SOURCE_SYSTEM, SOURCE_BACKPORTS) = range(4)
+
# actual source.list entries
class SourceEntry:
@@ -234,9 +236,96 @@ class SourcesList:
line = line + "\n"
self.list.insert(pos, SourceEntry(line))
+ def disable_components(self, comps, source_entry):
+ """Disable components of a source"""
+ comps_remove = set(comps) & set(source_entry.comps)
+ if len(comps_remove) >= len(source_entry.comps):
+ # disable the whole source
+ source_entry.disabled = True
+ elif len(comps_remove) > 0:
+ # Remove the sections from the original source
+ comps_new = set(source_entry.comps) - comps_remove
+ comps_write=""
+ for comp in comps_new:
+ comps_write += " %s" % comp
+ line = "%s %s %s %s" % (source.type, source.uri, source.dist,
+ comps_write)
+ if source.comment:
+ line += "# %s" % source.comment
+ line += "\n"
+ index = self.list.index(source_entry)
+ file = self.list[index].file
+ self.list[index] = SourceEntry(line, file)
+
+ # Add a disabled line with the disabled comps after the
+ # original line
+ comps_write=""
+ for comp in comps_remove:
+ comps_write = " %s" % comp
+ line_disabled = "#%s %s %s %s" % (source.type, source.uri, source.dist,
+ comps_remove)
+ if source.comment:
+ line_disabled += "# %s" % source.comment
+ line_disabled += "\n"
+ self.list.insert[index+1](SourceEntry(line_disabled, file))
+
+ def remove_components(self, comps, source_entry):
+ """ Remove components of a source"""
+ # The components that need to be removed from the source
+ comps_remove = set(comps) & set(source_entry.comps)
+ if len(comps_remove) >= len(source_entry.comps):
+ # Delete the whole source if there are no comps left
+ self.list.remove(source_entry)
+ elif len(comps_remove) > 0:
+ # Remove the sections from the original source
+ comps_new = set(source_entry.comps) - comps_remove
+ comps_write = ""
+ for comp in comps_new:
+ comps_write += " %s" % comp
+ line = "%s %s %s %s" % (source.type, source.uri, source.dist,
+ comps_write)
+ if source.comment:
+ line += "# %s" % source.comment
+ line += "\n"
+ index = self.list.index(source_entry)
+ file = self.list[index].file
+ self.list[index] = SourceEntry(line, file)
+
+ def render_source(self, source):
+ """Render a nice output to show the source in a treeview"""
+ (nice_type, nice_dist, nice_comps, special) = self.matcher.match(source)
+
+ if special in (SOURCE_UPDATES, SOURCE_BACKPORTS, SOURCE_SECURITY):
+ contents = "<b>%s</b>" % nice_dist
+ elif special == SOURCE_SYSTEM:
+ contents = "<b>%s</b>" % nice_dist
+ if source.type in ("deb-src", "rpm-src"):
+ contents += " (%s)" % nice_type
+ for comp in nice_comps:
+ contents += "\n%s" % comp
+ else:
+ contents = "<b>%s</b>" % nice_dist
+ if source.type in ("deb-src", "rpm-src"):
+ contents += " (%s)" % nice_type
+ for comp in nice_comps:
+ contents += "%s" % comp
+ return contents
+
def remove(self, source_entry):
self.list.remove(source_entry)
+ def clearBackup(self, backup_ext):
+ " remove backuped 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):
+ os.remove(dir+file+backup_ext)
+ # 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):
+ os.remove(file+backup_ext)
+
def restoreBackup(self, backup_ext):
" restore sources.list files based on the backup extension "
dir = apt_pkg.Config.FindDir("Dir::Etc")
@@ -278,10 +367,90 @@ class SourcesList:
files[source.file].write(source.str())
for f in files:
files[f].close()
+
+ def check_for_endangered_dists(self):
+ # To store the sources that provide updates
+ self.sources_updates = []
+ # To store the sources that provide backports
+ self.sources_backports = []
+ # To store the sources that provide securtiy fixes
+ self.sources_security = []
+ # To store the activated components of each dist
+ self.system_comps = {}
+
+ # The matcher searches sets the required special tags
+ self.matcher = SourceEntryMatcher()
+
+ for source in self.list:
+ if source.invalid:
+ continue
+ (nice_type, nice_dist, nice_comps, special) = self.matcher.match(source)
+ #print "match: %s %s" % (source.dist, special)
+
+ # Collect the components of an activated system dist
+ if special == SOURCE_SYSTEM and source.disabled != True:
+ if self.system_comps.has_key(source.dist):
+ current = self.system_comps[source.dist]
+ self.system_comps[source.dist] = (current | set(source.comps))
+ else:
+ self.system_comps[source.dist] = set(source.comps)
+
+ # Collect sources that provide updates
+ elif special == SOURCE_UPDATES:
+ self.sources_updates.append(source)
+ elif special == SOURCE_SECURITY:
+ self.sources_security.append(source)
+ elif special == SOURCE_BACKPORTS:
+ self.sources_backports.append(source)
+
+ #print "\nSystem Compos: %s " % self.system_comps
+
+ # Check if each security source contains all components of
+ # the same dist
+ self.check_updates(self.sources_security)
+ self.check_updates(self.sources_updates)
+ self.check_updates(self.sources_backports)
+
+ def check_updates(self, updates):
+ modified = False
+ for source in updates:
+ #print "SecSource: %s" % source.dist
+ # Skip the "-security" and "-updates" from the dist
+ i = source.dist.find("-")
+ dist = source.dist[:i]
+ # Are there any active components for the dist?
+ if self.system_comps.has_key(dist):
+ comps_sys = self.system_comps[dist]
+ comps_sec = set(source.comps)
+ # Are there components without updates?
+ comps_endangered = comps_sys - comps_sec
+ #print "In Danger: %s " % comps_endangered
+ if len(comps_endangered) > 0:
+ # convert the set into a list
+ comps_write=""
+ for comp in comps_sys:
+ comps_write += " %s" % comp
+ # add all system components to the securtiy line
+ line = "%s %s %s %s" % (source.type, source.uri, source.dist,
+ comps_write)
+ if source.comment:
+ line += "# %s" % source.comment
+ line += "\n"
+ index = self.list.index(source)
+ file = self.list[index].file
+ self.list[index] = SourceEntry(line, file)
+ modified = True
+ else:
+ # FIXME: What to do if there are no system sources?
+ # To disable the security updates would be the best
+ # option, but what about people with a local mirror
+ # that fetch sec updates from the ubuntu servers
+ pass
+ return modified
# templates for the add dialog
class SourceEntryTemplate(SourceEntry):
- def __init__(self,a_type,uri,dist,description,comps):
+ def __init__(self, a_type, uri, dist, description, comps):
self.comps = []
self.comps_descriptions = []
self.type = a_type
@@ -303,6 +472,8 @@ class SourceEntryTemplates:
dinfo = DistInfo (base_dir=datadir+"channels/")
+ self.dist = dinfo.dist
+
for suite in dinfo.suites:
comps = []
for comp in suite.components:
@@ -323,12 +494,14 @@ class SourceEntryMatcher:
self.description = a_descr
class MatchDist:
- def __init__(self,a_uri,a_dist, a_descr,l_comps, l_comps_descr):
+ def __init__(self, a_uri, a_dist, a_descr, l_comps,
+ l_comps_descr, special=None):
self.uri = a_uri
self.dist = a_dist
self.description = a_descr
self.comps = l_comps
self.comps_descriptions = l_comps_descr
+ self.special = special
def __init__(self):
_ = gettext.gettext
@@ -338,93 +511,142 @@ class SourceEntryMatcher:
self.dist_list = []
+ #UBUNTU
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.04",
+ ".*",
+ _("Cdrom with Ubuntu 6.04 'Dapper "\
+ "Drake'"),
+ ubuntu_comps, ubuntu_comps_descr,
+ SOURCE_SYSTEM))
self.dist_list.append(self.MatchDist("cdrom:\[Ubuntu.*5.10",
".*",
- _("CD disk with Ubuntu 5.10 'Breezy Badger'"),
- ubuntu_comps, ubuntu_comps_descr))
+ _("Cdrom with Ubuntu 5.10 'Breezy "\
+ "Badger'"),
+ ubuntu_comps, ubuntu_comps_descr,
+ SOURCE_SYSTEM))
self.dist_list.append(self.MatchDist("cdrom:\[Ubuntu.*5.04",
".*",
- _("CD disk with Ubuntu 5.04 \"Hoary Hedgehog\""),
- ubuntu_comps, ubuntu_comps_descr))
+ _("Cdrom with Ubuntu 5.04 'Hoary "\
+ "Hedgehog'"),
+ ubuntu_comps, ubuntu_comps_descr,
+ SOURCE_SYSTEM))
self.dist_list.append(self.MatchDist("cdrom:\[Ubuntu.*4.10",
".*",
- _("CD disk with Ubuntu 4.10 \"Warty Warthog\""),
- ubuntu_comps, ubuntu_comps_descr))
+ _("Cdrom with Ubuntu 4.10 'Warty "\
+ "Warthog'"),
+ ubuntu_comps, ubuntu_comps_descr,
+ SOURCE_SYSTEM))
# URIs
# Warty
self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
"^warty$",
"Ubuntu 4.10 'Warty Warthog'",
- ubuntu_comps, ubuntu_comps_descr))
+ ubuntu_comps, ubuntu_comps_descr,
+ SOURCE_SYSTEM))
self.dist_list.append(self.MatchDist(".*security.ubuntu.com/ubuntu",
"^warty-security$",
_("Ubuntu 4.10 Security Updates"),
- ubuntu_comps, ubuntu_comps_descr))
+ ubuntu_comps, ubuntu_comps_descr,
+ SOURCE_SECURITY))
self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
"^warty-security$",
_("Ubuntu 4.10 Security Updates"),
- ubuntu_comps, ubuntu_comps_descr))
+ ubuntu_comps, ubuntu_comps_descr,
+ SOURCE_SECURITY))
+ self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
+ "^warty-backports$",
+ _("Ubuntu 4.10 Backports"),
+ ubuntu_comps, ubuntu_comps_descr,
+ SOURCE_BACKPORTS))
self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
"^warty-updates$",
_("Ubuntu 4.10 Updates"),
- ubuntu_comps, ubuntu_comps_descr))
+ ubuntu_comps, ubuntu_comps_descr,
+ SOURCE_UPDATES))
# Hoary
self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
"^hoary-security$",
_("Ubuntu 5.04 Security Updates"),
- ubuntu_comps, ubuntu_comps_descr))
+ ubuntu_comps, ubuntu_comps_descr,
+ SOURCE_SECURITY))
self.dist_list.append(self.MatchDist(".*security.ubuntu.com/ubuntu",
"^hoary-security$",
_("Ubuntu 5.04 Security Updates"),
- ubuntu_comps, ubuntu_comps_descr))
+ ubuntu_comps, ubuntu_comps_descr,
+ SOURCE_SECURITY))
self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
"^hoary$",
"Ubuntu 5.04 'Hoary Hedgehog'",
- ubuntu_comps, ubuntu_comps_descr))
+ ubuntu_comps, ubuntu_comps_descr,
+ SOURCE_SYSTEM))
+ self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
+ "^hoary-backports$",
+ _("Ubuntu 5.04 Backports"),
+ ubuntu_comps, ubuntu_comps_descr,
+ SOURCE_BACKPORTS))
self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
"^hoary-updates$",
_("Ubuntu 5.04 Updates"),
- ubuntu_comps, ubuntu_comps_descr))
+ ubuntu_comps, ubuntu_comps_descr,
+ SOURCE_UPDATES))
# Breezy
self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
"^breezy-security$",
_("Ubuntu 5.10 Security Updates"),
- ubuntu_comps, ubuntu_comps_descr))
+ ubuntu_comps, ubuntu_comps_descr,
+ SOURCE_SECURITY))
self.dist_list.append(self.MatchDist(".*security.ubuntu.com/ubuntu",
"^breezy-security$",
_("Ubuntu 5.10 Security Updates"),
- ubuntu_comps, ubuntu_comps_descr))
+ ubuntu_comps, ubuntu_comps_descr,
+ SOURCE_SECURITY))
self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
"^breezy$",
"Ubuntu 5.10 'Breezy Badger'",
- ubuntu_comps, ubuntu_comps_descr))
+ ubuntu_comps, ubuntu_comps_descr,
+ SOURCE_SYSTEM))
+ self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
+ "^breezy-backports$",
+ _("Ubuntu 5.10 Backports"),
+ ubuntu_comps, ubuntu_comps_descr,
+ SOURCE_BACKPORTS))
self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
"^breezy-updates$",
_("Ubuntu 5.10 Updates"),
- ubuntu_comps, ubuntu_comps_descr))
+ ubuntu_comps, ubuntu_comps_descr,
+ SOURCE_UPDATES))
# dapper
self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
"^dapper-security$",
_("Ubuntu 6.04 Security Updates"),
- ubuntu_comps, ubuntu_comps_descr))
+ ubuntu_comps, ubuntu_comps_descr,
+ SOURCE_SECURITY))
self.dist_list.append(self.MatchDist(".*security.ubuntu.com/ubuntu",
"^dapper-security$",
_("Ubuntu 6.04 Security Updates"),
- ubuntu_comps, ubuntu_comps_descr))
+ ubuntu_comps, ubuntu_comps_descr,
+ SOURCE_SECURITY))
self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
"^dapper$",
"Ubuntu 6.04 'Dapper Drake'",
- ubuntu_comps, ubuntu_comps_descr))
+ ubuntu_comps, ubuntu_comps_descr,
+ SOURCE_SYSTEM))
+ self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
+ "^dapper-backports$",
+ _("Ubuntu 6.04 Backports"),
+ ubuntu_comps, ubuntu_comps_descr,
+ SOURCE_BACKPORTS))
self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
"^dapper-updates$",
_("Ubuntu 6.04 Updates"),
- ubuntu_comps, ubuntu_comps_descr))
+ ubuntu_comps, ubuntu_comps_descr,
+ SOURCE_UPDATES))
# DEBIAN
@@ -439,50 +661,57 @@ class SourceEntryMatcher:
self.dist_list.append(self.MatchDist(".*debian.org/debian",
"^sarge$",
_("Debian 3.1 'Sarge'"),
- debian_comps, debian_comps_descr))
+ debian_comps, debian_comps_descr,
+ SOURCE_SYSTEM))
self.dist_list.append(self.MatchDist(".*debian.org/debian",
"^woody$",
_("Debian 3.0 'Woody'"),
- debian_comps, debian_comps_descr))
+ debian_comps, debian_comps_descr,
+ SOURCE_SYSTEM))
# securtiy
self.dist_list.append(self.MatchDist(".*security.debian.org",
"^stable.*$",
_("Debian Stable Security Updates"),
- debian_comps, debian_comps_descr))
+ debian_comps, debian_comps_descr,
+ SOURCE_SECURITY))
# dists by status
self.dist_list.append(self.MatchDist(".*debian.org/debian",
"^stable$",
_("Debian Stable"),
- debian_comps, debian_comps_descr))
+ debian_comps, debian_comps_descr,
+ SOURCE_SYSTEM))
self.dist_list.append(self.MatchDist(".*debian.org/debian",
"^testing$",
_("Debian Testing"),
- debian_comps, debian_comps_descr))
+ debian_comps, debian_comps_descr,
+ SOURCE_SYSTEM))
self.dist_list.append(self.MatchDist(".*debian.org/debian",
"^unstable$",
_("Debian Unstable 'Sid'"),
- debian_comps, debian_comps_descr))
+ debian_comps, debian_comps_descr,
+ SOURCE_SYSTEM))
# non-us
self.dist_list.append(self.MatchDist(".*debian.org/debian-non-US",
"^stable.*$",
_("Debian Non-US (Stable)"),
- debian_comps, debian_comps_descr))
+ debian_comps, debian_comps_descr,
+ SOURCE_SYSTEM))
self.dist_list.append(self.MatchDist(".*debian.org/debian-non-US",
"^testing.*$",
_("Debian Non-US (Testing)"),
- debian_comps, debian_comps_descr))
+ debian_comps, debian_comps_descr,
+ SOURCE_SYSTEM))
self.dist_list.append(self.MatchDist(".*debian.org/debian-non-US",
"^unstable.*$",
_("Debian Non-US (Unstable)"),
- debian_comps, debian_comps_descr))
-
+ debian_comps, debian_comps_descr,
+ SOURCE_SYSTEM))
-
-
def match(self,source):
_ = gettext.gettext
# some sane defaults first
+ special = None
type_description = source.type
dist_description = source.uri + " " + source.dist
# if there is a comment use it instead of the url
@@ -498,23 +727,24 @@ class SourceEntryMatcher:
type_description = _(t.description)
break
+ comp_descriptions = []
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 = ""
+ comp_descriptions = []
+ special = d.special
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]
+ comp_descriptions.append(d.comps_descriptions[i])
found = True
if found == False:
- comp_description = comp_description+" "+c
+ comp_descriptions.append(c)
break
-
-
- return (type_description,dist_description,comp_description)
+
+ return (type_description, dist_description, comp_descriptions, special)
# some simple tests
diff --git a/SoftwareProperties/dialog_add.py b/SoftwareProperties/dialog_add.py
index effd9f24..a1ac713b 100644
--- a/SoftwareProperties/dialog_add.py
+++ b/SoftwareProperties/dialog_add.py
@@ -26,6 +26,7 @@ import os
import gobject
import gtk
import gtk.glade
+from gettext import gettext as _
import aptsources
@@ -44,7 +45,9 @@ class dialog_add:
self.main = widget = self.gladexml.get_widget("dialog_add")
self.main.set_transient_for(self.parent)
-
+
+ self.vbox = self.gladexml.get_widget("vbox_comps")
+
# Setup the official channel widgets
self.combo = self.gladexml.get_widget("combobox_what")
self.gladexml.signal_connect("on_combobox_what_changed", self.on_combobox_what_changed, None)
@@ -52,6 +55,11 @@ class dialog_add:
self.combo.pack_start(cell, True)
self.combo.add_attribute(cell, 'text', 0)
self.fill_combo(self.combo)
+ self.label_dist = self.gladexml.get_widget("label_dist")
+ if self.templatelist.dist != "":
+ # TRANSLATORS: %s is the distribution name, eg. Ubuntu or Debian
+ self.label_dist.set_markup("<b>%s</b>" % \
+ _("%s channels" % self.templatelist.dist))
# Setup the custom channel widgets
self.entry = self.gladexml.get_widget("entry_source_line")
@@ -96,7 +104,7 @@ class dialog_add:
for check in self.comps:
check.set_sensitive(state)
self.official = state
- self.button_add.set_sensitive(state)
+ self.count_comps()
def fill_combo(self,combo):
liststore = gtk.ListStore(gobject.TYPE_STRING,gobject.TYPE_PYOBJECT)
@@ -107,8 +115,7 @@ class dialog_add:
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)
+ self.vbox.foreach(lambda widget,vbox: self.vbox.remove(widget), self.vbox)
liststore = combobox.get_model()
a_iter = liststore.iter_nth_child(None, combobox.get_active())
(name, template) = liststore.get(a_iter, 0,1)
@@ -119,22 +126,31 @@ class dialog_add:
checkbox = gtk.CheckButton(c.description)
checkbox.set_active(c.on_by_default)
checkbox.set_data("name",c.name)
- vbox.pack_start(checkbox)
+ checkbox.connect("toggled", self.count_comps)
+ self.vbox.pack_start(checkbox)
checkbox.show()
self.comps.append(checkbox)
+ self.count_comps()
def get_enabled_comps(self, checkbutton):
if checkbutton.get_active():
self.selected_comps.append(checkbutton.get_data("name"))
+ def count_comps(self, *args):
+ button_add = self.gladexml.get_widget("button_add_channel")
+ self.selected_comps=[]
+ self.vbox.foreach(self.get_enabled_comps)
+ if len(self.selected_comps) > 0:
+ button_add.set_sensitive(True)
+ else:
+ button_add.set_sensitive(False)
+
def run(self):
res = self.main.run()
if res == gtk.RESPONSE_OK:
# add repository
if self.official == True:
self.selected_comps = []
- vbox = self.gladexml.get_widget("vbox_comps")
- vbox.foreach(self.get_enabled_comps)
self.sourceslist.add(self.selected.type,
self.selected.uri,
self.selected.dist,
diff --git a/SoftwareProperties/dialog_sources_list.py b/SoftwareProperties/dialog_sources_list.py
index 9159d01f..a09542c8 100644
--- a/SoftwareProperties/dialog_sources_list.py
+++ b/SoftwareProperties/dialog_sources_list.py
@@ -39,6 +39,8 @@ class AddSourcesList:
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)
@@ -49,35 +51,31 @@ class AddSourcesList:
except:
self.error()
return
- self.matcher = SourceEntryMatcher()
# show the found channels or an error message
if len(self.sources.list) > 0:
self.button_close.hide()
- found = False
+ counter = 0
for source in self.sources.list:
if source.invalid or source.disabled:
continue
- found = True
- (a_type, dist, comps) = self.matcher.match(source)
-
- line = "<b>%s</b> (%s)%s" %\
- (dist, a_type, comps)
+ counter = counter +1
+ line = self.sources.render_source(source)
self.store.append([line])
- if found == False:
+ if counter == 0:
self.error()
return
header = gettext.ngettext("Add the following software channel?",
"Add the following software channels?",
- len(self.sources.list))
+ counter)
body = _("You can install software from a channel. Use "\
"trusted channels, only.")
self.label.set_markup("<big><b>%s</b></big>\n\n%s" % (header, body))
self.button_add.set_use_underline(True)
self.button_add.set_label(gettext.ngettext("_Add Channel",
"_Add Channels",
- len(self.sources.list)))
+ counter))
else:
self.error()
return
@@ -118,5 +116,6 @@ class AddSourcesList:
class SingleSourcesList(SourcesList):
def __init__(self, file):
+ self.matcher = SourceEntryMatcher()
self.list = []
self.load(file)