1 #!/usr/bin/python2.4
   2 #
   3 # CDDL HEADER START
   4 #
   5 # The contents of this file are subject to the terms of the
   6 # Common Development and Distribution License (the "License").
   7 # You may not use this file except in compliance with the License.
   8 #
   9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10 # or http://www.opensolaris.org/os/licensing.
  11 # See the License for the specific language governing permissions
  12 # and limitations under the License.
  13 #
  14 # When distributing Covered Code, include this CDDL HEADER in each
  15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16 # If applicable, add the following below this CDDL HEADER, with the
  17 # fields enclosed by brackets "[]" replaced with your own identifying
  18 # information: Portions Copyright [yyyy] [name of copyright owner]
  19 #
  20 # CDDL HEADER END
  21 #
  22 # Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23 # Use is subject to license terms.
  24 #
  25 
  26 # Progress:
  27 # Startup Progress has two phases:
  28 # - Start phase:
  29 #   The start phase should be fairly constant at around a few seconds and so is given 5%
  30 #   of the total progress bar.
  31 # - Package entry loading phase:
  32 #   The package entry loading phase is given the remaining 95% of the bar for progress.
  33 
  34 INITIAL_PROGRESS_TIME_INTERVAL = 0.5      # Time to update progress during start phase
  35 INITIAL_PROGRESS_TIME_PERCENTAGE = 0.005  # Amount to update progress during start phase
  36 INITIAL_PROGRESS_TOTAL_PERCENTAGE = 0.05  # Total progress for start phase
  37 PACKAGE_PROGRESS_TOTAL_INCREMENTS = 95    # Total increments for loading phase
  38 PACKAGE_PROGRESS_PERCENT_INCREMENT = 0.01 # Amount to update progress during loading phase
  39 PACKAGE_PROGRESS_PERCENT_TOTAL = 1.0      # Total progress for loading phase
  40 MAX_DESC_LEN = 60                         # Max length of the description
  41 MAX_INFO_CACHE_LIMIT = 100                # Max number of package descriptions to cache
  42 NOTEBOOK_PACKAGE_LIST_PAGE = 0            # Main Package List page index
  43 NOTEBOOK_START_PAGE = 1                   # Main View Start page index
  44 INFO_NOTEBOOK_LICENSE_PAGE = 3            # License Tab index
  45 SHOW_INFO_DELAY = 600       # Delay before showing selected pacakge information
  46 SHOW_LICENSE_DELAY = 600    # Delay before showing license information
  47 SEARCH_STR_FORMAT = "<%s>"
  48 SEARCH_LIMIT = 100                        # Maximum number of results shown for
  49                                           # api search
  50 MIN_APP_WIDTH = 750                       # Minimum application width
  51 MIN_APP_HEIGHT = 500                     # Minimum application height
  52 INITIAL_APP_WIDTH_PREFERENCES = "/apps/packagemanager/preferences/initial_app_width"
  53 INITIAL_APP_HEIGHT_PREFERENCES = "/apps/packagemanager/preferences/initial_app_height"
  54 INITIAL_APP_HPOS_PREFERENCES = "/apps/packagemanager/preferences/initial_app_hposition"
  55 INITIAL_APP_VPOS_PREFERENCES = "/apps/packagemanager/preferences/initial_app_vposition"
  56 INITIAL_SHOW_FILTER_PREFERENCES = "/apps/packagemanager/preferences/initial_show_filter"
  57 INITIAL_SECTION_PREFERENCES = "/apps/packagemanager/preferences/initial_section"
  58 SHOW_STARTPAGE_PREFERENCES = "/apps/packagemanager/preferences/show_startpage"
  59 API_SEARCH_ERROR_PREFERENCES = "/apps/packagemanager/preferences/api_search_error"
  60 CATEGORIES_STATUS_COLUMN_INDEX = 0   # Index of Status Column in Categories TreeView
  61 
  62 STATUS_COLUMN_INDEX = 2   # Index of Status Column in Application TreeView
  63 
  64 PKG_CLIENT_NAME = "packagemanager"
  65 
  66 # Location for themable icons
  67 ICON_LOCATION = "usr/share/package-manager/icons"
  68 # Load Start Page from lang dir if available
  69 START_PAGE_CACHE_LANG_BASE = "var/pkg/gui_cache/startpagebase/%s/%s"
  70 START_PAGE_LANG_BASE = "usr/share/package-manager/data/startpagebase/%s/%s"
  71 START_PAGE_HOME = "startpage.html" # Default page
  72 
  73 # StartPage Action support for url's on StartPage pages
  74 PM_ACTION = 'pm-action'          # Action field for StartPage url's
  75 
  76 # Internal Example: <a href="pm?pm-action=internal&uri=top_picks.html">
  77 ACTION_INTERNAL = 'internal'   # Internal Action value: pm-action=internal
  78 INTERNAL_URI = 'uri'           # Internal field: uri to navigate to in StartPage
  79                                # without protocol scheme specified
  80 
  81 # External Example: <a href="pm?pm-action=external&uri=www.opensolaris.com">
  82 ACTION_EXTERNAL = 'external'   # External Action value: pm-action=external
  83 EXTERNAL_URI = 'uri'           # External field: uri to navigate to in external
  84                                # default browser without protocol scheme specified
  85 EXTERNAL_PROTOCOL = 'protocol' # External field: optional protocol scheme,
  86                                # defaults to http
  87 DEFAULT_PROTOCOL = 'http'
  88 
  89 import getopt
  90 import pwd
  91 import os
  92 import sys
  93 import time
  94 import locale
  95 import itertools
  96 import urllib
  97 import urlparse
  98 import socket
  99 import gettext
 100 import signal
 101 from threading import Thread
 102 from threading import Lock
 103 from urllib2 import HTTPError, URLError
 104 from cPickle import UnpicklingError
 105 
 106 try:
 107         import gobject
 108         import gnome
 109         gobject.threads_init()
 110         import gconf
 111         import gtk
 112         import gtk.glade
 113         import pygtk
 114         pygtk.require("2.0")
 115         import gtkhtml2
 116         import pango
 117         from glib import GError
 118 except ImportError:
 119         sys.exit(1)
 120 import pkg.misc as misc
 121 import pkg.client.progress as progress
 122 import pkg.client.api_errors as api_errors
 123 import pkg.client.api as api
 124 import pkg.client.publisher as publisher
 125 import pkg.portable as portable
 126 import pkg.fmri as fmri
 127 import pkg.gui.repository as repository
 128 import pkg.gui.beadmin as beadm
 129 import pkg.gui.cache as cache
 130 import pkg.gui.misc as gui_misc
 131 import pkg.gui.imageinfo as imageinfo
 132 import pkg.gui.installupdate as installupdate
 133 import pkg.gui.enumerations as enumerations
 134 import pkg.gui.parseqs as parseqs
 135 import pkg.gui.webinstall as webinstall
 136 from pkg.client import global_settings
 137 
 138 # Put _() in the global namespace
 139 import __builtin__
 140 __builtin__._ = gettext.gettext
 141 
 142 (
 143 DISPLAY_LINK,
 144 CLICK_LINK,
 145 ) = range(2)
 146 
 147 class PackageManager:
 148         def __init__(self):
 149                 signal.signal(signal.SIGINT, self.__main_application_quit)
 150                 # We reset the HOME directory in case the user called us
 151                 # with gksu and had NFS mounted home directory in which
 152                 # case dbus called from gconf cannot write to the directory.
 153                 if os.getuid() == 0:
 154                         dir = self.__find_root_home_dir()
 155                         os.putenv('HOME', dir)
 156                 self.api_o = None
 157                 self.cache_o = None
 158                 self.img_timestamp = None
 159                 self.client = gconf.client_get_default()
 160                 try:
 161                         self.initial_show_filter = \
 162                             self.client.get_int(INITIAL_SHOW_FILTER_PREFERENCES)
 163                         self.initial_section = \
 164                             self.client.get_int(INITIAL_SECTION_PREFERENCES)
 165                         self.show_startpage = \
 166                             self.client.get_bool(SHOW_STARTPAGE_PREFERENCES)
 167                         self.gconf_not_show_repos = \
 168                             self.client.get_string(API_SEARCH_ERROR_PREFERENCES)
 169                         self.initial_app_width = \
 170                             self.client.get_int(INITIAL_APP_WIDTH_PREFERENCES)
 171                         self.initial_app_height = \
 172                             self.client.get_int(INITIAL_APP_HEIGHT_PREFERENCES)
 173                         self.initial_app_hpos = \
 174                             self.client.get_int(INITIAL_APP_HPOS_PREFERENCES)
 175                         self.initial_app_vpos = \
 176                             self.client.get_int(INITIAL_APP_VPOS_PREFERENCES)
 177                 except GError:
 178                         # Default values - the same as in the 
 179                         # packagemanager-preferences.schemas
 180                         self.initial_show_filter = 0
 181                         self.initial_section = 3
 182                         self.show_startpage = True
 183                         self.gconf_not_show_repos = ""
 184                         self.initial_app_width = 800
 185                         self.initial_app_height = 600
 186                         self.initial_app_hpos = 200
 187                         self.initial_app_vpos = 320
 188 
 189                 if not self.gconf_not_show_repos:
 190                         self.gconf_not_show_repos = ""
 191                 self.set_show_filter = 0
 192                 self.set_section = 0
 193                 self.current_search_option = 0
 194                 self.in_search_mode = False
 195 
 196                 # Override default PKG_TIMEOUT_MAX and PKG_CLIENT_TIMEOUT 
 197                 # if a value has been specified in the environment.
 198                 global_settings.PKG_TIMEOUT_MAX = int(os.environ.get(
 199                     "PKG_TIMEOUT_MAX", global_settings.PKG_TIMEOUT_MAX))
 200 
 201                 global_settings.PKG_CLIENT_TIMEOUT = int(os.environ.get(
 202                     "PKG_CLIENT_TIMEOUT", global_settings.PKG_CLIENT_TIMEOUT))
 203 
 204                 # This call only affects sockets created by Python.  The
 205                 # transport framework must set the timeout value internally
 206                 #
 207                 # value is in seconds
 208                 socket.setdefaulttimeout(global_settings.PKG_TIMEOUT_MAX)
 209 
 210                 global_settings.client_name = PKG_CLIENT_NAME
 211 
 212                 try:
 213                         self.application_dir = os.environ["PACKAGE_MANAGER_ROOT"]
 214                 except KeyError:
 215                         self.application_dir = "/"
 216                 misc.setlocale(locale.LC_ALL, "")
 217                 for module in (gettext, gtk.glade):
 218                         module.bindtextdomain("pkg", os.path.join(
 219                             self.application_dir,
 220                             "usr/share/locale"))
 221                         module.textdomain("pkg")
 222                 # XXX Remove and use _() where self._ and self.parent._ are being used
 223                 self.main_window_title = _('Package Manager')
 224                 self.user_rights = portable.is_admin()
 225                 self.cancelled = False                    # For background processes
 226                 self.image_directory = None
 227                 self.description_thread_running = False   # For background processes
 228                 gtk.rc_parse('~/.gtkrc-1.2-gnome2')       # Load gtk theme
 229                 self.progress_stop_timer_thread = False
 230                 self.progress_fraction_time_count = 0
 231                 self.progress_canceled = False
 232                 self.catalog_loaded = False
 233                 self.image_dir_arg = None
 234                 self.update_all_proceed = False
 235                 self.ua_be_name = None
 236                 self.application_path = None
 237                 self.default_publisher = None
 238                 self.current_repos_with_search_errors = []
 239                 self.first_run = True
 240                 self.in_reload = False
 241                 self.selected_pkgstem = None
 242                 self.selected_model = None
 243                 self.selected_path = None
 244                 self.info_cache = {}
 245                 self.selected = 0
 246                 self.selected_pkgs = {}
 247                 self.to_install_update = {}
 248                 self.to_remove = {}
 249                 self.in_startpage_startup = self.show_startpage
 250                 self.lang = None
 251                 self.lang_root = None
 252                 self.visible_status_id = 0
 253                 self.categories_status_id = 0
 254                 self.icon_theme = gtk.IconTheme()
 255                 icon_location = os.path.join(self.application_dir, ICON_LOCATION)
 256                 self.icon_theme.append_search_path(icon_location)
 257                 self.search_options = [
 258                     ('ips-search',
 259                     gui_misc.get_icon(self.icon_theme, 'search', 20),
 260                     _("_Current Repository"),
 261                     _("Search Current Repository")),
 262                     ('ips-search-all',
 263                     gui_misc.get_icon(self.icon_theme, 'search_all', 20),
 264                     _("_All Repositories"),
 265                     _("Search All Repositories"))
 266                     ]
 267                 self.__register_iconsets(self.search_options)               
 268                 self.visible_repository = None
 269                 self.visible_repository_uptodate = False
 270                 self.last_active_publisher = None
 271                 self.search_start = 0
 272                 self.search_time_sec = 0
 273                 self.section_list = None
 274                 self.filter_list = self.__get_new_filter_liststore()
 275                 self.application_list = None
 276                 self.a11y_application_treeview = None
 277                 self.a11y_categories_treeview = None
 278                 self.application_treeview_range = None
 279                 self.application_treeview_initialized = False
 280                 self.categories_treeview_range = None
 281                 self.categories_treeview_initialized = False
 282                 self.category_list = None
 283                 self.repositories_list = None
 284                 self.pr = progress.NullProgressTracker()
 285                 self.pylintstub = None
 286                 self.release_notes_url = "http://www.opensolaris.org"
 287                 self.__image_activity_lock = Lock()
 288 
 289                 # Create Widgets and show gui
 290                 self.gladefile = os.path.join(self.application_dir,
 291                     "usr/share/package-manager/packagemanager.glade")
 292                 w_tree_main = gtk.glade.XML(self.gladefile, "mainwindow")
 293                 w_tree_progress = gtk.glade.XML(self.gladefile, "progressdialog")
 294                 w_tree_preferences = gtk.glade.XML(self.gladefile, "preferencesdialog")
 295                 w_tree_api_search_error = gtk.glade.XML(self.gladefile,
 296                     "api_search_error")
 297                 self.w_preferencesdialog = \
 298                     w_tree_preferences.get_widget("preferencesdialog")
 299                 self.w_startpage_checkbutton = \
 300                     w_tree_preferences.get_widget("startpage_checkbutton")
 301                 self.api_search_error_dialog = \
 302                     w_tree_api_search_error.get_widget("api_search_error")
 303                 self.api_search_error_textview = \
 304                     w_tree_api_search_error.get_widget("api_search_error_text")
 305                 self.api_search_checkbox = \
 306                     w_tree_api_search_error.get_widget("api_search_checkbox")
 307                 self.api_search_button = \
 308                     w_tree_api_search_error.get_widget("api_search_button")
 309                 infobuffer = self.api_search_error_textview.get_buffer()
 310                 infobuffer.create_tag("bold", weight=pango.WEIGHT_BOLD)
 311 
 312                 self.w_main_window = w_tree_main.get_widget("mainwindow")
 313                 self.w_main_hpaned = \
 314                     w_tree_main.get_widget("main_hpaned")
 315                 self.w_main_vpaned = \
 316                     w_tree_main.get_widget("main_vpaned")
 317 
 318                 self.w_application_treeview = \
 319                     w_tree_main.get_widget("applicationtreeview")
 320                 self.w_categories_treeview = w_tree_main.get_widget("categoriestreeview")
 321                 self.w_info_notebook = w_tree_main.get_widget("details_notebook")
 322                 self.w_generalinfo_textview = \
 323                     w_tree_main.get_widget("generalinfotextview")
 324                 self.w_generalinfo_textview.set_wrap_mode(gtk.WRAP_WORD)
 325                 self.w_installedfiles_textview = \
 326                     w_tree_main.get_widget("installedfilestextview")
 327                 self.w_license_textview = \
 328                     w_tree_main.get_widget("licensetextview")
 329                 self.w_dependencies_textview = \
 330                     w_tree_main.get_widget("dependenciestextview")
 331                 self.w_packagename_label = w_tree_main.get_widget("packagenamelabel")
 332                 self.w_shortdescription_label = \
 333                     w_tree_main.get_widget("shortdescriptionlabel")
 334                 w_package_hbox = \
 335                     w_tree_main.get_widget("package_hbox")
 336                 self.w_general_info_label = \
 337                     w_tree_main.get_widget("general_info_label")
 338                 self.w_startpage_frame = \
 339                     w_tree_main.get_widget("startpage_frame")
 340                 self.w_startpage_eventbox = \
 341                     w_tree_main.get_widget("startpage_eventbox")
 342                 self.w_startpage_eventbox.modify_bg(gtk.STATE_NORMAL,
 343                     gtk.gdk.color_parse("white"))
 344 
 345                 self.w_main_statusbar = w_tree_main.get_widget("statusbar")
 346                 self.w_infosearch_frame = w_tree_main.get_widget("infosearch_frame")
 347                 self.w_infosearch_button = w_tree_main.get_widget("infosearch_button")
 348 
 349                 self.w_main_view_notebook = \
 350                     w_tree_main.get_widget("main_view_notebook")
 351                 self.w_searchentry = w_tree_main.get_widget("searchentry")
 352                 self.w_installupdate_button = \
 353                     w_tree_main.get_widget("install_update_button")
 354                 self.w_remove_button = w_tree_main.get_widget("remove_button")
 355                 self.w_updateall_button = w_tree_main.get_widget("update_all_button")
 356                 self.w_reload_button = w_tree_main.get_widget("reloadbutton")
 357                 self.w_repository_combobox = w_tree_main.get_widget("repositorycombobox")
 358                 self.w_sections_combobox = w_tree_main.get_widget("sectionscombobox")
 359                 self.w_filter_combobox = w_tree_main.get_widget("filtercombobox")
 360                 self.w_packageicon_image = w_tree_main.get_widget("packageimage")
 361                 self.w_installupdate_menuitem = \
 362                     w_tree_main.get_widget("package_install_update")
 363                 self.w_remove_menuitem = w_tree_main.get_widget("package_remove")
 364                 self.w_updateall_menuitem = w_tree_main.get_widget("package_update_all")
 365                 self.w_cut_menuitem = w_tree_main.get_widget("edit_cut")
 366                 self.w_copy_menuitem = w_tree_main.get_widget("edit_copy")
 367                 self.w_paste_menuitem = w_tree_main.get_widget("edit_paste")
 368                 self.w_clear_menuitem = w_tree_main.get_widget("edit_clear")
 369                 self.w_selectall_menuitem = w_tree_main.get_widget("edit_select_all")
 370                 self.w_selectupdates_menuitem = \
 371                     w_tree_main.get_widget("edit_select_updates")
 372                 self.w_deselect_menuitem = w_tree_main.get_widget("edit_deselect")
 373                 self.w_main_clipboard =  gtk.clipboard_get(gtk.gdk.SELECTION_CLIPBOARD)
 374                 self.w_progress_dialog = w_tree_progress.get_widget("progressdialog")
 375                 self.w_progress_dialog.connect('delete-event', lambda stub1, stub2: True)
 376                 self.w_progress_dialog.set_title(_("Update All"))
 377                 self.w_progressinfo_label = w_tree_progress.get_widget("progressinfo")
 378                 self.w_progressinfo_label.set_text(_(
 379                     "Checking SUNWipkg and SUNWipkg-gui versions\n\nPlease wait ..."))
 380                 self.w_progressbar = w_tree_progress.get_widget("progressbar")
 381                 self.w_progressbar.set_pulse_step(0.1)
 382                 self.w_progress_cancel = w_tree_progress.get_widget("progresscancel")
 383                 self.progress_canceled = False
 384                 self.w_clear_search_button = w_tree_main.get_widget("clear_search")
 385                 self.w_clear_search_button.set_sensitive(False)
 386                 clear_search_image = w_tree_main.get_widget("clear_image")
 387                 clear_search_image.set_from_stock(gtk.STOCK_CLEAR, gtk.ICON_SIZE_MENU)
 388                 self.saved_filter_combobox_active = self.initial_show_filter
 389                 self.search_image = w_tree_main.get_widget("search_image")
 390                 self.search_button = w_tree_main.get_widget("set_search")
 391                 self.a11y_search_button = self.search_button.get_accessible()
 392                 self.is_search_all = False
 393                 self.searchmenu = gtk.Menu()
 394                 self.search_image.set_from_pixbuf(self.search_options[0][1])
 395                 self.a11y_search_button.set_description(self.search_options[0][3])
 396                 for stock_id, pixbuf, label, description in self.search_options:
 397                         action = gtk.Action(stock_id, label, None, stock_id)
 398                         action.connect('activate',
 399                             self.__search_menu_item_activate)
 400                         menu_item = action.create_menu_item()
 401                         self.searchmenu.append(menu_item)
 402                         self.pylintstub = description
 403                         self.pylintstub = pixbuf
 404                 self.changing_search_option = False
 405                 self.saved_repository_combobox_active = -1
 406                 self.saved_sections_combobox_active = 0
 407                 self.saved_application_list = None
 408                 self.saved_application_list_filter = None
 409                 self.saved_application_list_sort = None
 410                 self.saved_category_list = None
 411                 self.saved_section_list = None
 412                 self.saved_selected_application_path = None
 413                 self.statusbar_message_id = 0
 414                 toolbar =  w_tree_main.get_widget("toolbutton2")
 415                 toolbar.set_expand(True)
 416                 self.__init_repository_tree_view()
 417                 self.install_button_tooltip = gtk.Tooltips()
 418                 self.remove_button_tooltip = gtk.Tooltips()
 419                 self.__update_reload_button()
 420                 self.w_main_window.set_title(self.main_window_title)
 421                 self.w_searchentry.grab_focus()
 422 
 423                 # Update All Completed Dialog
 424                 w_xmltree_ua_completed = gtk.glade.XML(self.gladefile,
 425                     "ua_completed_dialog")
 426                 self.w_ua_completed_dialog = w_xmltree_ua_completed.get_widget(
 427                     "ua_completed_dialog")
 428                 self.w_ua_completed_dialog .connect("destroy",
 429                     self.__on_ua_completed_close)
 430                 self.w_ua_completed_release_label = w_xmltree_ua_completed.get_widget(
 431                     "ua_completed_release_label")
 432                 self.w_ua_completed_linkbutton = w_xmltree_ua_completed.get_widget(
 433                     "ua_completed_linkbutton")
 434 
 435                 # Setup Start Page
 436                 self.document = None
 437                 self.view = None
 438                 self.current_url = None
 439                 self.opener = None
 440                 self.__setup_startpage(self.show_startpage)
 441 
 442                 try:
 443                         dic_mainwindow = \
 444                             {
 445                                 "on_mainwindow_delete_event": \
 446                                     self.__on_mainwindow_delete_event,
 447                                 "on_searchentry_changed":self.__on_searchentry_changed,
 448                                 "on_searchentry_focus_in_event": \
 449                                     self.__on_searchentry_focus_in,
 450                                 "on_searchentry_focus_out_event": \
 451                                     self.__on_searchentry_focus_out,
 452                                 "on_searchentry_activate": \
 453                                     self.__on_searchentry_activate,
 454                                 "on_sectionscombobox_changed": \
 455                                     self.__on_sectionscombobox_changed,
 456                                 "on_filtercombobox_changed": \
 457                                     self.__on_filtercombobox_changed,
 458                                 "on_repositorycombobox_changed": \
 459                                     self.__on_repositorycombobox_changed,
 460                                 #menu signals
 461                                 "on_file_quit_activate":self.__on_file_quit_activate,
 462                                 "on_file_be_activate":self.__on_file_be_activate,
 463                                 "on_package_install_update_activate": \
 464                                     self.__on_install_update,
 465                                 "on_settings_edit_repositories_activate": \
 466                                     self.__on_edit_repositories_activate,
 467                                 "on_package_remove_activate":self.__on_remove,
 468                                 "on_help_about_activate":self.__on_help_about,
 469                                 "on_help_help_activate":self.__on_help_help,
 470                                 "on_edit_paste_activate":self.__on_edit_paste,
 471                                 "on_edit_clear_activate":self.__on_clear_paste,
 472                                 "on_edit_copy_activate":self.__on_copy,
 473                                 "on_edit_cut_activate":self.__on_cut,
 474                                 "on_edit_search_activate":self.__on_edit_search_clicked,
 475                                 "on_set_search_clicked":self.__on_set_search_clicked,
 476                                 "on_set_search_button_press_event":self.__on_set_search,
 477                                 "on_clear_search_clicked":self.__on_clear_search,
 478                                 "on_edit_select_all_activate":self.__on_select_all,
 479                                 "on_edit_select_updates_activate": \
 480                                     self.__on_select_updates,
 481                                 "on_edit_deselect_activate":self.__on_deselect,
 482                                 "on_edit_preferences_activate":self.__on_preferences,
 483                                 # XXX disabled until new API
 484                                 "on_package_update_all_activate":self.__on_update_all,
 485                                 #toolbar signals
 486                                 # XXX disabled until new API
 487                                 "on_update_all_button_clicked":self.__on_update_all,
 488                                 "on_reload_button_clicked":self.__on_reload,
 489                                 "on_install_update_button_clicked": \
 490                                     self.__on_install_update,
 491                                 "on_remove_button_clicked":self.__on_remove,
 492                                 "on_help_start_page_activate":self.__on_startpage,
 493                                 "on_details_notebook_switch_page": \
 494                                     self.__on_notebook_change,
 495                                 "on_infosearch_button_clicked": \
 496                                     self.__on_infosearch_button_clicked,
 497                             }
 498                         dic_progress = \
 499                             {
 500                                 "on_cancel_progressdialog_clicked": \
 501                                     self.__on_cancel_progressdialog_clicked,
 502                             }
 503                         dic_preferences = \
 504                             {
 505                                 "on_startpage_checkbutton_toggled": \
 506                                     self.__on_startpage_checkbutton_toggled,
 507                                 "on_preferenceshelp_clicked": \
 508                                     self.__on_preferenceshelp_clicked,
 509                                 "on_preferencesclose_clicked": \
 510                                     self.__on_preferencesclose_clicked,
 511                             }
 512                         dic_api_search_error = \
 513                             {
 514                                 "on_api_search_checkbox_toggled": \
 515                                     self.__on_api_search_checkbox_toggled,
 516                                 "on_api_search_button_clicked": \
 517                                     self.__on_api_search_button_clicked,
 518                                 "on_api_search_error_delete_event": \
 519                                     self.__on_api_search_error_delete_event,
 520                             }
 521                         dic_completed = \
 522                             {
 523                                 "on_ua_complete_close_button_clicked": \
 524                                      self.__on_ua_completed_close,
 525                                 "on_ua_completed_linkbutton_clicked": \
 526                                      self.__on_ua_completed_linkbutton_clicked,                                     
 527                             }
 528                         w_xmltree_ua_completed.signal_autoconnect(dic_completed)
 529         
 530                             
 531                         w_tree_main.signal_autoconnect(dic_mainwindow)
 532                         w_tree_progress.signal_autoconnect(dic_progress)
 533                         w_tree_preferences.signal_autoconnect(dic_preferences)
 534                         w_tree_api_search_error.signal_autoconnect(
 535                             dic_api_search_error)
 536                 except AttributeError, error:
 537                         print _(
 538                             "GUI will not respond to any event! %s."
 539                             "Check declare_signals()") \
 540                             % error
 541 
 542                 self.package_selection = None
 543                 self.category_list_filter = None
 544                 self.application_list_filter = None
 545                 self.application_list_sort = None
 546                 self.application_refilter_id = 0
 547                 self.application_refilter_idle_id = 0
 548                 self.last_show_info_id = 0
 549                 self.show_info_id = 0
 550                 self.last_show_licenses_id = 0
 551                 self.show_licenses_id = 0
 552                 self.showing_empty_details = False
 553                 self.in_setup = True
 554                 if self.initial_app_width >= MIN_APP_WIDTH and \
 555                         self.initial_app_height >= MIN_APP_HEIGHT:
 556                         self.w_main_window.resize(self.initial_app_width,
 557                             self.initial_app_height)
 558                 if self.initial_app_hpos > 0:
 559                         self.w_main_hpaned.set_position(self.initial_app_hpos)
 560                 if self.initial_app_vpos > 0:
 561                         self.w_main_vpaned.set_position(self.initial_app_vpos)
 562                 self.w_main_window.show_all()
 563                 gdk_win = self.w_main_window.get_window()
 564                 self.gdk_window = gtk.gdk.Window(gdk_win, gtk.gdk.screen_width(),
 565                     gtk.gdk.screen_height(), gtk.gdk.WINDOW_CHILD, 0, gtk.gdk.INPUT_ONLY)
 566                 gdk_cursor = gtk.gdk.Cursor(gtk.gdk.WATCH)
 567                 self.gdk_window.set_cursor(gdk_cursor)
 568                 # Until package icons become available hide Package Icon Panel
 569                 w_package_hbox.hide()
 570                 if self.show_startpage:
 571                         self.w_main_view_notebook.set_current_page(NOTEBOOK_START_PAGE)
 572                 else:
 573                         self.w_main_view_notebook.set_current_page(
 574                             NOTEBOOK_PACKAGE_LIST_PAGE)
 575                 self.api_search_error_dialog.set_transient_for(self.w_main_window)
 576                 self.__setup_text_signals()
 577 
 578         def __setup_text_signals(self):
 579                 self.w_generalinfo_textview.get_buffer().connect(
 580                     "notify::has-selection", self.__on_text_buffer_has_selection)
 581                 self.w_installedfiles_textview.get_buffer().connect(
 582                     "notify::has-selection", self.__on_text_buffer_has_selection)
 583                 self.w_dependencies_textview.get_buffer().connect(
 584                     "notify::has-selection", self.__on_text_buffer_has_selection)
 585                 self.w_license_textview.get_buffer().connect(
 586                     "notify::has-selection", self.__on_text_buffer_has_selection)
 587                 self.w_searchentry.connect(
 588                     "notify::cursor-position", self.__on_searchentry_selection)
 589                 self.w_searchentry.connect(
 590                     "notify::selection-bound", self.__on_searchentry_selection)
 591                 self.w_generalinfo_textview.connect(
 592                     "focus-in-event", self.__on_textview_focus_in)
 593                 self.w_installedfiles_textview.connect(
 594                     "focus-in-event", self.__on_textview_focus_in)
 595                 self.w_dependencies_textview.connect(
 596                     "focus-in-event", self.__on_textview_focus_in)
 597                 self.w_license_textview.connect(
 598                     "focus-in-event", self.__on_textview_focus_in)
 599                 self.w_generalinfo_textview.connect(
 600                     "focus-out-event", self.__on_textview_focus_out)
 601                 self.w_installedfiles_textview.connect(
 602                     "focus-out-event", self.__on_textview_focus_out)
 603                 self.w_dependencies_textview.connect(
 604                     "focus-out-event", self.__on_textview_focus_out)
 605                 self.w_license_textview.connect(
 606                     "focus-out-event", self.__on_textview_focus_out)
 607 
 608         def __on_textview_focus_in(self, widget, event):
 609                 char_count = widget.get_buffer().get_char_count()
 610                 if char_count > 0:
 611                         self.w_selectall_menuitem.set_sensitive(True)
 612                 else:
 613                         self.w_selectall_menuitem.set_sensitive(False)
 614                 bounds = widget.get_buffer().get_selection_bounds()
 615                 if bounds:
 616                         offset1 = bounds[0].get_offset() 
 617                         offset2 = bounds[1].get_offset() 
 618                         if abs(offset2 - offset1) == char_count:
 619                                 self.w_selectall_menuitem.set_sensitive(False)
 620                         self.w_deselect_menuitem.set_sensitive(True)
 621                         self.w_copy_menuitem.set_sensitive(True)
 622                 else:
 623                         self.w_deselect_menuitem.set_sensitive(False)
 624 
 625         def __on_textview_focus_out(self, widget, event):
 626                 self.__enable_disable_select_all()
 627                 self.__enable_disable_deselect()
 628                 self.w_copy_menuitem.set_sensitive(False)
 629 
 630         def __on_text_buffer_has_selection(self, object, pspec):
 631                 if object.get_selection_bounds():
 632                         self.w_copy_menuitem.set_sensitive(True)
 633                         self.w_deselect_menuitem.set_sensitive(True)
 634                 else:
 635                         self.w_copy_menuitem.set_sensitive(False)
 636                         self.w_deselect_menuitem.set_sensitive(False)
 637 
 638         def __register_iconsets(self, icon_info):
 639                 factory = gtk.IconFactory()
 640                 for stock_id, pixbuf, name, description in icon_info:
 641                         iconset = gtk.IconSet(pixbuf)
 642                         factory.add(stock_id, iconset)
 643                         self.pylintstub = name
 644                         self.pylintstub = description
 645                 factory.add_default()
 646 
 647         def __set_search_option(self, i):
 648                 # The value i is the index in the table search_options
 649                 # of the current choice.
 650                 # Index 0 corresponds to Current Repository.
 651                 # We assume that anything else is search all.
 652                 # This may need to be revisited if more search options are
 653                 # added.
 654                 if i == self.current_search_option:
 655                         return
 656                 self.current_search_option = i
 657                 self.changing_search_option = True
 658                 is_search_all = (i != 0)
 659                 self.__update_repository_combobox_for_search(is_search_all)
 660                 if is_search_all:
 661                         self.__setup_before_search_all_mode()
 662                 else:
 663                         self.__restore_setup_for_browse()
 664                 self.changing_search_option = False
 665 
 666         def __update_repository_combobox_for_search(self, is_search_all):
 667                 if is_search_all:
 668                         self.saved_repository_combobox_active = \
 669                             self.w_repository_combobox.get_active()
 670                 self.__disconnect_repository_model()
 671                 if is_search_all:
 672                         self.repositories_list.prepend(
 673                             [-1, _("All Repositories Search Results"), ])
 674                 else:
 675                         self.repositories_list.remove(
 676                             self.repositories_list.get_iter_first())
 677                 self.w_repository_combobox.set_model(self.repositories_list)
 678                 self.visible_repository = None
 679 
 680 
 681         def __link_load_blank(self):
 682                 self.document.clear()
 683                 self.document.open_stream('text/html')
 684                 self.document.write_stream(_(
 685                     "<html><head></head><body></body></html>"))
 686                 self.document.close_stream()
 687 
 688         def __search_menu_item_activate(self, widget):
 689                 name = widget.get_name()
 690                 i = 0
 691                 for stock_id, pixbuf, label, description in self.search_options:
 692                         if stock_id == name:
 693                                 self.__set_search_option(i)
 694                                 self.search_image.set_from_pixbuf(pixbuf)
 695                                 self.a11y_search_button.set_description(description)
 696                                 break
 697                         i += 1
 698                         self.pylintstub = label
 699 
 700         def __setup_startpage(self, show_startpage):
 701                 self.opener = urllib.FancyURLopener()
 702                 self.document = gtkhtml2.Document()
 703                 self.document.connect('request_url', self.__request_url)
 704                 self.document.connect('link_clicked', self.__handle_link)
 705                 self.document.clear()
 706 
 707                 self.view = gtkhtml2.View()
 708                 self.view.set_document(self.document)
 709                 self.view.connect('request_object', self.__request_object)
 710                 self.view.connect('on_url', self.__on_url)
 711 
 712                 try:
 713                         self.lang, encode = locale.getlocale(locale.LC_CTYPE)
 714                         if debug:
 715                                 print "Lang: %s: Encode: %s" % (self.lang, encode)
 716                 except locale.Error:
 717                         self.lang = "C"
 718                 if self.lang == None or self.lang == "":
 719                         self.lang = "C"
 720                 self.lang_root = self.lang.split('_')[0]
 721                 if show_startpage:
 722                         self.__load_startpage()
 723                 self.w_startpage_frame.add(self.view)
 724 
 725         # Stub handler required by GtkHtml widget
 726         def __request_object(self, *vargs):
 727                 pass
 728 
 729         def __load_startpage(self):
 730                 if self.__load_startpage_locale(START_PAGE_CACHE_LANG_BASE):
 731                         return
 732                 if self.__load_startpage_locale(START_PAGE_LANG_BASE):
 733                         return                        
 734                 self.__handle_startpage_load_error(start_page_url)
 735 
 736 
 737         def __load_startpage_locale(self, start_page_lang_base):
 738                 start_page_url = os.path.join(self.application_dir,
 739                         start_page_lang_base % (self.lang, START_PAGE_HOME))
 740                 if self.__load_uri(self.document, start_page_url):
 741                         return True
 742                         
 743                 if self.lang_root != None and self.lang_root != self.lang:
 744                         start_page_url = os.path.join(self.application_dir,
 745                                 start_page_lang_base % (self.lang_root, START_PAGE_HOME))
 746                         if self.__load_uri(self.document, start_page_url):
 747                                 return True
 748 
 749                 start_page_url = os.path.join(self.application_dir,
 750                         start_page_lang_base % ("C", START_PAGE_HOME))
 751                 if self.__load_uri(self.document, start_page_url):
 752                         return True
 753                 return False
 754 
 755         def __handle_startpage_load_error(self, start_page_url):
 756                 self.document.open_stream('text/html')
 757                 self.document.write_stream(_(
 758                     "<html><head></head><body><H2>Welcome to"
 759                     "PackageManager!</H2><br>"
 760                     "<font color='#0000FF'>Warning: Unable to "
 761                     "load Start Page:<br>%s</font></body></html>"
 762                     % (start_page_url)))
 763                 self.document.close_stream()
 764 
 765         def __parse_api_search_error(self, error):
 766                 self.current_repos_with_search_errors = []
 767                 if "failed_servers" in error.__dict__ and len(error.failed_servers) > 0:
 768                         #TBD we should not have to parse the error output
 769                         rem_str = " doesn't speak a known version of search operation"
 770                         timeout_str = "urlopen error timed out"
 771                         repos = []
 772                         for err in error.failed_servers:
 773                                 err_str = str(err[1])
 774                                 if rem_str in err_str:
 775                                         repo = err_str.replace(rem_str,"")
 776                                         self.current_repos_with_search_errors.append(repo)
 777                                 elif timeout_str in err_str:
 778                                         repo = err[0].repositories[0].origins[0].uri
 779                                         self.current_repos_with_search_errors.append(repo)
 780 
 781         def __on_infosearch_button_clicked(self, widget):
 782                 self.__handle_api_search_error(True)
 783 
 784         def __handle_api_search_error(self, show_all=False):
 785                 if len(self.current_repos_with_search_errors) == 0:
 786                         self.w_infosearch_frame.hide()
 787                         return
 788                 else:
 789                         self.w_infosearch_button.set_size_request(26, 22)
 790                         self.w_infosearch_frame.show()
 791 
 792                 repo_pubs = self.__get_repo_publishers()
 793                 repo_count = 0
 794                 for url in self.current_repos_with_search_errors:
 795                         if show_all or (url not in self.gconf_not_show_repos):
 796                                 repo_count += 1
 797                 if repo_count == 0:
 798                         return
 799 
 800                 infobuffer = self.api_search_error_textview.get_buffer()
 801                 infobuffer.set_text("")
 802                 textiter = infobuffer.get_end_iter()
 803                 for url in self.current_repos_with_search_errors:
 804                         if show_all or (url not in self.gconf_not_show_repos):
 805                                 infobuffer.insert_with_tags_by_name(textiter,
 806                                         "%s" % repo_pubs[url], "bold")
 807                                 infobuffer.insert(textiter, " (%s)\n" % url)
 808                 self.api_search_checkbox.set_active(False)
 809                 self.api_search_error_dialog.show()
 810                 self.api_search_button.grab_focus()
 811 
 812         def __get_repo_publishers(self):
 813                 repo_pub_dict = {}
 814                 pubs = self.api_o.get_publishers()
 815                 for pub in pubs:
 816                         repo = pub.selected_repository
 817                         origin = repo.origins[0]
 818                         repo_pub_dict[origin.uri] = pub.prefix
 819                 return repo_pub_dict
 820 
 821         def __on_url(self, view, link):
 822                 # Handle mouse over events on links and reset when not on link
 823                 if link == None or link == "":
 824                         self.update_statusbar()
 825                 else:
 826                         display_link = self.__handle_link(None, link, DISPLAY_LINK)
 827                         if display_link != None:
 828                                 self.w_main_statusbar.push(0, display_link)
 829                         else:
 830                                 self.update_statusbar()
 831 
 832         @staticmethod
 833         def __is_relative_to_server(url):
 834                 parts = urlparse.urlparse(url)
 835                 if parts[0] or parts[1]:
 836                         return 0
 837                 return 1
 838 
 839         def __open_url(self, url):
 840                 uri = self.__resolve_uri(url)
 841                 return self.opener.open(uri)
 842 
 843         def __resolve_uri(self, uri):
 844                 if self.__is_relative_to_server(uri) and self.current_url != uri:
 845                         return urlparse.urljoin(self.current_url, uri)
 846                 return uri
 847 
 848         def __request_url(self, document, url, stream):
 849                 f = self.__open_url(url)
 850                 stream.set_cancel_func(self.__stream_cancel)
 851                 stream.write(f.read())
 852 
 853         # Stub handler required by GtkHtml widget or widget will assert
 854         def __stream_cancel(self, *vargs):
 855                 pass
 856 
 857         def __load_uri(self, document, link):
 858                 self.w_main_statusbar.push(0, _("Loading... " + link))
 859                 try:
 860                         f = self.__open_url(link)
 861                 except  (IOError, OSError), err:
 862                         if debug:
 863                                 print "err: %s" % (err)
 864                         self.w_main_statusbar.push(0, _("Stopped"))
 865                         return False
 866                 self.current_url = self.__resolve_uri(link)
 867 
 868                 self.document.clear()
 869                 headers = f.info()
 870                 mime = headers.getheader('Content-type').split(';')[0]
 871                 if mime:
 872                         self.document.open_stream(mime)
 873                 else:
 874                         self.document.open_stream('text/plain')
 875 
 876                 self.document.write_stream(f.read())
 877                 self.document.close_stream()
 878                 self.w_main_statusbar.push(0, _("Done"))
 879                 return True
 880 
 881         def __link_load_error(self, link):
 882                 self.document.clear()
 883                 self.document.open_stream('text/html')
 884                 self.document.write_stream(_(
 885                     "<html><head></head><body><font color='#000000'>\
 886                     <a href='stub'></a></font>\
 887                     <a href='pm?%s=internal&uri=%s'>\
 888                     <IMG SRC = 'startpage_star.png' \
 889                     style='border-style: none'></a> <br><br>\
 890                     <h2><font color='#0000FF'>Warning: Unable to \
 891                     load URL</font></h2><br>%s</body></html>"
 892                     % (PM_ACTION, START_PAGE_HOME, link)))
 893                 self.document.close_stream()
 894 
 895         def __handle_link(self, document, link, handle_what = CLICK_LINK):
 896                 query_dict = self.__urlparse_qs(link)
 897 
 898                 action = None
 899                 if query_dict.has_key(PM_ACTION):
 900                         action = query_dict[PM_ACTION][0]
 901                 elif handle_what == DISPLAY_LINK:
 902                         return link
 903                 ext_uri = ""
 904                 protocol = None
 905 
 906                 # Internal Browse
 907                 if action == ACTION_INTERNAL:
 908                         if query_dict.has_key(INTERNAL_URI):
 909                                 int_uri = query_dict[INTERNAL_URI][0]
 910                                 if handle_what == DISPLAY_LINK:
 911                                         return int_uri
 912                         else:
 913                                 if handle_what == CLICK_LINK:
 914                                         self.__link_load_error(_("No URI specified"))
 915                                 return
 916                         if handle_what == CLICK_LINK and \
 917                             not self.__load_uri(document, int_uri):
 918                                 self.__link_load_error(int_uri)
 919                         return
 920                 # External browse
 921                 elif action == ACTION_EXTERNAL:
 922                         if query_dict.has_key(EXTERNAL_URI):
 923                                 ext_uri = query_dict[EXTERNAL_URI][0]
 924                         else:
 925                                 if handle_what == CLICK_LINK:
 926                                         self.__link_load_error(_("No URI specified"))
 927                                 return
 928                         if query_dict.has_key(EXTERNAL_PROTOCOL):
 929                                 protocol = query_dict[EXTERNAL_PROTOCOL][0]
 930                         else:
 931                                 protocol = DEFAULT_PROTOCOL
 932 
 933                         if handle_what == DISPLAY_LINK:
 934                                 return protocol + "://" + ext_uri
 935                         try:
 936                                 gnome.url_show(protocol + "://" + ext_uri)
 937                         except gobject.GError:
 938                                 self.__link_load_error(protocol + "://" + ext_uri)
 939                 elif handle_what == DISPLAY_LINK:
 940                         return None
 941                 elif action == None:
 942                         try:
 943                                 gnome.url_show(link)
 944                         except gobject.GError:
 945                                 self.__link_load_error(link)
 946                 # Handle empty and unsupported actions
 947                 elif action == "":
 948                         self.__link_load_error(_("Empty Action not supported"
 949                             % action))
 950                         return
 951                 elif action != None:
 952                         self.__link_load_error(_("Action not supported: %s"
 953                             % action))
 954                         return
 955 
 956         @staticmethod
 957         def __urlparse_qs(url, keep_blank_values=0, strict_parsing=0):
 958                 scheme, netloc, url, params, querystring, fragment = urlparse.urlparse(
 959                     url)
 960                 if debug:
 961                         print ("Query: scheme %s, netloc %s, url %s, params %s,"
 962                             "querystring %s, fragment %s"
 963                             % (scheme, netloc, url, params, querystring, fragment))
 964                 return parseqs.parse_qs(querystring)
 965 
 966         @staticmethod
 967         def __get_new_application_liststore():
 968                 return gtk.ListStore(
 969                         gobject.TYPE_BOOLEAN,     # enumerations.MARK_COLUMN
 970                         gtk.gdk.Pixbuf,           # enumerations.STATUS_ICON_COLUMN
 971                         gobject.TYPE_STRING,      # enumerations.NAME_COLUMN
 972                         gobject.TYPE_STRING,      # enumerations.DESCRIPTION_COLUMN
 973                         gobject.TYPE_INT,         # enumerations.STATUS_COLUMN
 974                         gobject.TYPE_PYOBJECT,    # enumerations.FMRI_COLUMN
 975                         gobject.TYPE_STRING,      # enumerations.STEM_COLUMN
 976                         gobject.TYPE_STRING,      # enumerations.DISPLAY_NAME_COLUMN
 977                         gobject.TYPE_BOOLEAN,     # enumerations.IS_VISIBLE_COLUMN
 978                         gobject.TYPE_PYOBJECT,    # enumerations.CATEGORY_LIST_COLUMN
 979                         gobject.TYPE_STRING       # enumerations.REPOSITORY_COLUMN
 980                         )
 981 
 982         @staticmethod
 983         def __get_new_category_liststore():
 984                 return gtk.ListStore(
 985                         gobject.TYPE_INT,         # enumerations.CATEGORY_ID
 986                         gobject.TYPE_STRING,      # enumerations.CATEGORY_NAME
 987                         gobject.TYPE_STRING,      # enumerations.CATEGORY_DESCRIPTION
 988                         gtk.gdk.Pixbuf,           # enumerations.CATEGORY_ICON
 989                         gobject.TYPE_BOOLEAN,     # enumerations.CATEGORY_ICON_VISIBLE
 990                         gobject.TYPE_BOOLEAN,     # enumerations.CATEGORY_VISIBLE
 991                         gobject.TYPE_PYOBJECT,    # enumerations.SECTION_LIST_OBJECT
 992                         )
 993 
 994         @staticmethod
 995         def __get_new_section_liststore():
 996                 return gtk.ListStore(
 997                         gobject.TYPE_INT,         # enumerations.SECTION_ID
 998                         gobject.TYPE_STRING,      # enumerations.SECTION_NAME
 999                         gobject.TYPE_STRING,      # enumerations.SECTION_SUBCATEGORY
1000                         gobject.TYPE_BOOLEAN,     # enumerations.SECTION_ENABLED
1001                         )
1002 
1003         @staticmethod
1004         def __get_new_filter_liststore():
1005                 return gtk.ListStore(
1006                         gobject.TYPE_INT,         # enumerations.FILTER_ID
1007                         gobject.TYPE_STRING,      # enumerations.FILTER_NAME
1008                         )
1009 
1010         @staticmethod
1011         def __get_new_repositories_liststore():
1012                 return gtk.ListStore(
1013                         gobject.TYPE_INT,         # enumerations.REPOSITORY_ID
1014                         gobject.TYPE_STRING,      # enumerations.REPOSITORY_NAME
1015                         )
1016 
1017         def __init_application_tree_view(self, application_list,
1018             application_list_filter, application_list_sort):
1019                 ##APPLICATION MAIN TREEVIEW
1020                 if application_list_filter == None:
1021                         application_list_filter = application_list.filter_new()
1022                 if application_list_sort == None:
1023                         application_list_sort = \
1024                             gtk.TreeModelSort(application_list_filter)
1025                         application_list_sort.set_sort_column_id(
1026                             enumerations.NAME_COLUMN, gtk.SORT_ASCENDING)
1027                         application_list_sort.set_sort_func(
1028                             enumerations.STATUS_ICON_COLUMN, self.__status_sort_func)
1029                 toggle_renderer = gtk.CellRendererToggle()
1030 
1031                 column = gtk.TreeViewColumn("", toggle_renderer, \
1032                     active = enumerations.MARK_COLUMN)
1033                 column.set_sort_column_id(enumerations.MARK_COLUMN)
1034                 column.set_sort_indicator(True)
1035                 column.set_cell_data_func(toggle_renderer, self.cell_data_function, None)
1036                 column.connect_after('clicked',
1037                     self.__application_treeview_column_sorted, None)
1038                 self.w_application_treeview.append_column(column)
1039                 name_renderer = gtk.CellRendererText()
1040                 column = gtk.TreeViewColumn(_("Name"), name_renderer,
1041                     text = enumerations.NAME_COLUMN)
1042                 column.set_resizable(True)
1043                 column.set_sort_column_id(enumerations.NAME_COLUMN)
1044                 column.set_sort_indicator(True)
1045                 column.set_cell_data_func(name_renderer, self.cell_data_function, None)
1046                 column.connect_after('clicked',
1047                     self.__application_treeview_column_sorted, None)
1048                 self.w_application_treeview.append_column(column)
1049                 column = self.__create_icon_column(_("Status"), True,
1050                     enumerations.STATUS_ICON_COLUMN, True)
1051                 column.set_sort_column_id(enumerations.STATUS_ICON_COLUMN)
1052                 column.set_sort_indicator(True)
1053                 column.connect_after('clicked',
1054                     self.__application_treeview_column_sorted, None)
1055                 self.w_application_treeview.append_column(column)
1056                 if self.is_search_all:
1057                         repository_renderer = gtk.CellRendererText()
1058                         column = gtk.TreeViewColumn(_('Repository'),
1059                             repository_renderer,
1060                             text = enumerations.AUTHORITY_COLUMN)
1061                         column.set_sort_column_id(enumerations.AUTHORITY_COLUMN)
1062                         column.set_resizable(True)
1063                         column.set_sort_indicator(True)
1064                         column.set_cell_data_func(repository_renderer,
1065                             self.cell_data_function, None)
1066                         column.connect_after('clicked',
1067                             self.__application_treeview_column_sorted, None)
1068                         self.w_application_treeview.append_column(column)
1069                 description_renderer = gtk.CellRendererText()
1070                 column = gtk.TreeViewColumn(_('Description'),
1071                     description_renderer,
1072                     text = enumerations.DESCRIPTION_COLUMN)
1073                 column.set_sort_column_id(enumerations.DESCRIPTION_COLUMN)
1074                 column.set_resizable(True)
1075                 column.set_sort_indicator(True)
1076                 column.set_cell_data_func(description_renderer,
1077                     self.cell_data_function, None)
1078                 column.connect_after('clicked',
1079                     self.__application_treeview_column_sorted, None)
1080                 self.w_application_treeview.append_column(column)
1081                 #Added selection listener
1082                 self.package_selection = self.w_application_treeview.get_selection()
1083                 self.application_list = application_list
1084                 self.application_list_filter = application_list_filter
1085                 self.application_list_sort = application_list_sort
1086                 toggle_renderer.connect('toggled', self.__active_pane_toggle,
1087                     application_list_sort)
1088 
1089         def __init_tree_views(self, application_list, category_list, 
1090             section_list, application_list_filter = None, 
1091             application_list_sort = None):
1092                 '''This function connects treeviews with their models and also applies
1093                 filters'''
1094                 if category_list == None:
1095                         self.w_application_treeview.set_model(None)
1096                         self.__remove_treeview_columns(self.w_application_treeview)
1097                 elif application_list == None:
1098                         self.w_categories_treeview.set_model(None)
1099                         self.__remove_treeview_columns(self.w_categories_treeview)
1100                 else:
1101                         self.__disconnect_models()
1102                         self.__remove_treeview_columns(self.w_application_treeview)
1103                         self.__remove_treeview_columns(self.w_categories_treeview)
1104                 # The logic for set section needs to be here as some sections
1105                 # might be not enabled. In such situation we are setting the set
1106                 # section to "All Categories" one.
1107                 if section_list != None:
1108                         row = section_list[self.set_section]
1109                         if row[enumerations.SECTION_ENABLED] and \
1110                             self.set_section >= 0 and \
1111                             self.set_section < len(section_list):
1112                                 if row[enumerations.SECTION_ID] != self.set_section:
1113                                         self.set_section = 0
1114                         else:
1115                                 self.set_section = 0
1116 
1117                 if application_list != None:
1118                         self.__init_application_tree_view(application_list,
1119                             application_list_filter, application_list_sort)
1120 
1121                 if self.first_run:
1122                         # When vadj changes we need to set image descriptions
1123                         # on visible status icons. This catches moving the scroll bars
1124                         # and scrolling up and down using keyboard.
1125                         vadj = self.w_application_treeview.get_vadjustment()
1126                         vadj.connect('value-changed',
1127                             self.__application_treeview_vadjustment_changed, None)
1128                         vadj = self.w_categories_treeview.get_vadjustment()
1129                         vadj.connect('value-changed',
1130                             self.__categories_treeview_vadjustment_changed, None)
1131 
1132                         # When the size of the application_treeview changes
1133                         # we need to set image descriptions on visible status icons.
1134                         self.w_application_treeview.connect('size-allocate',
1135                             self.__application_treeview_size_allocate, None)
1136                         self.w_categories_treeview.connect('size-allocate',
1137                             self.__categories_treeview_size_allocate, None)
1138 
1139                 if category_list != None:
1140                         ##CATEGORIES TREEVIEW
1141                         #enumerations.CATEGORY_NAME
1142                         category_list_filter = category_list.filter_new()
1143                         column =  self.__create_icon_column("", False,
1144                             enumerations.CATEGORY_ICON, False)
1145                         self.w_categories_treeview.append_column(column)
1146                         enumerations.CATEGORY_NAME_renderer = gtk.CellRendererText()
1147                         column = gtk.TreeViewColumn(_('Name'),
1148                             enumerations.CATEGORY_NAME_renderer,
1149                             text = enumerations.CATEGORY_NAME)
1150                         self.w_categories_treeview.append_column(column)
1151                         #Added selection listener
1152                         category_selection = self.w_categories_treeview.get_selection()
1153                         category_selection.set_mode(gtk.SELECTION_SINGLE)
1154 
1155                 if self.first_run:
1156                         ##SECTION COMBOBOX
1157                         #enumerations.SECTION_NAME
1158                         cell = gtk.CellRendererText()
1159                         self.w_sections_combobox.pack_start(cell, True)
1160                         self.w_sections_combobox.add_attribute(cell, 'text',
1161                             enumerations.SECTION_NAME)
1162                         self.w_sections_combobox.set_row_separator_func(
1163                             self.combobox_id_separator)
1164                         self.w_sections_combobox.add_attribute( cell,
1165                             'sensitive', enumerations.SECTION_ENABLED )
1166                         ##FILTER COMBOBOX
1167                         #enumerations.FILTER_NAME
1168                         cell = gtk.CellRendererText()
1169                         self.w_filter_combobox.pack_start(cell, True)
1170                         self.w_filter_combobox.add_attribute(cell, 'text',
1171                             enumerations.FILTER_NAME)
1172                         self.w_filter_combobox.set_row_separator_func(
1173                             self.combobox_id_separator)
1174 
1175                 if section_list != None:
1176                         self.section_list = section_list
1177                 if category_list != None:
1178                         self.category_list = category_list
1179                         self.category_list_filter = category_list_filter
1180                         self.w_categories_treeview.set_model(category_list_filter)
1181                         if not self.is_search_all:
1182                                 category_list_filter.set_visible_func(
1183                                     self.category_filter)
1184                                 self.__set_categories_visibility(self.set_section)
1185                         self.a11y_categories_treeview = \
1186                             self.w_categories_treeview.get_accessible()
1187                 if application_list != None:
1188                         if category_list != None:
1189                                 self.w_sections_combobox.set_model(section_list)
1190                                 self.w_sections_combobox.set_active(self.set_section)
1191                                 self.w_filter_combobox.set_model(self.filter_list)
1192                                 self.w_filter_combobox.set_active(self.set_show_filter)
1193                         self.w_application_treeview.set_model(
1194                             self.application_list_sort)
1195                         if not self.in_search_mode:
1196                                 if application_list_filter == None:
1197                                         self.application_list_filter.set_visible_func(
1198                                             self.__application_filter)
1199 
1200                 category_selection = self.w_categories_treeview.get_selection()
1201                 category_model, category_iter = category_selection.get_selected()
1202                 self.pylintstub = category_model
1203                 if not category_iter and not self.in_search_mode:
1204                 #no category was selected, so select "All"
1205                         category_selection.select_path(0)
1206                         category_model, category_iter = category_selection.get_selected()
1207                 if self.first_run:
1208                         category_selection.connect("changed",
1209                             self.__on_category_selection_changed, None)
1210                         self.w_categories_treeview.connect("row-activated",
1211                             self.__on_category_row_activated, None)
1212                         self.w_categories_treeview.connect("focus-in-event",
1213                             self.__on_category_focus_in, None)
1214                         self.package_selection.set_mode(gtk.SELECTION_SINGLE)
1215                         self.package_selection.connect("changed",
1216                             self.__on_package_selection_changed, None)
1217 
1218                 self.a11y_application_treeview = \
1219                     self.w_application_treeview.get_accessible()
1220                 self.process_package_list_end()
1221 
1222         def __categories_treeview_size_allocate(self, widget, allocation, user_data):
1223                 # We ignore any changes in the size during initialization.
1224                 if self.categories_treeview_initialized:
1225                         if self.categories_status_id == 0:
1226                                 self.categories_status_id = gobject.idle_add(
1227                                     self.__set_accessible_categories_visible_status)
1228 
1229         def __categories_treeview_vadjustment_changed(self, widget, user_data):
1230                 self.__set_accessible_categories_visible_status()
1231 
1232         def __set_accessible_categories_status(self, model, itr):
1233                 status = model.get_value(itr, enumerations.CATEGORY_ICON)
1234                 if status != None:
1235                         desc = _("Updates Available")
1236                 else:
1237                         desc = None
1238                 if desc != None:
1239                         obj = self.a11y_categories_treeview.ref_at(
1240                             int(model.get_string_from_iter(itr)),
1241                             CATEGORIES_STATUS_COLUMN_INDEX)
1242                         obj.set_image_description(desc)
1243 
1244         def __set_accessible_categories_visible_status(self):
1245                 self.categories_status_id = 0
1246                 if self.a11y_categories_treeview.get_n_accessible_children() == 0:
1247                         # accessibility is not enabled
1248                         return
1249 
1250                 visible_range = self.w_categories_treeview.get_visible_range()
1251                 if visible_range == None:
1252                         return
1253                 start = visible_range[0][0]
1254                 end = visible_range[1][0]
1255                 # We try to minimize the range of accessible objects
1256                 # on which we set image descriptions
1257                 if self.categories_treeview_range != None:
1258                         old_start = self.categories_treeview_range[0][0]
1259                         old_end = self.categories_treeview_range[1][0]
1260                          # Old range is the same or smaller than new range
1261                          # so do nothing
1262                         if start >= old_start and end <= old_end:
1263                                 return
1264                         if start < old_end:
1265                                 if end < old_end:
1266                                         if end >= old_start:
1267                                                 end = old_start
1268                                 else:
1269                                         start = old_end
1270                 self.categories_treeview_range = visible_range
1271                 model = self.category_list_filter
1272                 itr = model.get_iter_from_string(str(start))
1273                 while start <= end:
1274                         start += 1
1275                         self.__set_accessible_categories_status(model, itr)
1276                         itr = model.iter_next(itr)
1277 
1278         def __application_treeview_column_sorted(self, widget, user_data):
1279                 self.__set_visible_status(False)
1280 
1281         def __init_repository_tree_view(self):
1282                 cell = gtk.CellRendererText()
1283                 self.w_repository_combobox.pack_start(cell, True)
1284                 self.w_repository_combobox.add_attribute(cell, 'text',
1285                     enumerations.REPOSITORY_NAME)
1286                 self.w_repository_combobox.set_row_separator_func(
1287                     self.combobox_id_separator)
1288 
1289         def __application_treeview_size_allocate(self, widget, allocation, user_data):
1290                 # We ignore any changes in the size during initialization.
1291                 if self.visible_status_id == 0:
1292                         self.visible_status_id = gobject.idle_add(
1293                             self.__set_visible_status)
1294 
1295         def __application_treeview_vadjustment_changed(self, widget, user_data):
1296                 self.__set_visible_status()
1297 
1298         def __set_accessible_status(self, model, itr):
1299                 status = model.get_value(itr, enumerations.STATUS_COLUMN)
1300                 if status == enumerations.INSTALLED:
1301                         desc = _("Installed")
1302                 elif status == enumerations.NOT_INSTALLED:
1303                         desc = _("Not Installed")
1304                 elif status == enumerations.UPDATABLE:
1305                         desc = _("Updates Available")
1306                 else:
1307                         desc = None
1308                 if desc != None:
1309                         obj = self.a11y_application_treeview.ref_at(
1310                             int(model.get_string_from_iter(itr)),
1311                             STATUS_COLUMN_INDEX)
1312                         obj.set_image_description(desc)
1313 
1314         def __set_visible_status(self, check_range = True):
1315                 self.visible_status_id = 0
1316                 if self.w_main_view_notebook.get_current_page() != \
1317                     NOTEBOOK_PACKAGE_LIST_PAGE:
1318                         return
1319                 a11y_enabled = False
1320                 if self.a11y_application_treeview.get_n_accessible_children() != 0:
1321                         a11y_enabled = True
1322 
1323                 visible_range = self.w_application_treeview.get_visible_range()
1324                 if visible_range == None:
1325                         return
1326                 start = visible_range[0][0]
1327                 end = visible_range[1][0]
1328                 if debug_descriptions:
1329                         print "Range Start: %d End: %d" % (start, end)
1330 
1331                 # Switching Publishers need to use default range
1332                 active_pub = self.__get_active_publisher()
1333                 if self.last_active_publisher != active_pub:
1334                         check_range = False
1335                 self.last_active_publisher = active_pub
1336                 if self.in_search_mode:
1337                         check_range = False
1338                 
1339                 if self.application_treeview_range != None:
1340                         if check_range:
1341                                 old_start = self.application_treeview_range[0][0]
1342                                 old_end = self.application_treeview_range[1][0]
1343                                  # Old range is the same or smaller than new range
1344                                  # so do nothing
1345                                 if start >= old_start and end <= old_end:
1346                                         return
1347                                 if start < old_end:
1348                                         if end < old_end:
1349                                                 if end >= old_start:
1350                                                         end = old_start
1351                                         else:
1352                                                 start = old_end
1353                 if debug_descriptions:
1354                         print "Adjusted Range Start: %d End: %d" % (start, end)
1355                 self.application_treeview_range = visible_range
1356 
1357                 sort_filt_model = \
1358                     self.w_application_treeview.get_model() #gtk.TreeModelSort
1359                 filt_model = sort_filt_model.get_model() #gtk.TreeModelFilter
1360                 model = filt_model.get_model() #gtk.ListStore
1361                 sf_itr = sort_filt_model.get_iter_from_string(str(start))                
1362                 pkg_stems_and_itr_to_fetch = {}
1363                 while start <= end:
1364                         filtered_itr = sort_filt_model.convert_iter_to_child_iter(None,
1365                             sf_itr)
1366                         app_itr = filt_model.convert_iter_to_child_iter(filtered_itr)
1367 
1368                         desc = sort_filt_model.get_value(sf_itr,
1369                             enumerations.DESCRIPTION_COLUMN)
1370                         # Only Fetch description for packages without a
1371                         # description
1372                         if desc == '...':
1373                                 fmri = sort_filt_model.get_value(sf_itr,
1374                                     enumerations.FMRI_COLUMN)
1375                                 pkg_stem = fmri.get_pkg_stem(
1376                                     include_scheme = True)
1377                                 pkg_stems_and_itr_to_fetch[pkg_stem] = \
1378                                     model.get_string_from_iter(app_itr)
1379                         if a11y_enabled:
1380                                 self.__set_accessible_status(sort_filt_model, sf_itr)
1381                         start += 1
1382                         sf_itr = sort_filt_model.iter_next(sf_itr)
1383 
1384                 if debug_descriptions:
1385                         print "PKGS to FETCH: \n%s" % pkg_stems_and_itr_to_fetch
1386                 if len(pkg_stems_and_itr_to_fetch) > 0:
1387                         Thread(target = self.__get_pkg_descriptions,
1388                             args = [pkg_stems_and_itr_to_fetch, model]).start() 
1389                     
1390         def __doing_search(self):
1391                 return self.search_start > 0
1392                 
1393         def __get_pkg_descriptions(self, pkg_stems_and_itr_to_fetch, orig_model):
1394                 # Note: no need to aquire lock even though this can be called from
1395                 # multiple threads, it is just creating an update job and dispatching it
1396                 # to the idle handler, not modifying any global state
1397                 info = None
1398                 if not self.__doing_search():
1399                         gobject.idle_add(self.__update_statusbar_message,
1400                             _("Fetching descriptions..."))
1401                 try:
1402                         info = self.api_o.info(pkg_stems_and_itr_to_fetch.keys(), False,
1403                                 frozenset([api.PackageInfo.IDENTITY,
1404                                     api.PackageInfo.SUMMARY]))
1405                 except api_errors.TransportError:
1406                         self.update_statusbar()
1407                         return
1408                 if info and len(info.get(0)) == 0:
1409                         self.update_statusbar()
1410                         return
1411                 pkg_infos = info.get(0)
1412                 pkg_descriptions_for_update = []
1413                 for pkg_info in pkg_infos:
1414                         short_fmri = fmri.PkgFmri(pkg_info.fmri).get_pkg_stem(
1415                             include_scheme = True)
1416                         pkg_descriptions_for_update.append((short_fmri,
1417                             pkg_stems_and_itr_to_fetch[short_fmri],
1418                             pkg_info.summary))
1419                 if debug_descriptions:
1420                         print "FETCHED PKGS: \n%s" % pkg_descriptions_for_update
1421                 gobject.idle_add(self.__update_description_from_iter,
1422                     pkg_descriptions_for_update, orig_model)
1423 
1424         def __update_description_from_iter(self, pkg_descriptions_for_update, orig_model):
1425                 sort_filt_model = \
1426                     self.w_application_treeview.get_model() #gtk.TreeModelSort
1427                 filt_model = sort_filt_model.get_model() #gtk.TreeModelFilter
1428                 model = filt_model.get_model() #gtk.ListStore
1429 
1430                 #If model has changed abandon description updates
1431                 if orig_model != model:
1432                         return
1433 
1434                 if debug_descriptions:
1435                         print "UPDATE DESCRIPTIONS: \n%s" % pkg_descriptions_for_update
1436                 for pkg_stem, path, summary in pkg_descriptions_for_update:
1437                         itr = model.get_iter_from_string(path)
1438                         stored_pkg_fmri = model.get_value(itr, enumerations.FMRI_COLUMN)
1439                         stored_pkg_stem = stored_pkg_fmri.get_pkg_stem(
1440                             include_scheme = True)
1441 
1442                         if pkg_stem != stored_pkg_stem:
1443                                 if debug:
1444                                         print ("__update_description_from_iter(): "
1445                                             "model not consistent so abandoning "
1446                                             "these description updates.")
1447                                 self.update_statusbar()
1448                                 return
1449                         model.set_value(itr, enumerations.DESCRIPTION_COLUMN, summary)
1450                 if not self.__doing_search():
1451                         self.update_statusbar()
1452 
1453         def __create_icon_column(self, name, expand_pixbuf, enum_value, set_data_func):
1454                 column = gtk.TreeViewColumn()
1455                 column.set_title(name)
1456                 #Commented, since there was funny jumping of the icons
1457                 #column.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
1458                 render_pixbuf = gtk.CellRendererPixbuf()
1459                 column.pack_start(render_pixbuf, expand = expand_pixbuf)
1460                 column.add_attribute(render_pixbuf, "pixbuf", enum_value)
1461                 column.set_fixed_width(32)
1462                 if set_data_func:
1463                         column.set_cell_data_func(render_pixbuf,
1464                             self.cell_data_function, None)
1465                 return column
1466 
1467         def __disconnect_models(self):
1468                 self.w_application_treeview.set_model(None)
1469                 self.w_categories_treeview.set_model(None)
1470                 self.w_sections_combobox.set_model(None)
1471                 self.w_filter_combobox.set_model(None)
1472 
1473         def __disconnect_repository_model(self):
1474                 self.w_repository_combobox.set_model(None)
1475 
1476         @staticmethod
1477         def __status_sort_func(treemodel, iter1, iter2, user_data=None):
1478                 get_val = treemodel.get_value
1479                 status1 = get_val(iter1, enumerations.STATUS_COLUMN)
1480                 status2 = get_val(iter2, enumerations.STATUS_COLUMN)
1481                 return cmp(status1, status2)
1482 
1483         @staticmethod
1484         def __remove_treeview_columns(treeview):
1485                 columns = treeview.get_columns()
1486                 if columns:
1487                         for column in columns:
1488                                 treeview.remove_column(column)
1489 
1490         @staticmethod
1491         def __init_sections(section_list):
1492                 '''This function is for initializing sections combo box, also adds "All"
1493                 Category. It sets active section combobox entry "All"'''
1494                 cat_path = None
1495                 enabled = True
1496                 # We enable only first section and later we might enable the rest,
1497                 # depending if there are some packages connected with them
1498                 section_list.append([0, _('All Categories'), cat_path, enabled ])
1499                 section_list.append([-1, "", cat_path, enabled ])
1500                 enabled = False
1501                 section_list.append([2, _('Meta Packages'), cat_path, enabled ])
1502                 section_list.append([3, _('Applications'), cat_path, enabled ])
1503                 section_list.append([4, _('Desktop (GNOME)'), cat_path, enabled ])
1504                 section_list.append([5, _('Development'), cat_path, enabled ])
1505                 section_list.append([6, _('Distributions'), cat_path, enabled ])
1506                 section_list.append([7, _('Drivers'), cat_path, enabled ])
1507                 section_list.append([8, _('System'), cat_path, enabled ])
1508                 section_list.append([9, _('Web Services'), cat_path, enabled ])
1509 
1510         def __init_show_filter(self):
1511                 self.filter_list.append([enumerations.FILTER_ALL, _('All Packages'), ])
1512                 self.filter_list.append([enumerations.FILTER_INSTALLED,
1513                     _('Installed Packages'), ])
1514                 self.filter_list.append([enumerations.FILTER_UPDATES,
1515                     _('Updates'), ])
1516                 self.filter_list.append([enumerations.FILTER_NOT_INSTALLED,
1517                     _('Non-installed Packages'), ])
1518                 self.filter_list.append([-1, "", ])
1519                 self.filter_list.append([enumerations.FILTER_SELECTED,
1520                     _('Selected Packages'), ])
1521                 if self.initial_show_filter >= enumerations.FILTER_ALL and \
1522                     self.initial_show_filter < len(self.filter_list):
1523                         row = self.filter_list[self.initial_show_filter]
1524                         if row[enumerations.SECTION_ID] != self.initial_show_filter:
1525                                 self.initial_show_filter = enumerations.FILTER_ALL
1526                 else:
1527                         self.initial_show_filter = enumerations.FILTER_ALL
1528 
1529 
1530         def __on_cancel_progressdialog_clicked(self, widget):
1531                 self.progress_canceled = True
1532                 self.progress_stop_timer_thread = True
1533 
1534         def __on_mainwindow_delete_event(self, widget, event):
1535                 ''' handler for delete event of the main window '''
1536                 if self.__check_if_something_was_changed() == True:
1537                         # XXX Change this to not quit and show dialog
1538                         # XXX if some changes were applied:
1539                         self.__main_application_quit()
1540                         return True
1541                 else:
1542                         self.__main_application_quit()
1543 
1544         def __on_api_search_error_delete_event(self, widget, event):
1545                 self.__on_api_search_button_clicked(None)
1546 
1547         def __on_api_search_button_clicked(self, widget):
1548                 self.api_search_error_dialog.hide()
1549 
1550         def __on_file_quit_activate(self, widget):
1551                 ''' handler for quit menu event '''
1552                 self.__on_mainwindow_delete_event(None, None)
1553 
1554         def __on_ua_completed_close(self, widget):
1555                 self.w_ua_completed_dialog.hide()
1556                 self.__on_mainwindow_delete_event(None, None)
1557 
1558         def __on_edit_repositories_activate(self, widget):
1559                 ''' handler for repository menu event '''
1560                 repository.Repository(self)
1561 
1562         def __on_file_be_activate(self, widget):
1563                 ''' handler for be menu event '''
1564                 beadm.Beadmin(self)
1565 
1566         def __on_searchentry_changed(self, widget):
1567                 if widget.get_text_length() > 0:
1568                         self.w_clear_search_button.set_sensitive(True)
1569                 else:
1570                         self.w_clear_search_button.set_sensitive(False)
1571                 self.__enable_disable_entry_selection(widget)
1572                 if self.is_search_all and not self.changing_search_option:
1573                         if self.w_searchentry.get_text() == "":
1574                                 self.w_infosearch_frame.hide()
1575                                 self.__link_load_blank()
1576                                 self.w_main_view_notebook.set_current_page(
1577                                     NOTEBOOK_START_PAGE)
1578                                 self.__update_statusbar_for_search()
1579                                 self.w_searchentry.grab_focus()
1580 
1581         def __update_statusbar_for_search(self):
1582                 self.__update_statusbar_message(
1583                     self.search_options[self.current_search_option][3])
1584 
1585         def __update_statusbar_message(self, message):
1586                 if self.statusbar_message_id > 0:
1587                         self.w_main_statusbar.remove(0, self.statusbar_message_id)
1588                         self.statusbar_message_id = 0
1589                 self.statusbar_message_id = self.w_main_statusbar.push(0, message)
1590 
1591         def __setup_before_search_all_mode(self):
1592                 self.is_search_all = True
1593                 self.w_infosearch_frame.hide()
1594 
1595                 self.__save_setup_before_search()
1596                 self.w_repository_combobox.set_active(0)
1597                 self.__link_load_blank()
1598                 self.w_main_view_notebook.set_current_page(
1599                     NOTEBOOK_START_PAGE)
1600                 self.__update_statusbar_for_search()
1601                 self.w_searchentry.grab_focus()
1602                 if len(self.w_searchentry.get_text()) > 0:
1603                         start, end = self.w_searchentry.get_selection_bounds()
1604                         self.w_searchentry.select_region(end, end)
1605                 self.__unselect_category()
1606 
1607         def __clear_before_search(self):
1608                 self.in_setup = True
1609                 application_list = self.__get_new_application_liststore()
1610                 self.__set_empty_details_panel()
1611                 self.__set_main_view_package_list()
1612                 self.__init_tree_views(application_list, None, None)
1613                 self.__unselect_category()
1614 
1615         def __restore_setup_for_browse(self):
1616                 self.in_search_mode = False
1617                 self.is_search_all = False
1618                 self.w_infosearch_frame.hide()
1619 
1620                 self.set_busy_cursor()
1621                 self.w_repository_combobox.set_active(
1622                     self.saved_repository_combobox_active)
1623                 self.set_section = self.saved_sections_combobox_active
1624                 self.set_show_filter = self.saved_filter_combobox_active
1625                 if self.saved_category_list == self.category_list:
1626                         self.__init_tree_views(self.saved_application_list,
1627                             None, None,
1628                             self.saved_application_list_filter,
1629                             self.saved_application_list_sort)
1630                 else:
1631                         self.__init_tree_views(self.saved_application_list,
1632                             self.saved_category_list, self.saved_section_list,
1633                             self.saved_application_list_filter,
1634                             self.saved_application_list_sort)
1635                         
1636                 self.__set_main_view_package_list()
1637 
1638         def __save_setup_before_search(self, single_search=False):
1639                 #Do not save search data models
1640                 if self.in_search_mode:
1641                         return
1642                 self.saved_sections_combobox_active = \
1643                         self.w_sections_combobox.get_active()
1644                 self.saved_filter_combobox_active = \
1645                         self.w_filter_combobox.get_active()                        
1646                 self.saved_application_list = self.application_list
1647                 self.saved_application_list_sort = \
1648                         self.application_list_sort
1649                 self.saved_application_list_filter = \
1650                         self.application_list_filter
1651                 self.saved_category_list = self.category_list
1652                 self.saved_section_list = self.section_list
1653                 if single_search:
1654                         self.saved_repository_combobox_active = \
1655                                 self.w_repository_combobox.get_active()
1656                 self.w_filter_combobox.set_active(0)
1657 
1658         def __do_search(self):
1659                 self.search_start = 0
1660                 if self.changing_search_option:
1661                         return
1662                 active = self.w_filter_combobox.get_active()
1663                 if active != enumerations.FILTER_SELECTED:
1664                         self.saved_filter_combobox_active = active                        
1665                 if len(self.w_searchentry.get_text()) == 0:
1666                         return
1667                 if not self.is_search_all:
1668                         self.__save_setup_before_search(single_search=True)
1669                 self.__clear_before_search()
1670                 self.set_busy_cursor()
1671                 self.in_search_mode = True
1672                         
1673                 self.w_infosearch_frame.hide()
1674                 self.__update_statusbar_message(_("Searching..."))
1675                 if not self.is_search_all:
1676                         Thread(target = self.__do_api_search,
1677                             args = (self.is_search_all, )).start()
1678                 else:
1679                         Thread(target = self.__do_api_search,
1680                             args = ()).start()
1681 
1682         def __unselect_category(self):
1683                 selection = self.w_categories_treeview.get_selection()
1684                 model, itr = selection.get_selected()
1685                 if itr:
1686                         cat_path = model.get_string_from_iter(itr)
1687                         selected_section = self.w_sections_combobox.get_active()
1688                         section_row = self.section_list[selected_section]
1689                         section_row[enumerations.SECTION_SUBCATEGORY] = cat_path
1690                         selection.unselect_all()
1691 
1692         def __process_after_search_failure(self):
1693                 self.search_start = 0
1694                 self.search_time_sec = 0
1695                 self.application_list = []
1696                 self.update_statusbar()
1697                 self.unset_busy_cursor()
1698                 self.in_setup = False
1699 
1700         def __get_origin_uri(self, repo):
1701                 if repo == None:
1702                         return None
1703                 origin_uri = repo.origins[0]
1704                 ret_uri = None
1705                 if isinstance(origin_uri, str):
1706                         if len(origin_uri) > 0:
1707                                 ret_uri = origin_uri.strip("/")
1708                 elif isinstance(origin_uri, publisher.RepositoryURI):
1709                         uri = origin_uri.uri
1710                         if uri != None and len(uri) > 0:
1711                                 ret_uri = uri.strip("/")
1712                 return ret_uri
1713 
1714 
1715         def __do_api_search(self, search_all = True):
1716                 self.search_start = time.time()
1717                 self.search_time_sec = 0
1718                 text = self.w_searchentry.get_text()
1719                 # Here we call the search API to get the results
1720                 searches = []
1721                 servers = []
1722                 result = []
1723                 pargs = []
1724                 search_str = SEARCH_STR_FORMAT % text
1725                 pargs.append(search_str)
1726                 if search_all:
1727                         servers = None
1728                 else:
1729                         pub_prefix = self.__get_active_publisher()
1730                         if pub_prefix != None:
1731                                 pub = self.api_o.get_publisher(prefix=pub_prefix)
1732                         else:
1733                                 pub = self.api_o.get_preferred_publisher()
1734                         origin_uri = self.__get_origin_uri(pub.selected_repository)
1735                         servers.append({"origin": origin_uri})
1736                 if debug:
1737                         print "pargs:", pargs
1738                         print "servers:", servers
1739                         
1740                 case_sensitive = False
1741                 searches.append(self.api_o.remote_search(
1742                     [api.Query(" ".join(pargs), case_sensitive, True, None, None)],
1743                     servers=servers))
1744                 result_tuple = {}
1745                 try:
1746                         for query_num, publisher, (v, return_type, tmp) in \
1747                             itertools.chain(*searches):
1748                                 if v == 1 and \
1749                                     return_type == api.Query.RETURN_PACKAGES:
1750                                         repo = None
1751                                         if publisher is not None \
1752                                             and "prefix" in publisher:
1753                                                 repo = publisher["prefix"]
1754                                         name = fmri.PkgFmri(str(tmp)).get_name()
1755                                         result_tuple[(name, repo)] = -1
1756                                         if len(result_tuple) == SEARCH_LIMIT:
1757                                                 break
1758                                 else:
1759                                         # We are not interested in this error
1760                                         gobject.idle_add(self.w_progress_dialog.hide)
1761                                         self.__process_after_search_failure()
1762                                         return
1763                                 self.pylintstub = query_num
1764                 except api_errors.ProblematicSearchServers, ex:
1765                         self.__parse_api_search_error(ex)
1766                         gobject.idle_add(self.w_progress_dialog.hide)
1767                         gobject.idle_add(self.__handle_api_search_error)
1768                         if len(result_tuple) == 0:
1769                                 self.__process_after_search_with_zero_results()
1770                                 return
1771                 except Exception, ex:
1772                         # We are not interested in this error
1773                         gobject.idle_add(self.w_progress_dialog.hide)
1774                         self.__process_after_search_failure()
1775                         return
1776                 if debug:
1777                         print "Number of search results:", len(result_tuple)
1778                 for name, repo in result_tuple:
1779                         a_res = name, repo
1780                         result.append(a_res)
1781                 if len(result) == 0:
1782                         if debug:
1783                                 print "No search results"
1784                         self.__process_after_search_with_zero_results()
1785                         return
1786                 # We cannot get status of the packages if catalogs have not
1787                 # been loaded so we pause for up to 5 seconds here to
1788                 # allow catalogs to be loaded
1789                 times = 5
1790                 while self.catalog_loaded == False:
1791                         if times == 0:
1792                                 break
1793                         time.sleep(1)
1794                         times -= 1
1795                 self.in_setup = True
1796                 application_list = self.__get_list_from_search(result)
1797                 if self.search_start > 0:
1798                         self.search_time_sec = int(time.time() - self.search_start)
1799                 self.search_start = 0
1800                 gobject.idle_add(self.__set_empty_details_panel)
1801                 gobject.idle_add(self.__set_main_view_package_list)
1802                 gobject.idle_add(self.__init_tree_views, application_list,
1803                     None, None)
1804 
1805         def __process_after_search_with_zero_results(self):
1806                 if self.search_start > 0:
1807                         self.search_time_sec = int(time.time() - self.search_start)
1808                 self.search_start = 0
1809                 self.in_setup = True
1810                 application_list = self.__get_new_application_liststore()
1811                 gobject.idle_add(self.__set_empty_details_panel)
1812                 gobject.idle_add(self.__set_main_view_package_list)
1813                 gobject.idle_add(self.__init_tree_views, application_list, None, None)
1814 
1815         def __get_list_from_search(self, search_result):
1816                 application_list = self.__get_new_application_liststore()
1817                 self.__add_pkgs_to_list_from_search(search_result,
1818                     application_list)
1819                 return application_list
1820 
1821         def __add_pkgs_to_list_from_search(self, search_result,
1822             application_list):
1823                 pargs = []
1824                 default_pub = self.api_o.get_preferred_publisher().prefix
1825                 for name, publisher in search_result:
1826                         pargs.append("pkg://" + publisher + "/" + name)
1827                 # We now need to get the status for each package
1828                 if debug_descriptions:
1829                         print "pargs:", pargs
1830                 try:
1831                         pkgs_known = self.__get_inventory_list(pargs,
1832                             True, True)
1833                 except api_errors.InventoryException:
1834                         # This can happen if load_catalogs has not been run
1835                         err = _("Unable to get status for search results.\n"
1836                             "The catalogs have not been loaded.\n"
1837                             "Please try after few seconds.\n")
1838                         gobject.idle_add(self.w_progress_dialog.hide)
1839                         gobject.idle_add(self.error_occurred, err)
1840                         return
1841                 return self.__add_pkgs_to_lists(pkgs_known, application_list,
1842                     None, None)
1843 
1844         def __application_refilter(self):
1845                 ''' Disconnecting the model from the treeview improves
1846                 performance when assistive technologies are enabled'''
1847                 if self.in_setup:
1848                         return
1849                 self.application_refilter_id = 0
1850                 self.application_refilter_idle_id = 0
1851                 if not self.in_search_mode:
1852                         model = self.w_application_treeview.get_model()
1853                         self.w_application_treeview.set_model(None)
1854                         self.application_list_filter.refilter()
1855                         self.w_application_treeview.set_model(model)
1856                 gobject.idle_add(self.__set_empty_details_panel)
1857                 gobject.idle_add(self.__enable_disable_selection_menus)
1858                 gobject.idle_add(self.__enable_disable_install_remove)
1859                 self.application_treeview_initialized = True
1860                 self.application_treeview_range = None
1861                 if self.visible_status_id == 0:
1862                         self.visible_status_id = gobject.idle_add(
1863                             self.__set_visible_status)
1864                 self.categories_treeview_initialized = True
1865                 self.categories_treeview_range = None
1866                 if self.categories_status_id == 0:
1867                         self.categories_status_id = gobject.idle_add(
1868                             self.__set_accessible_categories_visible_status)
1869                 return False
1870 
1871         def __on_edit_paste(self, widget):
1872                 self.w_searchentry.paste_clipboard()
1873 
1874         def __on_clear_paste(self, widget):
1875                 bounds = self.w_searchentry.get_selection_bounds()
1876                 self.w_searchentry.delete_text(bounds[0], bounds[1])
1877                 return
1878 
1879         def __on_copy(self, widget):
1880                 focus_widget = self.w_main_window.get_focus()
1881                 if focus_widget == self.w_searchentry:
1882                         self.w_searchentry.copy_clipboard()
1883                         self.w_paste_menuitem.set_sensitive(True)
1884                 elif self.__is_a_textview(focus_widget):
1885                         focus_widget.get_buffer().copy_clipboard(
1886                             self.w_main_clipboard)
1887 
1888         def __on_cut(self, widget):
1889                 self.w_searchentry.cut_clipboard()
1890                 self.w_paste_menuitem.set_sensitive(True)
1891 
1892         def __popup_position_func(self, menu):
1893                 ''' Position popup menu immediately below search button'''
1894                 root = self.w_main_window.window.get_origin()
1895                 alloc = self.search_button.get_allocation()
1896                 return (root[0] + alloc.x, root[1] + alloc.y + alloc.height, False)
1897 
1898         def __on_set_search(self, widget, event):
1899                 if  event.type == gtk.gdk.BUTTON_PRESS:
1900                         self.searchmenu.popup(None, None, self.__popup_position_func,
1901                             event.button, event.time)
1902                         return True
1903                 return False
1904 
1905         def __on_set_search_clicked(self, widget):
1906                 self.searchmenu.popup(None, None, self.__popup_position_func,
1907                     0, 0)
1908                 return True
1909 
1910         def __on_edit_search_clicked(self, widget):
1911                 self.w_searchentry.grab_focus()
1912 
1913         def __on_clear_search(self, widget):
1914                 self.w_searchentry.delete_text(0, -1)
1915                 self.__do_search()
1916                 return
1917 
1918         def __on_startpage(self, widget):
1919                 self.__load_startpage()
1920                 self.w_main_view_notebook.set_current_page(NOTEBOOK_START_PAGE)
1921 
1922         def __on_notebook_change(self, widget, event, pagenum):
1923                 if (pagenum == INFO_NOTEBOOK_LICENSE_PAGE and 
1924                     not self.showing_empty_details):
1925                         licbuffer = self.w_license_textview.get_buffer()
1926                         leg_txt = _("Fetching legal information...")
1927                         licbuffer.set_text(leg_txt)
1928                         if self.show_licenses_id != 0:
1929                                 gobject.source_remove(self.show_licenses_id)
1930                                 self.show_licenses_id = 0
1931                         self.last_show_licenses_id = self.show_licenses_id = \
1932                             gobject.timeout_add(SHOW_LICENSE_DELAY,
1933                                 self.__show_licenses)
1934 
1935         def __is_a_textview(self, widget):
1936                 if (widget == self.w_generalinfo_textview or
1937                     widget == self.w_installedfiles_textview or
1938                     widget == self.w_dependencies_textview or
1939                     widget == self.w_license_textview):
1940                         return True
1941                 else:
1942                         return False
1943                     
1944                     
1945         def __on_select_all(self, widget):
1946                 focus_widget = self.w_main_window.get_focus()
1947                 if self.__is_a_textview(focus_widget):
1948                         focus_widget.emit('select-all', True)
1949                         self.w_selectall_menuitem.set_sensitive(False)
1950                         self.w_deselect_menuitem.set_sensitive(True)
1951                         return
1952                 elif focus_widget == self.w_searchentry:
1953                         focus_widget.select_region(0, -1)
1954                         self.w_selectall_menuitem.set_sensitive(False)
1955                         self.w_deselect_menuitem.set_sensitive(True)
1956                         return
1957 
1958                 sort_filt_model = \
1959                     self.w_application_treeview.get_model() #gtk.TreeModelSort
1960                 filt_model = sort_filt_model.get_model() #gtk.TreeModelFilter
1961                 model = filt_model.get_model() #gtk.ListStore
1962                 iter_next = sort_filt_model.get_iter_first()
1963                 list_of_paths = []
1964                 while iter_next != None:
1965                         sorted_path = sort_filt_model.get_path(iter_next)
1966                         filtered_path = \
1967                             sort_filt_model.convert_path_to_child_path(sorted_path)
1968                         path = filt_model.convert_path_to_child_path(filtered_path)
1969                         list_of_paths.append(path)
1970                         iter_next = sort_filt_model.iter_next(iter_next)
1971                 for path in list_of_paths:
1972                         itr = model.get_iter(path)
1973                         already_marked = model.get_value(itr, enumerations.MARK_COLUMN)
1974                         if not already_marked:
1975                                 model.set_value(itr, enumerations.MARK_COLUMN, True)
1976                                 pkg_stem = model.get_value(itr,
1977                                     enumerations.STEM_COLUMN)
1978                                 pkg_status = model.get_value(itr,
1979                                     enumerations.STATUS_COLUMN)
1980                                 self.__add_pkg_stem_to_list(pkg_stem, pkg_status)
1981                 self.w_selectall_menuitem.set_sensitive(False)
1982                 self.w_deselect_menuitem.set_sensitive(True)
1983                 self.__enable_disable_selection_menus()
1984                 self.update_statusbar()
1985                 self.__enable_disable_install_remove()
1986 
1987         def __on_select_updates(self, widget):
1988                 sort_filt_model = \
1989                     self.w_application_treeview.get_model() #gtk.TreeModelSort
1990                 filt_model = sort_filt_model.get_model() #gtk.TreeModelFilter
1991                 model = filt_model.get_model() #gtk.ListStore
1992                 iter_next = sort_filt_model.get_iter_first()
1993                 list_of_paths = []
1994                 while iter_next != None:
1995                         sorted_path = sort_filt_model.get_path(iter_next)
1996                         filtered_iter = sort_filt_model.convert_iter_to_child_iter(None, \
1997                             iter_next)
1998                         app_iter = filt_model.convert_iter_to_child_iter(filtered_iter)
1999 
2000                         filtered_path = \
2001                             sort_filt_model.convert_path_to_child_path(sorted_path)
2002                         path = filt_model.convert_path_to_child_path(filtered_path)
2003                         if model.get_value(app_iter, \
2004                             enumerations.STATUS_COLUMN) == enumerations.UPDATABLE:
2005                                 list_of_paths.append(path)
2006                         iter_next = sort_filt_model.iter_next(iter_next)
2007                 for path in list_of_paths:
2008                         itr = model.get_iter(path)
2009                         model.set_value(itr, enumerations.MARK_COLUMN, True)
2010                         pkg_stem = model.get_value(itr, enumerations.STEM_COLUMN)
2011                         pkg_status = model.get_value(itr, enumerations.STATUS_COLUMN)
2012                         self.__add_pkg_stem_to_list(pkg_stem, pkg_status)
2013                 self.__enable_disable_selection_menus()
2014                 self.update_statusbar()
2015                 self.__enable_disable_install_remove()
2016 
2017         def __on_deselect(self, widget):
2018                 focus_widget = self.w_main_window.get_focus()
2019                 if self.__is_a_textview(focus_widget):
2020                         focus_widget.emit('select-all', False)
2021                         self.w_deselect_menuitem.set_sensitive(False)
2022                         self.w_selectall_menuitem.set_sensitive(True)
2023                         return
2024                 elif focus_widget == self.w_searchentry:
2025                         focus_widget.select_region(0, 0)
2026                         self.w_deselect_menuitem.set_sensitive(False)
2027                         self.w_selectall_menuitem.set_sensitive(True)
2028                         return
2029 
2030                 sort_filt_model = \
2031                     self.w_application_treeview.get_model() #gtk.TreeModelSort
2032                 filt_model = sort_filt_model.get_model() #gtk.TreeModelFilter
2033                 model = filt_model.get_model() #gtk.ListStore
2034                 iter_next = sort_filt_model.get_iter_first()
2035                 list_of_paths = []
2036                 while iter_next != None:
2037                         sorted_path = sort_filt_model.get_path(iter_next)
2038                         filtered_iter = sort_filt_model.convert_iter_to_child_iter(None, \
2039                             iter_next)
2040                         app_iter = filt_model.convert_iter_to_child_iter(filtered_iter)
2041                         filtered_path = \
2042                             sort_filt_model.convert_path_to_child_path(sorted_path)
2043                         path = filt_model.convert_path_to_child_path(filtered_path)
2044                         if model.get_value(app_iter, enumerations.MARK_COLUMN):
2045                                 list_of_paths.append(path)
2046                         iter_next = sort_filt_model.iter_next(iter_next)
2047                 for path in list_of_paths:
2048                         itr = model.get_iter(path)
2049                         already_deselected = not model.get_value(itr,
2050                             enumerations.MARK_COLUMN)
2051                         if not already_deselected:
2052                                 model.set_value(itr, enumerations.MARK_COLUMN, False)
2053                                 self.__remove_pkg_stem_from_list(model.get_value(itr,
2054                                     enumerations.STEM_COLUMN))
2055                 self.w_selectall_menuitem.set_sensitive(True)
2056                 self.w_deselect_menuitem.set_sensitive(False)
2057                 self.__enable_disable_selection_menus()
2058                 self.update_statusbar()
2059                 self.__enable_disable_install_remove()
2060 
2061         def __on_preferences(self, widget):
2062                 self.w_startpage_checkbutton.set_active(self.show_startpage)
2063                 self.w_preferencesdialog.show()
2064 
2065         def __on_preferencesclose_clicked(self, widget):
2066                 self.w_preferencesdialog.hide()
2067 
2068         def __on_preferenceshelp_clicked(self, widget):
2069                 gui_misc.display_help(self.application_dir, "pm_win")
2070 
2071         def __on_startpage_checkbutton_toggled(self, widget):
2072                 self.show_startpage = self.w_startpage_checkbutton.get_active()
2073                 try:
2074                         self.client.set_bool(SHOW_STARTPAGE_PREFERENCES,
2075                             self.show_startpage)
2076                 except GError:
2077                         pass
2078 
2079         def __on_api_search_checkbox_toggled(self, widget):
2080                 active = self.api_search_checkbox.get_active()
2081                 if len(self.current_repos_with_search_errors) > 0:
2082                         if active:
2083                                 for url in self.current_repos_with_search_errors:
2084                                         if url not in self.gconf_not_show_repos:
2085                                                 self.gconf_not_show_repos += url + ","
2086                         else:
2087                                 for url in self.current_repos_with_search_errors:
2088                                         self.gconf_not_show_repos = \
2089                                             self.gconf_not_show_repos.replace(
2090                                             url + ",", "")
2091                         try:
2092                                 self.client.set_string(API_SEARCH_ERROR_PREFERENCES,
2093                                     self.gconf_not_show_repos)
2094                         except GError:
2095                                 pass
2096 
2097         def __on_searchentry_focus_in(self, widget, event):
2098                 if self.w_main_clipboard.wait_is_text_available():
2099                         self.w_paste_menuitem.set_sensitive(True)
2100                 char_count = widget.get_text_length()
2101                 if char_count > 0:
2102                         self.w_selectall_menuitem.set_sensitive(True)
2103                 else:
2104                         self.w_selectall_menuitem.set_sensitive(False)
2105                 bounds = widget.get_selection_bounds()
2106                 if bounds:
2107                         offset1 = bounds[0]
2108                         offset2 = bounds[1] 
2109                         if abs(offset2 - offset1) == char_count:
2110                                 self.w_selectall_menuitem.set_sensitive(False)
2111                         self.w_deselect_menuitem.set_sensitive(True)
2112                         self.w_copy_menuitem.set_sensitive(True)
2113                 else:
2114                         self.w_deselect_menuitem.set_sensitive(False)
2115 
2116         def __on_searchentry_focus_out(self, widget, event):
2117                 self.w_paste_menuitem.set_sensitive(False)
2118                 self.__enable_disable_select_all()
2119                 self.__enable_disable_deselect()
2120                 self.w_cut_menuitem.set_sensitive(False)
2121                 self.w_copy_menuitem.set_sensitive(False)
2122                 self.w_clear_menuitem.set_sensitive(False)
2123                 return False
2124 
2125         def __on_searchentry_activate(self, widget):
2126                 self.__do_search()
2127 
2128         def __on_searchentry_selection(self, widget, pspec):
2129                 self.__enable_disable_entry_selection(widget)
2130 
2131         def __enable_disable_entry_selection(self, widget):
2132                 char_count = widget.get_text_length()
2133                 bounds = widget.get_selection_bounds()
2134                 if bounds:
2135                         #enable selection functions
2136                         self.w_cut_menuitem.set_sensitive(True)
2137                         self.w_copy_menuitem.set_sensitive(True)
2138                         self.w_clear_menuitem.set_sensitive(True)
2139                         if char_count == abs(bounds[1] - bounds[0]):
2140                                 self.w_selectall_menuitem.set_sensitive(False)
2141                         else:
2142                                 self.w_selectall_menuitem.set_sensitive(True)
2143                         self.w_deselect_menuitem.set_sensitive(True)
2144                 else:
2145                         self.w_cut_menuitem.set_sensitive(False)
2146                         self.w_copy_menuitem.set_sensitive(False)
2147                         self.w_clear_menuitem.set_sensitive(False)
2148                         self.w_deselect_menuitem.set_sensitive(False)
2149                         if char_count == 0:
2150                                 self.w_selectall_menuitem.set_sensitive(False)
2151                         else:
2152                                 self.w_selectall_menuitem.set_sensitive(True)
2153 
2154         def __refilter_on_idle(self):
2155                 if self.application_refilter_id != 0:
2156                         gobject.source_remove(self.application_refilter_id)
2157                         self.application_refilter_id = 0
2158                 if self.application_refilter_idle_id == 0:
2159                         self.application_refilter_idle_id = gobject.idle_add(
2160                             self.__application_refilter)
2161 
2162         def __on_category_focus_in(self, widget, event, user):
2163                 self.__on_category_row_activated(None, None, None, user)
2164 
2165         def __on_category_row_activated(self, view, path, col, user):
2166                 '''This function is for handling category double click activations'''
2167                 if self.w_filter_combobox.get_model():
2168                         self.w_filter_combobox.set_active(self.saved_filter_combobox_active)
2169                 self.w_searchentry.delete_text(0, -1)
2170                 if self.in_search_mode or self.is_search_all:
2171                         self.__unset_search(True)
2172                         if self.selected == 0:
2173                                 gobject.idle_add(self.__enable_disable_install_remove)
2174                         return
2175                 self.__set_main_view_package_list()
2176                 self.set_busy_cursor()
2177                 self.__refilter_on_idle()
2178                 if self.selected == 0:
2179                         gobject.idle_add(self.__enable_disable_install_remove)
2180 
2181         def __set_main_view_package_list(self):
2182                 # Only switch from Start Page View to List view if we are not in startup
2183                 if not self.in_startpage_startup:
2184                         self.w_main_view_notebook.set_current_page(
2185                                 NOTEBOOK_PACKAGE_LIST_PAGE)
2186 
2187         def __on_category_selection_changed(self, selection, widget):
2188                 '''This function is for handling category selection changes'''
2189                 if self.in_setup or self.changing_search_option:
2190                         return
2191                 model, itr = selection.get_selected()
2192                 if itr:
2193                         cat_path = model.get_string_from_iter(itr)
2194                         if self.is_search_all:
2195                                 selected_section = self.set_section
2196                         else:
2197                                 selected_section = self.w_sections_combobox.get_active()
2198                         section_row = self.section_list[selected_section]
2199                         section_row[enumerations.SECTION_SUBCATEGORY] = cat_path
2200 
2201                 if self.in_search_mode or self.is_search_all:
2202                         return
2203                 
2204                 if self.saved_filter_combobox_active != None:
2205                         self.w_filter_combobox.set_active(self.saved_filter_combobox_active)
2206                 self.__set_main_view_package_list()
2207 
2208                 self.set_busy_cursor()
2209                 self.__refilter_on_idle()
2210                 if self.selected == 0:
2211                         gobject.idle_add(self.__enable_disable_install_remove)
2212 
2213         def __process_package_selection(self):
2214                 model, itr = self.package_selection.get_selected()
2215                 if self.show_info_id != 0:
2216                         gobject.source_remove(self.show_info_id)
2217                         self.show_info_id = 0
2218                 if itr:
2219                         self.__enable_disable_install_remove()
2220                         self.selected_pkgstem = \
2221                                model.get_value(itr, enumerations.STEM_COLUMN)
2222                         pkg = model.get_value(itr, enumerations.FMRI_COLUMN)
2223                         gobject.idle_add(self.__show_fetching_package_info, pkg)
2224                         self.showing_empty_details = False
2225                         self.last_show_info_id = self.show_info_id = \
2226                             gobject.timeout_add(SHOW_INFO_DELAY,
2227                                 self.__show_info, model, model.get_path(itr))
2228                         if (self.w_info_notebook.get_current_page() == 
2229                             INFO_NOTEBOOK_LICENSE_PAGE):
2230                                 self.__on_notebook_change(None, None, 
2231                                     INFO_NOTEBOOK_LICENSE_PAGE)
2232                 else:
2233                         self.selected_model = None
2234                         self.selected_path = None
2235                         self.selected_pkgstem = None
2236 
2237         def __on_package_selection_changed(self, selection, widget):
2238                 '''This function is for handling package selection changes'''
2239                 if self.in_setup:
2240                         return
2241                 self.__process_package_selection()
2242 
2243         def __on_filtercombobox_changed(self, widget):
2244                 '''On filter combobox changed'''
2245                 if self.in_setup or self.changing_search_option:
2246                         return
2247                 active = self.w_filter_combobox.get_active()
2248                 if active != enumerations.FILTER_SELECTED:
2249                         self.saved_filter_combobox_active = active
2250                 self.__set_main_view_package_list()
2251                 if self.in_search_mode or self.is_search_all:
2252                         self.set_busy_cursor()
2253                         self.saved_filter_combobox_active = \
2254                             self.w_filter_combobox.get_active()
2255                         self.__unset_search(True)
2256                         return
2257                 self.set_busy_cursor()
2258                 self.__refilter_on_idle()
2259                 if self.selected == 0:
2260                         gobject.idle_add(self.__enable_disable_install_remove)
2261 
2262         def __set_categories_visibility(self, selected_section):
2263                 self.category_list[0][enumerations.CATEGORY_ICON] = None
2264                 if selected_section == 0:
2265                         for category in self.category_list:
2266                                 category[enumerations.CATEGORY_VISIBLE] = True
2267                 else:
2268                         for category in self.category_list:
2269                                 if category[enumerations.CATEGORY_ID] == 0:
2270                                         category[enumerations.CATEGORY_VISIBLE] = True
2271                                 else:
2272                                         category_list = \
2273                                             category[enumerations.SECTION_LIST_OBJECT]
2274                                         if not category_list:
2275                                                 category[enumerations.CATEGORY_VISIBLE] \
2276                                                     = False
2277                                         else:
2278                                                 for section in category_list:
2279                                                         if section == selected_section:
2280                                                                 category[enumerations. \
2281                                                                     CATEGORY_VISIBLE] = \
2282                                                                     True
2283                                                         else:
2284                                                                 category[enumerations. \
2285                                                                     CATEGORY_VISIBLE] = \
2286                                                                     False
2287 
2288                 # Set category icon for All if a visible category has it
2289                 for category in self.category_list:
2290                         if category[enumerations.CATEGORY_ICON] != None:
2291                                 self.category_list[0][enumerations.CATEGORY_ICON] = \
2292                                     category[enumerations.CATEGORY_ICON]
2293                                 break
2294 
2295                 section_row = self.section_list[selected_section]
2296                 cat_path = section_row[enumerations.SECTION_SUBCATEGORY]
2297                 if cat_path != None:
2298                         itr = self.category_list_filter.get_iter_from_string(cat_path)
2299                         path = self.category_list_filter.get_path(itr)
2300                         self.w_categories_treeview.set_cursor(path,
2301                             None, start_editing=False)
2302 
2303         def __on_sectionscombobox_changed(self, widget):
2304                 '''On section combobox changed'''
2305                 if self.in_setup:
2306                         return
2307                 if self.changing_search_option:
2308                         return
2309                 self.__set_main_view_package_list()
2310                 self.set_busy_cursor()
2311                 self.__set_first_category_text()
2312                 self.__set_categories_visibility(widget.get_active())
2313                 self.category_list_filter.refilter()
2314                 if self.in_search_mode or self.is_search_all:
2315                         self.saved_sections_combobox_active = \
2316                             self.w_sections_combobox.get_active()
2317                         self.__unset_search(True)
2318                         return
2319                 self.__refilter_on_idle()
2320                 if self.selected == 0:
2321                         gobject.idle_add(self.__enable_disable_install_remove)
2322 
2323         def __set_first_category_text(self):
2324                 active_section = self.w_sections_combobox.get_active()
2325                 all_cat_text = _("All")
2326                 if active_section != 0:
2327                         all_cat_text += " " + self.section_list[active_section][1]
2328                 category_model = self.w_categories_treeview.get_model()
2329                 if category_model:
2330                         list_store = category_model.get_model()
2331                         list_store[0][1] = all_cat_text
2332 
2333         def __unset_search(self, same_repo):
2334                 self.w_infosearch_frame.hide()
2335                 self.changing_search_option = True
2336                 self.current_search_option = 0
2337                 visible_repository = self.__get_visible_repository_name()
2338                 if visible_repository in self.selected_pkgs:
2339                         self.selected_pkgs.pop(visible_repository)
2340                 if visible_repository in self.to_install_update:
2341                         self.to_install_update.pop(visible_repository)
2342                 if visible_repository in self.to_remove:
2343                         self.to_remove.pop(visible_repository)
2344                 self.__update_tooltips()
2345                 if self.is_search_all:
2346                         self.__update_repository_combobox_for_search(False)
2347                 pixbuf = self.search_options[0][1]
2348                 self.search_image.set_from_pixbuf(pixbuf)
2349                 self.in_search_mode = False
2350                 self.is_search_all = False
2351                 if same_repo:
2352                         self.__restore_setup_for_browse()
2353                 self.changing_search_option = False
2354 
2355         def __on_repositorycombobox_changed(self, widget):
2356                 '''On repository combobox changed'''
2357                 if self.changing_search_option:
2358                         return
2359                 self.changing_search_option = True
2360                 active_publisher = self.__get_active_publisher()
2361                 if self.is_search_all:
2362                         same_repo = False
2363                         active =  self.w_repository_combobox.get_active() - 1
2364                         if active == -1:
2365                                 # We get here is we choose "Add ..." when
2366                                 # doing api search
2367                                 self.changing_search_option = False
2368                                 return
2369                         if not active_publisher == _("Add..."):
2370                                 if self.saved_repository_combobox_active == active:
2371                                         same_repo = True
2372                                 self.__unset_search(same_repo)
2373                                 self.w_repository_combobox.set_active(active)
2374 
2375                         if same_repo:
2376                                 self.changing_search_option = False
2377                                 return
2378                         active_publisher = self.__get_active_publisher()
2379                 self.changing_search_option = False
2380                 if self.visible_repository == active_publisher:
2381                 # If we are coming back to the same repository, we do
2382                 # not want to setup publishers. This is the case when
2383                 # we are calling Add... then we are firing the event for
2384                 # Add... case and immediately coming back to the
2385                 # previously selected repository.
2386                         return
2387                 # Checking for Add... is fine enough, as the repository
2388                 # name cannot contain "..." in the name.
2389                 if active_publisher == _("Add..."):
2390                         index = -1
2391                         if self.is_search_all:
2392                                 index = 0
2393                         else:
2394                                 model = self.w_repository_combobox.get_model()
2395                                 for entry in model:
2396                                         if entry[1] == self.visible_repository:
2397                                                 index = entry[0]
2398                                                 break
2399                         # We do not want to switch permanently to the Add...
2400                         self.w_repository_combobox.set_active(index)
2401                         self.__on_edit_repositories_activate(None)
2402                         return
2403                 self.cancelled = True
2404                 self.in_setup = True
2405                 self.set_busy_cursor()
2406                 self.__set_empty_details_panel()
2407                 if self.in_search_mode:
2408                         self.__unset_search(False)
2409                         self.w_searchentry.grab_focus()
2410                         if len(self.w_searchentry.get_text()) > 0:
2411                                 start, end = self.w_searchentry.get_selection_bounds()
2412                                 self.w_searchentry.select_region(end, end)
2413 
2414                 pub = [active_publisher, ]
2415                 self.set_show_filter = self.initial_show_filter
2416                 self.set_section = self.initial_section
2417                 Thread(target = self.__setup_publisher, args = [pub]).start()
2418                 self.__set_main_view_package_list()
2419 
2420         def __get_active_publisher(self):
2421                 pub_iter = self.w_repository_combobox.get_active_iter()
2422                 if pub_iter == None:
2423                         return None
2424                 return self.repositories_list.get_value(pub_iter, \
2425                             enumerations.REPOSITORY_NAME)
2426 
2427         def __setup_publisher(self, publishers=[]):
2428                 self.saved_filter_combobox_active = self.initial_show_filter
2429                 application_list, category_list , section_list = \
2430                     self.__get_application_categories_lists(publishers)
2431                 gobject.idle_add(self.__init_tree_views, application_list,
2432                     category_list, section_list)
2433 
2434         def __get_application_categories_lists(self, publishers=[]):
2435                 if not self.visible_repository:
2436                         self.visible_repository = self.__get_active_publisher()
2437                 application_list = self.__get_new_application_liststore()
2438                 category_list = self.__get_new_category_liststore()
2439                 section_list = self.__get_new_section_liststore()
2440                 first_loop = True
2441                 for publisher in publishers:
2442                         uptodate = False
2443                         try:
2444                                 uptodate = self.__check_if_cache_uptodate(publisher)
2445                                 if uptodate:
2446                                         self.__add_pkgs_to_lists_from_cache(publisher,
2447                                             application_list, category_list,
2448                                             section_list)
2449                         except (UnpicklingError, EOFError, IOError):
2450                                 #Most likely cache is corrupted, silently load list
2451                                 #from api.
2452                                 application_list = self.__get_new_application_liststore()
2453                                 category_list = self.__get_new_category_liststore()
2454                                 uptodate = False
2455                         if not uptodate:
2456                                 if first_loop == True:
2457                                         first_loop = False
2458                                         gobject.idle_add(self.setup_progressdialog_show)
2459                                 self.api_o.refresh(pubs=[publisher])
2460                                 self.__add_pkgs_to_lists_from_api(publisher,
2461                                     application_list, category_list, section_list)
2462                                 category_list.prepend([0, _('All'), None, None, False,
2463                                     True, None])
2464                         if self.application_list and self.category_list and \
2465                             not self.visible_repository_uptodate:
2466                                 if self.visible_repository:
2467                                         self.__dump_datamodels(self.visible_repository,
2468                                             self.application_list, self.category_list,
2469                                             self.section_list)
2470                         self.visible_repository = self.__get_active_publisher()
2471                         self.visible_repository_uptodate = uptodate
2472                 return application_list, category_list, section_list
2473 
2474         def __check_if_cache_uptodate(self, publisher):
2475                 if self.cache_o:
2476                         return self.cache_o.check_if_cache_uptodate(publisher)
2477                 return False
2478 
2479         def __dump_datamodels(self, publisher, application_list, category_list,
2480             section_list):
2481                 if self.cache_o:
2482                         if self.img_timestamp == \
2483                             self.cache_o.get_index_timestamp():
2484                                 Thread(target = self.cache_o.dump_datamodels,
2485                                     args = (publisher, application_list, category_list,
2486                                     section_list)).start()
2487                         else:
2488                                 self.__remove_cache()
2489 
2490         def __remove_cache(self):
2491                 model = self.w_repository_combobox.get_model()
2492                 for publisher in model:
2493                         pub_name = publisher[1]
2494                         if pub_name and pub_name != _("Add..."):
2495                                 Thread(target = self.cache_o.remove_datamodel,
2496                                     args = [publisher[1]]).start()
2497 
2498         def __on_install_update(self, widget):
2499                 self.api_o.reset()
2500                 install_update = []
2501                 if self.selected == 0:
2502                         model, itr = self.package_selection.get_selected()
2503                         if itr:
2504                                 install_update.append(
2505                                     model.get_value(itr, enumerations.STEM_COLUMN))
2506                 else:
2507                         visible_repository = self.__get_visible_repository_name()
2508                         pkgs = self.selected_pkgs.get(visible_repository)
2509                         if pkgs:
2510                                 for pkg_stem in pkgs:
2511                                         status = pkgs.get(pkg_stem)
2512                                         if status == enumerations.NOT_INSTALLED or \
2513                                             status == enumerations.UPDATABLE:
2514                                                 install_update.append(pkg_stem)
2515 
2516                 if self.img_timestamp != self.cache_o.get_index_timestamp():
2517                         self.img_timestamp = None
2518                         self.__remove_cache()
2519 
2520                 installupdate.InstallUpdate(install_update, self, \
2521                     self.api_o, ips_update = False, \
2522                     action = enumerations.INSTALL_UPDATE)
2523 
2524         def __on_update_all(self, widget):
2525                 self.api_o.reset()
2526                 installupdate.InstallUpdate([], self,
2527                     self.api_o, ips_update = False,
2528                     action = enumerations.IMAGE_UPDATE, be_name = self.ua_be_name,
2529                     parent_name = _("Package Manager"),
2530                     pkg_list = ["SUNWipkg", "SUNWipkg-gui"],
2531                     main_window = self.w_main_window)
2532                 return
2533 
2534         def __on_ua_completed_linkbutton_clicked(self, widget):
2535                 try:
2536                         gnome.url_show(self.release_notes_url)
2537                 except gobject.GError:
2538                         self.error_occurred(_("Unable to navigate to:\n\t%s") % 
2539                             self.release_notes_url)
2540 
2541         def __on_help_about(self, widget):
2542                 wTreePlan = gtk.glade.XML(self.gladefile, "aboutdialog")
2543                 aboutdialog = wTreePlan.get_widget("aboutdialog")
2544                 aboutdialog.connect("response", lambda x = None, \
2545                     y = None: aboutdialog.destroy())
2546                 aboutdialog.run()
2547 
2548         def __on_help_help(self, widget):
2549                 gui_misc.display_help(self.application_dir)
2550 
2551         def __on_remove(self, widget):
2552                 self.api_o.reset()
2553                 remove_list = []
2554                 if self.selected == 0:
2555                         model, itr = self.package_selection.get_selected()
2556                         if itr:
2557                                 remove_list.append(
2558                                     model.get_value(itr, enumerations.STEM_COLUMN))
2559                 else:
2560                         visible_repository = self.__get_visible_repository_name()
2561                         pkgs = self.selected_pkgs.get(visible_repository)
2562                         if pkgs:
2563                                 for pkg_stem in pkgs:
2564                                         status = pkgs.get(pkg_stem)
2565                                         if status == enumerations.INSTALLED or \
2566                                             status == enumerations.UPDATABLE:
2567                                                 remove_list.append(pkg_stem)
2568 
2569                 if self.img_timestamp != self.cache_o.get_index_timestamp():
2570                         self.img_timestamp = None
2571                         self.__remove_cache()
2572 
2573                 installupdate.InstallUpdate(remove_list, self,
2574                     self.api_o, ips_update = False,
2575                     action = enumerations.REMOVE)
2576 
2577         def __on_reload(self, widget):
2578                 if self.description_thread_running:
2579                         self.cancelled = True
2580                 if self.in_search_mode or self.is_search_all:
2581                         self.__unset_search(False)
2582                 self.__set_empty_details_panel()
2583                 self.in_setup = True
2584                 self.visible_repository = None
2585                 if widget != None:
2586                         self.__remove_cache()
2587                 self.w_progress_dialog.set_title(_("Refreshing catalogs"))
2588                 self.w_progressinfo_label.set_text(_("Refreshing catalogs..."))
2589                 self.progress_stop_timer_thread = False
2590                 Thread(target = self.__progressdialog_progress_pulse).start()
2591                 self.w_progress_dialog.show()
2592                 self.w_progress_cancel.hide()
2593                 self.__disconnect_models()
2594                 self.in_reload = True
2595                 Thread(target = self.__catalog_refresh).start()
2596 
2597         def __catalog_refresh_done(self):
2598                 self.progress_stop_timer_thread = True
2599                 #Let the progress_pulse finish. This should be done other way, but at
2600                 #The moment this works fine
2601                 time.sleep(0.2)
2602                 gobject.idle_add(self.w_progress_cancel.show)
2603                 gobject.idle_add(self.process_package_list_start,
2604                     self.image_directory)
2605 
2606         def __main_application_quit(self, be_name = None):
2607                 '''quits the main gtk loop'''
2608                 self.cancelled = True
2609                 if self.in_setup:
2610                         return
2611 
2612                 if be_name:
2613                         if self.image_dir_arg:
2614                                 gobject.spawn_async([self.application_path, "-R",
2615                                     self.image_dir_arg, "-U", be_name])
2616                         else:
2617                                 gobject.spawn_async([self.application_path,
2618                                     "-U", be_name])
2619                 elif not self.in_search_mode:
2620                         visible_repository = self.__get_visible_repository_name()
2621                         self.__dump_datamodels(visible_repository,
2622                                 self.application_list, self.category_list,
2623                                 self.section_list)
2624 
2625                 width, height = self.w_main_window.get_size()
2626                 hpos = self.w_main_hpaned.get_position()
2627                 vpos = self.w_main_vpaned.get_position()
2628                 try:
2629                         self.client.set_int(INITIAL_APP_WIDTH_PREFERENCES, width)
2630                         self.client.set_int(INITIAL_APP_HEIGHT_PREFERENCES, height)
2631                         self.client.set_int(INITIAL_APP_HPOS_PREFERENCES, hpos)
2632                         self.client.set_int(INITIAL_APP_VPOS_PREFERENCES, vpos)
2633                 except GError:
2634                         pass
2635 
2636                 self.w_main_window.hide()
2637                 while gtk.events_pending():
2638                         gtk.main_iteration(False)
2639                 gtk.main_quit()
2640                 sys.exit(0)
2641                 return True
2642 
2643         def __check_if_something_was_changed(self):
2644                 ''' Returns True if any of the check boxes for package was changed, false
2645                 if not'''
2646                 if self.application_list:
2647                         for pkg in self.application_list:
2648                                 if pkg[enumerations.MARK_COLUMN] == True:
2649                                         return True
2650                 return False
2651 
2652         def __setup_repositories_combobox(self, api_o, repositories_list):
2653                 self.__disconnect_repository_model()
2654                 default_pub = api_o.get_preferred_publisher().prefix
2655                 if self.default_publisher != default_pub:
2656                         self.__clear_pkg_selections()
2657                         self.default_publisher = default_pub
2658                 selected_repos = []
2659                 enabled_repos = []
2660                 for repo in self.selected_pkgs:
2661                         selected_repos.append(repo)
2662                 i = 0
2663                 active = 0
2664                 for pub in api_o.get_publishers():
2665                         if pub.disabled:
2666                                 continue
2667                         prefix = pub.prefix
2668                         if cmp(prefix, self.default_publisher) == 0:
2669                                 active = i
2670                         repositories_list.append([i, prefix, ])
2671                         enabled_repos.append(prefix)
2672                         i = i + 1
2673                 repositories_list.append([-1, "", ])
2674                 repositories_list.append([-1, _("Add..."), ])
2675                 pkgs_to_remove = []
2676                 for repo_name in selected_repos:
2677                         if repo_name not in enabled_repos:
2678                                 pkg_stems = self.selected_pkgs.get(repo_name)
2679                                 for pkg_stem in pkg_stems:
2680                                         pkgs_to_remove.append(pkg_stem)
2681                 for pkg_stem in pkgs_to_remove:
2682                         self.__remove_pkg_stem_from_list(pkg_stem)
2683                 self.w_repository_combobox.set_model(repositories_list)
2684                 if self.default_publisher:
2685                         self.w_repository_combobox.set_active(active)
2686                 else:
2687                         self.w_repository_combobox.set_active(0)
2688 
2689         def __active_pane_toggle(self, cell, path, model_sort):
2690                 '''Toggle function for column enumerations.MARK_COLUMN'''
2691                 applicationModel = model_sort.get_model()
2692                 applicationPath = model_sort.convert_path_to_child_path(path)
2693                 filterModel = applicationModel.get_model()
2694                 child_path = applicationModel.convert_path_to_child_path(applicationPath)
2695                 itr = filterModel.get_iter(child_path)
2696                 if itr:
2697                         modified = filterModel.get_value(itr, enumerations.MARK_COLUMN)
2698                         filterModel.set_value(itr, enumerations.MARK_COLUMN,
2699                             not modified)
2700                         pkg_status = filterModel.get_value(itr,
2701                             enumerations.STATUS_COLUMN)
2702                         pkg_stem = filterModel.get_value(itr, enumerations.STEM_COLUMN)
2703                         if modified:
2704                                 self.__remove_pkg_stem_from_list(pkg_stem)
2705                         else:
2706                                 self.__add_pkg_stem_to_list(pkg_stem, pkg_status)
2707                         self.update_statusbar()
2708                         self.__enable_disable_selection_menus()
2709 
2710         def __update_reload_button(self):
2711                 if self.user_rights:
2712                         self.w_reload_button.set_sensitive(True)
2713                 else:
2714                         self.w_reload_button.set_sensitive(False)
2715 
2716         def __add_pkg_stem_to_list(self, stem, status):
2717                 publisher = self.__get_active_publisher()
2718                 if self.selected_pkgs.get(publisher) == None:
2719                         self.selected_pkgs[publisher] = {}
2720                 self.selected_pkgs.get(publisher)[stem] = status
2721                 if status == enumerations.NOT_INSTALLED or \
2722                     status == enumerations.UPDATABLE:
2723                         if self.to_install_update.get(publisher) == None:
2724                                 self.to_install_update[publisher] = 1
2725                         else:
2726                                 self.to_install_update[publisher] += 1
2727                 if status == enumerations.UPDATABLE or status == enumerations.INSTALLED:
2728                         if self.to_remove.get(publisher) == None:
2729                                 self.to_remove[publisher] = 1
2730                         else:
2731                                 self.to_remove[publisher] += 1
2732                 self.__update_tooltips()
2733 
2734         def __update_tooltips(self):
2735                 to_remove = None
2736                 to_install = None
2737                 no_iter = 0
2738                 for publisher in self.to_remove:
2739                         packages = self.to_remove.get(publisher)
2740                         if packages > 0:
2741                                 if no_iter == 0:
2742                                         to_remove = _("Selected for Removal:")
2743                                 to_remove += "\n   %s: %d" % (publisher, packages)
2744                                 no_iter += 1
2745                 no_iter = 0
2746                 for publisher in self.to_install_update:
2747                         packages = self.to_install_update.get(publisher)
2748                         if packages > 0:
2749                                 if no_iter == 0:
2750                                         to_install = _("Selected for Install/Update:")
2751                                 to_install += "\n   %s: %d" % (publisher, packages)
2752                                 no_iter += 1
2753                 if not to_install:
2754                         to_install = _("Select packages by marking the checkbox "
2755                             "and click to Install/Update.")
2756                 self.w_installupdate_button.set_tooltip(self.install_button_tooltip,
2757                     to_install)
2758                 if not to_remove:
2759                         to_remove = _("Select packages by marking the checkbox "
2760                             "and click to Remove selected.")
2761                 self.w_remove_button.set_tooltip(self.remove_button_tooltip, to_remove)
2762 
2763         def __remove_pkg_stem_from_list(self, stem):
2764                 remove_pub = []
2765                 for publisher in self.selected_pkgs:
2766                         pkgs = self.selected_pkgs.get(publisher)
2767                         status = None
2768                         if stem in pkgs:
2769                                 status = pkgs.pop(stem)
2770                         if status == enumerations.NOT_INSTALLED or \
2771                             status == enumerations.UPDATABLE:
2772                                 if self.to_install_update.get(publisher) == None:
2773                                         self.to_install_update[publisher] = 0
2774                                 else:
2775                                         self.to_install_update[publisher] -= 1
2776                         if status == enumerations.UPDATABLE or \
2777                             status == enumerations.INSTALLED:
2778                                 if self.to_remove.get(publisher) == None:
2779                                         self.to_remove[publisher] = 0
2780                                 else:
2781                                         self.to_remove[publisher] -= 1
2782                         if len(pkgs) == 0:
2783                                 remove_pub.append(publisher)
2784                 for publisher in remove_pub:
2785                         self.selected_pkgs.pop(publisher)
2786                 self.__update_tooltips()
2787 
2788         def __clear_pkg_selections(self):
2789                 # We clear the selections as the preffered repository was changed
2790                 # and pkg stems are not valid.
2791                 remove_pub = []
2792                 for publisher in self.selected_pkgs:
2793                         stems = self.selected_pkgs.get(publisher)
2794                         for pkg_stem in stems:
2795                                 remove_pub.append(pkg_stem)
2796                 for pkg_stem in remove_pub:
2797                         self.__remove_pkg_stem_from_list(pkg_stem)
2798 
2799         def __set_empty_details_panel(self):
2800                 self.showing_empty_details = True
2801                 if self.show_info_id != 0:
2802                         gobject.source_remove(self.show_info_id)
2803                         self.show_info_id = 0
2804                 if self.show_licenses_id != 0:
2805                         gobject.source_remove(self.show_licenses_id)
2806                         self.show_licenses_id = 0
2807                 pkg_name = _("Package Name")
2808                 self.w_packagename_label.set_markup("<b>" + pkg_name + "</b>")
2809                 self.w_general_info_label.set_markup("<b>" + pkg_name + "</b>")
2810                 self.w_installedfiles_textview.get_buffer().set_text("")
2811                 self.w_dependencies_textview.get_buffer().set_text("")
2812                 self.w_generalinfo_textview.get_buffer().set_text("")
2813                 self.w_license_textview.get_buffer().set_text("")
2814                 return
2815 
2816         def __show_fetching_package_info(self, pkg):
2817                 pkg_name = pkg.get_name()
2818                 self.w_packagename_label.set_markup("<b>" + pkg_name + "</b>")
2819                 self.w_general_info_label.set_markup("<b>" + pkg_name + "</b>")
2820 
2821                 pkg_stem = pkg.get_pkg_stem()
2822                 if self.__setting_from_cache(pkg_stem):
2823                         return
2824 
2825                 self.w_shortdescription_label.set_text(
2826                     _("Fetching description..."))
2827                 instbuffer = self.w_installedfiles_textview.get_buffer()
2828                 depbuffer = self.w_dependencies_textview.get_buffer()
2829                 infobuffer = self.w_generalinfo_textview.get_buffer()
2830                 fetching_text = _("Fetching information...")
2831                 instbuffer.set_text(fetching_text)
2832                 depbuffer.set_text(fetching_text)
2833                 infobuffer.set_text(fetching_text)
2834                 return
2835 
2836         def __setting_from_cache(self, pkg_stem):
2837                 if len(self.info_cache) > MAX_INFO_CACHE_LIMIT:
2838                         self.info_cache = {}
2839 
2840                 if self.info_cache.has_key(pkg_stem):
2841                         self.w_shortdescription_label.set_text(
2842                             self.info_cache[pkg_stem][0])
2843                         instbuffer = self.w_installedfiles_textview.get_buffer()
2844                         depbuffer = self.w_dependencies_textview.get_buffer()
2845                         infobuffer = self.w_generalinfo_textview.get_buffer()
2846                         infobuffer.set_text(self.info_cache[pkg_stem][1])
2847                         instbuffer.set_text(self.info_cache[pkg_stem][2])
2848                         depbuffer.set_text(self.info_cache[pkg_stem][3])
2849                         return True
2850                 else:
2851                         return False
2852 
2853         def __update_package_info(self, pkg, local_info, remote_info, info_id):
2854                 if self.showing_empty_details or (info_id != 
2855                     self.last_show_info_id):
2856                         return
2857                 pkg_name = pkg.get_name()
2858                 pkg_stem = pkg.get_pkg_stem()
2859                 self.w_packagename_label.set_markup("<b>" + pkg_name + "</b>")
2860                 self.w_general_info_label.set_markup("<b>" + pkg_name + "</b>")
2861                 installed = True
2862 
2863                 if self.__setting_from_cache(pkg_stem):
2864                         return
2865 
2866                 instbuffer = self.w_installedfiles_textview.get_buffer()
2867                 depbuffer = self.w_dependencies_textview.get_buffer()
2868                 infobuffer = self.w_generalinfo_textview.get_buffer()
2869 
2870                 if not local_info and not remote_info:
2871                         network_str = \
2872                             _("\nThis might be caused by network problem "
2873                             "while accessing the repository.")
2874                         self.w_shortdescription_label.set_text(
2875                             _("Description not available for this package...") +
2876                             network_str)
2877                         instbuffer.set_text( \
2878                             _("Files Details not available for this package...") +
2879                             network_str)
2880                         depbuffer.set_text(_(
2881                             "Dependencies info not available for this package...") +
2882                             network_str)
2883                         infobuffer.set_text(
2884                             _("Information not available for this package...") +
2885                             network_str)
2886                         return
2887 
2888                 if not local_info:
2889                         # Package is not installed
2890                         local_info = remote_info
2891                         installed = False
2892 
2893                 if not remote_info:
2894                         remote_info = local_info
2895                         installed = True
2896 
2897                 description = local_info.summary
2898                 #XXX long term need to have something more robust here for multi byte
2899                 if len(description) > MAX_DESC_LEN:
2900                         description = description[:MAX_DESC_LEN] + " ..."
2901                 self.w_shortdescription_label.set_text(description)
2902                 inst_str = _("Root: %s\n") % self.api_o.img.get_root()
2903                 dep_str = _("Dependencies:\n")
2904 
2905                 if local_info.dependencies:
2906                         dep_str += ''.join(
2907                             ["\t%s\n" % x for x in local_info.dependencies])
2908                 if local_info.dirs:
2909                         inst_str += ''.join(["\t%s\n" % x for x in local_info.dirs])
2910                 if local_info.files:
2911                         inst_str += ''.join(["\t%s\n" % x for x in local_info.files])
2912                 if local_info.hardlinks:
2913                         inst_str += ''.join(["\t%s\n" % x for x in local_info.hardlinks])
2914                 if local_info.links:
2915                         inst_str += ''.join(["\t%s\n" % x for x in local_info.links])
2916                 info_str = ""
2917                 labs = {}
2918                 labs["sum"] = _("Summary:\t\t")
2919                 labs["size"] = _("Size:\t\t\t")
2920                 labs["cat"] = _("Category:\t\t")
2921                 labs["ins"] = _("Installed Version:\t")
2922                 labs["lat"] = _("Latest Version:\t")
2923                 labs["pkg_date"] = _("Packaging Date:\t")
2924                 labs["fmri"] = _("FMRI:\t\t\t")
2925                 labs["repository"] = _("Repository:\t\t")
2926                 max_len = 0
2927                 for lab in labs:
2928                         if len(labs[lab]) > max_len:
2929                                 max_len = len(labs[lab])
2930                 categories = _("None")
2931                 if local_info.category_info_list:
2932                         verbose = len(local_info.category_info_list) > 1
2933                         categories = ""
2934                         categories += local_info.category_info_list[0].__str__(verbose)
2935                         if len(local_info.category_info_list) > 1:
2936                                 for ci in local_info.category_info_list[1:]:
2937                                         categories += ", " + ci.__str__(verbose)
2938                 summary = _("None")
2939                 if local_info.summary:
2940                         summary = local_info.summary
2941                 info_str += "  %s %s" % (labs["sum"], summary)
2942                 info_str += "\n  %s %s" % (labs["size"],
2943                     misc.bytes_to_str(local_info.size))
2944                 info_str += "\n  %s %s" % (labs["cat"], categories)
2945                 if installed:
2946                         info_str += "\n  %s %s,%s-%s" % (labs["ins"], local_info.version,
2947                             local_info.build_release, local_info.branch)
2948                 info_str += "\n  %s %s,%s-%s" % (labs["lat"], remote_info.version,
2949                     remote_info.build_release, remote_info.branch)
2950                 info_str += "\n  %s %s" % (labs["pkg_date"], local_info.packaging_date)
2951                 info_str += "\n  %s %s" % (labs["fmri"], local_info.fmri)
2952                 info_str += "\n  %s %s" % (labs["repository"], local_info.publisher)
2953                 infobuffer.set_text(info_str)
2954                 instbuffer.set_text(inst_str)
2955                 depbuffer.set_text(dep_str)
2956                 self.info_cache[pkg_stem] = \
2957                     (description, info_str, inst_str, dep_str)
2958 
2959         def __update_package_license(self, licenses, license_id):
2960                 if self.showing_empty_details or (license_id !=
2961                     self.last_show_licenses_id):
2962                         return
2963                 lic = ""
2964                 lic_u = ""
2965                 if licenses == None:
2966                         lic_u = _("Not available")
2967                 else:
2968                         for licens in licenses:
2969                                 lic += licens.get_text()
2970                                 lic += "\n"
2971                         try:
2972                                 lic_u = unicode(lic, "utf-8")
2973                         except UnicodeDecodeError:
2974                                 lic_u += ""
2975                 licbuffer = self.w_license_textview.get_buffer()
2976                 licbuffer.set_text(lic_u)
2977 
2978         def __show_licenses(self):
2979                 self.show_licenses_id = 0
2980                 if self.catalog_loaded == False:
2981                         return
2982                 Thread(target = self.__show_package_licenses,
2983                     args = (self.selected_pkgstem, self.last_show_licenses_id,)).start()
2984 
2985         def __show_package_licenses(self, selected_pkgstem, license_id):
2986                 if selected_pkgstem == None:
2987                         gobject.idle_add(self.__update_package_license, None,
2988                             self.last_show_licenses_id)
2989                         return
2990                 info = None
2991                 try:
2992                         info = self.api_o.info([selected_pkgstem],
2993                             True, frozenset([api.PackageInfo.LICENSES]))
2994                 except (api_errors.TransportError):
2995                         pass
2996                 if self.showing_empty_details or (license_id != 
2997                     self.last_show_licenses_id):
2998                         return
2999                 if not info or (info and len(info.get(0)) == 0):
3000                         try:
3001                         # Get license from remote
3002                                 info = self.api_o.info([selected_pkgstem],
3003                                     False, frozenset([api.PackageInfo.LICENSES]))
3004                         except (api_errors.TransportError):
3005                                 pass
3006                 if self.showing_empty_details or (license_id != 
3007                     self.last_show_licenses_id):
3008                         return
3009                 pkgs_info = None
3010                 package_info = None
3011                 no_licenses = 0
3012                 if info:
3013                         pkgs_info = info[0]
3014                 if pkgs_info:
3015                         package_info = pkgs_info[0]
3016                 if package_info:
3017                         no_licenses = len(package_info.licenses)
3018                 if no_licenses == 0:
3019                         gobject.idle_add(self.__update_package_license, None, 
3020                             license_id)
3021                         return
3022                 else:
3023                         gobject.idle_add(self.__update_package_license,
3024                             package_info.licenses, license_id)
3025 
3026         def __get_pkg_info(self, pkg_stem, local):
3027                 info = None
3028                 try:
3029                         info = self.api_o.info([pkg_stem], local,
3030                             api.PackageInfo.ALL_OPTIONS -
3031                             frozenset([api.PackageInfo.LICENSES]))
3032                 except (api_errors.TransportError):
3033                         return info
3034                 pkgs_info = None
3035                 package_info = None
3036                 if info:
3037                         pkgs_info = info[0]
3038                 if pkgs_info:
3039                         package_info = pkgs_info[0]
3040                 if package_info:
3041                         return package_info
3042                 else:
3043                         return None
3044 
3045         def __show_info(self, model, path):
3046                 self.show_info_id = 0
3047                 if self.catalog_loaded == False:
3048                         self.selected_model = model
3049                         self.selected_path = path
3050                         return
3051                 if not (model and path):
3052                         return
3053                 if self.selected_model != None:
3054                         if (self.selected_model != model or
3055                             self.selected_path != path):
3056                         # This can happen after catalogs are loaded in
3057                         # enable_disable_update_all and a different
3058                         # package is selected before enable_disable_update_all
3059                         # calls __show_info. We set these variable to None
3060                         # so that when __show_info is called it does nothing.
3061                                 self.selected_model = None
3062                                 self.selected_path = None
3063 
3064                 itr = model.get_iter(path)
3065                 pkg = model.get_value(itr, enumerations.FMRI_COLUMN)
3066                 pkg_stem = model.get_value(itr, enumerations.STEM_COLUMN)
3067                 pkg_status = model.get_value(itr, enumerations.STATUS_COLUMN)
3068                 if self.info_cache.has_key(pkg_stem):
3069                         return
3070                 Thread(target = self.__show_package_info,
3071                     args = (pkg, pkg_stem, pkg_status, self.last_show_info_id)).start()
3072 
3073         def __show_package_info(self, pkg, pkg_stem, pkg_status, info_id):
3074                 self.api_o.log_operation_start("info")
3075                 local_info = None
3076                 remote_info = None
3077                 if not self.showing_empty_details and (info_id ==
3078                     self.last_show_info_id) and (pkg_status ==
3079                     enumerations.INSTALLED or pkg_status ==
3080                     enumerations.UPDATABLE):
3081                         local_info = self.__get_pkg_info(pkg_stem, True)
3082                 if not self.showing_empty_details and (info_id ==
3083                     self.last_show_info_id) and (pkg_status ==
3084                     enumerations.NOT_INSTALLED or pkg_status ==
3085                     enumerations.UPDATABLE):
3086                         remote_info = self.__get_pkg_info(pkg_stem, False)
3087                 if not self.showing_empty_details and (info_id ==
3088                     self.last_show_info_id):
3089                         gobject.idle_add(self.__update_package_info, pkg,
3090                             local_info, remote_info, info_id)
3091                 self.api_o.log_operation_end()
3092                 return
3093 
3094         # This function is ported from pkg.actions.generic.distinguished_name()
3095         @staticmethod
3096         def __locale_distinguished_name(action):
3097                 if action.key_attr == None:
3098                         return str(action)
3099                 return "%s: %s" % \
3100                     (_(action.name), action.attrs.get(action.key_attr, "???"))
3101 
3102         def __application_filter(self, model, itr):
3103                 '''This function is used to filter content in the main
3104                 application view'''
3105                 if self.in_setup or self.cancelled:
3106                         return False
3107                 filter_id = self.w_filter_combobox.get_active()
3108                 if filter_id == enumerations.FILTER_SELECTED:
3109                         return model.get_value(itr, enumerations.MARK_COLUMN)
3110                 # XXX Show filter, chenge text to integers
3111                 selected_category = 0
3112                 category_selection = self.w_categories_treeview.get_selection()
3113                 category_model, category_iter = category_selection.get_selected()
3114                 if category_iter:
3115                         selected_category = category_model.get_value(category_iter,
3116                             enumerations.CATEGORY_ID)
3117                 category_list = model.get_value(itr, enumerations.CATEGORY_LIST_COLUMN)
3118                 selected_section = self.w_sections_combobox.get_active()
3119                 category = False
3120                 if selected_section == 0 and selected_category == 0:
3121                         #For section "All" and category "All" always true
3122                         category = True
3123                 elif selected_category != 0:
3124                         if category_list and selected_category in category_list:
3125                                 category = True
3126                 elif category_list:
3127                         #The selected category is "All" so we need to check
3128                         #If the package belongs to one of the visible categories
3129                         for visible_category in category_model:
3130                                 visible_id = visible_category[enumerations.CATEGORY_ID]
3131                                 if visible_id in category_list:
3132                                         category = True
3133                                         break
3134                 if (model.get_value(itr, enumerations.IS_VISIBLE_COLUMN) == False):
3135                         return False
3136                 return (category &
3137                     self.__is_package_filtered(model, itr, filter_id))
3138 
3139         @staticmethod
3140         def __is_package_filtered(model, itr, filter_id):
3141                 '''Function for filtercombobox'''
3142                 if filter_id == enumerations.FILTER_ALL:
3143                         return True
3144                 status = model.get_value(itr, enumerations.STATUS_COLUMN)
3145                 if filter_id == enumerations.FILTER_INSTALLED:
3146                         return (status == enumerations.INSTALLED or status == \
3147                             enumerations.UPDATABLE)
3148                 elif filter_id == enumerations.FILTER_UPDATES:
3149                         return status == enumerations.UPDATABLE
3150                 elif filter_id == enumerations.FILTER_NOT_INSTALLED:
3151                         return status == enumerations.NOT_INSTALLED
3152 
3153         def __is_pkg_repository_visible(self, model, itr):
3154                 if len(self.repositories_list) <= 1:
3155                         return True
3156                 else:
3157                         visible_repository = self.__get_visible_repository_name()
3158                         pkg = model.get_value(itr, enumerations.FMRI_COLUMN)
3159                         if not pkg:
3160                                 return False
3161                         if cmp(pkg.get_publisher(), visible_repository) == 0:
3162                                 return True
3163                         else:
3164                                 return False
3165 
3166         def __get_visible_repository_name(self):
3167                 pub_iter = self.w_repository_combobox.get_active_iter()
3168                 if pub_iter == None:
3169                         return None
3170                 visible = self.repositories_list.get_value(pub_iter, \
3171                     enumerations.REPOSITORY_NAME)
3172                 return visible
3173 
3174         def __enable_disable_selection_menus(self):
3175                 if self.in_setup:
3176                         return
3177                 self.__enable_disable_select_updates()
3178                 if not self.__doing_search():
3179                         self.unset_busy_cursor()
3180 
3181         def __enable_disable_select_all(self):
3182                 if self.in_setup:
3183                         return
3184                 if len(self.w_application_treeview.get_model()) > 0:
3185                         for row in self.w_application_treeview.get_model():
3186                                 if not row[enumerations.MARK_COLUMN]:
3187                                         self.w_selectall_menuitem.set_sensitive(True)
3188                                         return
3189                         self.w_selectall_menuitem.set_sensitive(False)
3190                 else:
3191                         self.w_selectall_menuitem.set_sensitive(False)
3192 
3193         def __enable_disable_install_remove(self):
3194                 if not self.user_rights:
3195                         self.w_installupdate_button.set_sensitive(False)
3196                         self.w_installupdate_menuitem.set_sensitive(False)
3197                         self.w_remove_button.set_sensitive(False)
3198                         self.w_remove_menuitem.set_sensitive(False)
3199                         return
3200                 selected_removal = self.__enable_if_selected_for_removal()
3201                 selected_install_update = self.__enable_if_selected_for_install_update()
3202                 if selected_removal or selected_install_update:
3203                         return
3204                 remove = False
3205                 install = False
3206                 if self.selected == 0:
3207                         model, itr = self.package_selection.get_selected()
3208                         if itr:
3209                                 status = \
3210                                        model.get_value(itr, enumerations.STATUS_COLUMN)
3211                                 if status == enumerations.NOT_INSTALLED:
3212                                         remove = False
3213                                         install = True
3214                                 elif status == enumerations.UPDATABLE:
3215                                         remove = True
3216                                         install = True
3217                                 elif status == enumerations.INSTALLED:
3218                                         remove = True
3219                                         install = False
3220                                 self.w_installupdate_button.set_sensitive(install)
3221                                 self.w_installupdate_menuitem.set_sensitive(install)
3222                                 self.w_remove_button.set_sensitive(remove)
3223                                 self.w_remove_menuitem.set_sensitive(remove)
3224 
3225         def __enable_if_selected_for_removal(self):
3226                 sensitive = False
3227                 visible_repository = self.__get_visible_repository_name()
3228                 selected = self.to_remove.get(visible_repository)
3229                 if selected > 0:
3230                         sensitive = True
3231                 self.w_remove_button.set_sensitive(sensitive)
3232                 self.w_remove_menuitem.set_sensitive(sensitive)
3233                 return sensitive
3234 
3235         def __enable_if_selected_for_install_update(self):
3236                 sensitive = False
3237                 visible_repository = self.__get_visible_repository_name()
3238                 selected = self.to_install_update.get(visible_repository)
3239                 if selected > 0:
3240                         sensitive = True
3241                 self.w_installupdate_button.set_sensitive(sensitive)
3242                 self.w_installupdate_menuitem.set_sensitive(sensitive)
3243                 return sensitive
3244 
3245         def __enable_disable_select_updates(self):
3246                 for row in self.w_application_treeview.get_model():
3247                         if row[enumerations.STATUS_COLUMN] == enumerations.UPDATABLE:
3248                                 if not row[enumerations.MARK_COLUMN]:
3249                                         self.w_selectupdates_menuitem. \
3250                                             set_sensitive(True)
3251                                         return
3252                 self.w_selectupdates_menuitem.set_sensitive(False)
3253                 return
3254 
3255         def __get_inventory_list(self, pargs, all_known, all_versions):
3256                 self.__image_activity_lock.acquire()
3257                 try:
3258                         res = misc.get_inventory_list(self.api_o.img, 
3259                             pargs, all_known, all_versions)
3260                 finally:
3261                         self.__image_activity_lock.release()
3262                 return res
3263 
3264         def __enable_disable_update_all(self):
3265                 #XXX Api to provide fast information if there are some updates
3266                 #available within image
3267                 gobject.idle_add(self.w_updateall_button.set_sensitive, False)
3268                 gobject.idle_add(self.w_updateall_menuitem.set_sensitive, False)
3269                 update_available = self.__check_if_updates_available()
3270                 gobject.idle_add(self.__g_enable_disable_update_all, update_available)
3271                 gobject.idle_add(self.__show_info_after_catalog_load)
3272                 return False
3273 
3274         def __show_info_after_catalog_load(self):
3275                 self.__show_info(self.selected_model, self.selected_path)
3276                 self.selected_model = None
3277                 self.selected_path = None
3278                 if (self.w_info_notebook.get_current_page() == 
3279                     INFO_NOTEBOOK_LICENSE_PAGE and
3280                     not self.showing_empty_details):
3281                         self.__show_licenses()
3282 
3283         def __check_if_updates_available(self):
3284                 try:
3285                         self.catalog_loaded = False
3286                         self.api_o.refresh()
3287                         self.catalog_loaded = True
3288                         res = self.__get_inventory_list([], False, False)
3289                         for pfmri, state in res:
3290                                 if state["upgradable"]:
3291                                         self.pylintstub = pfmri
3292                                         return True
3293 
3294                 except api_errors.InventoryException:
3295                         gobject.idle_add(self.__set_empty_details_panel)
3296                         return False
3297                 return False
3298 
3299         def __g_enable_disable_update_all(self, update_available):
3300                 self.w_updateall_button.set_sensitive(update_available)
3301                 self.w_updateall_menuitem.set_sensitive(update_available)
3302                 self.__enable_disable_install_remove()
3303 
3304         def __enable_disable_deselect(self):
3305                 if self.w_application_treeview.get_model():
3306                         for row in self.w_application_treeview.get_model():
3307                                 if row[enumerations.MARK_COLUMN]:
3308                                         self.w_deselect_menuitem.set_sensitive(True)
3309                                         return
3310                 self.w_deselect_menuitem.set_sensitive(False)
3311                 return
3312 
3313         def __catalog_refresh(self, reload_gui=True):
3314                 """Update image's catalogs."""
3315                 try:
3316                         # Since the user requested the refresh, perform it
3317                         # immediately for all publishers.
3318                         self.api_o.refresh(immediate=True)
3319                         # Refresh will load the catalogs.
3320                         self.catalog_loaded = True
3321                 except api_errors.PublisherError:
3322                         # In current implementation, this will never happen
3323                         # We are not refreshing specific publisher
3324                         self.__catalog_refresh_done()
3325                         raise
3326                 except api_errors.PermissionsException:
3327                         #Error will already have been reported in
3328                         #Manage Repository dialog
3329                         self.__catalog_refresh_done()
3330                         return -1
3331                 except api_errors.CatalogRefreshException, cre:
3332                         total = cre.total
3333                         succeeded = cre.succeeded
3334                         ermsg = _("Network problem.\n\n")
3335                         ermsg += _("Details:\n")
3336                         ermsg += "%s/%s" % (succeeded, total)
3337                         ermsg += _(" catalogs successfully updated:\n")
3338                         for pub, err in cre.failed:
3339                                 if isinstance(err, HTTPError):
3340                                         ermsg += "   %s: %s - %s\n" % \
3341                                             (err.filename, err.code, err.msg)
3342                                 elif isinstance(err, URLError):
3343                                         if err.args[0][0] == 8:
3344                                                 ermsg += "    %s: %s\n" % \
3345                                                     (urlparse.urlsplit(
3346                                                         pub["origin"])[1].split(":")[0],
3347                                                     err.args[0][1])
3348                                         else:
3349                                                 if isinstance(err.args[0], \
3350                                                     socket.timeout):
3351                                                         ermsg += "    %s: %s\n" % \
3352                                                             (pub["origin"], "timeout")
3353                                                 else:
3354                                                         ermsg += "    %s: %s\n" % \
3355                                                             (pub["origin"], \
3356                                                             err.args[0][1])
3357                                 elif "data" in err.__dict__ and err.data:
3358                                         ermsg += err.data
3359                                 else:
3360                                         ermsg += _("Unknown error")
3361                                         ermsg += "\n"
3362 
3363                         gobject.idle_add(self.error_occurred, ermsg,
3364                             None, gtk.MESSAGE_INFO)
3365                         self.__catalog_refresh_done()
3366                         return -1
3367                 except api_errors.InvalidDepotResponseException, idrex:
3368                         err = str(idrex)
3369                         gobject.idle_add(self.error_occurred, err,
3370                             None, gtk.MESSAGE_INFO)
3371                         self.__catalog_refresh_done()
3372                         return -1
3373                 except api_errors.PublisherError:
3374                         self.__catalog_refresh_done()
3375                         raise
3376                 except Exception:
3377                         self.__catalog_refresh_done()
3378                         raise
3379                 if reload_gui:
3380                         self.__catalog_refresh_done()
3381                 return 0
3382 
3383         def __add_pkgs_to_lists_from_cache(self, publisher, application_list,
3384             category_list, section_list):
3385                 if self.cache_o:
3386                         self.cache_o.load_application_list(publisher, application_list,
3387                             self.selected_pkgs)
3388                         self.cache_o.load_category_list(publisher, category_list)
3389                         self.cache_o.load_section_list(publisher, section_list)
3390 
3391         def __add_pkgs_to_lists_from_api(self, publisher, application_list,
3392             category_list, section_list):
3393                 """ This method set up image from the given directory and
3394                 returns the image object or None"""
3395                 pargs = []
3396                 pargs.append("pkg://" + publisher + "/*")
3397                 try:
3398                         pkgs_known = self.__get_inventory_list(pargs,
3399                             True, True)
3400                 except api_errors.InventoryException:
3401                         # This can happen if the repository does not
3402                         # contain any packages
3403                         err = _("Selected repository does not contain any packages.")
3404                         gobject.idle_add(self.w_progress_dialog.hide)
3405                         gobject.idle_add(self.error_occurred, err, None,
3406                             gtk.MESSAGE_INFO)
3407                         self.unset_busy_cursor()
3408                         pkgs_known = []
3409 
3410                 return self.__add_pkgs_to_lists(pkgs_known, application_list,
3411                     category_list, section_list)
3412 
3413         def __add_pkgs_to_lists(self, pkgs_known, application_list,
3414             category_list, section_list):
3415                 if section_list != None:
3416                         self.__init_sections(section_list)
3417                 #Only one instance of those icons should be in memory
3418                 update_available_icon = gui_misc.get_icon(self.icon_theme,
3419                     "status_newupdate")
3420                 installed_icon = gui_misc.get_icon(self.icon_theme,
3421                     "status_installed")
3422                 update_for_category_icon = \
3423                     self.get_icon_pixbuf_from_glade_dir("legend_newupdate")
3424                 #Imageinfo for categories
3425                 imginfo = imageinfo.ImageInfo()
3426                 sectioninfo = imageinfo.ImageInfo()
3427                 pubs = [p.prefix for p in self.api_o.get_publishers()]
3428                 categories = {}
3429                 sections = {}
3430                 share_path = "/usr/share/package-manager/data/"
3431                 for pub in pubs:
3432                         category = imginfo.read(self.application_dir +
3433                             share_path + pub)
3434                         if len(category) == 0:
3435                                 category = imginfo.read(self.application_dir +
3436                                     share_path + "opensolaris.org")
3437                         categories[pub] = category
3438                         section = sectioninfo.read(self.application_dir +
3439                             share_path + pub + ".sections")
3440                         if len(section) == 0:
3441                                 section = sectioninfo.read(self.application_dir +
3442                                     share_path + "opensolaris.org.sections")
3443                         sections[pub] = section
3444                 pkg_count = 0
3445                 pkg_add = 0
3446                 progress_percent = INITIAL_PROGRESS_TOTAL_PERCENTAGE
3447                 total_pkg_count = len(pkgs_known)
3448                 progress_increment = \
3449                         total_pkg_count / PACKAGE_PROGRESS_TOTAL_INCREMENTS
3450                 self.progress_stop_timer_thread = True
3451                 while gtk.events_pending():
3452                         gtk.main_iteration(False)
3453                 prev_stem = ""
3454                 prev_pfmri_str = ""
3455                 next_app = None
3456                 pkg_name = None
3457                 pkg_publisher = None
3458                 prev_state = None
3459                 category_icon = None
3460                 for pkg, state in pkgs_known:
3461                         if prev_pfmri_str and \
3462                             prev_pfmri_str == pkg.get_short_fmri() and \
3463                             prev_state == state:
3464                                 pkg_count += 1
3465                                 continue
3466                         if prev_stem and \
3467                             prev_stem == pkg.get_pkg_stem() and \
3468                             prev_state["state"] == "known" and \
3469                             state["state"] == "installed":
3470                                 pass
3471                         elif next_app != None:
3472                                 self.__add_package_to_list(next_app,
3473                                     application_list,
3474                                     pkg_add, pkg_name,
3475                                     category_icon,
3476                                     categories, category_list, pkg_publisher)
3477                                 pkg_add += 1
3478                         prev_stem = pkg.get_pkg_stem()
3479                         prev_pfmri_str = pkg.get_short_fmri()
3480                         prev_state = state
3481 
3482                         if progress_increment > 0 and pkg_count % progress_increment == 0:
3483                                 progress_percent += PACKAGE_PROGRESS_PERCENT_INCREMENT
3484                                 if progress_percent <= PACKAGE_PROGRESS_PERCENT_TOTAL:
3485                                         self.__progressdialog_progress_percent(
3486                                             progress_percent, pkg_count, total_pkg_count)
3487                                 while gtk.events_pending():
3488                                         gtk.main_iteration(False)
3489 
3490                         status_icon = None
3491                         category_icon = None
3492                         pkg_name = pkg.get_name()
3493                         pkg_name = gui_misc.get_pkg_name(pkg_name)
3494                         pkg_stem = pkg.get_pkg_stem()
3495                         pkg_publisher = pkg.get_publisher()
3496                         pkg_state = enumerations.NOT_INSTALLED
3497                         if state["state"] == "installed":
3498                                 pkg_state = enumerations.INSTALLED
3499                                 if state["upgradable"] == True:
3500                                         status_icon = update_available_icon
3501                                         category_icon = update_for_category_icon
3502                                         pkg_state = enumerations.UPDATABLE
3503                                 else:
3504                                         status_icon = installed_icon
3505                         marked = False
3506                         if not self.is_search_all:
3507                                 pkgs = self.selected_pkgs.get(pkg_publisher)
3508                                 if pkgs != None:
3509                                         if pkg_stem in pkgs:
3510                                                 marked = True
3511                         next_app = \
3512                             [
3513                                 marked, status_icon, pkg_name, '...', pkg_state,
3514                                 pkg, pkg_stem, None, True, None, pkg_publisher
3515                             ]
3516                         pkg_count += 1
3517 
3518                 if next_app:
3519                         self.__add_package_to_list(next_app, application_list, 
3520                             pkg_add, pkg_name, category_icon, categories, 
3521                             category_list, pkg_publisher)
3522                         pkg_add += 1
3523                 if category_list != None:
3524                         self.__add_categories_to_sections(sections,
3525                             category_list, section_list)
3526                 self.__progressdialog_progress_percent(PACKAGE_PROGRESS_PERCENT_TOTAL,
3527                     total_pkg_count, total_pkg_count)
3528                 return
3529 
3530         def __add_categories_to_sections(self, sections, category_list, section_list):
3531                 for publisher in sections:
3532                         for section in sections[publisher]:
3533                                 for category in sections[publisher][section].split(","):
3534                                         self.__add_category_to_section(_(category),
3535                                             _(section), category_list, section_list)
3536 
3537                 #1915 Sort the Categories into alphabetical order and prepend All Category
3538                 if len(category_list) > 0:
3539                         rows = [tuple(r) + (i,) for i, r in enumerate(category_list)]
3540                         rows.sort(self.__sort)
3541                         r = []
3542                         category_list.reorder([r[-1] for r in rows])
3543                 return
3544 
3545         def __add_package_to_list(self, app, application_list, pkg_add,
3546             pkg_name, category_icon, categories, category_list, publisher):
3547                 row_iter = application_list.insert(pkg_add, app)
3548                 if category_list == None:
3549                         return
3550                 cat_pub = categories.get(publisher)
3551                 if pkg_name in cat_pub:
3552                         pkg_categories = cat_pub.get(pkg_name)
3553                         for pcat in pkg_categories.split(","):
3554                                 self.__add_package_to_category(_(pcat), None,
3555                                     category_icon, row_iter, application_list,
3556                                     category_list)
3557 
3558         @staticmethod
3559         def __add_package_to_category(category_name, category_description,
3560             category_icon, package, application_list, category_list):
3561                 if not package or category_name == _('All'):
3562                         return
3563                 if not category_name:
3564                         return
3565                 category_id = None
3566                 icon_visible = False
3567                 if category_icon:
3568                         icon_visible = True
3569                 for category in category_list:
3570                         if category[enumerations.CATEGORY_NAME] == category_name:
3571                                 category_id = category[enumerations.CATEGORY_ID]
3572                                 if category_icon:
3573                                         category[enumerations.CATEGORY_ICON] = \
3574                                             category_icon
3575                                         category[enumerations.CATEGORY_ICON_VISIBLE] = \
3576                                             icon_visible
3577                                 break
3578                 if not category_id:                       # Category not exists
3579                         category_id = len(category_list) + 1
3580                         category_list.append([category_id, category_name,
3581                             category_description, category_icon, icon_visible,
3582                             True, None])
3583                 if application_list.get_value(package,
3584                     enumerations.CATEGORY_LIST_COLUMN):
3585                         a = application_list.get_value(package,
3586                             enumerations.CATEGORY_LIST_COLUMN)
3587                         a.append(category_id)
3588                 else:
3589                         category_list = []
3590                         category_list.append(category_id)
3591                         application_list.set(package,
3592                             enumerations.CATEGORY_LIST_COLUMN, category_list)
3593 
3594         @staticmethod
3595         def __add_category_to_section(category_name, section_name, category_list,
3596             section_list):
3597                 '''Adds the section to section list in category. If there is no such
3598                 section, than it is not added. If there was already section than it
3599                 is skipped. Sections must be case sensitive'''
3600                 if not category_name:
3601                         return
3602                 for section in section_list:
3603                         if section[enumerations.SECTION_NAME] == section_name:
3604                                 section_id = section[enumerations.SECTION_ID]
3605                                 for category in category_list:
3606                                         if category[enumerations.CATEGORY_NAME] == \
3607                                             category_name:
3608                                                 section_lst = category[ \
3609                                                     enumerations.SECTION_LIST_OBJECT]
3610                                                 section[enumerations.SECTION_ENABLED] = \
3611                                                     True
3612                                                 if not section_lst:
3613                                                         category[ \
3614                                                     enumerations.SECTION_LIST_OBJECT] = \
3615                                                             [section_id, ]
3616                                                 else:
3617                                                         if not section_name in \
3618                                                             section_lst:
3619                                                                 section_lst.append(
3620                                                                     section_id)
3621 
3622         def __progressdialog_progress_pulse(self):
3623                 while not self.progress_stop_timer_thread:
3624                         gobject.idle_add(self.w_progressbar.pulse)
3625                         time.sleep(0.1)
3626                 gobject.idle_add(self.w_progress_dialog.hide)
3627                 self.progress_stop_timer_thread = False
3628 
3629         # For initial setup before loading package entries allow 5% of progress bar
3630         # update it on a time base as we have no other way to judge progress at this point
3631         def __progressdialog_progress_time(self):
3632                 while not self.progress_stop_timer_thread and \
3633                         self.progress_fraction_time_count <= \
3634                             INITIAL_PROGRESS_TOTAL_PERCENTAGE:
3635 
3636                         gobject.idle_add(self.w_progressbar.set_fraction,
3637                             self.progress_fraction_time_count)
3638                         self.progress_fraction_time_count += \
3639                                 INITIAL_PROGRESS_TIME_PERCENTAGE
3640                         time.sleep(INITIAL_PROGRESS_TIME_INTERVAL)
3641                 self.progress_stop_timer_thread = False
3642                 self.progress_fraction_time_count = 0
3643 
3644         def __progressdialog_progress_percent(self, fraction, count, total):
3645                 gobject.idle_add(self.w_progressinfo_label.set_text, _(
3646                     "Processing package entries: %d of %d") % (count, total)  )
3647                 gobject.idle_add(self.w_progressbar.set_fraction, fraction)
3648 
3649         def error_occurred(self, error_msg, msg_title=None, msg_type=gtk.MESSAGE_ERROR):
3650                 if msg_title:
3651                         title = msg_title
3652                 else:
3653                         title = _("Package Manager")
3654                 gui_misc.error_occurred(self.w_main_window, error_msg,
3655                     title, msg_type, use_markup=True)
3656 
3657 
3658                 msgbox = gtk.MessageDialog(parent =
3659                     self.w_main_window,
3660                     buttons = gtk.BUTTONS_CLOSE,
3661                     flags = gtk.DIALOG_MODAL,
3662                     type = msg_type,
3663                     message_format = None)
3664                 msgbox.set_property('text', error_msg)
3665                 title = None
3666                 if msg_title:
3667                         title = msg_title
3668                 else:
3669                         title = _("Package Manager")
3670                 msgbox.set_title(title)
3671                 msgbox.run()
3672                 msgbox.destroy()
3673 
3674 #-----------------------------------------------------------------------------#
3675 # Static Methods
3676 #-----------------------------------------------------------------------------#
3677 
3678         #@staticmethod
3679         #def N_(message):
3680         #        return message
3681 
3682         @staticmethod
3683         def __sort(a, b):
3684                 return cmp(a[1], b[1])
3685 
3686         @staticmethod
3687         def cell_data_function(column, renderer, model, itr, data):
3688                 '''Function which sets the background colour to black if package is
3689                 selected'''
3690                 if itr:
3691                         if model.get_value(itr, enumerations.MARK_COLUMN):
3692                                 renderer.set_property("cell-background", "#ffe5cc")
3693                                 renderer.set_property("cell-background-set", True)
3694                         else:
3695                                 renderer.set_property("cell-background-set", False)
3696 
3697         @staticmethod
3698         def combobox_separator(model, itr):
3699                 return model.get_value(itr, enumerations.FILTER_NAME) == ""
3700 
3701         @staticmethod
3702         def combobox_id_separator(model, itr):
3703                 return model.get_value(itr, 0) == -1 and \
3704                     model.get_value(itr, 1) == ""
3705 
3706         @staticmethod
3707         def category_filter(model, itr):
3708                 '''This function filters category in the main application view'''
3709                 return model.get_value(itr, enumerations.CATEGORY_VISIBLE)
3710 
3711         @staticmethod
3712         def get_datetime(version):
3713                 dt = None
3714                 try:
3715                         dt = version.get_datetime()
3716                 except AttributeError:
3717                         dt = version.get_timestamp()
3718                 return dt
3719 
3720         @staticmethod
3721         def get_installed_version(api_o, pkg):
3722                 info = api_o.info([pkg], False, frozenset(
3723                     [api.PackageInfo.STATE, api.PackageInfo.IDENTITY]))
3724                 found = info[api.ImageInterface.INFO_FOUND]
3725                 try:
3726                         version = found[0]
3727                 except IndexError:
3728                         version = None
3729                 return version
3730 
3731 #-----------------------------------------------------------------------------#
3732 # Public Methods
3733 #-----------------------------------------------------------------------------#
3734         def setup_progressdialog_show(self):
3735                 self.w_progress_dialog.set_title(_("Loading Repository Information"))
3736                 self.w_progressinfo_label.set_text(
3737                     _( "Fetching package entries ..."))
3738                 self.w_progress_cancel.hide()
3739                 self.w_progress_dialog.show()
3740                 Thread(target = self.__progressdialog_progress_time).start()
3741 
3742         def setup_progressdialog_hide(self):
3743                 self.progress_stop_timer_thread = True
3744                 self.w_progress_dialog.hide()
3745 
3746         def init_show_filter(self):
3747                 self.__init_show_filter()                #Initiates filter
3748 
3749         def reload_packages(self):
3750                 self.api_o = gui_misc.get_api_object(self.image_directory, 
3751                     self.pr, self.w_main_window)
3752                 self.cache_o = self.__get_cache_obj(self.icon_theme, 
3753                     self.application_dir, self.api_o)
3754                 self.__on_reload(None)
3755 
3756         def set_busy_cursor(self):
3757                 self.gdk_window.show()
3758 
3759         def unset_busy_cursor(self):
3760                 self.gdk_window.hide()
3761 
3762         def process_package_list_start(self, image_directory):
3763                 self.image_directory = image_directory
3764                 if not self.api_o:
3765                         self.api_o = gui_misc.get_api_object(image_directory, 
3766                             self.pr, self.w_main_window)
3767                         self.cache_o = self.__get_cache_obj(self.icon_theme,
3768                             self.application_dir, self.api_o)
3769                         self.img_timestamp = self.cache_o.get_index_timestamp()
3770                 self.repositories_list = self.__get_new_repositories_liststore()
3771                 self.__setup_repositories_combobox(self.api_o, self.repositories_list)
3772 
3773         @staticmethod
3774         def __get_cache_obj(icon_theme, application_dir, api_o):
3775                 cache_o = cache.CacheListStores(icon_theme, application_dir,
3776                     api_o)
3777                 return cache_o
3778 
3779         def process_package_list_end(self):
3780                 self.__set_first_category_text()
3781                 self.in_startpage_startup = False
3782                 if self.update_all_proceed:
3783                 # TODO: Handle situation where only SUNWipkg/SUNWipg-gui have been updated
3784                 # in update all: bug 6357
3785                         self.__on_update_all(None)
3786                         self.update_all_proceed = False
3787                 self.setup_progressdialog_hide()
3788                 self.__enable_disable_install_remove()
3789                 self.update_statusbar()
3790                 self.in_setup = False
3791                 self.cancelled = False
3792                 if self.set_section != 0 or \
3793                     self.set_show_filter != enumerations.FILTER_ALL:
3794                         self.__application_refilter()
3795                 else:
3796                         self.unset_busy_cursor()
3797                 
3798                 if self.first_run or self.in_reload:
3799                         Thread(target = self.__enable_disable_update_all).start()
3800                 self.first_run = False
3801                 self.in_reload = False
3802 
3803         def get_icon_pixbuf_from_glade_dir(self, icon_name):
3804                 return gui_misc.get_pixbuf_from_path(self.application_dir +
3805                     "/usr/share/package-manager/", icon_name)
3806 
3807         def update_statusbar(self):
3808                 '''Function which updates statusbar'''
3809                 if self.statusbar_message_id > 0:
3810                         self.w_main_statusbar.remove(0, self.statusbar_message_id)
3811                         self.statusbar_message_id = 0
3812                 search_text = self.w_searchentry.get_text()
3813                 if self.in_search_mode:
3814                         if self.is_search_all:
3815                                 opt_str = _('Searched All for "%s"') % (search_text)
3816                         else:
3817                                 opt_str = \
3818                                         _('Searched %(last_active)s '
3819                                             'for "%(search_text)s"') \
3820                                         % {"last_active" : self.last_active_publisher,
3821                                             "search_text" : search_text}
3822                         if len(self.application_list) == SEARCH_LIMIT:
3823                                 fmt_str = _("%(option_str)s:  first %(number)d "
3824                                     "found %(time)s")
3825                         else:
3826                                 fmt_str = _("%(option_str)s:  %(number)d found %(time)s")
3827                         time_str = ""
3828                         if self.search_time_sec > 0:
3829                                 time_str = _("in %d seconds") % self.search_time_sec
3830                         status_str = fmt_str % {"option_str" : opt_str,
3831                             "number" : len(self.application_list), "time" : time_str}
3832                         self.w_main_statusbar.push(0, status_str)
3833                         return
3834                 installed = 0
3835                 self.selected = 0
3836                 sel = 0
3837                 if self.application_list == None:
3838                         return
3839                 visible_repository = self.__get_visible_repository_name()
3840                 pkgs = self.selected_pkgs.get(visible_repository)
3841                 if pkgs:
3842                         self.selected = len(pkgs)
3843                 for pkg_row in self.application_list:
3844                         if pkg_row[enumerations.STATUS_COLUMN] == enumerations.INSTALLED \
3845                             or pkg_row[enumerations.STATUS_COLUMN] == \
3846                             enumerations.UPDATABLE:
3847                                 installed = installed + 1
3848                         if pkg_row[enumerations.MARK_COLUMN]:
3849                                 sel = sel + 1
3850                 listed_str = _('%d listed') % len(self.application_list)
3851                 sel_str = _('%d selected') % sel
3852                 inst_str = _('%d installed') % installed
3853                 status_str = _("%s: %s , %s, %s.") % (visible_repository, listed_str,
3854                         inst_str, sel_str)
3855                 self.w_main_statusbar.push(0, status_str)
3856 
3857         def update_package_list(self, update_list):
3858                 if update_list == None and self.img_timestamp:
3859                         return
3860                 visible_repository = self.__get_visible_repository_name()
3861                 default_publisher = self.default_publisher
3862                 self.api_o.refresh()
3863                 if not self.img_timestamp:
3864                         self.img_timestamp = self.cache_o.get_index_timestamp()
3865                         self.__on_reload(None)
3866                         return
3867                 self.img_timestamp = self.cache_o.get_index_timestamp()
3868                 installed_icon = gui_misc.get_icon(self.icon_theme,
3869                     "status_installed")
3870                 visible_list = update_list.get(visible_repository)
3871                 if visible_list:
3872                         i = 0
3873                         while i < len(visible_list):
3874                                 visible_list[i] = gui_misc.get_pkg_name(
3875                                     visible_list[i])
3876                                 i +=  1
3877                         for row in self.application_list:
3878                                 if row[enumerations.NAME_COLUMN] in visible_list:
3879                                         pkg = row[enumerations.FMRI_COLUMN]
3880                                         pkg_stem = row[enumerations.STEM_COLUMN]
3881                                         self.__remove_pkg_stem_from_list(pkg_stem)
3882                                         if self.info_cache.has_key(pkg_stem):
3883                                                 del self.info_cache[pkg_stem]
3884                                         package_info = self.get_installed_version(
3885                                             self.api_o, pkg_stem)
3886                                         package_installed =  (package_info.state 
3887                                             == api.PackageInfo.INSTALLED)
3888                                         print pkg_stem, package_installed
3889                                         if package_installed:
3890                                                 row[enumerations.STATUS_COLUMN] = \
3891                                                     enumerations.INSTALLED
3892                                                 row[enumerations.STATUS_ICON_COLUMN] = \
3893                                                     installed_icon
3894                                         else:
3895                                                 row[enumerations.STATUS_COLUMN] = \
3896                                                     enumerations.NOT_INSTALLED
3897                                                 row[enumerations.STATUS_ICON_COLUMN] = \
3898                                                     None
3899                                         row[enumerations.MARK_COLUMN] = False
3900                         self.__dump_datamodels(visible_repository,
3901                                 self.application_list, self.category_list,
3902                                 self.section_list)
3903                 for publisher in update_list:
3904                         if publisher != visible_repository:
3905                                 pkg_list = update_list.get(publisher)
3906                                 for pkg in pkg_list:
3907                                         pkg_stem = None
3908                                         if publisher != default_publisher:
3909                                                 pkg_stem = "pkg://%s/%s" % \
3910                                                         (publisher, pkg)
3911                                         else:
3912                                                 pkg_stem = "pkg:/%s" % pkg
3913                                         if pkg_stem:
3914                                                 if self.info_cache.has_key(pkg_stem):
3915                                                         del self.info_cache[pkg_stem]
3916                                                 self.__remove_pkg_stem_from_list(pkg_stem)
3917                 self.__process_package_selection()
3918                 self.__enable_disable_selection_menus()
3919                 self.__enable_disable_install_remove()
3920                 self.update_statusbar()
3921                 Thread(target = self.__enable_disable_update_all).start()
3922 
3923         @staticmethod
3924         def __find_root_home_dir():
3925                 return_str = '/var/tmp'
3926                  
3927                 try:
3928                         lines = pwd.getpwnam('root')
3929                 except KeyError:
3930                         if debug:
3931                                 print "Error getting passwd database entry for root"
3932                         return return_str
3933                 try:
3934                         return_str = lines[5]
3935                 except IndexError:
3936                         if debug:
3937                                 print "Error getting home directory for root"
3938                 return return_str
3939 
3940         def restart_after_ips_update(self, be_name):
3941                 self.__main_application_quit(be_name)
3942 
3943         def shutdown_after_image_update(self):
3944                 info_str = _("The Update All action is now complete and "
3945                     "Package Manager will close.\n\nReview the posted release notes "
3946                     "before rebooting your system:\n\n"
3947                     )
3948                 self.w_ua_completed_release_label.set_text(info_str.strip('\n'))
3949 
3950                 info_str = misc.get_release_notes_url()
3951                 self.w_ua_completed_linkbutton.set_uri(info_str)
3952                 self.w_ua_completed_linkbutton.set_label(info_str)
3953                 self.release_notes_url = info_str
3954                 
3955                 self.w_ua_completed_dialog.set_title(_("Update All Complete"))
3956                 self.w_ua_completed_dialog.show()
3957 
3958 ###############################################################################
3959 #-----------------------------------------------------------------------------#
3960 # Main
3961 #-----------------------------------------------------------------------------#
3962 
3963 def main():
3964         gtk.main()
3965         return 0
3966 
3967 if __name__ == '__main__':
3968         debug = False
3969         debug_descriptions = False
3970         update_all_proceed = False
3971         ua_be_name = None
3972         app_path = None
3973         image_dir = None
3974         info_install_arg = None
3975         save_selected = _("Save selected...")
3976         save_selected_pkgs = _("Save selected packages...")
3977         reboot_needed = _("The installed package(s) require a reboot before "
3978             "installation can be completed.")
3979 
3980         try:
3981                 opts, args = getopt.getopt(sys.argv[1:], "hR:U:i:", \
3982                     ["help", "image-dir=", "update-all=", "info-install="])
3983         except getopt.error, msg:
3984                 print "%s, for help use --help" % msg
3985                 sys.exit(2)
3986 
3987         if os.path.isabs(sys.argv[0]):
3988                 app_path = sys.argv[0]
3989         else:
3990                 cmd = os.path.join(os.getcwd(), sys.argv[0])
3991                 app_path = os.path.realpath(cmd)
3992 
3993         for option, argument in opts:
3994                 if option in ("-h", "--help"):
3995                         print """\
3996 Use -R (--image-dir) to specify image directory.
3997 Use -U (--update-all) to proceed with Update All"""
3998                         sys.exit(0)
3999                 if option in ("-R", "--image-dir"):
4000                         image_dir = argument
4001                 if option in ("-U", "--update-all"):
4002                         update_all_proceed = True
4003                         ua_be_name = argument
4004                 if option in ("-i", "--info-install"):
4005                         info_install_arg = argument
4006 
4007         if image_dir == None:
4008                 try:
4009                         image_dir = os.environ["PKG_IMAGE"]
4010                 except KeyError:
4011                         image_dir = os.getcwd()
4012         try:
4013                 gtk.init_check()
4014         except RuntimeError, e:
4015                 print _("Unable to initialize gtk")
4016                 print str(e)
4017                 sys.exit(1)
4018 
4019         # Setup webinstall
4020         if info_install_arg or len(sys.argv) == 2:
4021                 webinstall = webinstall.Webinstall(image_dir)
4022                 if len(sys.argv) == 2:
4023                         info_install_arg = sys.argv[1]
4024                 webinstall.process_param(info_install_arg)
4025                 main()
4026                 sys.exit(0)
4027 
4028         # Setup packagemanager
4029         packagemanager = PackageManager()
4030         packagemanager.application_path = app_path
4031         packagemanager.image_dir_arg = image_dir
4032         packagemanager.update_all_proceed = update_all_proceed
4033         packagemanager.ua_be_name = ua_be_name
4034 
4035         while gtk.events_pending():
4036                 gtk.main_iteration(False)
4037 
4038         packagemanager.init_show_filter()
4039 
4040         packagemanager.process_package_list_start(image_dir)
4041 
4042         main()