home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / lib / python2.6 / dist-packages / AppInstall / AppInstall.pyc (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2009-10-12  |  40.5 KB  |  1,070 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. import gtk
  5. import gtk.glade as gtk
  6. import gtk.gdk as gtk
  7. import gobject
  8. import gconf
  9. import pango
  10. import gettext
  11. from gettext import gettext as _
  12. from math import log
  13. app = 'gnome-app-install'
  14. gettext.textdomain(app)
  15. gettext.bindtextdomain(app)
  16. gtk.glade.textdomain(app)
  17. gtk.glade.bindtextdomain(app)
  18. from widgets.SearchEntry import SearchEntry
  19. from widgets.AppDescView import AppDescView
  20. from widgets.AppListView import AppListView
  21. import gc
  22. import stat
  23. import glob
  24. import re
  25. import subprocess
  26. import tempfile
  27. import warnings
  28. import os
  29. import sys
  30. from datetime import datetime
  31. import distros
  32. import dbus
  33. import dbus.service as dbus
  34. import dbus.glib as dbus
  35. import time
  36. from warnings import warn
  37. warnings.filterwarnings('ignore', 'ICON:.*', UserWarning)
  38. warnings.filterwarnings('ignore', 'apt API not stable yet', FutureWarning)
  39. import apt
  40. import apt_pkg
  41. from aptsources.sourceslist import SourcesList, is_mirror
  42. from DialogComplete import DialogComplete
  43. from DialogPendingChanges import DialogPendingChanges
  44. from DialogMultipleApps import DialogMultipleApps
  45. from DialogProprietary import DialogProprietary
  46. from PackageWorker import PackageWorker
  47. from Menu import ApplicationMenu
  48. from SimpleGladeApp import SimpleGladeApp
  49. from Progress import GtkOpProgressWindow, GtkCdromProgress
  50. from Util import *
  51. from Cache import MyCache
  52. from Menu import SHOW_ALL, SHOW_ONLY_SUPPORTED, SHOW_ONLY_FREE, SHOW_ONLY_MAIN, SHOW_ONLY_PROPRIETARY, SHOW_ONLY_THIRD_PARTY, SHOW_ONLY_INSTALLED
  53.  
  54. class AppInstallDbusControler(dbus.service.Object):
  55.     ''' this is a helper to provide the AppInstallIFace '''
  56.     
  57.     def __init__(self, parent, bus_name, object_path = '/org/freedesktop/AppInstallObject'):
  58.         dbus.service.Object.__init__(self, bus_name, object_path)
  59.         self.parent = parent
  60.  
  61.     
  62.     def bringToFront(self):
  63.         self.parent.window_main.present()
  64.         return True
  65.  
  66.     bringToFront = dbus.service.method('org.freedesktop.AppInstallIFace')(bringToFront)
  67.  
  68.  
  69. class AppInstall(SimpleGladeApp):
  70.     
  71.     def __init__(self, options, activation_style):
  72.         if not options.test_mode:
  73.             self.setupDbus()
  74.         
  75.         self.search_timeout_id = 0
  76.         self.activation_style = activation_style
  77.         self.distro = distros.get_distro()
  78.         self.icons = gtk.icon_theme_get_default()
  79.         
  80.         try:
  81.             gtk.window_set_default_icon(self.icons.load_icon('gnome-app-install', 32, 0))
  82.         except gobject.GError:
  83.             pass
  84.  
  85.         SimpleGladeApp.__init__(self, domain = 'gnome-app-install', path = options.datadir + '/gnome-app-install.glade')
  86.         self.channelsdir = options.desktopdir + '/channels'
  87.         self.datadir = options.datadir
  88.         self.cachedir = options.cachedir
  89.         self.desktopdir = options.desktopdir
  90.         self.transient_for = None
  91.         if options.transient_for:
  92.             self.transient_for = gtk.gdk.window_foreign_new(options.transient_for)
  93.             if self.transient_for:
  94.                 self.window_main.realize()
  95.                 self.window_main.window.set_transient_for(self.transient_for)
  96.             
  97.         
  98.         self.button_ok.set_sensitive(False)
  99.         self.sort_by_ranking = False
  100.         self.config = gconf.client_get_default()
  101.         self.config.add_dir('/apps/gnome-app-install', gconf.CLIENT_PRELOAD_NONE)
  102.         self.tooltips = gtk.Tooltips()
  103.         self.tipmap = { }
  104.         self.search_entry = SearchEntry(self.icons)
  105.         self.search_hbox.add(self.search_entry)
  106.         self.search_entry.connect('terms-changed', self._perform_search)
  107.         self.search_entry.show()
  108.         self.treeview_packages = AppListView(self.icons)
  109.         self.scrolled_window.add(self.treeview_packages)
  110.         self.treeview_packages.show()
  111.         self.textview_description = AppDescView()
  112.         self.scrolled_description.add(self.textview_description)
  113.         self.scrolled_description.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
  114.         msg = _('To install an application check the box next to the application. Uncheck the box to remove the application.') + '\n'
  115.         msg += _('To perform advanced tasks use the Synaptic package manager.')
  116.         header = _('Quick Introduction')
  117.         self.textview_description.show_message(header, msg)
  118.         self.textview_description.show()
  119.         self.setupTreeview()
  120.         self.components_seen = self.config.get_list('/apps/gnome-app-install/components_seen', 'string')
  121.         filter_to_restore = self.config.get_int('/apps/gnome-app-install/filter_applications')
  122.         if filter_to_restore not in range(7):
  123.             filter_to_restore = 0
  124.         
  125.         list_filters = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_BOOLEAN, gobject.TYPE_STRING, gobject.TYPE_INT)
  126.         self.combobox_filter.set_model(list_filters)
  127.         filter_renderer = gtk.CellRendererText()
  128.         self.combobox_filter.pack_start(filter_renderer)
  129.         filters = []
  130.         sorted_keys = self.distro.filters_primary.keys()
  131.         sorted_keys.sort()
  132.         for filter in sorted_keys:
  133.             filters.append((self.distro.filters_primary[filter][0], False, self.distro.filters_primary[filter][1], filter))
  134.         
  135.         if self.distro.filters_secondary:
  136.             filters.append(('separator', True, 'separator', -1))
  137.             sorted_keys = self.distro.filters_secondary.keys()
  138.             sorted_keys.sort()
  139.             for filter in sorted_keys:
  140.                 filters.append((self.distro.filters_secondary[filter][0], False, self.distro.filters_secondary[filter][1], filter))
  141.             
  142.         
  143.         if not self.activation_style.isInstallerOnly:
  144.             filters.extend([
  145.                 ('separator', True, 'separator', -1),
  146.                 (_('Installed applications only'), False, _('Show only applications that are installed on your computer'), SHOW_ONLY_INSTALLED)])
  147.         
  148.         for desc, sep, tooltip, filter in filters:
  149.             list_filters.append((desc, sep, tooltip, filter))
  150.             self.combobox_filter.set_row_separator_func(self.separator_filter)
  151.             self.combobox_filter.set_cell_data_func(filter_renderer, self.tooltip_on_filter)
  152.             if filter == filter_to_restore:
  153.                 self.combobox_filter.set_active(len(list_filters) - 1)
  154.                 self.tooltips.set_tip(self.eventbox_filter, tooltip)
  155.                 continue
  156.         
  157.         self.combobox_filter.connect('changed', self.on_combobox_filter_changed)
  158.         if self.activation_style.isSpecific():
  159.             self.activation_style.modifyUserInterface(self)
  160.         else:
  161.             maximized = self.config.get_bool('/apps/gnome-app-install/state/window_maximized')
  162.             height = self.config.get_int('/apps/gnome-app-install/state/window_height')
  163.             width = self.config.get_int('/apps/gnome-app-install/state/window_width')
  164.             if type(maximized) == bool and maximized == True:
  165.                 self.window_main.maximize()
  166.             elif type(width) == int and type(height) == int and width > 0 and height > 0:
  167.                 self.window_main.set_property('default_width', width)
  168.                 self.window_main.set_property('default_height', height)
  169.             
  170.         if not self.transient_for:
  171.             self.window_main.show()
  172.         
  173.         self.addon_cd = options.addon_cd
  174.         self.addCD()
  175.         self.updateCache(filter_to_restore)
  176.         self.textview_description.hook(self.cache, self.menu, self.icons, self.tooltips, self.distro)
  177.         self.treeview_packages.hook(self.cache, self.menu)
  178.         self.treeview_categories.set_cursor((0,))
  179.         self.multiple_pkgs_seen = set()
  180.         self.window_main.show()
  181.         self.packageWorker = PackageWorker(options.addon_cd)
  182.         self.treeview_packages.connect('toggled', self.on_install_toggle)
  183.         self.treeview_packages.connect('row-activated', self.on_treeview_packages_row_activated)
  184.         self.treeview_packages.connect('cursor-changed', self.on_treeview_packages_cursor_changed)
  185.         if not options.test_mode:
  186.             self._checkAptCache()
  187.         
  188.         if gtk.REALIZED & self.search_entry.flags():
  189.             self.search_entry.grab_focus()
  190.         else:
  191.             self.treeview_packages.grab_focus()
  192.  
  193.     
  194.     def addCD(self):
  195.         ''' check for addon cd and if available and not yet added
  196.             add itadd addon cd
  197.         '''
  198.         if self.addon_cd is not None:
  199.             
  200.             try:
  201.                 self.window_main.set_sensitive(False)
  202.                 self.setBusy(True)
  203.                 cd_desktopdir = os.path.join(self.addon_cd, 'app-install')
  204.                 if os.path.exists(cd_desktopdir):
  205.                     cdrom = apt.cdrom.Cdrom(progress = GtkCdromProgress(self), mountpoint = self.addon_cd)
  206.                     if not cdrom.inSourcesList:
  207.                         cdrom.add()
  208.                     
  209.                     self.desktopdir = cd_desktopdir
  210.                     self.cachedir = None
  211.             except SystemError:
  212.                 e = None
  213.                 print 'SystemError while adding addon CD:\n%s' % e
  214.                 header = _('Error reading the addon CD')
  215.                 msg = _('The addon CD may be corrupt ')
  216.                 d = gtk.MessageDialog(parent = self.window_main, flags = gtk.DIALOG_MODAL, type = gtk.MESSAGE_ERROR, buttons = gtk.BUTTONS_CLOSE)
  217.                 d.set_title('')
  218.                 d.set_markup('<big><b>%s</b></big>\n\n%s' % (header, msg))
  219.                 d.realize()
  220.                 d.window.set_functions(gtk.gdk.FUNC_MOVE)
  221.                 d.run()
  222.                 d.destroy()
  223.                 sys.exit(1)
  224.             except:
  225.                 None<EXCEPTION MATCH>SystemError
  226.             
  227.  
  228.         None<EXCEPTION MATCH>SystemError
  229.  
  230.     
  231.     def _checkAptCache(self):
  232.         time_cache = self.config.get_int('/apps/gnome-app-install/cache_dialog_time')
  233.         for f in glob.glob('/var/lib/apt/lists/*Packages'):
  234.             mt = os.stat(f)[stat.ST_MTIME]
  235.             ct = os.stat(f)[stat.ST_CTIME]
  236.             if mt > time_cache:
  237.                 time_cache = mt
  238.             
  239.             if ct > time_cache:
  240.                 time_cache = ct
  241.                 continue
  242.         
  243.         if not os.path.exists('/etc/apt/sources.list'):
  244.             return None
  245.         time_source = os.stat('/etc/apt/sources.list')[stat.ST_MTIME]
  246.         for f in glob.glob('/etc/apt/sources.list.d/*.list'):
  247.             mt = os.stat(f)[stat.ST_MTIME]
  248.             ct = os.stat(f)[stat.ST_CTIME]
  249.             if mt > time_source:
  250.                 time_source = mt
  251.             
  252.             if ct > time_source:
  253.                 time_source = ct
  254.                 continue
  255.         
  256.         if time_cache < time_source:
  257.             self.dialog_cache_outdated.set_transient_for(self.window_main)
  258.             self.dialog_cache_outdated.realize()
  259.             self.dialog_cache_outdated.window.set_functions(gtk.gdk.FUNC_MOVE)
  260.             res = self.dialog_cache_outdated.run()
  261.             self.dialog_cache_outdated.hide()
  262.             if res == gtk.RESPONSE_YES:
  263.                 self.reloadSources()
  264.                 self.config.set_int('/apps/gnome-app-install/cache_dialog_time', int(time.time()))
  265.             
  266.         
  267.  
  268.     
  269.     def separator_filter(self, model, iter, user_data = None):
  270.         '''Used to draw a spearator in the combobox for the filters'''
  271.         return model.get_value(iter, 1)
  272.  
  273.     
  274.     def setupDbus(self):
  275.         ''' this sets up a dbus listener if none is installed alread '''
  276.         dbus.mainloop.glib.DBusGMainLoop(set_as_default = True)
  277.         
  278.         try:
  279.             bus = dbus.SessionBus()
  280.         except:
  281.             print 'warning: could not initiate dbus'
  282.             return None
  283.  
  284.         
  285.         try:
  286.             proxy_obj = bus.get_object('org.freedesktop.AppInstall', '/org/freedesktop/AppInstallObject')
  287.             iface = dbus.Interface(proxy_obj, 'org.freedesktop.AppInstallIFace')
  288.             iface.bringToFront()
  289.             sys.exit(0)
  290.         except dbus.DBusException:
  291.             e = None
  292.             
  293.             try:
  294.                 bus_name = dbus.service.BusName('org.freedesktop.AppInstall', bus)
  295.                 self.dbusControler = AppInstallDbusControler(self, bus_name)
  296.             except Exception:
  297.                 e = None
  298.                 print "can't init dbus"
  299.                 return None
  300.             
  301.  
  302.             None<EXCEPTION MATCH>Exception
  303.  
  304.  
  305.     
  306.     def setBusy(self, flag):
  307.         ''' Show a watch cursor if the app is busy for more than 0.3 sec.
  308.             Furthermore provide a loop to handle user interface events '''
  309.         if self.window_main.window is None:
  310.             return None
  311.         if flag == True:
  312.             self.window_main.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
  313.         else:
  314.             self.window_main.window.set_cursor(None)
  315.         while gtk.events_pending():
  316.             gtk.main_iteration()
  317.  
  318.     
  319.     def on_combobox_filter_changed(self, combobox):
  320.         '''The filter for the application list was changed'''
  321.         self.setBusy(True)
  322.         active = combobox.get_active()
  323.         model = combobox.get_model()
  324.         iter = model.get_iter(active)
  325.         filter_new = model.get_value(iter, 3)
  326.         if filter_new in range(7):
  327.             self.config.set_int('/apps/gnome-app-install/filter_applications', filter_new)
  328.             self.refilter(filter = filter_new)
  329.         
  330.         tooltip = model.get_value(iter, 2)
  331.         self.tooltips.set_tip(self.eventbox_filter, tooltip)
  332.         self.setBusy(False)
  333.  
  334.     
  335.     def refilter(self, filter = None, terms = None, model = None):
  336.         '''
  337.         Applies the given filter or search terms to the menu filter and provides
  338.         a visual feedback for empty results
  339.         '''
  340.         if filter != None:
  341.             self.menu.filter = filter
  342.         
  343.         if terms != None:
  344.             self.menu.searchTerms = terms
  345.         
  346.         self.menu._refilter(model)
  347.         if len(self.menu.treeview_packages.get_model()) == 0:
  348.             self.show_no_results_msg()
  349.             self.treeview_packages.set_sensitive(False)
  350.         else:
  351.             self.treeview_packages.set_sensitive(True)
  352.             self.menu.treeview_packages.set_cursor(0)
  353.  
  354.     
  355.     def on_window_main_key_press_event(self, widget, event):
  356.         GDK_q = 113
  357.         if event.state & gtk.gdk.CONTROL_MASK and event.keyval == GDK_q:
  358.             self.on_window_main_delete_event(self.window_main, None)
  359.         
  360.  
  361.     
  362.     def error_no_indexfiles(self):
  363.         ''' show an error message that no index files could be found
  364.         '''
  365.         header = _('The list of applications is not available')
  366.         msg = _("Click on 'Reload' to load it. To reload the list you need a working internet connection. ")
  367.         d = gtk.MessageDialog(parent = self.window_main, flags = gtk.DIALOG_MODAL, type = gtk.MESSAGE_INFO)
  368.         d.add_buttons(gtk.STOCK_REFRESH, gtk.RESPONSE_YES, gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)
  369.         d.set_title('')
  370.         d.set_markup('<big><b>%s</b></big>\n\n%s' % (header, msg))
  371.         d.realize()
  372.         d.window.set_functions(gtk.gdk.FUNC_MOVE)
  373.         res = d.run()
  374.         d.destroy()
  375.         if res == gtk.RESPONSE_YES:
  376.             self.reloadSources()
  377.         
  378.  
  379.     
  380.     def error_not_available(self, item):
  381.         '''Show an error message that the application cannot be installed'''
  382.         header = _('%s cannot be installed on your computer type (%s)') % (item.name, self.cache.getArch())
  383.         msg = _('Either the application requires special hardware features or the vendor decided to not support your computer type.')
  384.         d = gtk.MessageDialog(parent = self.window_main, flags = gtk.DIALOG_MODAL, type = gtk.MESSAGE_ERROR, buttons = gtk.BUTTONS_CLOSE)
  385.         d.set_title('')
  386.         d.set_markup('<big><b>%s</b></big>\n\n%s' % (header, msg))
  387.         d.realize()
  388.         d.window.set_functions(gtk.gdk.FUNC_MOVE)
  389.         d.run()
  390.         d.destroy()
  391.  
  392.     
  393.     def tooltip_on_filter(self, cell_view, cell_renderer, model, iter):
  394.         '''
  395.         Show a disclaimer in the tooltips of the filters
  396.         '''
  397.         id = model.get_path(iter)[0]
  398.         item_text = model.get_value(iter, 0)
  399.         item_disclaimer = model.get_value(iter, 2)
  400.         cell_renderer.set_property('text', item_text)
  401.         if isinstance(cell_view, gtk.TreeViewColumn):
  402.             return None
  403.         cell_parent = cell_view.get_parent()
  404.         if isinstance(cell_parent, gtk.MenuItem):
  405.             if cell_parent not in self.tipmap or self.tipmap[cell_parent] != item_disclaimer:
  406.                 self.tipmap[cell_parent] = item_disclaimer
  407.                 self.tooltips.set_tip(cell_parent, item_disclaimer)
  408.             
  409.  
  410.     
  411.     def canNotInstallApp(self, pkg):
  412.         ''' helper that displays a message if the package can not
  413.             be installed '''
  414.         d = gtk.MessageDialog(parent = self.window_main, flags = gtk.DIALOG_MODAL, type = gtk.MESSAGE_ERROR, buttons = gtk.BUTTONS_CLOSE)
  415.         d.set_title('')
  416.         d.set_markup('<big><b>%s</b></big>\n\n%s' % (_("Cannot install '%s'") % pkg, _("This application conflicts with other installed software. To install '%s' the conflicting software must be removed first.\n\nSwitch to the 'synaptic' package manager to resolve this conflict.") % pkg))
  417.         d.realize()
  418.         d.window.set_functions(gtk.gdk.FUNC_MOVE)
  419.         d.run()
  420.         d.destroy()
  421.         self.cache.clean()
  422.         return False
  423.  
  424.     
  425.     def _ensureInArchive(self, item):
  426.         ''' check and make sure the package is in available archive '''
  427.         pkg = item.pkgname
  428.         return True
  429.  
  430.     
  431.     def tryRemove(self, item):
  432.         self.cache.clean()
  433.         pkg = item.pkgname
  434.         self.cache[pkg].markDelete(autoFix = False)
  435.         if self.cache._depcache.BrokenCount > 0:
  436.             d = gtk.MessageDialog(parent = self.window_main, flags = gtk.DIALOG_MODAL, type = gtk.MESSAGE_ERROR, buttons = gtk.BUTTONS_CLOSE)
  437.             d.set_title('')
  438.             d.set_markup('<big><b>%s</b></big>\n\n%s' % (_("Cannot remove '%s'") % pkg, _('One or more applications depend on %s. To remove %s and the dependent applications, use the Synaptic package manager.') % (pkg, pkg)))
  439.             d.realize()
  440.             d.window.set_functions(gtk.gdk.FUNC_MOVE)
  441.             d.run()
  442.             d.destroy()
  443.             self.cache.clean()
  444.             return False
  445.         self.cache.clean()
  446.         return True
  447.  
  448.     
  449.     def tryInstall(self, item):
  450.         pkg = item.pkgname
  451.         self.cache.clean()
  452.         apt_error = False
  453.         group = apt_pkg.GetPkgActionGroup(self.cache._depcache)
  454.         (to_add, to_rm) = self.menu.getChanges()
  455.         for app in to_add:
  456.             self.cache[app.pkgname].markInstall()
  457.         
  458.         del group
  459.         
  460.         try:
  461.             self.cache[pkg].markInstall(autoFix = True)
  462.         except SystemError:
  463.             e = None
  464.             apt_error = True
  465.         except KeyError:
  466.             self.error_not_available(item)
  467.             return False
  468.  
  469.         for app in to_add:
  470.             if not self.cache[app.pkgname].markedInstall:
  471.                 apt_error = True
  472.                 continue
  473.             item_replaces != removals if self.cache._depcache.DelCount > 0 and self.cache._depcache.BrokenCount == 0 and not apt_error else item_replaces != removals
  474.         
  475.         if apt_error or self.cache._depcache.BrokenCount > 0:
  476.             return self.canNotInstallApp(pkg)
  477.         return True
  478.  
  479.     
  480.     def tryKeep(self, item):
  481.         if hasattr(item, 'replaces'):
  482.             for r in item.replaces:
  483.                 apps = self.menu.pkg_to_app[r]
  484.                 for app in apps:
  485.                     app.toInstall = not (app.toInstall)
  486.                 
  487.             
  488.             self.treeview_packages.queue_draw()
  489.         
  490.         return True
  491.  
  492.     
  493.     def _ensureUnsupportedOrLegalWarning(self, item):
  494.         ''' warn:
  495.             - on potential legal problems (codecs) always
  496.             - when a universe or multiverse package is installed for
  497.               the first time
  498.         '''
  499.         if item.patentBadness == True:
  500.             dia = gtk.MessageDialog(parent = self.window_main, type = gtk.MESSAGE_WARNING, buttons = gtk.BUTTONS_CANCEL)
  501.             header = _('Confirm installation of restricted software')
  502.             body = _('The use of this software may be restricted in some countries. You must verify that one of the following is true:\n\n* These restrictions do not apply in your country of legal residence\n* You have permission to use this software (for example, a patent license)\n* You are using this software for research purposes only')
  503.             dia.set_markup('<big><b>%s</b></big>\n\n%s' % (header, body))
  504.             dia.add_button(_('C_onfirm'), gtk.RESPONSE_OK)
  505.             res = dia.run()
  506.             dia.hide()
  507.             if res != gtk.RESPONSE_OK:
  508.                 return False
  509.             return True
  510.         return True
  511.  
  512.     
  513.     def _confirm_source_activation(self, item, need_internet = True):
  514.         '''
  515.         Ask the user if a specified componet of the distribution 
  516.         should be enabled
  517.         '''
  518.         primary = ''
  519.         secondary = ''
  520.         dia = gtk.MessageDialog(parent = self.window_main, type = gtk.MESSAGE_QUESTION, buttons = gtk.BUTTONS_CANCEL)
  521.         messages = self.distro.get_components_ask_msgs()
  522.         if item.component:
  523.             if messages.has_key(item.component):
  524.                 (primary, secondary) = messages[item.component]
  525.             else:
  526.                 (primary, secondary) = messages[None]
  527.                 primary = primary % item.component
  528.         elif item.channel:
  529.             if item.isv:
  530.                 vendor = item.isv
  531.             else:
  532.                 vendor = item.channel
  533.             primary = _('Enable the installation of software from %s?') % vendor
  534.             secondary = _('%s is provided by a third party vendor. The third party vendor is responsible for support and security updates.')
  535.         
  536.         if need_internet:
  537.             secondary += '\n\n%s' % _('You need a working internet connection to continue.')
  538.         
  539.         dia.set_markup('<b><big>%s</big></b>' % primary)
  540.         dia.format_secondary_markup(secondary % item.name)
  541.         dia.add_button(_('_Enable'), gtk.RESPONSE_OK)
  542.         ret = dia.run()
  543.         dia.hide()
  544.         if ret == gtk.RESPONSE_OK:
  545.             return True
  546.         return False
  547.  
  548.     
  549.     def on_install_toggle(self, widget, item):
  550.         self.setBusy(True)
  551.         pkg = item.pkgname
  552.         want_install = not (item.toInstall)
  553.         if self.cache.has_key(pkg):
  554.             pass
  555.         is_installed = self.cache[pkg].isInstalled
  556.         if want_install:
  557.             pass
  558.         install = not is_installed
  559.         if not want_install:
  560.             pass
  561.         remove = is_installed
  562.         if (want_install or is_installed) and not want_install:
  563.             pass
  564.         keep = not is_installed
  565.         if not install ^ remove ^ keep:
  566.             raise AssertionError
  567.         if install and not self.tryInstall(item):
  568.             self.setBusy(False)
  569.             return False
  570.         if remove and not self.tryRemove(item):
  571.             self.setBusy(False)
  572.             return False
  573.         if keep and not self.tryKeep(item):
  574.             self.setBusy(False)
  575.             return False
  576.         status = item.toInstall
  577.         self.button_ok.set_sensitive(self.menu.isChanged())
  578.         self.setBusy(False)
  579.  
  580.     
  581.     def addChannel(self, item):
  582.         '''Ask for confirmation to add the missing channel or
  583.            component of the current selected application'''
  584.         if item.thirdparty and item.channel:
  585.             dia = DialogProprietary(self.datadir, self.window_main, item)
  586.             res = dia.run()
  587.             dia.hide()
  588.             if res != gtk.RESPONSE_OK:
  589.                 return False
  590.         elif not self._confirm_source_activation(item):
  591.             return False
  592.         if item.component:
  593.             if item.component in self.distro.get_components_ask():
  594.                 self.components_seen.append(item.component)
  595.                 self.config.set_list('/apps/gnome-app-install/components_seen', 'string', self.components_seen)
  596.             
  597.             if not self.enableComponent(item.component):
  598.                 return False
  599.             for dep in self.distro.get_comp_dependencies(item.component):
  600.                 for it in self.cache._cache.FileList:
  601.                     if it.Component != '' and it.Component == dep:
  602.                         break
  603.                         continue
  604.                     self.enableComponent(item.component)
  605.                 elif not self.enableComponent(dep):
  606.                     return False
  607.             
  608.         elif item.channel:
  609.             if not self.enableChannel(item.channel):
  610.                 return False
  611.         else:
  612.             print 'ERROR: addChannel() called without channel or component'
  613.             return False
  614.         self.enableChannel(item.channel).reloadSources()
  615.         return True
  616.  
  617.     
  618.     def setupTreeview(self):
  619.         
  620.         def _icon_cell_func(column, cell, model, iter):
  621.             menuitem = model.get_value(iter, COL_ITEM)
  622.             if menuitem == None or menuitem.iconname == None:
  623.                 cell.set_property('pixbuf', None)
  624.                 cell.set_property('visible', False)
  625.                 return None
  626.             
  627.             try:
  628.                 icon = self.icons.load_icon(menuitem.iconname, 24, 0)
  629.             except gobject.GError:
  630.                 menuitem.iconname == None
  631.                 menuitem.iconname == None
  632.                 
  633.                 try:
  634.                     icon = self.icons.load_icon('applications-other', 24, 0)
  635.                 except gobject.GError:
  636.                     icon = self.icons.load_icon(gtk.STOCK_MISSING_IMAGE, 24, 0)
  637.                 except:
  638.                     None<EXCEPTION MATCH>gobject.GError
  639.                 
  640.  
  641.                 None<EXCEPTION MATCH>gobject.GError
  642.  
  643.             cell.set_property('pixbuf', icon)
  644.             cell.set_property('visible', True)
  645.  
  646.         column_cat = gtk.TreeViewColumn('')
  647.         renderer_cat_icon = gtk.CellRendererPixbuf()
  648.         column_cat.pack_start(renderer_cat_icon, False)
  649.         column_cat.set_cell_data_func(renderer_cat_icon, _icon_cell_func)
  650.         renderer_cat_name = gtk.CellRendererText()
  651.         renderer_cat_name.set_property('scale', 1)
  652.         column_cat.pack_start(renderer_cat_name, True)
  653.         column_cat.add_attribute(renderer_cat_name, 'markup', COL_CAT_NAME)
  654.         self.treeview_categories.append_column(column_cat)
  655.         self.treeview_categories.set_search_column(COL_CAT_NAME)
  656.  
  657.     
  658.     def saveState(self):
  659.         ''' save the current state of the app '''
  660.         (self.to_add, self.to_rm) = self.menu.getChanges()
  661.         (self.cursor_categories_path, x) = self.treeview_categories.get_cursor()
  662.         model = self.treeview_packages.get_model()
  663.         (packages_path, x) = self.treeview_packages.get_cursor()
  664.         if packages_path:
  665.             it = model.get_iter(packages_path)
  666.             self.cursor_pkgname = model.get_value(it, COL_NAME)
  667.         else:
  668.             self.cursor_pkgname = None
  669.  
  670.     
  671.     def restoreState(self):
  672.         ''' restore the current state of the app '''
  673.         self.window_main.set_sensitive(False)
  674.         self.treeview_categories.set_cursor(self.cursor_categories_path)
  675.         model = self.treeview_packages.get_model()
  676.         for item in self.to_add:
  677.             if self.cache.has_key(item.pkgname):
  678.                 
  679.                 try:
  680.                     self.cache[item.pkgname].markInstall(autoFix = True)
  681.                 except SystemError:
  682.                     continue
  683.  
  684.                 apps = self.menu.pkg_to_app[item.pkgname]
  685.                 for app in apps:
  686.                     app.toInstall = item.toInstall
  687.                 
  688.         
  689.         for item in self.to_rm:
  690.             if self.cache.has_key(item.pkgname):
  691.                 
  692.                 try:
  693.                     self.cache[item.pkgname].markDelete(autoFix = True)
  694.                 except SystemError:
  695.                     continue
  696.  
  697.                 apps = self.menu.pkg_to_app[item.pkgname]
  698.                 for app in apps:
  699.                     app.toInstall = item.toInstall
  700.                 
  701.         
  702.         search_term = self.search_entry.get_text()
  703.         if len(search_term) > 0:
  704.             self._perform_search(None, search_term)
  705.         
  706.         for it in iterate_list_store(model, model.get_iter_first()):
  707.             name = model.get_value(it, COL_NAME)
  708.             if name == self.cursor_pkgname:
  709.                 path = model.get_path(it)
  710.                 self.treeview_packages.set_cursor(path)
  711.                 break
  712.                 continue
  713.         
  714.         self.window_main.set_sensitive(True)
  715.         self.treeview_packages.queue_draw()
  716.  
  717.     
  718.     def updateCache(self, filter = SHOW_ONLY_SUPPORTED):
  719.         self.window_main.set_sensitive(False)
  720.         self.setBusy(True)
  721.         self.window_main.realize()
  722.         progress_transient_for = self.window_main
  723.         if self.transient_for is not None:
  724.             progress_transient_for = self.transient_for
  725.         
  726.         progress = GtkOpProgressWindow(self.glade, progress_transient_for)
  727.         
  728.         try:
  729.             if not hasattr(self, 'cache'):
  730.                 self.cache = MyCache(progress)
  731.             else:
  732.                 self.cache.open(progress)
  733.         except Exception:
  734.             e = None
  735.             header = _('Failed to check for installed and available applications')
  736.             msg = _("This is a major failure of your software management system. Please check for broken packages with synaptic, check the file permissions and correctness of the file '/etc/apt/sources.list' and reload the software information with: 'sudo apt-get update' and 'sudo apt-get install -f'.")
  737.             print e
  738.             d = gtk.MessageDialog(parent = self.window_main, flags = gtk.DIALOG_MODAL, type = gtk.MESSAGE_ERROR, buttons = gtk.BUTTONS_CLOSE)
  739.             d.set_title('')
  740.             d.set_markup('<big><b>%s</b></big>\n\n%s' % (header, msg))
  741.             d.realize()
  742.             d.window.set_functions(gtk.gdk.FUNC_MOVE)
  743.             d.run()
  744.             d.destroy()
  745.             sys.exit(1)
  746.  
  747.         if not hasattr(self, 'menu'):
  748.             progress.update(0.5)
  749.             self.menu = ApplicationMenu(self.desktopdir, self.cachedir, self.cache, self.treeview_packages, progress, filter, activation_style = self.activation_style)
  750.         else:
  751.             self.menu.refreshAfterCacheChange(progress)
  752.         self.treeview_categories.set_model(self.menu.get_categories_store())
  753.         adj = self.scrolled_window.get_vadjustment()
  754.         adj.set_value(0)
  755.         self.setBusy(False)
  756.         self.button_ok.set_sensitive(False)
  757.         self.window_main.set_sensitive(True)
  758.  
  759.     
  760.     def ignoreChanges(self):
  761.         '''
  762.         If any changes have been made, ask the user to apply them and return
  763.         a value based on the status.
  764.         Returns True if the changes should be thrown away and False otherwise
  765.         '''
  766.         if not self.menu.isChanged():
  767.             return True
  768.         (to_add, to_rm) = self.menu.getChanges()
  769.         dia = DialogPendingChanges(self.datadir, self.window_main, to_add, to_rm)
  770.         header = _('Apply changes to installed applications before closing?')
  771.         msg = _('If you do not apply your changes they will be lost permanently.')
  772.         dia.label_pending.set_markup('<big><b>%s</b></big>\n\n%s' % (header, msg))
  773.         dia.button_ignore_changes.set_label(_('_Close Without Applying'))
  774.         dia.button_ignore_changes.show()
  775.         dia.dialog_pending_changes.realize()
  776.         dia.dialog_pending_changes.window.set_functions(gtk.gdk.FUNC_MOVE)
  777.         res = dia.run()
  778.         dia.hide()
  779.         return res
  780.  
  781.     
  782.     def on_button_help_clicked(self, widget):
  783.         if os.path.exists('/usr/bin/yelp'):
  784.             subprocess.Popen([
  785.                 '/usr/bin/yelp',
  786.                 'ghelp:gnome-app-install'])
  787.         else:
  788.             d = gtk.MessageDialog(parent = self.window_main, flags = gtk.DIALOG_MODAL, type = gtk.MESSAGE_ERROR, buttons = gtk.BUTTONS_CLOSE)
  789.             header = _('No help available')
  790.             msg = _('To display the help, you need to install the "yelp" application.')
  791.             d.set_title('')
  792.             d.set_markup('<big><b>%s</b></big>\n\n%s' % (header, msg))
  793.             d.run()
  794.             d.destroy()
  795.  
  796.     
  797.     def applyChanges(self, to_add, to_rm):
  798.         '''
  799.         Install and remove the packages of the given applications and
  800.         show a status dialog afterwards
  801.         '''
  802.         self.setBusy(True)
  803.         pkgs_add = []([ item.pkgname for item in to_add ])
  804.         pkgs_rm = []([ item.pkgname for item in to_rm ])
  805.         ret = self.packageWorker.perform_action(self.window_main, self.cache, pkgs_add, pkgs_rm)
  806.         self.updateCache(filter = self.menu.filter)
  807.         dia = DialogComplete(self.datadir, self.window_main, to_add, to_rm, self.cache, self.activation_style.autoClose())
  808.         response = dia.run()
  809.         self.setBusy(False)
  810.         self.activation_style.changesSuccessfulNotify()
  811.         if response == gtk.RESPONSE_CLOSE:
  812.             self.quit()
  813.         elif response == 1:
  814.             self.applyChanges(to_add, to_rm)
  815.         
  816.         self.refilter()
  817.  
  818.     
  819.     def on_button_ok_clicked(self, button):
  820.         (to_add, to_rm) = self.menu.getChanges()
  821.         if self.activation_style.isInstallerOnly or self.confirmChanges(to_add, to_rm):
  822.             self.activation_style.userApprovedNotify()
  823.             self.applyChanges(to_add, to_rm)
  824.         
  825.  
  826.     
  827.     def confirmChanges(self, to_add, to_rm):
  828.         '''
  829.         Show a dialog that asks the user to confirm the given changes
  830.         '''
  831.         dia = DialogPendingChanges(self.datadir, self.window_main, to_add, to_rm)
  832.         header = _('Apply the following changes?')
  833.         msg = _('Please take a final look through the list of applications that will be installed or removed.')
  834.         dia.label_pending.set_markup('<big><b>%s</b></big>\n\n%s' % (header, msg))
  835.         res = dia.run()
  836.         dia.hide()
  837.         if res != gtk.RESPONSE_APPLY:
  838.             return False
  839.         return True
  840.  
  841.     
  842.     def _perform_search(self, widget, query):
  843.         '''
  844.         Filter and sort by rank being based on the entered terms. Otherwise 
  845.         sort by name
  846.         '''
  847.         self.setBusy(True)
  848.         model = self.treeview_packages.get_model()
  849.         if query.lstrip() != '':
  850.             search_terms = query.lower().split(' ')
  851.             self.sort_by_ranking = True
  852.             search_terms = query.lower().split(' ')
  853.             if not model.has_default_sort_func():
  854.                 model.set_default_sort_func(self.menu._ranking_sort_func)
  855.                 model.set_sort_column_id(-1, gtk.SORT_ASCENDING)
  856.             
  857.         else:
  858.             search_terms = []
  859.             self.sort_by_ranking = False
  860.             model.set_sort_column_id(COL_NAME, gtk.SORT_ASCENDING)
  861.             model.set_default_sort_func(self.menu._name_sort_func)
  862.         self.refilter(terms = search_terms)
  863.         self.setBusy(False)
  864.  
  865.     
  866.     def on_reload_activate(self, item):
  867.         self.reloadSources()
  868.  
  869.     
  870.     def on_button_cancel_clicked(self, item):
  871.         self.quit()
  872.  
  873.     
  874.     def reloadSources(self):
  875.         self.window_main.set_sensitive(False)
  876.         self.saveState()
  877.         ret = self.packageWorker.perform_action(self.window_main, None, action = PackageWorker.UPDATE)
  878.         self.updateCache(filter = self.menu.filter)
  879.         self.restoreState()
  880.         self.window_main.set_sensitive(True)
  881.         return ret
  882.  
  883.     
  884.     def enableChannel(self, channel):
  885.         ''' enables a channel with 3rd party software '''
  886.         channelpath = '%s/%s.list' % (self.channelsdir, channel)
  887.         channelkey = '%s/%s.key' % (self.channelsdir, channel)
  888.         if not os.path.exists(channelpath):
  889.             print "WARNING: channel '%s' not found" % channelpath
  890.             return None
  891.         cmd = [
  892.             'gksu',
  893.             '--desktop',
  894.             '/usr/share/applications/gnome-app-install.desktop',
  895.             '--',
  896.             'install',
  897.             '--mode=644',
  898.             '--owner=0',
  899.             channelpath,
  900.             apt_pkg.Config.FindDir('Dir::Etc::sourceparts')]
  901.         subprocess.call(cmd)
  902.         if os.path.exists(channelkey):
  903.             cmd = [
  904.                 'gksu',
  905.                 '--desktop',
  906.                 '/usr/share/applications/gnome-app-install.desktop',
  907.                 '--',
  908.                 'apt-key',
  909.                 'add',
  910.                 channelkey]
  911.             subprocess.call(cmd)
  912.         
  913.         return True
  914.  
  915.     
  916.     def enableComponent(self, component):
  917.         ''' Enables a component of the current distribution
  918.             (in a seperate file in /etc/apt/sources.list.d/$dist-$comp)
  919.         '''
  920.         if component == '':
  921.             print 'no repo found in enableRepository'
  922.             return None
  923.         cmd = [
  924.             'gksu',
  925.             '--desktop',
  926.             '/usr/share/applications/gnome-app-install.desktop',
  927.             '--',
  928.             'gnome-app-install-helper',
  929.             '-e',
  930.             component]
  931.         
  932.         try:
  933.             output = subprocess.Popen(cmd, stdout = subprocess.PIPE).communicate()[0]
  934.         except OSError:
  935.             component == ''
  936.             e = component == ''
  937.             print >>sys.stderr, 'Execution failed:', e
  938.         except:
  939.             component == ''
  940.  
  941.         if output == 'Enabled the %s component\n' % component:
  942.             return True
  943.         return False
  944.  
  945.     
  946.     def on_window_main_delete_event(self, window, event):
  947.         if window.get_property('sensitive') == False:
  948.             return True
  949.         if self.menu.isChanged():
  950.             ret = self.ignoreChanges()
  951.             if ret == gtk.RESPONSE_APPLY:
  952.                 (to_add, to_rm) = self.menu.getChanges()
  953.                 if not self.applyChanges(to_add, to_rm):
  954.                     return True
  955.             elif ret == gtk.RESPONSE_CANCEL:
  956.                 return True
  957.             window.get_property('sensitive') == False
  958.             if ret == gtk.RESPONSE_CLOSE:
  959.                 self.quit()
  960.             
  961.         
  962.         self.quit()
  963.  
  964.     
  965.     def on_window_main_destroy_event(self, data = None):
  966.         self.quit()
  967.  
  968.     
  969.     def quit(self):
  970.         '''
  971.         Stores the state of the main window and quits the application
  972.         '''
  973.         if not self.activation_style.isSpecific():
  974.             maximized = self.window_main.window.get_state() == gtk.gdk.WINDOW_STATE_MAXIMIZED
  975.             self.config.set_bool('/apps/gnome-app-install/state/window_maximized', maximized)
  976.             if not maximized:
  977.                 (width, height) = self.window_main.get_size()
  978.                 self.config.set_int('/apps/gnome-app-install/state/window_height', height)
  979.                 self.config.set_int('/apps/gnome-app-install/state/window_width', width)
  980.             
  981.         
  982.         self.activation_style.quitHook()
  983.         sys.exit(0)
  984.  
  985.     
  986.     def on_treeview_packages_row_activated(self, treeview, path, view_column):
  987.         iter = treeview.get_model().get_iter(path)
  988.         item = treeview.get_model().get_value(iter, COL_ITEM)
  989.         if item.architectures and self.cache.getArch() not in item.architectures:
  990.             return False
  991.         self.on_install_toggle(None, item)
  992.  
  993.     
  994.     def on_treeview_categories_cursor_changed(self, treeview):
  995.         '''
  996.         Show the applications that belong to the selected category and
  997.         restore the previos sorting
  998.         '''
  999.         path = treeview.get_cursor()[0]
  1000.         iter = treeview.get_model().get_iter(path)
  1001.         (name, item) = treeview.get_model()[iter]
  1002.         if path == (0,):
  1003.             self.setBusy(True)
  1004.         
  1005.         old_model = self.treeview_packages.get_model()
  1006.         (sort_column, sort_type) = old_model.get_sort_column_id()
  1007.         if self.sort_by_ranking:
  1008.             if sort_column == None:
  1009.                 sort_column = -1
  1010.                 sort_type = gtk.SORT_ASCENDING
  1011.             
  1012.             item.applications.set_default_sort_func(self.menu._ranking_sort_func)
  1013.         elif item.applications.has_default_sort_func():
  1014.             if sort_column == None:
  1015.                 sort_column = COL_NAME
  1016.                 sort_type = gtk.SORT_ASCENDING
  1017.             
  1018.             if path != (0,):
  1019.                 item.applications.set_default_sort_func(self.menu._name_sort_func)
  1020.             else:
  1021.                 item.applications.set_default_sort_func(None)
  1022.         else:
  1023.             sort_column = -1
  1024.             sort_type = gtk.SORT_ASCENDING
  1025.         item.applications.set_sort_column_id(sort_column, sort_type)
  1026.         item.applications.set_sort_column_id(-1, sort_type)
  1027.         self.refilter(model = item.applications)
  1028.         self.setBusy(False)
  1029.  
  1030.     
  1031.     def on_treeview_packages_cursor_changed(self, treeview):
  1032.         path = treeview.get_cursor()[0]
  1033.         iter = treeview.get_model().get_iter(path)
  1034.         (name, item, popcon) = treeview.get_model()[iter]
  1035.         self.textview_description.show_description(item)
  1036.  
  1037.     
  1038.     def show_no_results_msg(self):
  1039.         ''' Give the user some hints if the search returned 
  1040.             no results'''
  1041.         buffer = self.textview_description.get_buffer()
  1042.         buffer.set_text('')
  1043.         tag_table = buffer.get_tag_table()
  1044.         tag_table.foreach((lambda tag, table: table.remove(tag)), tag_table)
  1045.         tag_header = buffer.create_tag('first-line', weight = pango.WEIGHT_BOLD, pixels_above_lines = 6)
  1046.         msg = _('There is no matching application available.')
  1047.         iter = buffer.get_start_iter()
  1048.         buffer.insert_with_tags_by_name(iter, msg, 'first-line')
  1049.         if self.combobox_filter.get_property('visible') == True:
  1050.             if self.menu.filter == SHOW_ONLY_INSTALLED or self.menu.filter in self.distro.filters_secondary.keys():
  1051.                 if len(self.distro.filters_primary) == 1:
  1052.                     msg = _('To broaden your search, choose "%s".') % self.distro.filters_primary[self.distro.filters_primary.keys()[0]][0]
  1053.                 elif len(self.distro.filters_primary) == 2:
  1054.                     msg = _('To broaden your search, choose "%s" or "%s".') % (self.distro.filters_primary[self.distro.filters_primary.keys()[0]][0], self.distro.filters_primary[self.distro.filters_primary.keys()[1]][0])
  1055.                 else:
  1056.                     msg = _('To broaden your search, choose a different "Show" item.')
  1057.                 buffer.insert_with_tags(iter, '\n%s' % msg)
  1058.             
  1059.         
  1060.         if self.treeview_categories.get_property('visible') == True and self.treeview_categories.get_cursor()[0] != (0,):
  1061.             msg = '\n%s' % _("To broaden your search, choose 'All' categories.")
  1062.             buffer.insert_with_tags(iter, msg)
  1063.         
  1064.  
  1065.  
  1066. if __name__ == '__main__':
  1067.     app = AppInstall(os.path.abspath('menu-data'), os.path.abspath('data'), sys.argv)
  1068.     gtk.main()
  1069.  
  1070.