Home | History | Annotate | Download | only in ipsgui
      1 #!/usr/bin/env python
      2 
      3 CDDL = '''
      4 CDDL HEADER START
      5 
      6 The contents of this file are subject to the terms of the
      7 Common Development and Distribution License (the "License").
      8 You may not use this file except in compliance with the License.
      9 
     10 You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     11 or http://www.opensolaris.org/os/licensing.
     12 See the License for the specific language governing permissions
     13 and limitations under the License.
     14 
     15 When distributing Covered Code, include this CDDL HEADER in each
     16 file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     17 If applicable, add the following below this CDDL HEADER, with the
     18 fields enclosed by brackets "[]" replaced with your own identifying
     19 information: Portions Copyright [yyyy] [name of copyright owner]
     20 
     21 CDDL HEADER END
     22 '''
     23 
     24 #
     25 # Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     26 # Use is subject to license terms.
     27 #
     28 # ident	"%Z%%M%	%I%	%E% SMI"
     29 #
     30 
     31 # -*- coding: utf-8 -*-
     32 
     33 ### Import section START
     34    #--------------------------------------------------------------------------
     35 
     36 #Imports standard libraries
     37 import getopt
     38 import os
     39 import sys
     40 import time
     41 import pango
     42 import locale
     43 import gettext
     44 from threading import Thread
     45 
     46 #Imports modules from PyGTK
     47 try:
     48    import pygtk
     49    pygtk.require("2.0")
     50 except:
     51    pass
     52 try:
     53    import gobject
     54    gobject.threads_init()
     55    import gtk
     56    import gtk.glade
     57 except:
     58    sys.exit(1)
     59 
     60 #Imports modules from IPS
     61 import pkg.catalog as catalog
     62 import pkg.client.image as image
     63 import pkg.client.progress as progress
     64 
     65 import pkg.client.filelist as filelist
     66 
     67 #Imports local modules
     68 import pkg.gui.imageinfo as imageinfo
     69 import pkg.gui.installupdate as installupdate
     70 import pkg.gui.remove as remove
     71 #import pkg.gui.packagemanagerconfig as packagemanagerconfig
     72 import pkg.gui.enumerations as enumerations
     73 import pkg.gui.userrights as userrights
     74 
     75    #--------------------------------------------------------------------------
     76 ### Import section END
     77 
     78    #--------------------------------------------------------------------------
     79 ### Init threads section END
     80 
     81 class PackageManager:
     82    #--------------------------------------------------------------------------
     83    def __init__(self):
     84       pass
     85 
     86    #--------------------------------------------------------------------------
     87    def N_(self, message): return message
     88 
     89    #--------------------------------------------------------------------------
     90    def run_gui(self):
     91       '''This method prepares all widgets and runs empty GUI'''
     92       try:
     93          self.application_dir = os.environ["PACKAGE_MANAGER_ROOT"]
     94       except KeyError:
     95          self.application_dir = "/"
     96       locale.setlocale(locale.LC_ALL, '')
     97       for module in (gettext, gtk.glade):
     98          module.bindtextdomain("packagemanager",self.application_dir+"/usr/share/locale")
     99          module.textdomain("packagemanager")
    100       self._ = gettext.gettext
    101 #      self.pkgconfig = packagemanagerconfig.PackageManagerConfig() #Config
    102 #      self.pkgconfig.set_config_file_path(os.path.expanduser("~")+"/.packagemanager/config")  #Config path 
    103       main_window_title = self._('Package Manager - revision 0.1')
    104       rights = userrights.UserRights()
    105       self.user_rights = rights.check_administrative_rights()
    106       self.canceled = False                   # For background processes
    107       self.preparing_list = True              #
    108       self.description_thread_running = False # For background processes
    109 #      self.pkginfo_canceled = False           # For background processes
    110 #      self.pkginfo_thread_running = False     # For background processes
    111       self.pkginfo_thread = None              # For background processes
    112       gtk.rc_parse('~/.gtkrc-1.2-gnome2')     # Load gtk theme
    113       self.gladefile = self.application_dir + \
    114                        "/usr/share/package-manager/packagemanager.glade"
    115       self.wTree = gtk.glade.XML(self.gladefile, "mainwindow")
    116       self.application_list = None            #List for applications/main view
    117       self.category_list = None               #List for categories
    118       self.section_list = None                #List for sections
    119       self.clipboard_text = None
    120       self.create_models_lists()              #Creates gtk.ListStore for models
    121       self.pr = progress.NullProgressTracker()
    122       try:
    123          dic = self.declare_signals()
    124          self.wTree.signal_autoconnect(dic)
    125       except AttributeError, error:
    126          print self._('GUI will not respond to any event! %s.Check declare_signals()')\
    127                 % error
    128       self.create_available_widgets()         #Get widgets from glade file
    129       self.update_reload_button()
    130 
    131       self.clipboard.request_text(self.clipboard_text_received)
    132       self.mainwindow.set_title(main_window_title)
    133       self.init_tree_views()                 #Connects treeviews with models
    134       self.init_sections()                   #Initiates sections
    135       self.init_show_filter()                #Initiates filter sections
    136       self.mainwindow.show_all()
    137       #TODO: Uncomment for testing dialog:
    138       #self.installupdate.run()
    139       #self.downloadpreferences.run()
    140       #Switch to active in new thread.
    141       #Thread(target=self.switch_to_active_valid_image, args=()).start()
    142 
    143    #--------------------------------------------------------------------------
    144    def create_available_widgets(self):
    145       '''Create available widgets'''
    146       #Widnows
    147       self.mainwindow = self.wTree.get_widget("mainwindow")
    148       self.downloadingfiles = self.wTree.get_widget("downloadingfiles")
    149       self.applyingchanges = self.wTree.get_widget("applyingchanges")
    150       self.downloadpreferences1 = self.wTree.get_widget("downloadpreferences1")
    151       self.downloadingpackageinformation = \
    152                      self.wTree.get_widget("downloadingpackageinformation")
    153       self.managerepositories = self.wTree.get_widget("managerepositories")
    154 
    155       #Treeviews
    156       self.applicationtreeview = self.wTree.get_widget("applicationtreeview")
    157       self.categoriestreeview = self.wTree.get_widget("categoriestreeview")
    158 
    159       #Textviews
    160       self.generalinfotextview = self.wTree.get_widget("generalinfotextview")
    161       self.installedfilestextview = self.wTree.get_widget("installedfilestextview")
    162       self.dependenciestextview = self.wTree.get_widget("dependenciestextview")
    163 
    164       #Labels
    165       self.packagenamelabel = self.wTree.get_widget("packagenamelabel")
    166       self.shortdescriptionlabel = \
    167                                  self.wTree.get_widget("shortdescriptionlabel")
    168       #Search dialog
    169       self.searchentrydialog = self.wTree.get_widget("searchentry")
    170 
    171       #Buttons
    172       self.install_update_button = self.wTree.get_widget("install_update_button")
    173       self.remove_button = self.wTree.get_widget("remove_button")
    174       self.update_all_button = self.wTree.get_widget("update_all_button")
    175       self.reload_button = self.wTree.get_widget("reloadbutton")
    176 
    177       #Other
    178       self.repositorycombobox = self.wTree.get_widget("repositorycombobox")
    179       self.sectionscombobox = self.wTree.get_widget("sectionscombobox")
    180       self.filtercombobox = self.wTree.get_widget("filtercombobox")
    181       self.packageimage = self.wTree.get_widget("packageimage")
    182       self.statusbar = self.wTree.get_widget("statusbar")
    183 
    184       #Menu
    185       self.install_update_menu = self.wTree.get_widget("package_install_update")
    186       self.remove_menu = self.wTree.get_widget("package_remove")
    187       self.update_all_menu = self.wTree.get_widget("package_update_all")
    188       self.cut_menu = self.wTree.get_widget("edit_cut")
    189       self.copy_menu = self.wTree.get_widget("edit_copy")
    190       self.paste_menu = self.wTree.get_widget("edit_paste")
    191       self.clear_menu = self.wTree.get_widget("edit_clear")
    192       self.select_all_menu = self.wTree.get_widget("edit_select_all")
    193       self.select_updates_menu = self.wTree.get_widget("edit_select_updates")
    194       self.deselect_menu = self.wTree.get_widget("edit_deselect")
    195 
    196       #Clipboard
    197       self.clipboard = gtk.clipboard_get(gtk.gdk.SELECTION_CLIPBOARD)      
    198 
    199    #--------------------------------------------------------------------------
    200    def clipboard_text_received(self, clipboard, text, data):
    201       self.clipboard_text = text
    202       return
    203    #--------------------------------------------------------------------------
    204    def init_tree_views(self):
    205       '''This function connects treeviews with their models and also applies
    206          filters'''
    207       #TODO:1 Do we need to clear treeviews before appending columns?
    208       #TODO:2 Do we need to have hidden columns with not shown information
    209       #TODO:2 like objects, other lists or we can get those information from
    210       #TODO:2 lists rather than models???
    211       #TODO:3 Make sure that not only name is sortable, other columns should be
    212       #TODO:3 as well. Please refer to wireframes
    213       #TODO:4 check if there should be some padding between columns or the names
    214       #TODO:4 should have " name " instead of "name"
    215       #TODO:5 compare with ipsgui what should be added, like row activated??
    216       ##APPLICATION MAIN TREEVIEW
    217       self.application_list_filter = self.application_list.filter_new()
    218       self.application_list_filter.set_visible_func(self.application_filter)
    219       self.application_list_sort = \
    220                               gtk.TreeModelSort(self.application_list_filter)
    221       self.applicationtreeview.set_model(self.application_list_sort)
    222       #enumerations.MARK_COLUMN
    223       model = self.applicationtreeview.get_model()
    224       toggle_renderer = gtk.CellRendererToggle()
    225       toggle_renderer.connect('toggled', self.active_pane_toggle, model)
    226       column = gtk.TreeViewColumn("", toggle_renderer, active=enumerations.MARK_COLUMN)
    227       column.set_sort_column_id(enumerations.MARK_COLUMN)
    228       column.set_sort_indicator(True)
    229       column.set_cell_data_func(toggle_renderer, self.cell_data_function, None)
    230       self.applicationtreeview.append_column(column)
    231       #enumerations.STATUS_ICON_COLUMN
    232       column = gtk.TreeViewColumn()
    233       column.set_title("")
    234       #Commented, since there was funny jumping of the icons
    235       #column.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
    236       render_pixbuf = gtk.CellRendererPixbuf()
    237       column.pack_start(render_pixbuf, expand=False)
    238       column.add_attribute(render_pixbuf, "pixbuf", enumerations.STATUS_ICON_COLUMN)
    239       column.set_fixed_width(32)
    240       column.set_cell_data_func(render_pixbuf, self.cell_data_function, None)
    241       self.applicationtreeview.append_column(column)
    242       #enumerations.ICON_COLUMN
    243       column = gtk.TreeViewColumn()
    244       column.set_title("")
    245       #Commented, since there was funny jumping of the icons
    246       #column.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
    247       render_pixbuf = gtk.CellRendererPixbuf()
    248       column.pack_start(render_pixbuf, expand=False)
    249       column.add_attribute(render_pixbuf, "pixbuf", enumerations.ICON_COLUMN)
    250       column.set_fixed_width(32)
    251       column.set_cell_data_func(render_pixbuf, self.cell_data_function, None)
    252       self.applicationtreeview.append_column(column)
    253       #enumerations.NAME_COLUMN
    254       name_renderer = gtk.CellRendererText()
    255       column = gtk.TreeViewColumn(self._("Name"), name_renderer, \
    256                                               text=enumerations.NAME_COLUMN)
    257       column.set_sort_column_id(enumerations.NAME_COLUMN)
    258       column.set_sort_indicator(True)
    259       column.set_cell_data_func(name_renderer, self.cell_data_function, None)
    260       self.applicationtreeview.append_column(column)
    261       #enumerations.INSTALLED_VERSION_COLUMN
    262       installed_version_renderer = gtk.CellRendererText()
    263       column = gtk.TreeViewColumn(self._('Installed Version'), \
    264                      installed_version_renderer, text=enumerations.INSTALLED_VERSION_COLUMN)
    265       column.set_cell_data_func(installed_version_renderer, self.cell_data_function, None)
    266       self.applicationtreeview.append_column(column)
    267       #enumerations.LATEST_AVAILABLE_COLUMN
    268       latest_available_renderer = gtk.CellRendererText()
    269       column = gtk.TreeViewColumn(self._('Latest Version'), \
    270                        latest_available_renderer, text=enumerations.LATEST_AVAILABLE_COLUMN)
    271       column.set_cell_data_func(latest_available_renderer, self.cell_data_function, None)
    272       self.applicationtreeview.append_column(column)
    273       #enumerations.RATING_COLUMN
    274       rating_renderer = gtk.CellRendererText()
    275       column = gtk.TreeViewColumn(self._('Rating'), rating_renderer, text=enumerations.RATING_COLUMN)
    276       column.set_cell_data_func(rating_renderer, self.cell_data_function, None)
    277       #TODO: Rating column hidden
    278       #self.applicationtreeview.append_column(column)
    279       #enumerations.DESCRIPTION_COLUMN
    280       description_renderer = gtk.CellRendererText()
    281       column = gtk.TreeViewColumn(self._('Description'), description_renderer, \
    282                                                        text=enumerations.DESCRIPTION_COLUMN)
    283       column.set_cell_data_func(description_renderer, self.cell_data_function, None)
    284       self.applicationtreeview.append_column(column)
    285 
    286       #Added selection listener
    287       self.package_selection = self.applicationtreeview.get_selection()
    288       self.package_selection.set_mode(gtk.SELECTION_SINGLE)
    289       self.package_selection.connect("changed", self.on_package_selection_changed,
    290                                       None)
    291 
    292       ##CATEGORIES TREEVIEW
    293       #enumerations.CATEGORY_NAME
    294 
    295       self.category_list_filter = self.category_list.filter_new()
    296       self.category_list_filter.set_visible_func(self.category_filter)#,
    297                                                     #self.category_list)
    298       self.categoriestreeview.set_model(self.category_list_filter)
    299       enumerations.CATEGORY_NAME_renderer = gtk.CellRendererText()
    300       column = gtk.TreeViewColumn(self._('Name'), enumerations.CATEGORY_NAME_renderer, \
    301                                               text=enumerations.CATEGORY_NAME)
    302       self.categoriestreeview.append_column(column)
    303 
    304       #Added selection listener
    305       self.category_selection = self.categoriestreeview.get_selection()
    306       self.category_selection.set_mode(gtk.SELECTION_SINGLE)
    307       self.category_selection.connect("changed", self.on_category_selection_changed,
    308                                       None)
    309 
    310       ##SECTION COMBOBOX
    311       #enumerations.SECTION_NAME
    312       self.sectionscombobox.set_model(self.section_list)
    313       cell = gtk.CellRendererText()
    314       self.sectionscombobox.pack_start(cell, True)
    315       self.sectionscombobox.add_attribute(cell, 'text', enumerations.SECTION_NAME)
    316       self.sectionscombobox.set_row_separator_func(self.combobox_separator)
    317 
    318       ##FILTER COMBOBOX
    319       #enumerations.FILTER_NAME
    320       self.filtercombobox.set_model(self.filter_list)
    321       cell = gtk.CellRendererText()
    322       self.filtercombobox.pack_start(cell, True)
    323       self.filtercombobox.add_attribute(cell, 'text', enumerations.FILTER_NAME)
    324       self.filtercombobox.set_row_separator_func(self.combobox_separator)
    325 
    326       ##FILTER COMBOBOX
    327       #enumerations.FILTER_NAME
    328       self.repositorycombobox.set_model(self.repositories_list)
    329       cell = gtk.CellRendererText()
    330       self.repositorycombobox.pack_start(cell, True)
    331       self.repositorycombobox.add_attribute(cell, 'text', enumerations.REPOSITORY_NAME)
    332       self.repositorycombobox.set_row_separator_func(self.combobox_separator)
    333 
    334 
    335    #--------------------------------------------------------------------------
    336    def on_mainwindow_delete_event(self,widget, event):
    337       ''' handler for delete event of the main window '''
    338       if self.check_if_something_was_changed() == True:
    339          #TODO: Change this to not quit and show dialog
    340          #TODO: if some changes were applied:
    341          self.main_application_quit()
    342          return True
    343       else:
    344          self.main_application_quit()
    345    #--------------------------------------------------------------------------
    346    def download_pref_close_clicked(self,widget):
    347       self.downloadpreferences.destroy()
    348    #--------------------------------------------------------------------------
    349    def on_file_quit_activate(self,widget):
    350       ''' handler for quit menu event '''
    351       self.on_mainwindow_delete_event(None,None)
    352 
    353    def downloadpreferences_delete_event(self,widget,event):
    354       self.downloadpreferences.destroy()
    355 
    356    #--------------------------------------------------------------------------
    357    def on_settings_download_preferences_activate(self,widget):
    358       ''' handler for quit menu event '''
    359       wTree = gtk.glade.XML(self.gladefile, "downloadpreferences")
    360       self.downloadpreferences = wTree.get_widget("downloadpreferences")
    361       self.arch = wTree.get_widget("arch_1")
    362       self.debug = wTree.get_widget("debug_1")
    363       self.arch_2 = wTree.get_widget("arch_2")
    364       self.debug_2 = wTree.get_widget("debug_2")
    365       self.download_pref_reset_clicked(None)
    366 
    367       dic = {
    368                 #downloadpreferences signals                 
    369                 "download_pref_close_clicked":\
    370                                               self.download_pref_close_clicked,
    371                 "downloadpreferences_delete_event":\
    372                                           self.downloadpreferences_delete_event,
    373                 "download_pref_reset_clicked":\
    374                                           self.download_pref_reset_clicked,
    375             }
    376       wTree.signal_autoconnect(dic)
    377       self.downloadpreferences.run()
    378 
    379    #--------------------------------------------------------------------------
    380    def download_pref_reset_clicked(self,widget):
    381       #TODO: Not for rev 1
    382       return
    383       #config_attribute = self.pkgconfig.get_list_of_config_attributes()
    384       #arch = config_attribute.get('arch')
    385       #debug = config_attribute.get('debug')
    386       #if cmp(arch,"sparc") == 0:
    387       #   self.arch.set_active(True)
    388 
    389       #if cmp(debug,"True") == 0:
    390       #   self.debug.set_active(True)
    391 
    392       #if not arch:
    393       #   self.arch.set_active(True)
    394 
    395       #if not debug:
    396       #   self.debug.set_active(True)
    397       
    398    #--------------------------------------------------------------------------
    399    def main_application_quit(self):
    400       '''quits the main gtk loop'''
    401       self.canceled = True
    402       gtk.main_quit()
    403       sys.exit(0)
    404       return True
    405    #--------------------------------------------------------------------------
    406    def check_if_something_was_changed(self):
    407       ''' Returns True if any of the check boxes for package was changed, false
    408           if not'''
    409       for pkg in self.application_list:
    410          if pkg[enumerations.MARK_COLUMN] == True:
    411             return True
    412       return False
    413    #--------------------------------------------------------------------------
    414    def cell_data_function(self, column, renderer, model, iter, data):
    415       '''Function which sets the background colour to black if package is 
    416          selected'''
    417       if iter:
    418          if model.get_value(iter, enumerations.MARK_COLUMN):
    419             renderer.set_property("cell-background", "#ffe5cc")
    420             renderer.set_property("cell-background-set", True)
    421          else:
    422             renderer.set_property("cell-background-set", False)
    423 
    424    #--------------------------------------------------------------------------
    425    def combobox_separator(self,model,iter):
    426       return model.get_value(iter,enumerations.FILTER_NAME) == "" 
    427    #--------------------------------------------------------------------------
    428    def set_visible_packages_from_category(self,category):
    429       '''Sets all packages as visible from category'''
    430       if not category:
    431          return
    432       pkglist = category[PACKAGE_LIST_OBJECT];
    433       if pkglist:
    434          for pkg in pkglist:
    435             pkg[enumerations.IS_VISIBLE_COLUMN] = True
    436    #--------------------------------------------------------------------------
    437    def init_sections(self):
    438       '''This function is for initializing sections combo box, also adds "All"
    439          Category. It sets active section combobox entry "All"'''
    440       self.section_list.append([self._('All'),])
    441       self.section_list.append(["",])
    442       self.section_list.append([self._('Meta Packages'),])
    443       self.section_list.append([self._('Applications Desktop'),])
    444       self.section_list.append([self._('Applications Web-Based'),])
    445       self.section_list.append([self._('Operating System'),])
    446       self.section_list.append([self._('User Environment'),])
    447       self.section_list.append([self._('Web Infrastructure'),])
    448       self.category_list.append([self._('All'),None,None,True,None])
    449       self.sectionscombobox.set_active(0)
    450    #--------------------------------------------------------------------------
    451    def init_show_filter(self):
    452       self.filter_list.append([self._('All Packages'),])
    453       self.filter_list.append(["",])
    454       self.filter_list.append([self._('Installed Packages'),])
    455       self.filter_list.append([self._('Updates'),])
    456       self.filter_list.append(["",])
    457 #      self.filter_list.append([self._('Locked Packages'),])
    458 #      self.filter_list.append(["",])
    459       self.filter_list.append([self._('Selected Packages'),])
    460       self.filtercombobox.set_active(0)
    461    #--------------------------------------------------------------------------
    462    def setup_repositories_combobox(self,image):
    463       repositories = image.catalogs
    464       default_authority = image.get_default_authority()
    465       self.repositories_list.clear()
    466       i = 0
    467       active = 0
    468       for repo in repositories:
    469          if cmp(repo,default_authority) == 0:
    470             active = i
    471          i = i+1
    472          self.repositories_list.append([repo,])
    473       if default_authority:
    474          self.repositorycombobox.set_active(active)
    475       else:
    476          self.repositorycombobox.set_active(0)
    477    #--------------------------------------------------------------------------
    478    def active_pane_toggle(self, cell, path, model_sort):
    479       '''Toggle function for column enumerations.MARK_COLUMN'''
    480       applicationModel = model_sort.get_model()
    481       applicationPath = model_sort.convert_path_to_child_path(path)
    482       filterModel = applicationModel.get_model()
    483       child_path = applicationModel.convert_path_to_child_path(applicationPath)
    484       iter = filterModel.get_iter(child_path)
    485       if iter:
    486          modified = filterModel.get_value(iter, enumerations.MARK_COLUMN)
    487          filterModel.set_value(iter,enumerations.MARK_COLUMN,not modified)
    488          latest_available = filterModel.get_value(iter, enumerations.LATEST_AVAILABLE_COLUMN)
    489          installed_available = filterModel.get_value(iter, enumerations.INSTALLED_VERSION_COLUMN)
    490          self.update_statusbar()
    491          self.update_install_update_button(latest_available,modified)
    492          self.update_remove_button(installed_available,modified)
    493          self.enable_disable_selection_menus()
    494    #--------------------------------------------------------------------------
    495    def update_install_update_button(self, latest_available, toggle_true):
    496       if not toggle_true and self.user_rights:
    497          if latest_available:
    498             self.install_update_button.set_sensitive(True)
    499             self.install_update_menu.set_sensitive(True)
    500       else:
    501          available = None
    502          for row in self.application_list:
    503             if row[enumerations.MARK_COLUMN]:
    504                available = row[enumerations.LATEST_AVAILABLE_COLUMN]
    505                if available:
    506                   return
    507          if not available:
    508             self.install_update_button.set_sensitive(False)
    509             self.install_update_menu.set_sensitive(False)
    510 
    511    #--------------------------------------------------------------------------
    512    def update_reload_button(self):
    513       if self.user_rights:
    514          self.reload_button.set_sensitive(True)
    515       else:
    516          self.reload_button.set_sensitive(False)
    517 
    518    #--------------------------------------------------------------------------
    519    def update_remove_button(self, installed_available, toggle_true):
    520       if not toggle_true and self.user_rights:
    521          if installed_available:
    522             self.remove_button.set_sensitive(True)
    523             self.remove_menu.set_sensitive(True)
    524       else:
    525          available = None
    526          for row in self.application_list:
    527             if row[enumerations.MARK_COLUMN]:
    528                installed = row[enumerations.INSTALLED_VERSION_COLUMN]
    529                if installed:
    530                   return
    531          if not available:
    532             self.remove_button.set_sensitive(False)
    533             self.remove_menu.set_sensitive(False)
    534 
    535    #--------------------------------------------------------------------------
    536    def update_statusbar(self):
    537       '''Function which updates statusbar'''
    538 
    539       installed = 0
    540       selected = 0
    541       broken = 0
    542       for pkg in self.application_list:
    543          if pkg[enumerations.INSTALLED_VERSION_COLUMN]:
    544             installed = installed + 1
    545          if pkg[enumerations.MARK_COLUMN]:
    546             selected = selected + 1
    547 
    548       listed_str = self._('%d packages listed') % len(self.application_list)
    549       inst_str = self._('%d installed') % installed
    550       sel_str = self._('%d selected') % selected
    551       broken_str = self._('%d broken') % broken
    552 
    553       self.statusbar.push(0,listed_str + ', ' + inst_str + ', ' + sel_str +\
    554                          ', ' + broken_str + '.')
    555 
    556    #--------------------------------------------------------------------------
    557    def update_package_list(self):
    558       for row in self.application_list:
    559          if row[enumerations.MARK_COLUMN]:
    560             image =  row[enumerations.IMAGE_OBJECT_COLUMN]
    561             pkg = max(row[enumerations.PACKAGE_OBJECT_COLUMN])
    562             package_installed = self.get_installed_version(image,pkg)
    563             version_installed = None
    564             if package_installed:
    565                version_installed = package_installed.version.get_short_version()
    566 
    567             row[enumerations.MARK_COLUMN] = False
    568             row[enumerations.STATUS_ICON_COLUMN] = None
    569             row[enumerations.INSTALLED_VERSION_COLUMN] = version_installed
    570             row[enumerations.INSTALLED_OBJECT_COLUMN] = package_installed
    571             if not package_installed:
    572                dt = self.get_datetime(pkg.version)
    573                dt_str = (":%02d%02d") % (dt.month,dt.day)
    574                available_version = pkg.version.get_short_version()+dt_str
    575                row[enumerations.LATEST_AVAILABLE_COLUMN] = available_version
    576             else:
    577                row[enumerations.LATEST_AVAILABLE_COLUMN] = None
    578 
    579       self.install_update_button.set_sensitive(False)
    580       self.install_update_menu.set_sensitive(False)
    581       self.remove_button.set_sensitive(False)
    582       self.remove_menu.set_sensitive(False)
    583       self.enable_disable_selection_menus()
    584       self.update_statusbar()
    585    #--------------------------------------------------------------------------
    586    def get_datetime(self,version):
    587       dt = None
    588       try:
    589          dt = version.get_datetime()
    590       except AttributeError:
    591          dt = version.get_timestamp()
    592       return dt
    593    #--------------------------------------------------------------------------
    594    def on_searchentry_changed(self,widget):
    595       '''On text search field changed we should refilter the main view'''
    596       Thread(target=self.on_searchentry_threaded, args=()).start()
    597       #self.application_list_filter.refilter()
    598 
    599    def on_searchentry_threaded(self):
    600       gobject.idle_add(self.application_list_filter.refilter)
    601       gobject.idle_add(self.enable_disable_selection_menus)
    602 
    603    #--------------------------------------------------------------------------
    604    def on_edit_paste(self,widget):
    605       self.searchentrydialog.insert_text(self.clipboard_text,self.searchentrydialog.get_position())
    606 
    607    #--------------------------------------------------------------------------
    608    def on_clear_paste(self,widget):
    609       bounds = self.searchentrydialog.get_selection_bounds()
    610       text = self.searchentrydialog.get_chars(bounds[0],bounds[1])
    611       self.searchentrydialog.delete_text(bounds[0],bounds[1])
    612       return
    613    #--------------------------------------------------------------------------
    614    def on_copy(self,widget):
    615       bounds = self.searchentrydialog.get_selection_bounds()
    616       text = self.searchentrydialog.get_chars(bounds[0],bounds[1])
    617       self.clipboard.set_text(text)
    618       return
    619    #--------------------------------------------------------------------------
    620    def on_cut(self,widget):
    621       bounds = self.searchentrydialog.get_selection_bounds()
    622       text = self.searchentrydialog.get_chars(bounds[0],bounds[1])
    623       self.searchentrydialog.delete_text(bounds[0],bounds[1])
    624       self.clipboard.set_text(text)
    625       return
    626    #--------------------------------------------------------------------------
    627    def on_select_all(self,widget):
    628       sort_filt_model = self.applicationtreeview.get_model() #gtk.TreeModelSort
    629       filt_model = sort_filt_model.get_model() #gtk.TreeModelFilter