#!/usr/bin/python2.4 # gnome-software-properties.in - edit /etc/apt/sources.list # # Copyright (c) 2004 Canonical # 2004 Michiel Sikkes # # Author: Michiel Sikkes # Michael Vogt # # 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 pygtk import sys pygtk.require('2.0') import gtk import gtk.glade import gconf import gobject import os import gettext import re import string import time import tempfile import subprocess from optparse import OptionParser import apt_pkg sys.path.append("@prefix@/share/update-manager/python") import aptsources import dialog_add import dialog_edit import dialog_apt_key from dialog_settings import dialog_settings import shutil (LIST_MARKUP, LIST_ENABLED, LIST_ENTRY_OBJ) = range(3) class SoftwareConfigurator: def on_button_ok_clicked(self, widget, data): #self.save_periodic_config(periodicAptConfFile) location = "/etc/apt/sources.list" #backup first shutil.copy(location,location+".save") # write self.sourceslist.save(location) # write the source.list first, even if dirty=False, because # e.g. CD-ROM add does not set dirty variable even if it adds # something to the sources.list (but no reload needed) if self.dirty == False: gtk.main_quit() sys.exit(0) primary = "" + _("Repositories " "changed") + "" secondary = _("The repository information has changes. A backup copy of " "your sources.list is stored in %s.save. " "\n\n" "You need to reload the package list from the servers " "for your changes to take effect. Do you want to do this " "now?") % location dialog = gtk.MessageDialog(self.main_window,gtk.DIALOG_MODAL, gtk.MESSAGE_INFO,gtk.BUTTONS_YES_NO,"") dialog.set_markup(primary); dialog.format_secondary_text(secondary); #textview = gtk.TextView() #textview.set_editable(gtk.FALSE) #textbuffer = textview.get_buffer() #f = os.popen("/usr/bin/diff -u %s.save %s" % (location,location)) #diff = f.read() #textbuffer.set_text(diff) #if f.close() != None: # win = gtk.ScrolledWindow() # win.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC) # win.add(textview) # win.set_size_request(400,300) # win.show() # dialog.vbox.pack_start(child = win, padding = 6) # textview.show() res = dialog.run() dialog.destroy() if res == gtk.RESPONSE_YES: self.main_window.hide() # we are in "no-update" mode, this is used when the calling application # wants to deal with this itself if options.no_update: gtk.main_quit() sys.exit(1) child = subprocess.Popen(["/usr/sbin/synaptic", "--update-at-startup", "--hide-main-window","--non-interactive"], close_fds=True) # wait for the child to finish while child.poll() == None: time.sleep(0.05) while gtk.events_pending(): gtk.main_iteration() gtk.main_quit() sys.exit(1) gtk.main_quit() sys.exit(0) def on_button_edit_clicked(self, widget, data): selection = self.sourceslist_view.get_selection() (model, iter) = selection.get_selected() source_entry = model.get_value(iter, LIST_ENTRY_OBJ) edit = dialog_edit.dialog_edit(self.main_window,self.sourceslist, source_entry) if edit.run() == gtk.RESPONSE_OK: self.reloadsources(self.sourceslist,self.matcher) self.dirty = True def on_sourceslist_selection_changed(self, selection, data): (model, iter) = selection.get_selected() if iter != None: self.button_del.set_sensitive(True) self.button_edit.set_sensitive(True) else: self.button_del.set_sensitive(False) self.button_edit.set_sensitive(False) #def on_sourceslist_row_activated(self, treeview, path, column, data): # #print "on_row_activated()" # model = treeview.get_model() # source_entry = model.get_value(model.get_iter(path), LIST_ENTRY_OBJ) # edit = dialog_edit.dialog_edit(self.main_window,self.sourceslist, # source_entry) # edit.run() # self.reloadsources(self.sourceslist,self.matcher) def on_button_remove_clicked(self, widget, data): selection = self.sourceslist_view.get_selection() (model,a_iter) = selection.get_selected() if a_iter == None: return source = model.get_value(a_iter, LIST_ENTRY_OBJ) self.sourceslist.remove(source) self.reloadsources(self.sourceslist,self.matcher) self.dirty=True def on_button_add_clicked(self, widget, data): add = dialog_add.dialog_add(self.main_window,self.sourceslist) if add.run() == gtk.RESPONSE_OK: self.reloadsources(self.sourceslist,self.matcher) self.dirty=True def on_button_settings_clicked(self, widget, data): settings = dialog_settings(self.main_window, self.gladexml) settings.run() self.show_disabled = self.gconfclient.get_bool("/apps/gnome-software-properties/show_disabled") self.c_enabled.set_property("visible", self.show_disabled) self.reloadsources(self.sourceslist, self.matcher) def on_button_add_cdrom_clicked(self, widget, data): tmp = tempfile.NamedTemporaryFile() cmd = ["/usr/sbin/synaptic", "--hide-main-window", "--non-interactive", "-o","Dir::Etc::sourcelist=%s" % tmp.name,"--ask-cdrom" ] self.main_window.set_sensitive(False) proc = subprocess.Popen(cmd) # wait for process to finish while proc.poll() == None: while gtk.events_pending(): gtk.main_iteration() time.sleep(0.05) self.main_window.set_sensitive(True) # read tmp file with source name line = "" for x in open(tmp.name): line = x if line != "": self.sourceslist.list.append(aptsources.SourceEntry(line)) self.reloadsources(self.sourceslist,self.matcher) #self.dirty=True # no need here def on_button_authentication_clicked(self, widget, data): auth = dialog_apt_key.dialog_apt_key(self.main_window) auth.run() def reloadsources(self, sourceslist, matcher): #self.meta = meta_data() self.sourcesstore.clear() for source in sourceslist.list: if source.invalid or (source.disabled and not self.show_disabled): continue (a_type,dist,comps) = matcher.match(source) contents = "" if source.comment != "": contents += "%s\n\n" % (source.comment) contents +="%s (%s) \n%s" % (dist,a_type, comps) iter = self.sourcesstore.append([contents, not source.disabled, source]) def show_help(self, widget, data): print "self.show_help() called" # toggled on/off a source in the listview def toggled_enabled(self, renderer, path_string): iter = self.sourcesstore.get_iter_from_string(path_string) source = self.sourcesstore.get_value(iter, LIST_ENTRY_OBJ) self.dirty=True if self.sourcesstore.get_value(iter, LIST_ENABLED): self.sourcesstore.set_value(iter, LIST_ENABLED, False) source.set_enabled(False) else: self.sourcesstore.set_value(iter, LIST_ENABLED, True) source.set_enabled(True) def __init__(self): self.gconfclient = gconf.client_get_default() if os.path.exists("../data/gnome-software-properties.glade"): self.gladexml = gtk.glade.XML("../data/gnome-software-properties.glade") else: self.gladexml = gtk.glade.XML("@prefix@/share/update-manager/gnome-software-properties.glade") # do we show disabled sources? self.show_disabled = self.gconfclient.get_bool("/apps/gnome-software-properties/show_disabled") self.main_window = self.gladexml.get_widget("SoftwareConfigurator") # button on the right self.gladexml.signal_connect("on_button_edit_clicked", self.on_button_edit_clicked, None) self.button_edit = self.gladexml.get_widget("button_edit") self.button_del = self.gladexml.get_widget("button_remove") # Gets the treeview and creates a store for it. self.sourceslist_view = self.gladexml.get_widget("sourceslist") self.sourcesstore = gtk.ListStore(str, bool,gobject.TYPE_PYOBJECT) self.sourceslist_view.set_model(self.sourcesstore) #self.gladexml.signal_connect("on_sourceslist_row_activated", # self.on_sourceslist_row_activated, None) self.sourceslist_view.get_selection().connect("changed", self.on_sourceslist_selection_changed, None) # was something modified self.dirty=False # Create columns and append them. cr = gtk.CellRendererToggle() cr.set_property("activatable", True) cr.set_property("xpad", 10) cr.set_property("ypad", 10) cr.connect("toggled", self.toggled_enabled) self.c_enabled = gtk.TreeViewColumn("Enabled", cr, active=LIST_ENABLED) self.sourceslist_view.append_column(self.c_enabled) self.c_enabled.set_property("visible", self.show_disabled) tr = gtk.CellRendererText() tr.set_property("xpad", 10) tr.set_property("ypad", 10) c0 = gtk.TreeViewColumn("Entry", tr, markup=LIST_MARKUP) self.sourceslist_view.append_column(c0) self.sourceslist = aptsources.SourcesList("@sysconfdir@/apt/sources.list") self.matcher = aptsources.SourceEntryMatcher() # Empty and fill the sources store. self.reloadsources(self.sourceslist,self.matcher) self.main_window = self.gladexml.get_widget("SoftwareConfigurator") self.main_window.connect("delete_event", lambda widget,ev: gtk.main_quit()) okbutton = self.gladexml.get_widget("button_ok") okbutton.connect("clicked", self.on_button_ok_clicked, None) cancelbutton = self.gladexml.get_widget("button_cancel") cancelbutton.connect("clicked", lambda w,v: gtk.main_quit(), None) self.gladexml.signal_connect("on_button_add_clicked", self.on_button_add_clicked, None) self.gladexml.signal_connect("on_button_add_cdrom_clicked", self.on_button_add_cdrom_clicked, None) self.gladexml.signal_connect("on_button_remove_clicked", self.on_button_remove_clicked, None) self.gladexml.signal_connect("on_button_authentication_clicked", self.on_button_authentication_clicked, None) # settings self.gladexml.signal_connect("on_button_settings_clicked", self.on_button_settings_clicked, None) self.main_window.show() if options.toplevel != None: # don't show the add-cdrom button for now # FIXME: on the long run interface with apt-pkg/cdrom.h b = self.gladexml.get_widget("button_add_cdrom") b.hide() toplevel = gtk.gdk.window_foreign_new(int(options.toplevel)) self.main_window.window.set_transient_for(toplevel) # init the config apt_pkg.InitConfig() def main(self): gtk.main() if __name__ == "__main__": APP="update-manager" DIR="@prefix@/share/locale" gettext.bindtextdomain(APP, DIR) gettext.textdomain(APP) gtk.glade.bindtextdomain(APP, DIR) gtk.glade.textdomain(APP) _ = gettext.gettext #print "Software Configurator started..." # add option parser parser = OptionParser() parser.add_option("-n", "--no-update", action="store_true", dest="no_update", default=False, help="No update on repository change (usefull if called "\ "from a external program).") parser.add_option("-t", "--toplevel", action="store", type="string", dest="toplevel", help="Set x-window-id of the toplevel parent for the "\ "dialog (usefull for embedding)") (options, args) = parser.parse_args() ui = SoftwareConfigurator() ui.main() #print "Software Configurator ended..."