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