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_sort_column):
1019                 ##APPLICATION MAIN TREEVIEW
1020                 if application_list_filter == None:
1021                         application_list_filter = application_list.filter_new()
1022                 if application_list_sort == None:
1023                         application_list_sort = \
1024                             gtk.TreeModelSort(application_list_filter)
1025                         application_list_sort.set_sort_column_id(
1026                             application_sort_column, gtk.SORT_ASCENDING)
1027                         application_list_sort.set_sort_func(
1028                             enumerations.STATUS_ICON_COLUMN, self.__status_sort_func)
1029                 toggle_renderer = gtk.CellRendererToggle()
1030 
1031                 column = gtk.TreeViewColumn("", toggle_renderer, \
1032                     active = enumerations.MARK_COLUMN)
1033                 column.set_sort_column_id(enumerations.MARK_COLUMN)
1034                 column.set_sort_indicator(True)
1035                 column.set_cell_data_func(toggle_renderer, self.cell_data_function, None)
1036                 column.connect_after('clicked',
1037                     self.__application_treeview_column_sorted, None)
1038                 self.w_application_treeview.append_column(column)
1039                 name_renderer = gtk.CellRendererText()
1040                 column = gtk.TreeViewColumn(_("Name"), name_renderer,
1041                     text = enumerations.NAME_COLUMN)
1042                 column.set_resizable(True)
1043                 column.set_min_width(150)
1044                 column.set_sort_column_id(enumerations.NAME_COLUMN)
1045                 column.set_sort_indicator(True)
1046                 column.set_cell_data_func(name_renderer, self.cell_data_function, None)
1047                 column.connect_after('clicked',
1048                     self.__application_treeview_column_sorted, None)
1049                 self.w_application_treeview.append_column(column)
1050                 column = self.__create_icon_column(_("Status"), True,
1051                     enumerations.STATUS_ICON_COLUMN, True)
1052                 column.set_sort_column_id(enumerations.STATUS_ICON_COLUMN)
1053                 column.set_sort_indicator(True)
1054                 column.connect_after('clicked',
1055                     self.__application_treeview_column_sorted, None)
1056                 self.w_application_treeview.append_column(column)
1057                 if self.is_search_all:
1058                         repository_renderer = gtk.CellRendererText()
1059                         column = gtk.TreeViewColumn(_('Repository'),
1060                             repository_renderer,
1061                             text = enumerations.AUTHORITY_COLUMN)
1062                         column.set_sort_column_id(enumerations.AUTHORITY_COLUMN)
1063                         column.set_resizable(True)
1064                         column.set_sort_indicator(True)
1065                         column.set_cell_data_func(repository_renderer,
1066                             self.cell_data_function, None)
1067                         column.connect_after('clicked',
1068                             self.__application_treeview_column_sorted, None)
1069                         self.w_application_treeview.append_column(column)
1070                 description_renderer = gtk.CellRendererText()
1071                 column = gtk.TreeViewColumn(_('Description'),
1072                     description_renderer,
1073                     text = enumerations.DESCRIPTION_COLUMN)
1074                 column.set_sort_column_id(enumerations.DESCRIPTION_COLUMN)
1075                 column.set_resizable(True)
1076                 column.set_sort_indicator(True)
1077                 column.set_cell_data_func(description_renderer,
1078                     self.cell_data_function, None)
1079                 column.connect_after('clicked',
1080                     self.__application_treeview_column_sorted, None)
1081                 self.w_application_treeview.append_column(column)
1082                 #Added selection listener
1083                 self.package_selection = self.w_application_treeview.get_selection()
1084                 self.application_list = application_list
1085                 self.application_list_filter = application_list_filter
1086                 self.application_list_sort = application_list_sort
1087                 toggle_renderer.connect('toggled', self.__active_pane_toggle,
1088                     application_list_sort)
1089 
1090         def __init_tree_views(self, application_list, category_list, 
1091             section_list, application_list_filter = None, 
1092             application_list_sort = None, 
1093             application_sort_column = enumerations.NAME_COLUMN):
1094                 '''This function connects treeviews with their models and also applies
1095                 filters'''
1096                 if category_list == None:
1097                         self.w_application_treeview.set_model(None)
1098                         self.__remove_treeview_columns(self.w_application_treeview)
1099                 elif application_list == None:
1100                         self.w_categories_treeview.set_model(None)
1101                         self.__remove_treeview_columns(self.w_categories_treeview)
1102                 else:
1103                         self.__disconnect_models()
1104                         self.__remove_treeview_columns(self.w_application_treeview)
1105                         self.__remove_treeview_columns(self.w_categories_treeview)
1106                 # The logic for set section needs to be here as some sections
1107                 # might be not enabled. In such situation we are setting the set
1108                 # section to "All Categories" one.
1109                 if section_list != None:
1110                         row = section_list[self.set_section]
1111                         if row[enumerations.SECTION_ENABLED] and \
1112                             self.set_section >= 0 and \
1113                             self.set_section < len(section_list):
1114                                 if row[enumerations.SECTION_ID] != self.set_section:
1115                                         self.set_section = 0
1116                         else:
1117                                 self.set_section = 0
1118 
1119                 if application_list != None:
1120                         self.__init_application_tree_view(application_list,
1121                             application_list_filter, application_list_sort, 
1122                             application_sort_column)
1123 
1124                 if self.first_run:
1125                         # When vadj changes we need to set image descriptions
1126                         # on visible status icons. This catches moving the scroll bars
1127                         # and scrolling up and down using keyboard.
1128                         vadj = self.w_application_treeview.get_vadjustment()
1129                         vadj.connect('value-changed',
1130                             self.__application_treeview_vadjustment_changed, None)
1131                         vadj = self.w_categories_treeview.get_vadjustment()
1132                         vadj.connect('value-changed',
1133                             self.__categories_treeview_vadjustment_changed, None)
1134 
1135                         # When the size of the application_treeview changes
1136                         # we need to set image descriptions on visible status icons.
1137                         self.w_application_treeview.connect('size-allocate',
1138                             self.__application_treeview_size_allocate, None)
1139                         self.w_categories_treeview.connect('size-allocate',
1140                             self.__categories_treeview_size_allocate, None)
1141 
1142                 if category_list != None:
1143                         ##CATEGORIES TREEVIEW
1144                         #enumerations.CATEGORY_NAME
1145                         category_list_filter = category_list.filter_new()
1146                         column =  self.__create_icon_column("", False,
1147                             enumerations.CATEGORY_ICON, False)
1148                         self.w_categories_treeview.append_column(column)
1149                         enumerations.CATEGORY_NAME_renderer = gtk.CellRendererText()
1150                         column = gtk.TreeViewColumn(_('Name'),
1151                             enumerations.CATEGORY_NAME_renderer,
1152                             text = enumerations.CATEGORY_NAME)
1153                         self.w_categories_treeview.append_column(column)
1154                         #Added selection listener
1155                         category_selection = self.w_categories_treeview.get_selection()
1156                         category_selection.set_mode(gtk.SELECTION_SINGLE)
1157 
1158                 if self.first_run:
1159                         ##SECTION COMBOBOX
1160                         #enumerations.SECTION_NAME
1161                         cell = gtk.CellRendererText()
1162                         self.w_sections_combobox.pack_start(cell, True)
1163                         self.w_sections_combobox.add_attribute(cell, 'text',
1164                             enumerations.SECTION_NAME)
1165                         self.w_sections_combobox.set_row_separator_func(
1166                             self.combobox_id_separator)
1167                         self.w_sections_combobox.add_attribute( cell,
1168                             'sensitive', enumerations.SECTION_ENABLED )
1169                         ##FILTER COMBOBOX
1170                         #enumerations.FILTER_NAME
1171                         cell = gtk.CellRendererText()
1172                         self.w_filter_combobox.pack_start(cell, True)
1173                         self.w_filter_combobox.add_attribute(cell, 'text',
1174                             enumerations.FILTER_NAME)
1175                         self.w_filter_combobox.set_row_separator_func(
1176                             self.combobox_id_separator)
1177 
1178                 if section_list != None:
1179                         self.section_list = section_list
1180                 if category_list != None:
1181                         self.category_list = category_list
1182                         self.category_list_filter = category_list_filter
1183                         self.w_categories_treeview.set_model(category_list_filter)
1184                         if not self.is_search_all:
1185                                 category_list_filter.set_visible_func(
1186                                     self.category_filter)
1187                                 self.__set_categories_visibility(self.set_section)
1188                         self.a11y_categories_treeview = \
1189                             self.w_categories_treeview.get_accessible()
1190                 if application_list != None:
1191                         if category_list != None:
1192                                 self.w_sections_combobox.set_model(section_list)
1193                                 self.w_sections_combobox.set_active(self.set_section)
1194                                 self.w_filter_combobox.set_model(self.filter_list)
1195                                 self.w_filter_combobox.set_active(self.set_show_filter)
1196                         self.w_application_treeview.set_model(
1197                             self.application_list_sort)
1198                         if not self.in_search_mode:
1199                                 if application_list_filter == None:
1200                                         self.application_list_filter.set_visible_func(
1201                                             self.__application_filter)
1202 
1203                 category_selection = self.w_categories_treeview.get_selection()
1204                 category_model, category_iter = category_selection.get_selected()
1205                 self.pylintstub = category_model
1206                 if not category_iter and not self.in_search_mode:
1207                 #no category was selected, so select "All"
1208                         category_selection.select_path(0)
1209                         category_model, category_iter = category_selection.get_selected()
1210                 if self.first_run:
1211                         category_selection.connect("changed",
1212                             self.__on_category_selection_changed, None)
1213                         self.w_categories_treeview.connect("row-activated",
1214                             self.__on_category_row_activated, None)
1215                         self.w_categories_treeview.connect("focus-in-event",
1216                             self.__on_category_focus_in, None)
1217                         self.package_selection.set_mode(gtk.SELECTION_SINGLE)
1218                         self.package_selection.connect("changed",
1219                             self.__on_package_selection_changed, None)
1220 
1221                 self.a11y_application_treeview = \
1222                     self.w_application_treeview.get_accessible()
1223                 self.process_package_list_end()
1224 
1225         def __categories_treeview_size_allocate(self, widget, allocation, user_data):
1226                 # We ignore any changes in the size during initialization.
1227                 if self.categories_treeview_initialized:
1228                         if self.categories_status_id == 0:
1229                                 self.categories_status_id = gobject.idle_add(
1230                                     self.__set_accessible_categories_visible_status)
1231 
1232         def __categories_treeview_vadjustment_changed(self, widget, user_data):
1233                 self.__set_accessible_categories_visible_status()
1234 
1235         def __set_accessible_categories_status(self, model, itr):
1236                 status = model.get_value(itr, enumerations.CATEGORY_ICON)
1237                 if status != None:
1238                         desc = _("Updates Available")
1239                 else:
1240                         desc = None
1241                 if desc != None:
1242                         obj = self.a11y_categories_treeview.ref_at(
1243                             int(model.get_string_from_iter(itr)),
1244                             CATEGORIES_STATUS_COLUMN_INDEX)
1245                         obj.set_image_description(desc)
1246 
1247         def __set_accessible_categories_visible_status(self):
1248                 self.categories_status_id = 0
1249                 if self.a11y_categories_treeview.get_n_accessible_children() == 0:
1250                         # accessibility is not enabled
1251                         return
1252 
1253                 visible_range = self.w_categories_treeview.get_visible_range()
1254                 if visible_range == None:
1255                         return
1256                 start = visible_range[0][0]
1257                 end = visible_range[1][0]
1258                 # We try to minimize the range of accessible objects
1259                 # on which we set image descriptions
1260                 if self.categories_treeview_range != None:
1261                         old_start = self.categories_treeview_range[0][0]
1262                         old_end = self.categories_treeview_range[1][0]
1263                          # Old range is the same or smaller than new range
1264                          # so do nothing
1265                         if start >= old_start and end <= old_end:
1266                                 return
1267                         if start < old_end:
1268                                 if end < old_end:
1269                                         if end >= old_start:
1270                                                 end = old_start
1271                                 else:
1272                                         start = old_end
1273                 self.categories_treeview_range = visible_range
1274                 model = self.category_list_filter
1275                 itr = model.get_iter_from_string(str(start))
1276                 while start <= end:
1277                         start += 1
1278                         self.__set_accessible_categories_status(model, itr)
1279                         itr = model.iter_next(itr)
1280 
1281         def __application_treeview_column_sorted(self, widget, user_data):
1282                 self.__set_visible_status(False)
1283 
1284         def __init_repository_tree_view(self):
1285                 cell = gtk.CellRendererText()
1286                 self.w_repository_combobox.pack_start(cell, True)
1287                 self.w_repository_combobox.add_attribute(cell, 'text',
1288                     enumerations.REPOSITORY_NAME)
1289                 self.w_repository_combobox.set_row_separator_func(
1290                     self.combobox_id_separator)
1291 
1292         def __application_treeview_size_allocate(self, widget, allocation, user_data):
1293                 # We ignore any changes in the size during initialization.
1294                 if self.visible_status_id == 0:
1295                         self.visible_status_id = gobject.idle_add(
1296                             self.__set_visible_status)
1297 
1298         def __application_treeview_vadjustment_changed(self, widget, user_data):
1299                 self.__set_visible_status()
1300 
1301         def __set_accessible_status(self, model, itr):
1302                 status = model.get_value(itr, enumerations.STATUS_COLUMN)
1303                 if status == enumerations.INSTALLED:
1304                         desc = _("Installed")
1305                 elif status == enumerations.NOT_INSTALLED:
1306                         desc = _("Not Installed")
1307                 elif status == enumerations.UPDATABLE:
1308                         desc = _("Updates Available")
1309                 else:
1310                         desc = None
1311                 if desc != None:
1312                         obj = self.a11y_application_treeview.ref_at(
1313                             int(model.get_string_from_iter(itr)),
1314                             STATUS_COLUMN_INDEX)
1315                         obj.set_image_description(desc)
1316 
1317         def __set_visible_status(self, check_range = True):
1318                 self.visible_status_id = 0
1319                 if self.w_main_view_notebook.get_current_page() != \
1320                     NOTEBOOK_PACKAGE_LIST_PAGE:
1321                         return
1322                 if self.__doing_search():
1323                         return
1324 
1325                 a11y_enabled = False
1326                 if self.a11y_application_treeview.get_n_accessible_children() != 0:
1327                         a11y_enabled = True
1328 
1329                 visible_range = self.w_application_treeview.get_visible_range()
1330                 if visible_range == None:
1331                         return
1332                 start = visible_range[0][0]
1333                 end = visible_range[1][0]
1334                 if debug_descriptions:
1335                         print "Range Start: %d End: %d" % (start, end)
1336 
1337                 # Switching Publishers need to use default range
1338                 active_pub = self.__get_active_publisher()
1339                 if self.last_active_publisher != active_pub:
1340                         check_range = False
1341                 self.last_active_publisher = active_pub
1342                 if self.in_search_mode:
1343                         check_range = False
1344                 
1345                 if self.application_treeview_range != None:
1346                         if check_range:
1347                                 old_start = self.application_treeview_range[0][0]
1348                                 old_end = self.application_treeview_range[1][0]
1349                                  # Old range is the same or smaller than new range
1350                                  # so do nothing
1351                                 if start >= old_start and end <= old_end:
1352                                         return
1353                                 if start < old_end:
1354                                         if end < old_end:
1355                                                 if end >= old_start:
1356                                                         end = old_start
1357                                         else:
1358                                                 start = old_end
1359                 if debug_descriptions:
1360                         print "Adjusted Range Start: %d End: %d" % (start, end)
1361                 self.application_treeview_range = visible_range
1362 
1363                 sort_filt_model = \
1364                     self.w_application_treeview.get_model() #gtk.TreeModelSort
1365                 filt_model = sort_filt_model.get_model() #gtk.TreeModelFilter
1366                 model = filt_model.get_model() #gtk.ListStore
1367                 sf_itr = sort_filt_model.get_iter_from_string(str(start))                
1368                 pkg_stems_and_itr_to_fetch = {}
1369                 while start <= end:
1370                         filtered_itr = sort_filt_model.convert_iter_to_child_iter(None,
1371                             sf_itr)
1372                         app_itr = filt_model.convert_iter_to_child_iter(filtered_itr)
1373 
1374                         desc = sort_filt_model.get_value(sf_itr,
1375                             enumerations.DESCRIPTION_COLUMN)
1376                         # Only Fetch description for packages without a
1377                         # description
1378                         if desc == '...':
1379                                 fmri = sort_filt_model.get_value(sf_itr,
1380                                     enumerations.FMRI_COLUMN)
1381                                 if fmri != None:
1382                                         pkg_stem = fmri.get_pkg_stem(
1383                                             include_scheme = True)
1384                                         pkg_stems_and_itr_to_fetch[pkg_stem] = \
1385                                             model.get_string_from_iter(app_itr)
1386                         if a11y_enabled:
1387                                 self.__set_accessible_status(sort_filt_model, sf_itr)
1388                         start += 1
1389                         sf_itr = sort_filt_model.iter_next(sf_itr)
1390 
1391                 if debug_descriptions:
1392                         print "PKGS to FETCH: \n%s" % pkg_stems_and_itr_to_fetch
1393                 if len(pkg_stems_and_itr_to_fetch) > 0:
1394                         Thread(target = self.__get_pkg_descriptions,
1395                             args = [pkg_stems_and_itr_to_fetch, model]).start() 
1396                     
1397         def __doing_search(self):
1398                 return self.search_start > 0
1399                 
1400         def __get_pkg_descriptions(self, pkg_stems_and_itr_to_fetch, orig_model):
1401                 # Note: no need to aquire lock even though this can be called from
1402                 # multiple threads, it is just creating an update job and dispatching it
1403                 # to the idle handler, not modifying any global state
1404                 info = None
1405                 if not self.__doing_search():
1406                         gobject.idle_add(self.__update_statusbar_message,
1407                             _("Fetching descriptions..."))
1408                 try:
1409                         info = self.api_o.info(pkg_stems_and_itr_to_fetch.keys(), False,
1410                                 frozenset([api.PackageInfo.IDENTITY,
1411                                     api.PackageInfo.SUMMARY]))
1412                 except api_errors.TransportError:
1413                         self.update_statusbar()
1414                         return
1415                 if info and len(info.get(0)) == 0:
1416                         self.update_statusbar()
1417                         return
1418                 pkg_infos = info.get(0)
1419                 pkg_descriptions_for_update = []
1420                 for pkg_info in pkg_infos:
1421                         short_fmri = fmri.PkgFmri(pkg_info.fmri).get_pkg_stem(
1422                             include_scheme = True)
1423                         pkg_descriptions_for_update.append((short_fmri,
1424                             pkg_stems_and_itr_to_fetch[short_fmri],
1425                             pkg_info.summary))
1426                 if debug_descriptions:
1427                         print "FETCHED PKGS: \n%s" % pkg_descriptions_for_update
1428                 gobject.idle_add(self.__update_description_from_iter,
1429                     pkg_descriptions_for_update, orig_model)
1430 
1431         def __update_description_from_iter(self, pkg_descriptions_for_update, orig_model):
1432                 #If doing a search abandon description updates
1433                 if self.__doing_search():
1434                         return
1435 
1436                 sort_filt_model = \
1437                     self.w_application_treeview.get_model() #gtk.TreeModelSort
1438                 filt_model = sort_filt_model.get_model() #gtk.TreeModelFilter
1439                 model = filt_model.get_model() #gtk.ListStore
1440 
1441                 #If model has changed abandon description updates
1442                 if orig_model != model:
1443                         return
1444 
1445                 if debug_descriptions:
1446                         print "UPDATE DESCRIPTIONS: \n%s" % pkg_descriptions_for_update
1447                 for pkg_stem, path, summary in pkg_descriptions_for_update:
1448                         itr = model.get_iter_from_string(path)
1449                         stored_pkg_fmri = model.get_value(itr, enumerations.FMRI_COLUMN)
1450                         stored_pkg_stem = stored_pkg_fmri.get_pkg_stem(
1451                             include_scheme = True)
1452 
1453                         if pkg_stem != stored_pkg_stem:
1454                                 if debug:
1455                                         print ("__update_description_from_iter(): "
1456                                             "model not consistent so abandoning "
1457                                             "these description updates.")
1458                                 self.update_statusbar()
1459                                 return
1460                         model.set_value(itr, enumerations.DESCRIPTION_COLUMN, summary)
1461                 if not self.__doing_search():
1462                         self.update_statusbar()
1463 
1464         def __create_icon_column(self, name, expand_pixbuf, enum_value, set_data_func):
1465                 column = gtk.TreeViewColumn()
1466                 column.set_title(name)
1467                 #Commented, since there was funny jumping of the icons
1468                 #column.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
1469                 render_pixbuf = gtk.CellRendererPixbuf()
1470                 column.pack_start(render_pixbuf, expand = expand_pixbuf)
1471                 column.add_attribute(render_pixbuf, "pixbuf", enum_value)
1472                 column.set_fixed_width(32)
1473                 if set_data_func:
1474                         column.set_cell_data_func(render_pixbuf,
1475                             self.cell_data_function, None)
1476                 return column
1477 
1478         def __disconnect_models(self):
1479                 self.w_application_treeview.set_model(None)
1480                 self.w_categories_treeview.set_model(None)
1481                 self.w_sections_combobox.set_model(None)
1482                 self.w_filter_combobox.set_model(None)
1483 
1484         def __disconnect_repository_model(self):
1485                 self.w_repository_combobox.set_model(None)
1486 
1487         @staticmethod
1488         def __status_sort_func(treemodel, iter1, iter2, user_data=None):
1489                 get_val = treemodel.get_value
1490                 status1 = get_val(iter1, enumerations.STATUS_COLUMN)
1491                 status2 = get_val(iter2, enumerations.STATUS_COLUMN)
1492                 return cmp(status1, status2)
1493 
1494         @staticmethod
1495         def __remove_treeview_columns(treeview):
1496                 columns = treeview.get_columns()
1497                 if columns:
1498                         for column in columns:
1499                                 treeview.remove_column(column)
1500 
1501         @staticmethod
1502         def __init_sections(section_list):
1503                 '''This function is for initializing sections combo box, also adds "All"
1504                 Category. It sets active section combobox entry "All"'''
1505                 cat_path = None
1506                 enabled = True
1507                 # We enable only first section and later we might enable the rest,
1508                 # depending if there are some packages connected with them
1509                 section_list.append([0, _('All Categories'), cat_path, enabled ])
1510                 section_list.append([-1, "", cat_path, enabled ])
1511                 enabled = False
1512                 section_list.append([2, _('Meta Packages'), cat_path, enabled ])
1513                 section_list.append([3, _('Applications'), cat_path, enabled ])
1514                 section_list.append([4, _('Desktop (GNOME)'), cat_path, enabled ])
1515                 section_list.append([5, _('Development'), cat_path, enabled ])
1516                 section_list.append([6, _('Distributions'), cat_path, enabled ])
1517                 section_list.append([7, _('Drivers'), cat_path, enabled ])
1518                 section_list.append([8, _('System'), cat_path, enabled ])
1519                 section_list.append([9, _('Web Services'), cat_path, enabled ])
1520 
1521         def __init_show_filter(self):
1522                 self.filter_list.append([enumerations.FILTER_ALL, _('All Packages'), ])
1523                 self.filter_list.append([enumerations.FILTER_INSTALLED,
1524                     _('Installed Packages'), ])
1525                 self.filter_list.append([enumerations.FILTER_UPDATES,
1526                     _('Updates'), ])
1527                 self.filter_list.append([enumerations.FILTER_NOT_INSTALLED,
1528                     _('Non-installed Packages'), ])
1529                 self.filter_list.append([-1, "", ])
1530                 self.filter_list.append([enumerations.FILTER_SELECTED,
1531                     _('Selected Packages'), ])
1532                 if self.initial_show_filter >= enumerations.FILTER_ALL and \
1533                     self.initial_show_filter < len(self.filter_list):
1534                         row = self.filter_list[self.initial_show_filter]
1535                         if row[enumerations.SECTION_ID] != self.initial_show_filter:
1536                                 self.initial_show_filter = enumerations.FILTER_ALL
1537                 else:
1538                         self.initial_show_filter = enumerations.FILTER_ALL
1539 
1540 
1541         def __on_cancel_progressdialog_clicked(self, widget):
1542                 self.progress_canceled = True
1543                 self.progress_stop_timer_thread = True
1544 
1545         def __on_mainwindow_delete_event(self, widget, event):
1546                 ''' handler for delete event of the main window '''
1547                 if self.__check_if_something_was_changed() == True:
1548                         # XXX Change this to not quit and show dialog
1549                         # XXX if some changes were applied:
1550                         self.__main_application_quit()
1551                         return True
1552                 else:
1553                         self.__main_application_quit()
1554 
1555         def __on_api_search_error_delete_event(self, widget, event):
1556                 self.__on_api_search_button_clicked(None)
1557 
1558         def __on_api_search_button_clicked(self, widget):
1559                 self.api_search_error_dialog.hide()
1560 
1561         def __on_file_quit_activate(self, widget):
1562                 ''' handler for quit menu event '''
1563                 self.__on_mainwindow_delete_event(None, None)
1564 
1565         def __on_ua_completed_close(self, widget):
1566                 self.w_ua_completed_dialog.hide()
1567                 self.__on_mainwindow_delete_event(None, None)
1568 
1569         def __on_edit_repositories_activate(self, widget):
1570                 ''' handler for repository menu event '''
1571                 repository.Repository(self)
1572 
1573         def __on_file_be_activate(self, widget):
1574                 ''' handler for be menu event '''
1575                 beadm.Beadmin(self)
1576 
1577         def __on_searchentry_changed(self, widget):
1578                 if widget.get_text_length() > 0:
1579                         self.w_clear_search_button.set_sensitive(True)
1580                 else:
1581                         self.w_clear_search_button.set_sensitive(False)
1582                 self.__enable_disable_entry_selection(widget)
1583                 if self.is_search_all and not self.changing_search_option:
1584                         if self.w_searchentry.get_text() == "":
1585                                 self.w_infosearch_frame.hide()
1586                                 self.__link_load_blank()
1587                                 self.w_main_view_notebook.set_current_page(
1588                                     NOTEBOOK_START_PAGE)
1589                                 self.__update_statusbar_for_search()
1590                                 self.w_searchentry.grab_focus()
1591 
1592         def __update_statusbar_for_search(self):
1593                 self.__update_statusbar_message(
1594                     self.search_options[self.current_search_option][3])
1595 
1596         def __update_statusbar_message(self, message):
1597                 if self.statusbar_message_id > 0:
1598                         self.w_main_statusbar.remove(0, self.statusbar_message_id)
1599                         self.statusbar_message_id = 0
1600                 self.statusbar_message_id = self.w_main_statusbar.push(0, message)
1601 
1602         def __setup_before_search_all_mode(self):
1603                 self.is_search_all = True
1604                 self.w_infosearch_frame.hide()
1605 
1606                 self.__save_setup_before_search()
1607                 self.w_repository_combobox.set_active(0)
1608                 self.__link_load_blank()
1609                 self.w_main_view_notebook.set_current_page(
1610                     NOTEBOOK_START_PAGE)
1611                 self.__update_statusbar_for_search()
1612                 self.w_searchentry.grab_focus()
1613                 if len(self.w_searchentry.get_text()) > 0:
1614                         start, end = self.w_searchentry.get_selection_bounds()
1615                         self.w_searchentry.select_region(end, end)
1616                 self.__unselect_category()
1617 
1618         def __clear_before_search(self):
1619                 self.in_setup = True
1620                 application_list = self.__get_new_application_liststore()
1621                 self.__set_empty_details_panel()
1622                 self.__set_main_view_package_list()
1623                 self.__init_tree_views(application_list, None, None)
1624                 self.__unselect_category()
1625 
1626         def __restore_setup_for_browse(self):
1627                 self.in_search_mode = False
1628                 self.is_search_all = False
1629                 self.w_infosearch_frame.hide()
1630 
1631                 self.set_busy_cursor()
1632                 self.w_repository_combobox.set_active(
1633                     self.saved_repository_combobox_active)
1634                 self.set_section = self.saved_sections_combobox_active
1635                 self.set_show_filter = self.saved_filter_combobox_active
1636                 if self.saved_category_list == self.category_list:
1637                         self.__init_tree_views(self.saved_application_list,
1638                             None, None,
1639                             self.saved_application_list_filter,
1640                             self.saved_application_list_sort)
1641                 else:
1642                         self.__init_tree_views(self.saved_application_list,
1643                             self.saved_category_list, self.saved_section_list,
1644                             self.saved_application_list_filter,
1645                             self.saved_application_list_sort)
1646                         
1647                 self.__set_main_view_package_list()
1648 
1649         def __save_setup_before_search(self, single_search=False):
1650                 #Do not save search data models
1651                 if self.in_search_mode:
1652                         return
1653                 self.saved_sections_combobox_active = \
1654                         self.w_sections_combobox.get_active()
1655                 self.saved_filter_combobox_active = \
1656                         self.w_filter_combobox.get_active()                        
1657                 self.saved_application_list = self.application_list
1658                 self.saved_application_list_sort = \
1659                         self.application_list_sort
1660                 self.saved_application_list_filter = \
1661                         self.application_list_filter
1662                 self.saved_category_list = self.category_list
1663                 self.saved_section_list = self.section_list
1664                 if single_search:
1665                         self.saved_repository_combobox_active = \
1666                                 self.w_repository_combobox.get_active()
1667                 self.w_filter_combobox.set_active(0)
1668 
1669         def __do_search(self):
1670                 self.search_start = 0
1671                 if self.changing_search_option:
1672                         return
1673                 active = self.w_filter_combobox.get_active()
1674                 if active != enumerations.FILTER_SELECTED:
1675                         self.saved_filter_combobox_active = active                        
1676                 if len(self.w_searchentry.get_text()) == 0:
1677                         return
1678                 if not self.is_search_all:
1679                         self.__save_setup_before_search(single_search=True)
1680                 self.__clear_before_search()
1681                 self.set_busy_cursor()
1682                 self.in_search_mode = True
1683                         
1684                 self.w_infosearch_frame.hide()
1685                 self.__update_statusbar_message(_("Searching..."))
1686                 if not self.is_search_all:
1687                         Thread(target = self.__do_api_search,
1688                             args = (self.is_search_all, )).start()
1689                 else:
1690                         Thread(target = self.__do_api_search,
1691                             args = ()).start()
1692 
1693         def __unselect_category(self):
1694                 selection = self.w_categories_treeview.get_selection()
1695                 model, itr = selection.get_selected()
1696                 if itr:
1697                         cat_path = model.get_string_from_iter(itr)
1698                         selected_section = self.w_sections_combobox.get_active()
1699                         section_row = self.section_list[selected_section]
1700                         section_row[enumerations.SECTION_SUBCATEGORY] = cat_path
1701                         selection.unselect_all()
1702 
1703         def __process_after_search_failure(self):
1704                 self.search_start = 0
1705                 self.search_time_sec = 0
1706                 self.application_list = []
1707                 self.update_statusbar()
1708                 self.unset_busy_cursor()
1709                 self.in_setup = False
1710 
1711         def __get_origin_uri(self, repo):
1712                 if repo == None:
1713                         return None
1714                 origin_uri = repo.origins[0]
1715                 ret_uri = None
1716                 if isinstance(origin_uri, str):
1717                         if len(origin_uri) > 0:
1718                                 ret_uri = origin_uri.strip("/")
1719                 elif isinstance(origin_uri, publisher.RepositoryURI):
1720                         uri = origin_uri.uri
1721                         if uri != None and len(uri) > 0:
1722                                 ret_uri = uri.strip("/")
1723                 return ret_uri
1724 
1725 
1726         def __do_api_search(self, search_all = True):
1727                 self.search_start = time.time()
1728                 self.search_time_sec = 0
1729                 text = self.w_searchentry.get_text()
1730                 # Here we call the search API to get the results
1731                 searches = []
1732                 servers = []
1733                 result = []
1734                 pargs = []
1735                 search_str = SEARCH_STR_FORMAT % text
1736                 pargs.append(search_str)
1737                 if search_all:
1738                         servers = None
1739                 else:
1740                         pub_prefix = self.__get_active_publisher()
1741                         if pub_prefix != None:
1742                                 pub = self.api_o.get_publisher(prefix=pub_prefix)
1743                         else:
1744                                 pub = self.api_o.get_preferred_publisher()
1745                         origin_uri = self.__get_origin_uri(pub.selected_repository)
1746                         servers.append({"origin": origin_uri})
1747                 if debug:
1748                         print "Search: pargs %s servers: %s" % (pargs, servers)
1749 
1750                 #TBD If we ever search just Installed pkgs should allow for a local search
1751                 case_sensitive = False
1752                 return_actions = True
1753                 searches.append(self.api_o.remote_search(
1754                     [api.Query(" ".join(pargs), case_sensitive, return_actions)],
1755                     servers=servers))
1756                 if debug:
1757                         print "Search Args: %s : cs: %s : retact: %s" % \
1758                                 ("".join(pargs), case_sensitive, return_actions)
1759 
1760                 last_name = ""
1761                 self.current_search_publisher = None
1762 
1763                 # Sorting results by Name gives best overall appearance and flow
1764                 sort_col = enumerations.NAME_COLUMN
1765                 try:
1766                         for query_num, publisher, (v, return_type, tmp) in \
1767                             itertools.chain(*searches):
1768                                 if v < 1 or return_type != api.Query.RETURN_PACKAGES:
1769                                         gobject.idle_add(self.w_progress_dialog.hide)
1770                                         self.__process_after_search_failure()
1771                                         return
1772 
1773                                 pub = None
1774                                 if publisher is not None \
1775                                     and "prefix" in publisher:
1776                                         pub = publisher["prefix"]
1777                                 name = fmri.PkgFmri(str(tmp)).get_name()
1778                                 if last_name != name:
1779                                         if debug:
1780                                                 print "Result Name: %s (%s)" % (name, pub)
1781                                         a_res = name, pub
1782                                         result.append(a_res)
1783                                         #Ignore Status when fetching
1784                                         application_list = \
1785                                                 self.__get_min_list_from_search(result)
1786                                         self.current_search_publisher = pub
1787                                         self.in_setup = True
1788                                         gobject.idle_add(self.__init_tree_views, 
1789                                             application_list, None, None, None, None,
1790                                             sort_col)
1791                                 last_name = name
1792                                 self.pylintstub = query_num
1793                 except api_errors.ProblematicSearchServers, ex:
1794                         self.__process_api_search_error(ex)
1795                         gobject.idle_add(self.w_progress_dialog.hide)
1796                         gobject.idle_add(self.__handle_api_search_error)
1797                         if len(result) == 0:
1798                                 self.__process_after_search_with_zero_results()
1799                                 return
1800                 except Exception, ex:
1801                         # We are not interested in this error
1802                         gobject.idle_add(self.w_progress_dialog.hide)
1803                         self.__process_after_search_failure()
1804                         return
1805                 if debug:
1806                         print "Number of search results:", len(result)
1807                 if len(result) == 0:
1808                         if debug:
1809                                 print "No search results"
1810                         self.__process_after_search_with_zero_results()
1811                         return
1812                 # We cannot get status of the packages if catalogs have not
1813                 # been loaded so we pause for up to 5 seconds here to
1814                 # allow catalogs to be loaded
1815                 times = 5
1816                 while self.catalog_loaded == False:
1817                         if times == 0:
1818                                 break
1819                         time.sleep(1)
1820                         times -= 1
1821 
1822                 #Now fetch full result set with Status
1823                 self.in_setup = True
1824                 application_list = self.__get_full_list_from_search(result)
1825                 gobject.idle_add(self.__init_tree_views, application_list, None, None, \
1826                     None, None, sort_col)
1827 
1828                 if self.search_start > 0:
1829                         self.search_time_sec = int(time.time() - self.search_start)
1830                         if debug:
1831                                 print "Search time: %d (sec)" % self.search_time_sec
1832                 self.search_start = 0
1833 
1834         def __process_after_search_with_zero_results(self):
1835                 if self.search_start > 0:
1836                         self.search_time_sec = int(time.time() - self.search_start)
1837                 self.search_start = 0
1838                 self.in_setup = True
1839                 application_list = self.__get_new_application_liststore()
1840                 gobject.idle_add(self.__set_empty_details_panel)
1841                 gobject.idle_add(self.__set_main_view_package_list)
1842                 gobject.idle_add(self.__init_tree_views, application_list, None, None)
1843 
1844         def __get_min_list_from_search(self, search_result):
1845                 application_list = self.__get_new_application_liststore()
1846                 for name, publisher in search_result:
1847                         application_list.append(
1848                             [False, None, name, '...', enumerations.NOT_INSTALLED, None, 
1849                             "pkg://" + publisher + "/" + name, None, True, None, 
1850                             publisher])
1851                 return application_list
1852 
1853         def __get_full_list_from_search(self, search_result):
1854                 application_list = self.__get_new_application_liststore()
1855                 self.__add_pkgs_to_list_from_search(search_result,
1856                     application_list)
1857                 return application_list
1858 
1859         def __add_pkgs_to_list_from_search(self, search_result,
1860             application_list):
1861                 pargs = []
1862                 default_pub = self.api_o.get_preferred_publisher().prefix
1863                 for name, publisher in search_result:
1864                         pargs.append("pkg://" + publisher + "/" + name)
1865                 # We now need to get the status for each package
1866                 if debug_descriptions:
1867                         print "pargs:", pargs
1868                 try:
1869                         pkgs_known = self.__get_inventory_list(pargs,
1870                             True, True)
1871                 except api_errors.InventoryException:
1872                         # This can happen if load_catalogs has not been run
1873                         err = _("Unable to get status for search results.\n"
1874                             "The catalogs have not been loaded.\n"
1875                             "Please try after few seconds.\n")
1876                         gobject.idle_add(self.w_progress_dialog.hide)
1877                         gobject.idle_add(self.error_occurred, err)
1878                         return
1879                 return self.__add_pkgs_to_lists(pkgs_known, application_list,
1880                     None, None)
1881 
1882         def __application_refilter(self):
1883                 ''' Disconnecting the model from the treeview improves
1884                 performance when assistive technologies are enabled'''
1885                 if self.in_setup:
1886                         return
1887                 self.application_refilter_id = 0
1888                 self.application_refilter_idle_id = 0
1889                 if not self.in_search_mode:
1890                         model = self.w_application_treeview.get_model()
1891                         self.w_application_treeview.set_model(None)
1892                         self.application_list_filter.refilter()
1893                         self.w_application_treeview.set_model(model)
1894                 gobject.idle_add(self.__set_empty_details_panel)
1895                 gobject.idle_add(self.__enable_disable_selection_menus)
1896                 gobject.idle_add(self.__enable_disable_install_remove)
1897                 self.application_treeview_initialized = True
1898                 self.application_treeview_range = None
1899                 if self.visible_status_id == 0:
1900                         self.visible_status_id = gobject.idle_add(
1901                             self.__set_visible_status)
1902                 self.categories_treeview_initialized = True
1903                 self.categories_treeview_range = None
1904                 if self.categories_status_id == 0:
1905                         self.categories_status_id = gobject.idle_add(
1906                             self.__set_accessible_categories_visible_status)
1907                 return False
1908 
1909         def __on_edit_paste(self, widget):
1910                 self.w_searchentry.paste_clipboard()
1911 
1912         def __on_clear_paste(self, widget):
1913                 bounds = self.w_searchentry.get_selection_bounds()
1914                 self.w_searchentry.delete_text(bounds[0], bounds[1])
1915                 return
1916 
1917         def __on_copy(self, widget):
1918                 focus_widget = self.w_main_window.get_focus()
1919                 if focus_widget == self.w_searchentry:
1920                         self.w_searchentry.copy_clipboard()
1921                         self.w_paste_menuitem.set_sensitive(True)
1922                 elif self.__is_a_textview(focus_widget):
1923                         focus_widget.get_buffer().copy_clipboard(
1924                             self.w_main_clipboard)
1925 
1926         def __on_cut(self, widget):
1927                 self.w_searchentry.cut_clipboard()
1928                 self.w_paste_menuitem.set_sensitive(True)
1929 
1930         def __popup_position_func(self, menu):
1931                 ''' Position popup menu immediately below search button'''
1932                 root = self.w_main_window.window.get_origin()
1933                 alloc = self.search_button.get_allocation()
1934                 return (root[0] + alloc.x, root[1] + alloc.y + alloc.height, False)
1935 
1936         def __on_set_search(self, widget, event):
1937                 if  event.type == gtk.gdk.BUTTON_PRESS:
1938                         self.searchmenu.popup(None, None, self.__popup_position_func,
1939                             event.button, event.time)
1940                         return True
1941                 return False
1942 
1943         def __on_set_search_clicked(self, widget):
1944                 self.searchmenu.popup(None, None, self.__popup_position_func,
1945                     0, 0)
1946                 return True
1947 
1948         def __on_edit_search_clicked(self, widget):
1949                 self.w_searchentry.grab_focus()
1950 
1951         def __on_clear_search(self, widget):
1952                 self.w_searchentry.delete_text(0, -1)
1953                 self.__do_search()
1954                 return
1955 
1956         def __on_startpage(self, widget):
1957                 self.__load_startpage()
1958                 self.w_main_view_notebook.set_current_page(NOTEBOOK_START_PAGE)
1959 
1960         def __on_notebook_change(self, widget, event, pagenum):
1961                 if (pagenum == INFO_NOTEBOOK_LICENSE_PAGE and 
1962                     not self.showing_empty_details):
1963                         licbuffer = self.w_license_textview.get_buffer()
1964                         leg_txt = _("Fetching legal information...")
1965                         licbuffer.set_text(leg_txt)
1966                         if self.show_licenses_id != 0:
1967                                 gobject.source_remove(self.show_licenses_id)
1968                                 self.show_licenses_id = 0
1969                         self.last_show_licenses_id = self.show_licenses_id = \
1970                             gobject.timeout_add(SHOW_LICENSE_DELAY,
1971                                 self.__show_licenses)
1972 
1973         def __is_a_textview(self, widget):
1974                 if (widget == self.w_generalinfo_textview or
1975                     widget == self.w_installedfiles_textview or
1976                     widget == self.w_dependencies_textview or
1977                     widget == self.w_license_textview):
1978                         return True
1979                 else:
1980                         return False
1981                     
1982                     
1983         def __on_select_all(self, widget):
1984                 focus_widget = self.w_main_window.get_focus()
1985                 if self.__is_a_textview(focus_widget):
1986                         focus_widget.emit('select-all', True)
1987                         self.w_selectall_menuitem.set_sensitive(False)
1988                         self.w_deselect_menuitem.set_sensitive(True)
1989                         return
1990                 elif focus_widget == self.w_searchentry:
1991                         focus_widget.select_region(0, -1)
1992                         self.w_selectall_menuitem.set_sensitive(False)
1993                         self.w_deselect_menuitem.set_sensitive(True)
1994                         return
1995 
1996                 sort_filt_model = \
1997                     self.w_application_treeview.get_model() #gtk.TreeModelSort
1998                 filt_model = sort_filt_model.get_model() #gtk.TreeModelFilter
1999                 model = filt_model.get_model() #gtk.ListStore
2000                 iter_next = sort_filt_model.get_iter_first()
2001                 list_of_paths = []
2002                 while iter_next != None:
2003                         sorted_path = sort_filt_model.get_path(iter_next)
2004                         filtered_path = \
2005                             sort_filt_model.convert_path_to_child_path(sorted_path)
2006                         path = filt_model.convert_path_to_child_path(filtered_path)
2007                         list_of_paths.append(path)
2008                         iter_next = sort_filt_model.iter_next(iter_next)
2009                 for path in list_of_paths:
2010                         itr = model.get_iter(path)
2011                         already_marked = model.get_value(itr, enumerations.MARK_COLUMN)
2012                         if not already_marked:
2013                                 model.set_value(itr, enumerations.MARK_COLUMN, True)
2014                                 pkg_stem = model.get_value(itr,
2015                                     enumerations.STEM_COLUMN)
2016                                 pkg_status = model.get_value(itr,
2017                                     enumerations.STATUS_COLUMN)
2018                                 self.__add_pkg_stem_to_list(pkg_stem, pkg_status)
2019                 self.w_selectall_menuitem.set_sensitive(False)
2020                 self.w_deselect_menuitem.set_sensitive(True)
2021                 self.__enable_disable_selection_menus()
2022                 self.update_statusbar()
2023                 self.__enable_disable_install_remove()
2024 
2025         def __on_select_updates(self, widget):
2026                 sort_filt_model = \
2027                     self.w_application_treeview.get_model() #gtk.TreeModelSort
2028                 filt_model = sort_filt_model.get_model() #gtk.TreeModelFilter
2029                 model = filt_model.get_model() #gtk.ListStore
2030                 iter_next = sort_filt_model.get_iter_first()
2031                 list_of_paths = []
2032                 while iter_next != None:
2033                         sorted_path = sort_filt_model.get_path(iter_next)
2034                         filtered_iter = sort_filt_model.convert_iter_to_child_iter(None, \
2035                             iter_next)
2036                         app_iter = filt_model.convert_iter_to_child_iter(filtered_iter)
2037 
2038                         filtered_path = \
2039                             sort_filt_model.convert_path_to_child_path(sorted_path)
2040                         path = filt_model.convert_path_to_child_path(filtered_path)
2041                         if model.get_value(app_iter, \
2042                             enumerations.STATUS_COLUMN) == enumerations.UPDATABLE:
2043                                 list_of_paths.append(path)
2044                         iter_next = sort_filt_model.iter_next(iter_next)
2045                 for path in list_of_paths:
2046                         itr = model.get_iter(path)
2047                         model.set_value(itr, enumerations.MARK_COLUMN, True)
2048                         pkg_stem = model.get_value(itr, enumerations.STEM_COLUMN)
2049                         pkg_status = model.get_value(itr, enumerations.STATUS_COLUMN)
2050                         self.__add_pkg_stem_to_list(pkg_stem, pkg_status)
2051                 self.__enable_disable_selection_menus()
2052                 self.update_statusbar()
2053                 self.__enable_disable_install_remove()
2054 
2055         def __on_deselect(self, widget):
2056                 focus_widget = self.w_main_window.get_focus()
2057                 if self.__is_a_textview(focus_widget):
2058                         focus_widget.emit('select-all', False)
2059                         self.w_deselect_menuitem.set_sensitive(False)
2060                         self.w_selectall_menuitem.set_sensitive(True)
2061                         return
2062                 elif focus_widget == self.w_searchentry:
2063                         focus_widget.select_region(0, 0)
2064                         self.w_deselect_menuitem.set_sensitive(False)
2065                         self.w_selectall_menuitem.set_sensitive(True)
2066                         return
2067 
2068                 sort_filt_model = \
2069                     self.w_application_treeview.get_model() #gtk.TreeModelSort
2070                 filt_model = sort_filt_model.get_model() #gtk.TreeModelFilter
2071                 model = filt_model.get_model() #gtk.ListStore
2072                 iter_next = sort_filt_model.get_iter_first()
2073                 list_of_paths = []
2074                 while iter_next != None:
2075                         sorted_path = sort_filt_model.get_path(iter_next)
2076                         filtered_iter = sort_filt_model.convert_iter_to_child_iter(None, \
2077                             iter_next)
2078                         app_iter = filt_model.convert_iter_to_child_iter(filtered_iter)
2079                         filtered_path = \
2080                             sort_filt_model.convert_path_to_child_path(sorted_path)
2081                         path = filt_model.convert_path_to_child_path(filtered_path)
2082                         if model.get_value(app_iter, enumerations.MARK_COLUMN):
2083                                 list_of_paths.append(path)
2084                         iter_next = sort_filt_model.iter_next(iter_next)
2085                 for path in list_of_paths:
2086                         itr = model.get_iter(path)
2087                         already_deselected = not model.get_value(itr,
2088                             enumerations.MARK_COLUMN)
2089                         if not already_deselected:
2090                                 model.set_value(itr, enumerations.MARK_COLUMN, False)
2091                                 self.__remove_pkg_stem_from_list(model.get_value(itr,
2092                                     enumerations.STEM_COLUMN))
2093                 self.w_selectall_menuitem.set_sensitive(True)
2094                 self.w_deselect_menuitem.set_sensitive(False)
2095                 self.__enable_disable_selection_menus()
2096                 self.update_statusbar()
2097                 self.__enable_disable_install_remove()
2098 
2099         def __on_preferences(self, widget):
2100                 self.w_startpage_checkbutton.set_active(self.show_startpage)
2101                 self.w_preferencesdialog.show()
2102 
2103         def __on_preferencesclose_clicked(self, widget):
2104                 self.w_preferencesdialog.hide()
2105 
2106         def __on_preferenceshelp_clicked(self, widget):
2107                 gui_misc.display_help(self.application_dir, "pm_win")
2108 
2109         def __on_startpage_checkbutton_toggled(self, widget):
2110                 self.show_startpage = self.w_startpage_checkbutton.get_active()
2111                 try:
2112                         self.client.set_bool(SHOW_STARTPAGE_PREFERENCES,
2113                             self.show_startpage)
2114                 except GError:
2115                         pass
2116 
2117         def __on_api_search_checkbox_toggled(self, widget):
2118                 active = self.api_search_checkbox.get_active()
2119                 if len(self.current_repos_with_search_errors) > 0:
2120                         if active:
2121                                 for pub, err_type, err_str in \
2122                                         self.current_repos_with_search_errors:
2123                                         if pub not in self.gconf_not_show_repos:
2124                                                 self.gconf_not_show_repos += pub + ","
2125                         else:
2126                                 for pub, err_type, err_str in \
2127                                         self.current_repos_with_search_errors:
2128                                         self.gconf_not_show_repos = \
2129                                             self.gconf_not_show_repos.replace(
2130                                             pub + ",", "")
2131                         try:
2132                                 self.client.set_string(API_SEARCH_ERROR_PREFERENCES,
2133                                     self.gconf_not_show_repos)
2134                         except GError:
2135                                 pass
2136 
2137         def __on_searchentry_focus_in(self, widget, event):
2138                 if self.w_main_clipboard.wait_is_text_available():
2139                         self.w_paste_menuitem.set_sensitive(True)
2140                 char_count = widget.get_text_length()
2141                 if char_count > 0:
2142                         self.w_selectall_menuitem.set_sensitive(True)
2143                 else:
2144                         self.w_selectall_menuitem.set_sensitive(False)
2145                 bounds = widget.get_selection_bounds()
2146                 if bounds:
2147                         offset1 = bounds[0]
2148                         offset2 = bounds[1] 
2149                         if abs(offset2 - offset1) == char_count:
2150                                 self.w_selectall_menuitem.set_sensitive(False)
2151                         self.w_deselect_menuitem.set_sensitive(True)
2152                         self.w_copy_menuitem.set_sensitive(True)
2153                 else:
2154                         self.w_deselect_menuitem.set_sensitive(False)
2155 
2156         def __on_searchentry_focus_out(self, widget, event):
2157                 self.w_paste_menuitem.set_sensitive(False)
2158                 self.__enable_disable_select_all()
2159                 self.__enable_disable_deselect()
2160                 self.w_cut_menuitem.set_sensitive(False)
2161                 self.w_copy_menuitem.set_sensitive(False)
2162                 self.w_clear_menuitem.set_sensitive(False)
2163                 return False
2164 
2165         def __on_searchentry_activate(self, widget):
2166                 self.__do_search()
2167 
2168         def __on_searchentry_selection(self, widget, pspec):
2169                 self.__enable_disable_entry_selection(widget)
2170 
2171         def __enable_disable_entry_selection(self, widget):
2172                 char_count = widget.get_text_length()
2173                 bounds = widget.get_selection_bounds()
2174                 if bounds:
2175                         #enable selection functions
2176                         self.w_cut_menuitem.set_sensitive(True)
2177                         self.w_copy_menuitem.set_sensitive(True)
2178                         self.w_clear_menuitem.set_sensitive(True)
2179                         if char_count == abs(bounds[1] - bounds[0]):
2180                                 self.w_selectall_menuitem.set_sensitive(False)
2181                         else:
2182                                 self.w_selectall_menuitem.set_sensitive(True)
2183                         self.w_deselect_menuitem.set_sensitive(True)
2184                 else:
2185                         self.w_cut_menuitem.set_sensitive(False)
2186                         self.w_copy_menuitem.set_sensitive(False)
2187                         self.w_clear_menuitem.set_sensitive(False)
2188                         self.w_deselect_menuitem.set_sensitive(False)
2189                         if char_count == 0:
2190                                 self.w_selectall_menuitem.set_sensitive(False)
2191                         else:
2192                                 self.w_selectall_menuitem.set_sensitive(True)
2193 
2194         def __refilter_on_idle(self):
2195                 if self.application_refilter_id != 0:
2196                         gobject.source_remove(self.application_refilter_id)
2197                         self.application_refilter_id = 0
2198                 if self.application_refilter_idle_id == 0:
2199                         self.application_refilter_idle_id = gobject.idle_add(
2200                             self.__application_refilter)
2201 
2202         def __on_category_focus_in(self, widget, event, user):
2203                 self.__on_category_row_activated(None, None, None, user)
2204 
2205         def __on_category_row_activated(self, view, path, col, user):
2206                 '''This function is for handling category double click activations'''
2207                 if self.w_filter_combobox.get_model():
2208                         self.w_filter_combobox.set_active(self.saved_filter_combobox_active)
2209                 self.w_searchentry.delete_text(0, -1)
2210                 if self.in_search_mode or self.is_search_all:
2211                         self.__unset_search(True)
2212                         if self.selected == 0:
2213                                 gobject.idle_add(self.__enable_disable_install_remove)
2214                         return
2215                 self.__set_main_view_package_list()
2216                 self.set_busy_cursor()
2217                 self.__refilter_on_idle()
2218                 if self.selected == 0:
2219                         gobject.idle_add(self.__enable_disable_install_remove)
2220 
2221         def __set_main_view_package_list(self):
2222                 # Only switch from Start Page View to List view if we are not in startup
2223                 if not self.in_startpage_startup:
2224                         self.w_main_view_notebook.set_current_page(
2225                                 NOTEBOOK_PACKAGE_LIST_PAGE)
2226 
2227         def __on_category_selection_changed(self, selection, widget):
2228                 '''This function is for handling category selection changes'''
2229                 if self.in_setup or self.changing_search_option:
2230                         return
2231                 model, itr = selection.get_selected()
2232                 if itr:
2233                         cat_path = model.get_string_from_iter(itr)
2234                         if self.is_search_all:
2235                                 selected_section = self.set_section
2236                         else:
2237                                 selected_section = self.w_sections_combobox.get_active()
2238                         section_row = self.section_list[selected_section]
2239                         section_row[enumerations.SECTION_SUBCATEGORY] = cat_path
2240 
2241                 if self.in_search_mode or self.is_search_all:
2242                         return
2243                 
2244                 if self.saved_filter_combobox_active != None:
2245                         self.w_filter_combobox.set_active(self.saved_filter_combobox_active)
2246                 self.__set_main_view_package_list()
2247 
2248                 self.set_busy_cursor()
2249                 self.__refilter_on_idle()
2250                 if self.selected == 0:
2251                         gobject.idle_add(self.__enable_disable_install_remove)
2252 
2253         def __process_package_selection(self):
2254                 model, itr = self.package_selection.get_selected()
2255                 if self.show_info_id != 0:
2256                         gobject.source_remove(self.show_info_id)
2257                         self.show_info_id = 0
2258                 if itr:
2259                         self.__enable_disable_install_remove()
2260                         self.selected_pkgstem = \
2261                                model.get_value(itr, enumerations.STEM_COLUMN)
2262                         pkg = model.get_value(itr, enumerations.FMRI_COLUMN)
2263                         gobject.idle_add(self.__show_fetching_package_info, pkg)
2264                         self.showing_empty_details = False
2265                         self.last_show_info_id = self.show_info_id = \
2266                             gobject.timeout_add(SHOW_INFO_DELAY,
2267                                 self.__show_info, model, model.get_path(itr))
2268                         if (self.w_info_notebook.get_current_page() == 
2269                             INFO_NOTEBOOK_LICENSE_PAGE):
2270                                 self.__on_notebook_change(None, None, 
2271                                     INFO_NOTEBOOK_LICENSE_PAGE)
2272                 else:
2273                         self.selected_model = None
2274                         self.selected_path = None
2275                         self.selected_pkgstem = None
2276 
2277         def __on_package_selection_changed(self, selection, widget):
2278                 '''This function is for handling package selection changes'''
2279                 if self.in_setup:
2280                         return
2281                 self.__process_package_selection()
2282 
2283         def __on_filtercombobox_changed(self, widget):
2284                 '''On filter combobox changed'''
2285                 if self.in_setup or self.changing_search_option:
2286                         return
2287                 active = self.w_filter_combobox.get_active()
2288                 if active != enumerations.FILTER_SELECTED:
2289                         self.saved_filter_combobox_active = active
2290                 self.__set_main_view_package_list()
2291                 if self.in_search_mode or self.is_search_all:
2292                         self.set_busy_cursor()
2293                         self.saved_filter_combobox_active = \
2294                             self.w_filter_combobox.get_active()
2295                         self.__unset_search(True)
2296                         return
2297                 self.set_busy_cursor()
2298                 self.__refilter_on_idle()
2299                 if self.selected == 0:
2300                         gobject.idle_add(self.__enable_disable_install_remove)
2301 
2302         def __set_categories_visibility(self, selected_section):
2303                 self.category_list[0][enumerations.CATEGORY_ICON] = None
2304                 if selected_section == 0:
2305                         for category in self.category_list:
2306                                 category[enumerations.CATEGORY_VISIBLE] = True
2307                 else:
2308                         for category in self.category_list:
2309                                 if category[enumerations.CATEGORY_ID] == 0:
2310                                         category[enumerations.CATEGORY_VISIBLE] = True
2311                                 else:
2312                                         category_list = \
2313                                             category[enumerations.SECTION_LIST_OBJECT]
2314                                         if not category_list:
2315                                                 category[enumerations.CATEGORY_VISIBLE] \
2316                                                     = False
2317                                         else:
2318                                                 for section in category_list:
2319                                                         if section == selected_section:
2320                                                                 category[enumerations. \
2321                                                                     CATEGORY_VISIBLE] = \
2322                                                                     True
2323                                                         else:
2324                                                                 category[enumerations. \
2325                                                                     CATEGORY_VISIBLE] = \
2326                                                                     False
2327 
2328                 # Set category icon for All if a visible category has it
2329                 for category in self.category_list:
2330                         if category[enumerations.CATEGORY_ICON] != None:
2331                                 self.category_list[0][enumerations.CATEGORY_ICON] = \
2332                                     category[enumerations.CATEGORY_ICON]
2333                                 break
2334 
2335                 section_row = self.section_list[selected_section]
2336                 cat_path = section_row[enumerations.SECTION_SUBCATEGORY]
2337                 if cat_path != None:
2338                         itr = self.category_list_filter.get_iter_from_string(cat_path)
2339                         path = self.category_list_filter.get_path(itr)
2340                         self.w_categories_treeview.set_cursor(path,
2341                             None, start_editing=False)
2342 
2343         def __on_sectionscombobox_changed(self, widget):
2344                 '''On section combobox changed'''
2345                 if self.in_setup:
2346                         return
2347                 if self.changing_search_option:
2348                         return
2349                 self.__set_main_view_package_list()
2350                 self.set_busy_cursor()
2351                 self.__set_first_category_text()
2352                 self.__set_categories_visibility(widget.get_active())
2353                 self.category_list_filter.refilter()
2354                 if self.in_search_mode or self.is_search_all:
2355                         self.saved_sections_combobox_active = \
2356                             self.w_sections_combobox.get_active()
2357                         self.__unset_search(True)
2358                         return
2359                 self.__refilter_on_idle()
2360                 if self.selected == 0:
2361                         gobject.idle_add(self.__enable_disable_install_remove)
2362 
2363         def __set_first_category_text(self):
2364                 active_section = self.w_sections_combobox.get_active()
2365                 all_cat_text = _("All")
2366                 if active_section != 0:
2367                         all_cat_text += " " + self.section_list[active_section][1]
2368                 category_model = self.w_categories_treeview.get_model()
2369                 if category_model:
2370                         list_store = category_model.get_model()
2371                         list_store[0][1] = all_cat_text
2372 
2373         def __unset_search(self, same_repo):
2374                 self.w_infosearch_frame.hide()
2375                 self.changing_search_option = True
2376                 self.current_search_option = 0
2377                 visible_repository = self.__get_visible_repository_name()
2378                 if visible_repository in self.selected_pkgs:
2379                         self.selected_pkgs.pop(visible_repository)
2380                 if visible_repository in self.to_install_update:
2381                         self.to_install_update.pop(visible_repository)
2382                 if visible_repository in self.to_remove:
2383                         self.to_remove.pop(visible_repository)
2384                 self.__update_tooltips()
2385                 if self.is_search_all:
2386                         self.__update_repository_combobox_for_search(False)
2387                 pixbuf = self.search_options[0][1]
2388                 self.search_image.set_from_pixbuf(pixbuf)
2389                 self.in_search_mode = False
2390                 self.is_search_all = False
2391                 if same_repo:
2392                         self.__restore_setup_for_browse()
2393                 self.changing_search_option = False
2394 
2395         def __on_repositorycombobox_changed(self, widget):
2396                 '''On repository combobox changed'''
2397                 if self.changing_search_option:
2398                         return
2399                 self.changing_search_option = True
2400                 active_publisher = self.__get_active_publisher()
2401                 if self.is_search_all:
2402                         same_repo = False
2403                         active =  self.w_repository_combobox.get_active() - 1
2404                         if active == -1:
2405                                 # We get here is we choose "Add ..." when
2406                                 # doing api search
2407                                 self.changing_search_option = False
2408                                 return
2409                         if not active_publisher == _("Add..."):
2410                                 if self.saved_repository_combobox_active == active:
2411                                         same_repo = True
2412                                 self.__unset_search(same_repo)
2413                                 self.w_repository_combobox.set_active(active)
2414 
2415                         if same_repo:
2416                                 self.changing_search_option = False
2417                                 return
2418                         active_publisher = self.__get_active_publisher()
2419                 self.changing_search_option = False
2420                 if self.visible_repository == active_publisher:
2421                 # If we are coming back to the same repository, we do
2422                 # not want to setup publishers. This is the case when
2423                 # we are calling Add... then we are firing the event for
2424                 # Add... case and immediately coming back to the
2425                 # previously selected repository.
2426                         return
2427                 # Checking for Add... is fine enough, as the repository
2428                 # name cannot contain "..." in the name.
2429                 if active_publisher == _("Add..."):
2430                         index = -1
2431                         if self.is_search_all:
2432                                 index = 0
2433                         else:
2434                                 model = self.w_repository_combobox.get_model()
2435                                 for entry in model:
2436                                         if entry[1] == self.visible_repository:
2437                                                 index = entry[0]
2438                                                 break
2439                         # We do not want to switch permanently to the Add...
2440                         self.w_repository_combobox.set_active(index)
2441                         self.__on_edit_repositories_activate(None)
2442                         return
2443                 self.cancelled = True
2444                 self.in_setup = True
2445                 self.set_busy_cursor()
2446                 self.__set_empty_details_panel()
2447                 if self.in_search_mode:
2448                         self.__unset_search(False)
2449                         self.w_searchentry.grab_focus()
2450                         if len(self.w_searchentry.get_text()) > 0:
2451                                 start, end = self.w_searchentry.get_selection_bounds()
2452                                 self.w_searchentry.select_region(end, end)
2453 
2454                 pub = [active_publisher, ]
2455                 self.set_show_filter = self.initial_show_filter
2456                 self.set_section = self.initial_section
2457                 Thread(target = self.__setup_publisher, args = [pub]).start()
2458                 self.__set_main_view_package_list()
2459 
2460         def __get_active_publisher(self):
2461                 pub_iter = self.w_repository_combobox.get_active_iter()
2462                 if pub_iter == None:
2463                         return None
2464                 return self.repositories_list.get_value(pub_iter, \
2465                             enumerations.REPOSITORY_NAME)
2466 
2467         def __setup_publisher(self, publishers=[]):
2468                 self.saved_filter_combobox_active = self.initial_show_filter
2469                 application_list, category_list , section_list = \
2470                     self.__get_application_categories_lists(publishers)
2471                 self.__unset_saved()
2472                 gobject.idle_add(self.__init_tree_views, application_list,
2473                     category_list, section_list)
2474 
2475         def __unset_saved(self):
2476                 self.saved_application_list = None
2477                 self.saved_application_list_filter = None
2478                 self.saved_application_list_sort = None
2479                 self.saved_category_list = None
2480                 self.saved_section_list = None
2481 
2482         def __get_application_categories_lists(self, publishers=[]):
2483                 print "__get_application_categories_lists: ", self.visible_repository
2484                 if not self.visible_repository:
2485                         self.visible_repository = self.__get_active_publisher()
2486                 print "** __get_application_categories_lists: ", self.visible_repository
2487                 application_list = self.__get_new_application_liststore()
2488                 category_list = self.__get_new_category_liststore()
2489                 section_list = self.__get_new_section_liststore()
2490                 first_loop = True
2491                 for publisher in publishers:
2492                         uptodate = False
2493                         try:
2494                                 uptodate = self.__check_if_cache_uptodate(publisher)
2495                                 if uptodate:
2496                                         self.__add_pkgs_to_lists_from_cache(publisher,
2497                                             application_list, category_list,
2498                                             section_list)
2499                         except (UnpicklingError, EOFError, IOError):
2500                                 #Most likely cache is corrupted, silently load list
2501                                 #from api.
2502                                 application_list = self.__get_new_application_liststore()
2503                                 category_list = self.__get_new_category_liststore()
2504                                 uptodate = False
2505                         if not uptodate:
2506                                 if first_loop == True:
2507                                         first_loop = False
2508                                         gobject.idle_add(self.setup_progressdialog_show)
2509                                 self.api_o.refresh(pubs=[publisher])
2510                                 self.__add_pkgs_to_lists_from_api(publisher,
2511                                     application_list, category_list, section_list)
2512                                 category_list.prepend([0, _('All'), None, None, False,
2513                                     True, None])
2514                         if self.application_list and self.category_list and \
2515                             not self.visible_repository_uptodate:
2516                                 if self.visible_repository:
2517                                         dump_list = self.application_list
2518                                         if self.saved_application_list != None:
2519                                                 dump_list = \
2520                                                     self.saved_application_list
2521                                         self.__dump_datamodels(self.visible_repository,
2522                                             dump_list, self.category_list,
2523                                             self.section_list)
2524                         self.visible_repository = self.__get_active_publisher()
2525                         self.visible_repository_uptodate = uptodate
2526                 return application_list, category_list, section_list
2527 
2528         def __check_if_cache_uptodate(self, publisher):
2529                 if self.cache_o:
2530                         return self.cache_o.check_if_cache_uptodate(publisher)
2531                 return False
2532 
2533         def __dump_datamodels(self, publisher, application_list, category_list,
2534             section_list):
2535                 #Consistency check - only dump models if publisher passed in matches 
2536                 #publisher in application list
2537                 if application_list == None:
2538                         return
2539                 app_pub = application_list[0][enumerations.AUTHORITY_COLUMN]
2540                 if publisher != app_pub:
2541                         if debug:
2542                                 print "ERROR: __dump_data_models(): INCONSISTENT " \
2543                                         "pub %s != app_list_pub %s" % \
2544                                         (publisher,  app_pub)
2545                         return
2546 
2547                 if self.cache_o:
2548                         if self.img_timestamp == \
2549                             self.cache_o.get_index_timestamp():
2550                                 Thread(target = self.cache_o.dump_datamodels,
2551                                     args = (publisher, application_list, category_list,
2552                                     section_list)).start()
2553                         else:
2554                                 self.__remove_cache()
2555 
2556         def __remove_cache(self):
2557                 model = self.w_repository_combobox.get_model()
2558                 for publisher in model:
2559                         pub_name = publisher[1]
2560                         if pub_name and pub_name != _("Add..."):
2561                                 Thread(target = self.cache_o.remove_datamodel,
2562                                     args = [publisher[1]]).start()
2563 
2564         def __on_install_update(self, widget):
2565                 self.api_o.reset()
2566                 install_update = []
2567                 if self.selected == 0:
2568                         model, itr = self.package_selection.get_selected()
2569                         if itr:
2570                                 install_update.append(
2571                                     model.get_value(itr, enumerations.STEM_COLUMN))
2572                 else:
2573                         visible_repository = self.__get_visible_repository_name()
2574                         pkgs = self.selected_pkgs.get(visible_repository)
2575                         if pkgs:
2576                                 for pkg_stem in pkgs:
2577                                         status = pkgs.get(pkg_stem)
2578                                         if status == enumerations.NOT_INSTALLED or \
2579                                             status == enumerations.UPDATABLE:
2580                                                 install_update.append(pkg_stem)
2581 
2582                 if self.img_timestamp != self.cache_o.get_index_timestamp():
2583                         self.img_timestamp = None
2584                         self.__remove_cache()
2585 
2586                 installupdate.InstallUpdate(install_update, self, \
2587                     self.api_o, ips_update = False, \
2588                     action = enumerations.INSTALL_UPDATE)
2589 
2590         def __on_update_all(self, widget):
2591                 self.api_o.reset()
2592                 installupdate.InstallUpdate([], self,
2593                     self.api_o, ips_update = False,
2594                     action = enumerations.IMAGE_UPDATE, be_name = self.ua_be_name,
2595                     parent_name = _("Package Manager"),
2596                     pkg_list = ["SUNWipkg", "SUNWipkg-gui"],
2597                     main_window = self.w_main_window)
2598                 return
2599 
2600         def __on_ua_completed_linkbutton_clicked(self, widget):
2601                 try:
2602                         gnome.url_show(self.release_notes_url)
2603                 except gobject.GError:
2604                         self.error_occurred(_("Unable to navigate to:\n\t%s") % 
2605                             self.release_notes_url)
2606 
2607         def __on_help_about(self, widget):
2608                 wTreePlan = gtk.glade.XML(self.gladefile, "aboutdialog")
2609                 aboutdialog = wTreePlan.get_widget("aboutdialog")
2610                 aboutdialog.connect("response", lambda x = None, \
2611                     y = None: aboutdialog.destroy())
2612                 aboutdialog.run()
2613 
2614         def __on_help_help(self, widget):
2615                 gui_misc.display_help(self.application_dir)
2616 
2617         def __on_remove(self, widget):
2618                 self.api_o.reset()
2619                 remove_list = []
2620                 if self.selected == 0:
2621                         model, itr = self.package_selection.get_selected()
2622                         if itr:
2623                                 remove_list.append(
2624                                     model.get_value(itr, enumerations.STEM_COLUMN))
2625                 else:
2626                         visible_repository = self.__get_visible_repository_name()
2627                         pkgs = self.selected_pkgs.get(visible_repository)
2628                         if pkgs:
2629                                 for pkg_stem in pkgs:
2630                                         status = pkgs.get(pkg_stem)
2631                                         if status == enumerations.INSTALLED or \
2632                                             status == enumerations.UPDATABLE:
2633                                                 remove_list.append(pkg_stem)
2634 
2635                 if self.img_timestamp != self.cache_o.get_index_timestamp():
2636                         self.img_timestamp = None
2637                         self.__remove_cache()
2638 
2639                 installupdate.InstallUpdate(remove_list, self,
2640                     self.api_o, ips_update = False,
2641                     action = enumerations.REMOVE)
2642 
2643         def __on_reload(self, widget):
2644                 if self.description_thread_running:
2645                         self.cancelled = True
2646                 if self.in_search_mode or self.is_search_all:
2647                         self.__unset_search(False)
2648                 self.__set_empty_details_panel()
2649                 self.in_setup = True
2650                 self.visible_repository = None
2651                 if widget != None:
2652                         self.__remove_cache()
2653                 self.w_progress_dialog.set_title(_("Refreshing catalogs"))
2654                 self.w_progressinfo_label.set_text(_("Refreshing catalogs..."))
2655                 self.progress_stop_timer_thread = False
2656                 Thread(target = self.__progressdialog_progress_pulse).start()
2657                 self.w_progress_dialog.show()
2658                 self.w_progress_cancel.hide()
2659                 self.__disconnect_models()
2660                 self.in_reload = True
2661                 Thread(target = self.__catalog_refresh).start()
2662 
2663         def __catalog_refresh_done(self):
2664                 self.progress_stop_timer_thread = True
2665                 #Let the progress_pulse finish. This should be done other way, but at
2666                 #The moment this works fine
2667                 time.sleep(0.2)
2668                 gobject.idle_add(self.w_progress_cancel.show)
2669                 gobject.idle_add(self.process_package_list_start,
2670                     self.image_directory)
2671 
2672         def __main_application_quit(self, be_name = None):
2673                 '''quits the main gtk loop'''
2674                 self.cancelled = True
2675                 if self.in_setup:
2676                         return
2677 
2678                 if be_name:
2679                         if self.image_dir_arg:
2680                                 gobject.spawn_async([self.application_path, "-R",
2681                                     self.image_dir_arg, "-U", be_name])
2682                         else:
2683                                 gobject.spawn_async([self.application_path,
2684                                     "-U", be_name])
2685                 elif self.in_search_mode:
2686                         self.__dump_datamodels(self.visible_repository,
2687                             self.saved_application_list, self.category_list,
2688                             self.section_list)
2689                 else:
2690                         visible_repository = self.__get_visible_repository_name()
2691                         self.__dump_datamodels(visible_repository,
2692                                 self.application_list, self.category_list,
2693                                 self.section_list)
2694 
2695                 width, height = self.w_main_window.get_size()
2696                 hpos = self.w_main_hpaned.get_position()
2697                 vpos = self.w_main_vpaned.get_position()
2698                 try:
2699                         self.client.set_int(INITIAL_APP_WIDTH_PREFERENCES, width)
2700                         self.client.set_int(INITIAL_APP_HEIGHT_PREFERENCES, height)
2701                         self.client.set_int(INITIAL_APP_HPOS_PREFERENCES, hpos)
2702                         self.client.set_int(INITIAL_APP_VPOS_PREFERENCES, vpos)
2703                 except GError:
2704                         pass
2705 
2706                 self.w_main_window.hide()
2707                 while gtk.events_pending():
2708                         gtk.main_iteration(False)
2709                 gtk.main_quit()
2710                 sys.exit(0)
2711                 return True
2712 
2713         def __check_if_something_was_changed(self):
2714                 ''' Returns True if any of the check boxes for package was changed, false
2715                 if not'''
2716                 if self.application_list:
2717                         for pkg in self.application_list:
2718                                 if pkg[enumerations.MARK_COLUMN] == True:
2719                                         return True
2720                 return False
2721 
2722         def __setup_repositories_combobox(self, api_o, repositories_list):
2723                 self.__disconnect_repository_model()
2724                 default_pub = api_o.get_preferred_publisher().prefix
2725                 if self.default_publisher != default_pub:
2726                         self.__clear_pkg_selections()
2727                         self.default_publisher = default_pub
2728                 selected_repos = []
2729                 enabled_repos = []
2730                 for repo in self.selected_pkgs:
2731                         selected_repos.append(repo)
2732                 i = 0
2733                 active = 0
2734                 for pub in api_o.get_publishers():
2735                         if pub.disabled:
2736                                 continue
2737                         prefix = pub.prefix
2738                         if cmp(prefix, self.default_publisher) == 0:
2739                                 active = i
2740                         repositories_list.append([i, prefix, ])
2741                         enabled_repos.append(prefix)
2742                         i = i + 1
2743                 repositories_list.append([-1, "", ])
2744                 repositories_list.append([-1, _("Add..."), ])
2745                 pkgs_to_remove = []
2746                 for repo_name in selected_repos:
2747                         if repo_name not in enabled_repos:
2748                                 pkg_stems = self.selected_pkgs.get(repo_name)
2749                                 for pkg_stem in pkg_stems:
2750                                         pkgs_to_remove.append(pkg_stem)
2751                 for pkg_stem in pkgs_to_remove:
2752                         self.__remove_pkg_stem_from_list(pkg_stem)
2753                 self.w_repository_combobox.set_model(repositories_list)
2754                 if self.default_publisher:
2755                         self.w_repository_combobox.set_active(active)
2756                 else:
2757                         self.w_repository_combobox.set_active(0)
2758 
2759         def __active_pane_toggle(self, cell, path, model_sort):
2760                 '''Toggle function for column enumerations.MARK_COLUMN'''
2761                 applicationModel = model_sort.get_model()
2762                 applicationPath = model_sort.convert_path_to_child_path(path)
2763                 filterModel = applicationModel.get_model()
2764                 child_path = applicationModel.convert_path_to_child_path(applicationPath)
2765                 itr = filterModel.get_iter(child_path)
2766                 if itr:
2767                         modified = filterModel.get_value(itr, enumerations.MARK_COLUMN)
2768                         filterModel.set_value(itr, enumerations.MARK_COLUMN,
2769                             not modified)
2770                         pkg_status = filterModel.get_value(itr,
2771                             enumerations.STATUS_COLUMN)
2772                         pkg_stem = filterModel.get_value(itr, enumerations.STEM_COLUMN)
2773                         if modified:
2774                                 self.__remove_pkg_stem_from_list(pkg_stem)
2775                         else:
2776                                 self.__add_pkg_stem_to_list(pkg_stem, pkg_status)
2777                         self.update_statusbar()
2778                         self.__enable_disable_selection_menus()
2779 
2780         def __update_reload_button(self):
2781                 if self.user_rights:
2782                         self.w_reload_button.set_sensitive(True)
2783                 else:
2784                         self.w_reload_button.set_sensitive(False)
2785 
2786         def __add_pkg_stem_to_list(self, stem, status):
2787                 publisher = self.__get_active_publisher()
2788                 if self.selected_pkgs.get(publisher) == None:
2789                         self.selected_pkgs[publisher] = {}
2790                 self.selected_pkgs.get(publisher)[stem] = status
2791                 if status == enumerations.NOT_INSTALLED or \
2792                     status == enumerations.UPDATABLE:
2793                         if self.to_install_update.get(publisher) == None:
2794                                 self.to_install_update[publisher] = 1
2795                         else:
2796                                 self.to_install_update[publisher] += 1
2797                 if status == enumerations.UPDATABLE or status == enumerations.INSTALLED:
2798                         if self.to_remove.get(publisher) == None:
2799                                 self.to_remove[publisher] = 1
2800                         else:
2801                                 self.to_remove[publisher] += 1
2802                 self.__update_tooltips()
2803 
2804         def __update_tooltips(self):
2805                 to_remove = None
2806                 to_install = None
2807                 no_iter = 0
2808                 for publisher in self.to_remove:
2809                         packages = self.to_remove.get(publisher)
2810                         if packages > 0:
2811                                 if no_iter == 0:
2812                                         to_remove = _("Selected for Removal:")
2813                                 to_remove += "\n   %s: %d" % (publisher, packages)
2814                                 no_iter += 1
2815                 no_iter = 0
2816                 for publisher in self.to_install_update:
2817                         packages = self.to_install_update.get(publisher)
2818                         if packages > 0:
2819                                 if no_iter == 0:
2820                                         to_install = _("Selected for Install/Update:")
2821                                 to_install += "\n   %s: %d" % (publisher, packages)
2822                                 no_iter += 1
2823                 if not to_install:
2824                         to_install = _("Select packages by marking the checkbox "
2825                             "and click to Install/Update.")
2826                 self.w_installupdate_button.set_tooltip(self.install_button_tooltip,
2827                     to_install)
2828                 if not to_remove:
2829                         to_remove = _("Select packages by marking the checkbox "
2830                             "and click to Remove selected.")
2831                 self.w_remove_button.set_tooltip(self.remove_button_tooltip, to_remove)
2832 
2833         def __remove_pkg_stem_from_list(self, stem):
2834                 remove_pub = []
2835                 for publisher in self.selected_pkgs:
2836                         pkgs = self.selected_pkgs.get(publisher)
2837                         status = None
2838                         if stem in pkgs:
2839                                 status = pkgs.pop(stem)
2840                         if status == enumerations.NOT_INSTALLED or \
2841                             status == enumerations.UPDATABLE:
2842                                 if self.to_install_update.get(publisher) == None:
2843                                         self.to_install_update[publisher] = 0
2844                                 else:
2845                                         self.to_install_update[publisher] -= 1
2846                         if status == enumerations.UPDATABLE or \
2847                             status == enumerations.INSTALLED:
2848                                 if self.to_remove.get(publisher) == None:
2849                                         self.to_remove[publisher] = 0
2850                                 else:
2851                                         self.to_remove[publisher] -= 1
2852                         if len(pkgs) == 0:
2853                                 remove_pub.append(publisher)
2854                 for publisher in remove_pub:
2855                         self.selected_pkgs.pop(publisher)
2856                 self.__update_tooltips()
2857 
2858         def __clear_pkg_selections(self):
2859                 # We clear the selections as the preffered repository was changed
2860                 # and pkg stems are not valid.
2861                 remove_pub = []
2862                 for publisher in self.selected_pkgs:
2863                         stems = self.selected_pkgs.get(publisher)
2864                         for pkg_stem in stems:
2865                                 remove_pub.append(pkg_stem)
2866                 for pkg_stem in remove_pub:
2867                         self.__remove_pkg_stem_from_list(pkg_stem)
2868 
2869         def __set_empty_details_panel(self):
2870                 self.showing_empty_details = True
2871                 if self.show_info_id != 0:
2872                         gobject.source_remove(self.show_info_id)
2873                         self.show_info_id = 0
2874                 if self.show_licenses_id != 0:
2875                         gobject.source_remove(self.show_licenses_id)
2876                         self.show_licenses_id = 0
2877                 pkg_name = _("Package Name")
2878                 self.w_packagename_label.set_markup("<b>" + pkg_name + "</b>")
2879                 self.w_general_info_label.set_markup("<b>" + pkg_name + "</b>")
2880                 self.w_installedfiles_textview.get_buffer().set_text("")
2881                 self.w_dependencies_textview.get_buffer().set_text("")
2882                 self.w_generalinfo_textview.get_buffer().set_text("")
2883                 self.w_license_textview.get_buffer().set_text("")
2884                 return
2885 
2886         def __show_fetching_package_info(self, pkg):
2887                 pkg_name = pkg.get_name()
2888                 self.w_packagename_label.set_markup("<b>" + pkg_name + "</b>")
2889                 self.w_general_info_label.set_markup("<b>" + pkg_name + "</b>")
2890 
2891                 pkg_stem = pkg.get_pkg_stem()
2892                 if self.__setting_from_cache(pkg_stem):
2893                         return
2894 
2895                 self.w_shortdescription_label.set_text(
2896                     _("Fetching description..."))
2897                 instbuffer = self.w_installedfiles_textview.get_buffer()
2898                 depbuffer = self.w_dependencies_textview.get_buffer()
2899                 infobuffer = self.w_generalinfo_textview.get_buffer()
2900                 fetching_text = _("Fetching information...")
2901                 instbuffer.set_text(fetching_text)
2902                 depbuffer.set_text(fetching_text)
2903                 infobuffer.set_text(fetching_text)
2904                 return
2905 
2906         def __setting_from_cache(self, pkg_stem):
2907                 if len(self.info_cache) > MAX_INFO_CACHE_LIMIT:
2908                         self.info_cache = {}
2909 
2910                 if self.info_cache.has_key(pkg_stem):
2911                         self.w_shortdescription_label.set_text(
2912                             self.info_cache[pkg_stem][0])
2913                         instbuffer = self.w_installedfiles_textview.get_buffer()
2914                         depbuffer = self.w_dependencies_textview.get_buffer()
2915                         infobuffer = self.w_generalinfo_textview.get_buffer()
2916                         infobuffer.set_text(self.info_cache[pkg_stem][1])
2917                         instbuffer.set_text(self.info_cache[pkg_stem][2])
2918                         depbuffer.set_text(self.info_cache[pkg_stem][3])
2919                         return True
2920                 else:
2921                         return False
2922 
2923         def __update_package_info(self, pkg, local_info, remote_info, info_id):
2924                 if self.showing_empty_details or (info_id != 
2925                     self.last_show_info_id):
2926                         return
2927                 pkg_name = pkg.get_name()
2928                 pkg_stem = pkg.get_pkg_stem()
2929                 self.w_packagename_label.set_markup("<b>" + pkg_name + "</b>")
2930                 self.w_general_info_label.set_markup("<b>" + pkg_name + "</b>")
2931                 installed = True
2932 
2933                 if self.__setting_from_cache(pkg_stem):
2934                         return
2935 
2936                 instbuffer = self.w_installedfiles_textview.get_buffer()
2937                 depbuffer = self.w_dependencies_textview.get_buffer()
2938                 infobuffer = self.w_generalinfo_textview.get_buffer()
2939 
2940                 if not local_info and not remote_info:
2941                         network_str = \
2942                             _("\nThis might be caused by network problem "
2943                             "while accessing the repository.")
2944                         self.w_shortdescription_label.set_text(
2945                             _("Description not available for this package...") +
2946                             network_str)
2947                         instbuffer.set_text( \
2948                             _("Files Details not available for this package...") +
2949                             network_str)
2950                         depbuffer.set_text(_(
2951                             "Dependencies info not available for this package...") +
2952                             network_str)
2953                         infobuffer.set_text(
2954                             _("Information not available for this package...") +
2955                             network_str)
2956                         return
2957 
2958                 if not local_info:
2959                         # Package is not installed
2960                         local_info = remote_info
2961                         installed = False
2962 
2963                 if not remote_info:
2964                         remote_info = local_info
2965                         installed = True
2966 
2967                 description = local_info.summary
2968                 #XXX long term need to have something more robust here for multi byte
2969                 if len(description) > MAX_DESC_LEN:
2970                         description = description[:MAX_DESC_LEN] + " ..."
2971                 self.w_shortdescription_label.set_text(description)
2972                 inst_str = _("Root: %s\n") % self.api_o.img.get_root()
2973                 dep_str = _("Dependencies:\n")
2974 
2975                 if local_info.dependencies:
2976                         dep_str += ''.join(
2977                             ["\t%s\n" % x for x in local_info.dependencies])
2978                 if local_info.dirs:
2979                         inst_str += ''.join(["\t%s\n" % x for x in local_info.dirs])
2980                 if local_info.files:
2981                         inst_str += ''.join(["\t%s\n" % x for x in local_info.files])
2982                 if local_info.hardlinks:
2983                         inst_str += ''.join(["\t%s\n" % x for x in local_info.hardlinks])
2984                 if local_info.links:
2985                         inst_str += ''.join(["\t%s\n" % x for x in local_info.links])
2986                 info_str = ""
2987                 labs = {}
2988                 labs["sum"] = _("Summary:\t\t")
2989                 labs["size"] = _("Size:\t\t\t")
2990                 labs["cat"] = _("Category:\t\t")
2991                 labs["ins"] = _("Installed Version:\t")
2992                 labs["lat"] = _("Latest Version:\t")
2993                 labs["pkg_date"] = _("Packaging Date:\t")
2994                 labs["fmri"] = _("FMRI:\t\t\t")
2995                 labs["repository"] = _("Repository:\t\t")
2996                 max_len = 0
2997                 for lab in labs:
2998                         if len(labs[lab]) > max_len:
2999                                 max_len = len(labs[lab])
3000                 categories = _("None")
3001                 if local_info.category_info_list:
3002                         verbose = len(local_info.category_info_list) > 1
3003                         categories = ""
3004                         categories += local_info.category_info_list[0].__str__(verbose)
3005                         if len(local_info.category_info_list) > 1:
3006                                 for ci in local_info.category_info_list[1:]:
3007                                         categories += ", " + ci.__str__(verbose)
3008                 summary = _("None")
3009                 if local_info.summary:
3010                         summary = local_info.summary
3011                 info_str += "  %s %s" % (labs["sum"], summary)
3012                 info_str += "\n  %s %s" % (labs["size"],
3013                     misc.bytes_to_str(local_info.size))
3014                 info_str += "\n  %s %s" % (labs["cat"], categories)
3015                 if installed:
3016                         info_str += "\n  %s %s,%s-%s" % (labs["ins"], local_info.version,
3017                             local_info.build_release, local_info.branch)
3018                 info_str += "\n  %s %s,%s-%s" % (labs["lat"], remote_info.version,
3019                     remote_info.build_release, remote_info.branch)
3020                 info_str += "\n  %s %s" % (labs["pkg_date"], local_info.packaging_date)
3021                 info_str += "\n  %s %s" % (labs["fmri"], local_info.fmri)
3022                 info_str += "\n  %s %s" % (labs["repository"], local_info.publisher)
3023                 infobuffer.set_text(info_str)
3024                 instbuffer.set_text(inst_str)
3025                 depbuffer.set_text(dep_str)
3026                 self.info_cache[pkg_stem] = \
3027                     (description, info_str, inst_str, dep_str)
3028 
3029         def __update_package_license(self, licenses, license_id):
3030                 if self.showing_empty_details or (license_id !=
3031                     self.last_show_licenses_id):
3032                         return
3033                 lic = ""
3034                 lic_u = ""
3035                 if licenses == None:
3036                         lic_u = _("Not available")
3037                 else:
3038                         for licens in licenses:
3039                                 lic += licens.get_text()
3040                                 lic += "\n"
3041                         try:
3042                                 lic_u = unicode(lic, "utf-8")
3043                         except UnicodeDecodeError:
3044                                 lic_u += ""
3045                 licbuffer = self.w_license_textview.get_buffer()
3046                 licbuffer.set_text(lic_u)
3047 
3048         def __show_licenses(self):
3049                 self.show_licenses_id = 0
3050                 if self.catalog_loaded == False:
3051                         return
3052                 Thread(target = self.__show_package_licenses,
3053                     args = (self.selected_pkgstem, self.last_show_licenses_id,)).start()
3054 
3055         def __show_package_licenses(self, selected_pkgstem, license_id):
3056                 if selected_pkgstem == None:
3057                         gobject.idle_add(self.__update_package_license, None,
3058                             self.last_show_licenses_id)
3059                         return
3060                 info = None
3061                 try:
3062                         info = self.api_o.info([selected_pkgstem],
3063                             True, frozenset([api.PackageInfo.LICENSES]))
3064                 except (api_errors.TransportError):
3065                         pass
3066                 if self.showing_empty_details or (license_id != 
3067                     self.last_show_licenses_id):
3068                         return
3069                 if not info or (info and len(info.get(0)) == 0):
3070                         try:
3071                         # Get license from remote
3072                                 info = self.api_o.info([selected_pkgstem],
3073                                     False, frozenset([api.PackageInfo.LICENSES]))
3074                         except (api_errors.TransportError):
3075                                 pass
3076                 if self.showing_empty_details or (license_id != 
3077                     self.last_show_licenses_id):
3078                         return
3079                 pkgs_info = None
3080                 package_info = None
3081                 no_licenses = 0
3082                 if info:
3083                         pkgs_info = info[0]
3084                 if pkgs_info:
3085                         package_info = pkgs_info[0]
3086                 if package_info:
3087                         no_licenses = len(package_info.licenses)
3088                 if no_licenses == 0:
3089                         gobject.idle_add(self.__update_package_license, None, 
3090                             license_id)
3091                         return
3092                 else:
3093                         gobject.idle_add(self.__update_package_license,
3094                             package_info.licenses, license_id)
3095 
3096         def __get_pkg_info(self, pkg_stem, local):
3097                 info = None
3098                 try:
3099                         info = self.api_o.info([pkg_stem], local,
3100                             api.PackageInfo.ALL_OPTIONS -
3101                             frozenset([api.PackageInfo.LICENSES]))
3102                 except (api_errors.TransportError):
3103                         return info
3104                 pkgs_info = None
3105                 package_info = None
3106                 if info:
3107                         pkgs_info = info[0]
3108                 if pkgs_info:
3109                         package_info = pkgs_info[0]
3110                 if package_info:
3111                         return package_info
3112                 else:
3113                         return None
3114 
3115         def __show_info(self, model, path):
3116                 self.show_info_id = 0
3117                 if self.catalog_loaded == False:
3118                         self.selected_model = model
3119                         self.selected_path = path
3120                         return
3121                 if not (model and path):
3122                         return
3123                 if self.selected_model != None:
3124                         if (self.selected_model != model or
3125                             self.selected_path != path):
3126                         # This can happen after catalogs are loaded in
3127                         # enable_disable_update_all and a different
3128                         # package is selected before enable_disable_update_all
3129                         # calls __show_info. We set these variable to None
3130                         # so that when __show_info is called it does nothing.
3131                                 self.selected_model = None
3132                                 self.selected_path = None
3133 
3134                 itr = model.get_iter(path)
3135                 pkg = model.get_value(itr, enumerations.FMRI_COLUMN)
3136                 pkg_stem = model.get_value(itr, enumerations.STEM_COLUMN)
3137                 pkg_status = model.get_value(itr, enumerations.STATUS_COLUMN)
3138                 if self.info_cache.has_key(pkg_stem):
3139                         return
3140                 Thread(target = self.__show_package_info,
3141                     args = (pkg, pkg_stem, pkg_status, self.last_show_info_id)).start()
3142 
3143         def __show_package_info(self, pkg, pkg_stem, pkg_status, info_id):
3144                 self.api_o.log_operation_start("info")
3145                 local_info = None
3146                 remote_info = None
3147                 if not self.showing_empty_details and (info_id ==
3148                     self.last_show_info_id) and (pkg_status ==
3149                     enumerations.INSTALLED or pkg_status ==
3150                     enumerations.UPDATABLE):
3151                         local_info = self.__get_pkg_info(pkg_stem, True)
3152                 if not self.showing_empty_details and (info_id ==
3153                     self.last_show_info_id) and (pkg_status ==
3154                     enumerations.NOT_INSTALLED or pkg_status ==
3155                     enumerations.UPDATABLE):
3156                         remote_info = self.__get_pkg_info(pkg_stem, False)
3157                 if not self.showing_empty_details and (info_id ==
3158                     self.last_show_info_id):
3159                         gobject.idle_add(self.__update_package_info, pkg,
3160                             local_info, remote_info, info_id)
3161                 self.api_o.log_operation_end()
3162                 return
3163 
3164         # This function is ported from pkg.actions.generic.distinguished_name()
3165         @staticmethod
3166         def __locale_distinguished_name(action):
3167                 if action.key_attr == None:
3168                         return str(action)
3169                 return "%s: %s" % \
3170                     (_(action.name), action.attrs.get(action.key_attr, "???"))
3171 
3172         def __application_filter(self, model, itr):
3173                 '''This function is used to filter content in the main
3174                 application view'''
3175                 if self.in_setup or self.cancelled:
3176                         return False
3177                 filter_id = self.w_filter_combobox.get_active()
3178                 if filter_id == enumerations.FILTER_SELECTED:
3179                         return model.get_value(itr, enumerations.MARK_COLUMN)
3180                 # XXX Show filter, chenge text to integers
3181                 selected_category = 0
3182                 category_selection = self.w_categories_treeview.get_selection()
3183                 category_model, category_iter = category_selection.get_selected()
3184                 if category_iter:
3185                         selected_category = category_model.get_value(category_iter,
3186                             enumerations.CATEGORY_ID)
3187                 category_list = model.get_value(itr, enumerations.CATEGORY_LIST_COLUMN)
3188                 selected_section = self.w_sections_combobox.get_active()
3189                 category = False
3190                 if selected_section == 0 and selected_category == 0:
3191                         #For section "All" and category "All" always true
3192                         category = True
3193                 elif selected_category != 0:
3194                         if category_list and selected_category in category_list:
3195                                 category = True
3196                 elif category_list:
3197                         #The selected category is "All" so we need to check
3198                         #If the package belongs to one of the visible categories
3199                         for visible_category in category_model:
3200                                 visible_id = visible_category[enumerations.CATEGORY_ID]
3201                                 if visible_id in category_list:
3202                                         category = True
3203                                         break
3204                 if (model.get_value(itr, enumerations.IS_VISIBLE_COLUMN) == False):
3205                         return False
3206                 return (category &
3207                     self.__is_package_filtered(model, itr, filter_id))
3208 
3209         @staticmethod
3210         def __is_package_filtered(model, itr, filter_id):
3211                 '''Function for filtercombobox'''
3212                 if filter_id == enumerations.FILTER_ALL:
3213                         return True
3214                 status = model.get_value(itr, enumerations.STATUS_COLUMN)
3215                 if filter_id == enumerations.FILTER_INSTALLED:
3216                         return (status == enumerations.INSTALLED or status == \
3217                             enumerations.UPDATABLE)
3218                 elif filter_id == enumerations.FILTER_UPDATES:
3219                         return status == enumerations.UPDATABLE
3220                 elif filter_id == enumerations.FILTER_NOT_INSTALLED:
3221                         return status == enumerations.NOT_INSTALLED
3222 
3223         def __is_pkg_repository_visible(self, model, itr):
3224                 if len(self.repositories_list) <= 1:
3225                         return True
3226                 else:
3227                         visible_repository = self.__get_visible_repository_name()
3228                         pkg = model.get_value(itr, enumerations.FMRI_COLUMN)
3229                         if not pkg:
3230                                 return False
3231                         if cmp(pkg.get_publisher(), visible_repository) == 0:
3232                                 return True
3233                         else:
3234                                 return False
3235 
3236         def __get_visible_repository_name(self):
3237                 pub_iter = self.w_repository_combobox.get_active_iter()
3238                 if pub_iter == None:
3239                         return None
3240                 visible = self.repositories_list.get_value(pub_iter, \
3241                     enumerations.REPOSITORY_NAME)
3242                 return visible
3243 
3244         def __enable_disable_selection_menus(self):
3245                 if self.in_setup:
3246                         return
3247                 self.__enable_disable_select_updates()
3248                 if not self.__doing_search():
3249                         self.unset_busy_cursor()
3250 
3251         def __enable_disable_select_all(self):
3252                 if self.in_setup:
3253                         return
3254                 if len(self.w_application_treeview.get_model()) > 0:
3255                         for row in self.w_application_treeview.get_model():
3256                                 if not row[enumerations.MARK_COLUMN]:
3257                                         self.w_selectall_menuitem.set_sensitive(True)
3258                                         return
3259                         self.w_selectall_menuitem.set_sensitive(False)
3260                 else:
3261                         self.w_selectall_menuitem.set_sensitive(False)
3262 
3263         def __enable_disable_install_remove(self):
3264                 if not self.user_rights:
3265                         self.w_installupdate_button.set_sensitive(False)
3266                         self.w_installupdate_menuitem.set_sensitive(False)
3267                         self.w_remove_button.set_sensitive(False)
3268                         self.w_remove_menuitem.set_sensitive(False)
3269                         return
3270                 selected_removal = self.__enable_if_selected_for_removal()
3271                 selected_install_update = self.__enable_if_selected_for_install_update()
3272                 if selected_removal or selected_install_update:
3273                         return
3274                 remove = False
3275                 install = False
3276                 if self.selected == 0:
3277                         model, itr = self.package_selection.get_selected()
3278                         if itr:
3279                                 status = \
3280                                        model.get_value(itr, enumerations.STATUS_COLUMN)
3281                                 if status == enumerations.NOT_INSTALLED:
3282                                         remove = False
3283                                         install = True
3284                                 elif status == enumerations.UPDATABLE:
3285                                         remove = True
3286                                         install = True
3287                                 elif status == enumerations.INSTALLED:
3288                                         remove = True
3289                                         install = False
3290                                 self.w_installupdate_button.set_sensitive(install)
3291                                 self.w_installupdate_menuitem.set_sensitive(install)
3292                                 self.w_remove_button.set_sensitive(remove)
3293                                 self.w_remove_menuitem.set_sensitive(remove)
3294 
3295         def __enable_if_selected_for_removal(self):
3296                 sensitive = False
3297                 visible_repository = self.__get_visible_repository_name()
3298                 selected = self.to_remove.get(visible_repository)
3299                 if selected > 0:
3300                         sensitive = True
3301                 self.w_remove_button.set_sensitive(sensitive)
3302                 self.w_remove_menuitem.set_sensitive(sensitive)
3303                 return sensitive
3304 
3305         def __enable_if_selected_for_install_update(self):
3306                 sensitive = False
3307                 visible_repository = self.__get_visible_repository_name()
3308                 selected = self.to_install_update.get(visible_repository)
3309                 if selected > 0:
3310                         sensitive = True
3311                 self.w_installupdate_button.set_sensitive(sensitive)
3312                 self.w_installupdate_menuitem.set_sensitive(sensitive)
3313                 return sensitive
3314 
3315         def __enable_disable_select_updates(self):
3316                 for row in self.w_application_treeview.get_model():
3317                         if row[enumerations.STATUS_COLUMN] == enumerations.UPDATABLE:
3318                                 if not row[enumerations.MARK_COLUMN]:
3319                                         self.w_selectupdates_menuitem. \
3320                                             set_sensitive(True)
3321                                         return
3322                 self.w_selectupdates_menuitem.set_sensitive(False)
3323                 return
3324 
3325         def __get_inventory_list(self, pargs, all_known, all_versions):
3326                 self.__image_activity_lock.acquire()
3327                 try:
3328                         res = misc.get_inventory_list(self.api_o.img, 
3329                             pargs, all_known, all_versions)
3330                 finally:
3331                         self.__image_activity_lock.release()
3332                 return res
3333 
3334         def __enable_disable_update_all(self):
3335                 #XXX Api to provide fast information if there are some updates
3336                 #available within image
3337                 gobject.idle_add(self.w_updateall_button.set_sensitive, False)
3338                 gobject.idle_add(self.w_updateall_menuitem.set_sensitive, False)
3339                 update_available = self.__check_if_updates_available()
3340                 gobject.idle_add(self.__g_enable_disable_update_all, update_available)
3341                 gobject.idle_add(self.__show_info_after_catalog_load)
3342                 return False
3343 
3344         def __show_info_after_catalog_load(self):
3345                 self.__show_info(self.selected_model, self.selected_path)
3346                 self.selected_model = None
3347                 self.selected_path = None
3348                 if (self.w_info_notebook.get_current_page() == 
3349                     INFO_NOTEBOOK_LICENSE_PAGE and
3350                     not self.showing_empty_details):
3351                         self.__show_licenses()
3352 
3353         def __check_if_updates_available(self):
3354                 try:
3355                         self.catalog_loaded = False
3356                         self.api_o.refresh()
3357                         self.catalog_loaded = True
3358                         res = self.__get_inventory_list([], False, False)
3359                         for pfmri, state in res:
3360                                 if state["upgradable"]:
3361                                         self.pylintstub = pfmri
3362                                         return True
3363 
3364                 except api_errors.InventoryException:
3365                         gobject.idle_add(self.__set_empty_details_panel)
3366                         return False
3367                 return False
3368 
3369         def __g_enable_disable_update_all(self, update_available):
3370                 self.w_updateall_button.set_sensitive(update_available)
3371                 self.w_updateall_menuitem.set_sensitive(update_available)
3372                 self.__enable_disable_install_remove()
3373 
3374         def __enable_disable_deselect(self):
3375                 if self.w_application_treeview.get_model():
3376                         for row in self.w_application_treeview.get_model():
3377                                 if row[enumerations.MARK_COLUMN]:
3378                                         self.w_deselect_menuitem.set_sensitive(True)
3379                                         return
3380                 self.w_deselect_menuitem.set_sensitive(False)
3381                 return
3382 
3383         def __catalog_refresh(self, reload_gui=True):
3384                 """Update image's catalogs."""
3385                 try:
3386                         # Since the user requested the refresh, perform it
3387                         # immediately for all publishers.
3388                         self.api_o.refresh(immediate=True)
3389                         # Refresh will load the catalogs.
3390                         self.catalog_loaded = True
3391                 except api_errors.PublisherError:
3392                         # In current implementation, this will never happen
3393                         # We are not refreshing specific publisher
3394                         self.__catalog_refresh_done()
3395                         raise
3396                 except api_errors.PermissionsException:
3397                         #Error will already have been reported in
3398                         #Manage Repository dialog
3399                         self.__catalog_refresh_done()
3400                         return -1
3401                 except api_errors.CatalogRefreshException, cre:
3402                         total = cre.total
3403                         succeeded = cre.succeeded
3404                         ermsg = _("Network problem.\n\n")
3405                         ermsg += _("Details:\n")
3406                         ermsg += "%s/%s" % (succeeded, total)
3407                         ermsg += _(" catalogs successfully updated:\n")
3408                         for pub, err in cre.failed:
3409                                 if isinstance(err, HTTPError):
3410                                         ermsg += "   %s: %s - %s\n" % \
3411                                             (err.filename, err.code, err.msg)
3412                                 elif isinstance(err, URLError):
3413                                         if err.args[0][0] == 8:
3414                                                 ermsg += "    %s: %s\n" % \
3415                                                     (urlparse.urlsplit(
3416                                                         pub["origin"])[1].split(":")[0],
3417                                                     err.args[0][1])
3418                                         else:
3419                                                 if isinstance(err.args[0], \
3420                                                     socket.timeout):
3421                                                         ermsg += "    %s: %s\n" % \
3422                                                             (pub["origin"], "timeout")
3423                                                 else:
3424                                                         ermsg += "    %s: %s\n" % \
3425                                                             (pub["origin"], \
3426                                                             err.args[0][1])
3427                                 elif "data" in err.__dict__ and err.data:
3428                                         ermsg += err.data
3429                                 else:
3430                                         ermsg += _("Unknown error")
3431                                         ermsg += "\n"
3432 
3433                         gobject.idle_add(self.error_occurred, ermsg,
3434                             None, gtk.MESSAGE_INFO)
3435                         self.__catalog_refresh_done()
3436                         return -1
3437                 except api_errors.InvalidDepotResponseException, idrex:
3438                         err = str(idrex)
3439                         gobject.idle_add(self.error_occurred, err,
3440                             None, gtk.MESSAGE_INFO)
3441                         self.__catalog_refresh_done()
3442                         return -1
3443                 except api_errors.PublisherError:
3444                         self.__catalog_refresh_done()
3445                         raise
3446                 except Exception:
3447                         self.__catalog_refresh_done()
3448                         raise
3449                 if reload_gui:
3450                         self.__catalog_refresh_done()
3451                 return 0
3452 
3453         def __add_pkgs_to_lists_from_cache(self, publisher, application_list,
3454             category_list, section_list):
3455                 if self.cache_o:
3456                         self.cache_o.load_application_list(publisher, application_list,
3457                             self.selected_pkgs)
3458                         self.cache_o.load_category_list(publisher, category_list)
3459                         self.cache_o.load_section_list(publisher, section_list)
3460 
3461         def __add_pkgs_to_lists_from_api(self, publisher, application_list,
3462             category_list, section_list):
3463                 """ This method set up image from the given directory and
3464                 returns the image object or None"""
3465                 pargs = []
3466                 pargs.append("pkg://" + publisher + "/*")
3467                 try:
3468                         pkgs_known = self.__get_inventory_list(pargs,
3469                             True, True)
3470                 except api_errors.InventoryException:
3471                         # This can happen if the repository does not
3472                         # contain any packages
3473                         err = _("Selected repository does not contain any packages.")
3474                         gobject.idle_add(self.w_progress_dialog.hide)
3475                         gobject.idle_add(self.error_occurred, err, None,
3476                             gtk.MESSAGE_INFO)
3477                         self.unset_busy_cursor()
3478                         pkgs_known = []
3479 
3480                 return self.__add_pkgs_to_lists(pkgs_known, application_list,
3481                     category_list, section_list)
3482 
3483         def __add_pkgs_to_lists(self, pkgs_known, application_list,
3484             category_list, section_list):
3485                 if section_list != None:
3486                         self.__init_sections(section_list)
3487                 #Only one instance of those icons should be in memory
3488                 update_available_icon = gui_misc.get_icon(self.icon_theme,
3489                     "status_newupdate")
3490                 installed_icon = gui_misc.get_icon(self.icon_theme,
3491                     "status_installed")
3492                 update_for_category_icon = \
3493                     self.get_icon_pixbuf_from_glade_dir("legend_newupdate")
3494                 #Imageinfo for categories
3495                 imginfo = imageinfo.ImageInfo()
3496                 sectioninfo = imageinfo.ImageInfo()
3497                 pubs = [p.prefix for p in self.api_o.get_publishers()]
3498                 categories = {}
3499                 sections = {}
3500                 share_path = "/usr/share/package-manager/data/"
3501                 for pub in pubs:
3502                         category = imginfo.read(self.application_dir +
3503                             share_path + pub)
3504                         if len(category) == 0:
3505                                 category = imginfo.read(self.application_dir +
3506                                     share_path + "opensolaris.org")
3507                         categories[pub] = category
3508                         section = sectioninfo.read(self.application_dir +
3509                             share_path + pub + ".sections")
3510                         if len(section) == 0:
3511                                 section = sectioninfo.read(self.application_dir +
3512                                     share_path + "opensolaris.org.sections")
3513                         sections[pub] = section
3514                 pkg_count = 0
3515                 pkg_add = 0
3516                 progress_percent = INITIAL_PROGRESS_TOTAL_PERCENTAGE
3517                 total_pkg_count = len(pkgs_known)
3518                 progress_increment = \
3519                         total_pkg_count / PACKAGE_PROGRESS_TOTAL_INCREMENTS
3520                 self.progress_stop_timer_thread = True
3521                 while gtk.events_pending():
3522                         gtk.main_iteration(False)
3523                 prev_stem = ""
3524                 prev_pfmri_str = ""
3525                 next_app = None
3526                 pkg_name = None
3527                 pkg_publisher = None
3528                 prev_state = None
3529                 category_icon = None
3530                 for pkg, state in pkgs_known:
3531                         if prev_pfmri_str and \
3532                             prev_pfmri_str == pkg.get_short_fmri() and \
3533                             prev_state == state:
3534                                 pkg_count += 1
3535                                 continue
3536                         if prev_stem and \
3537                             prev_stem == pkg.get_pkg_stem() and \
3538                             prev_state["state"] == "known" and \
3539                             state["state"] == "installed":
3540                                 pass
3541                         elif next_app != None:
3542                                 self.__add_package_to_list(next_app,
3543                                     application_list,
3544                                     pkg_add, pkg_name,
3545                                     category_icon,
3546                                     categories, category_list, pkg_publisher)
3547                                 pkg_add += 1
3548                         prev_stem = pkg.get_pkg_stem()
3549                         prev_pfmri_str = pkg.get_short_fmri()
3550                         prev_state = state
3551 
3552                         if progress_increment > 0 and pkg_count % progress_increment == 0:
3553                                 progress_percent += PACKAGE_PROGRESS_PERCENT_INCREMENT
3554                                 if progress_percent <= PACKAGE_PROGRESS_PERCENT_TOTAL:
3555                                         self.__progressdialog_progress_percent(
3556                                             progress_percent, pkg_count, total_pkg_count)
3557                                 while gtk.events_pending():
3558                                         gtk.main_iteration(False)
3559 
3560                         status_icon = None
3561                         category_icon = None
3562                         pkg_name = pkg.get_name()
3563                         pkg_name = gui_misc.get_pkg_name(pkg_name)
3564                         pkg_stem = pkg.get_pkg_stem()
3565                         pkg_publisher = pkg.get_publisher()
3566                         pkg_state = enumerations.NOT_INSTALLED
3567                         if state["state"] == "installed":
3568                                 pkg_state = enumerations.INSTALLED
3569                                 if state["upgradable"] == True:
3570                                         status_icon = update_available_icon
3571                                         category_icon = update_for_category_icon
3572                                         pkg_state = enumerations.UPDATABLE
3573                                 else:
3574                                         status_icon = installed_icon
3575                         marked = False
3576                         if not self.is_search_all:
3577                                 pkgs = self.selected_pkgs.get(pkg_publisher)
3578                                 if pkgs != None:
3579                                         if pkg_stem in pkgs:
3580                                                 marked = True
3581                         next_app = \
3582                             [
3583                                 marked, status_icon, pkg_name, '...', pkg_state,
3584                                 pkg, pkg_stem, None, True, None, pkg_publisher
3585                             ]
3586                         pkg_count += 1
3587 
3588                 if next_app:
3589                         self.__add_package_to_list(next_app, application_list, 
3590                             pkg_add, pkg_name, category_icon, categories, 
3591                             category_list, pkg_publisher)
3592                         pkg_add += 1
3593                 if category_list != None:
3594                         self.__add_categories_to_sections(sections,
3595                             category_list, section_list)
3596                 self.__progressdialog_progress_percent(PACKAGE_PROGRESS_PERCENT_TOTAL,
3597                     total_pkg_count, total_pkg_count)
3598                 return
3599 
3600         def __add_categories_to_sections(self, sections, category_list, section_list):
3601                 for publisher in sections:
3602                         for section in sections[publisher]:
3603                                 for category in sections[publisher][section].split(","):
3604                                         self.__add_category_to_section(_(category),
3605                                             _(section), category_list, section_list)
3606 
3607                 #1915 Sort the Categories into alphabetical order and prepend All Category
3608                 if len(category_list) > 0:
3609                         rows = [tuple(r) + (i,) for i, r in enumerate(category_list)]
3610                         rows.sort(self.__sort)
3611                         r = []
3612                         category_list.reorder([r[-1] for r in rows])
3613                 return
3614 
3615         def __add_package_to_list(self, app, application_list, pkg_add,
3616             pkg_name, category_icon, categories, category_list, publisher):
3617                 row_iter = application_list.insert(pkg_add, app)
3618                 if category_list == None:
3619                         return
3620                 cat_pub = categories.get(publisher)
3621                 if pkg_name in cat_pub:
3622                         pkg_categories = cat_pub.get(pkg_name)
3623                         for pcat in pkg_categories.split(","):
3624                                 self.__add_package_to_category(_(pcat), None,
3625                                     category_icon, row_iter, application_list,
3626                                     category_list)
3627 
3628         @staticmethod
3629         def __add_package_to_category(category_name, category_description,
3630             category_icon, package, application_list, category_list):
3631                 if not package or category_name == _('All'):
3632                         return
3633                 if not category_name:
3634                         return
3635                 category_id = None
3636                 icon_visible = False
3637                 if category_icon:
3638                         icon_visible = True
3639                 for category in category_list:
3640                         if category[enumerations.CATEGORY_NAME] == category_name:
3641                                 category_id = category[enumerations.CATEGORY_ID]
3642                                 if category_icon:
3643                                         category[enumerations.CATEGORY_ICON] = \
3644                                             category_icon
3645                                         category[enumerations.CATEGORY_ICON_VISIBLE] = \
3646                                             icon_visible
3647                                 break
3648                 if not category_id:                       # Category not exists
3649                         category_id = len(category_list) + 1
3650                         category_list.append([category_id, category_name,
3651                             category_description, category_icon, icon_visible,
3652                             True, None])
3653                 if application_list.get_value(package,
3654                     enumerations.CATEGORY_LIST_COLUMN):
3655                         a = application_list.get_value(package,
3656                             enumerations.CATEGORY_LIST_COLUMN)
3657                         a.append(category_id)
3658                 else:
3659                         category_list = []
3660                         category_list.append(category_id)
3661                         application_list.set(package,
3662                             enumerations.CATEGORY_LIST_COLUMN, category_list)
3663 
3664         @staticmethod
3665         def __add_category_to_section(category_name, section_name, category_list,
3666             section_list):
3667                 '''Adds the section to section list in category. If there is no such
3668                 section, than it is not added. If there was already section than it
3669                 is skipped. Sections must be case sensitive'''
3670                 if not category_name:
3671                         return
3672                 for section in section_list:
3673                         if section[enumerations.SECTION_NAME] == section_name:
3674                                 section_id = section[enumerations.SECTION_ID]
3675                                 for category in category_list:
3676                                         if category[enumerations.CATEGORY_NAME] == \
3677                                             category_name:
3678                                                 section_lst = category[ \
3679                                                     enumerations.SECTION_LIST_OBJECT]
3680                                                 section[enumerations.SECTION_ENABLED] = \
3681                                                     True
3682                                                 if not section_lst:
3683                                                         category[ \
3684                                                     enumerations.SECTION_LIST_OBJECT] = \
3685                                                             [section_id, ]
3686                                                 else:
3687                                                         if not section_name in \
3688                                                             section_lst:
3689                                                                 section_lst.append(
3690                                                                     section_id)
3691 
3692         def __progressdialog_progress_pulse(self):
3693                 while not self.progress_stop_timer_thread:
3694                         gobject.idle_add(self.w_progressbar.pulse)
3695                         time.sleep(0.1)
3696                 gobject.idle_add(self.w_progress_dialog.hide)
3697                 self.progress_stop_timer_thread = False
3698 
3699         # For initial setup before loading package entries allow 5% of progress bar
3700         # update it on a time base as we have no other way to judge progress at this point
3701         def __progressdialog_progress_time(self):
3702                 while not self.progress_stop_timer_thread and \
3703                         self.progress_fraction_time_count <= \
3704                             INITIAL_PROGRESS_TOTAL_PERCENTAGE:
3705 
3706                         gobject.idle_add(self.w_progressbar.set_fraction,
3707                             self.progress_fraction_time_count)
3708                         self.progress_fraction_time_count += \
3709                                 INITIAL_PROGRESS_TIME_PERCENTAGE
3710                         time.sleep(INITIAL_PROGRESS_TIME_INTERVAL)
3711                 self.progress_stop_timer_thread = False
3712                 self.progress_fraction_time_count = 0
3713 
3714         def __progressdialog_progress_percent(self, fraction, count, total):
3715                 gobject.idle_add(self.w_progressinfo_label.set_text, _(
3716                     "Processing package entries: %d of %d") % (count, total)  )
3717                 gobject.idle_add(self.w_progressbar.set_fraction, fraction)
3718 
3719         def error_occurred(self, error_msg, msg_title=None, msg_type=gtk.MESSAGE_ERROR):
3720                 if msg_title:
3721                         title = msg_title
3722                 else:
3723                         title = _("Package Manager")
3724                 gui_misc.error_occurred(self.w_main_window, error_msg,
3725                     title, msg_type, use_markup=True)
3726 
3727 
3728                 msgbox = gtk.MessageDialog(parent =
3729                     self.w_main_window,
3730                     buttons = gtk.BUTTONS_CLOSE,
3731                     flags = gtk.DIALOG_MODAL,
3732                     type = msg_type,
3733                     message_format = None)
3734                 msgbox.set_property('text', error_msg)
3735                 title = None
3736                 if msg_title:
3737                         title = msg_title
3738                 else:
3739                         title = _("Package Manager")
3740                 msgbox.set_title(title)
3741                 msgbox.run()
3742                 msgbox.destroy()
3743 
3744 #-----------------------------------------------------------------------------#
3745 # Static Methods
3746 #-----------------------------------------------------------------------------#
3747 
3748         #@staticmethod
3749         #def N_(message):
3750         #        return message
3751 
3752         @staticmethod
3753         def __sort(a, b):
3754                 return cmp(a[1], b[1])
3755 
3756         @staticmethod
3757         def cell_data_function(column, renderer, model, itr, data):
3758                 '''Function which sets the background colour to black if package is
3759                 selected'''
3760                 if itr:
3761                         if model.get_value(itr, enumerations.MARK_COLUMN):
3762                                 renderer.set_property("cell-background", "#ffe5cc")
3763                                 renderer.set_property("cell-background-set", True)
3764                         else:
3765                                 renderer.set_property("cell-background-set", False)
3766 
3767         @staticmethod
3768         def combobox_separator(model, itr):
3769                 return model.get_value(itr, enumerations.FILTER_NAME) == ""
3770 
3771         @staticmethod
3772         def combobox_id_separator(model, itr):
3773                 return model.get_value(itr, 0) == -1 and \
3774                     model.get_value(itr, 1) == ""
3775 
3776         @staticmethod
3777         def category_filter(model, itr):
3778                 '''This function filters category in the main application view'''
3779                 return model.get_value(itr, enumerations.CATEGORY_VISIBLE)
3780 
3781         @staticmethod
3782         def get_datetime(version):
3783                 dt = None
3784                 try:
3785                         dt = version.get_datetime()
3786                 except AttributeError:
3787                         dt = version.get_timestamp()
3788                 return dt
3789 
3790         @staticmethod
3791         def get_installed_version(api_o, pkg):
3792                 info = api_o.info([pkg], False, frozenset(
3793                     [api.PackageInfo.STATE, api.PackageInfo.IDENTITY]))
3794                 found = info[api.ImageInterface.INFO_FOUND]
3795                 try:
3796                         version = found[0]
3797                 except IndexError:
3798                         version = None
3799                 return version
3800 
3801 #-----------------------------------------------------------------------------#
3802 # Public Methods
3803 #-----------------------------------------------------------------------------#
3804         def setup_progressdialog_show(self):
3805                 self.w_progress_dialog.set_title(_("Loading Repository Information"))
3806                 self.w_progressinfo_label.set_text(
3807                     _( "Fetching package entries ..."))
3808                 self.w_progress_cancel.hide()
3809                 self.w_progress_dialog.show()
3810                 Thread(target = self.__progressdialog_progress_time).start()
3811 
3812         def setup_progressdialog_hide(self):
3813                 self.progress_stop_timer_thread = True
3814                 self.w_progress_dialog.hide()
3815 
3816         def init_show_filter(self):
3817                 self.__init_show_filter()                #Initiates filter
3818 
3819         def reload_packages(self):
3820                 self.api_o = gui_misc.get_api_object(self.image_directory, 
3821                     self.pr, self.w_main_window)
3822                 self.cache_o = self.__get_cache_obj(self.icon_theme, 
3823                     self.application_dir, self.api_o)
3824                 self.__on_reload(None)
3825 
3826         def set_busy_cursor(self):
3827                 self.gdk_window.show()
3828 
3829         def unset_busy_cursor(self):
3830                 self.gdk_window.hide()
3831 
3832         def process_package_list_start(self, image_directory):
3833                 self.image_directory = image_directory
3834                 if not self.api_o:
3835                         self.api_o = gui_misc.get_api_object(image_directory, 
3836                             self.pr, self.w_main_window)
3837                         self.cache_o = self.__get_cache_obj(self.icon_theme,
3838                             self.application_dir, self.api_o)
3839                         self.img_timestamp = self.cache_o.get_index_timestamp()
3840                 self.repositories_list = self.__get_new_repositories_liststore()
3841                 self.__setup_repositories_combobox(self.api_o, self.repositories_list)
3842 
3843         @staticmethod
3844         def __get_cache_obj(icon_theme, application_dir, api_o):
3845                 cache_o = cache.CacheListStores(icon_theme, application_dir,
3846                     api_o)
3847                 return cache_o
3848 
3849         def process_package_list_end(self):
3850                 self.__set_first_category_text()
3851                 self.in_startpage_startup = False
3852                 if self.update_all_proceed:
3853                 # TODO: Handle situation where only SUNWipkg/SUNWipg-gui have been updated
3854                 # in update all: bug 6357
3855                         self.__on_update_all(None)
3856                         self.update_all_proceed = False
3857                 self.setup_progressdialog_hide()
3858                 self.__enable_disable_install_remove()
3859                 self.update_statusbar()
3860                 self.in_setup = False
3861                 self.cancelled = False
3862                 if self.set_section != 0 or \
3863                     self.set_show_filter != enumerations.FILTER_ALL:
3864                         self.__application_refilter()
3865                 else:
3866                         self.unset_busy_cursor()
3867                 
3868                 if self.first_run or self.in_reload:
3869                         Thread(target = self.__enable_disable_update_all).start()
3870                 self.first_run = False
3871                 self.in_reload = False
3872 
3873         def get_icon_pixbuf_from_glade_dir(self, icon_name):
3874                 return gui_misc.get_pixbuf_from_path(self.application_dir +
3875                     "/usr/share/package-manager/", icon_name)
3876 
3877         def update_statusbar(self):
3878                 '''Function which updates statusbar'''
3879                 if self.statusbar_message_id > 0:
3880                         self.w_main_statusbar.remove(0, self.statusbar_message_id)
3881                         self.statusbar_message_id = 0
3882                 search_text = self.w_searchentry.get_text()
3883 
3884                 if not self.in_search_mode:
3885                         installed = 0
3886                         self.selected = 0
3887                         sel = 0
3888                         if self.application_list == None:
3889                                 return
3890                         visible_repository = self.__get_visible_repository_name()
3891                         pkgs = self.selected_pkgs.get(visible_repository)
3892                         if pkgs:
3893                                 self.selected = len(pkgs)
3894                         for pkg_row in self.application_list:
3895                                 if pkg_row[enumerations.STATUS_COLUMN] == \
3896                                         enumerations.INSTALLED \
3897                                         or pkg_row[enumerations.STATUS_COLUMN] == \
3898                                     enumerations.UPDATABLE:
3899                                         installed = installed + 1
3900                                 if pkg_row[enumerations.MARK_COLUMN]:
3901                                         sel = sel + 1
3902                         listed_str = _('%d listed') % len(self.application_list)
3903                         sel_str = _('%d selected') % sel
3904                         inst_str = _('%d installed') % installed
3905                         status_str = _("%s: %s , %s, %s.") % (visible_repository,
3906                             listed_str, inst_str, sel_str)
3907                         self.w_main_statusbar.push(0, status_str)
3908                         return
3909 
3910                 # In Search Mode
3911                 active = ""
3912                 if self.is_search_all:
3913                         if self.__doing_search():
3914                                 if self.current_search_publisher != None:
3915                                         active = "(" + self.current_search_publisher + \
3916                                                 ") "
3917                                 opt_str = _('Searching... '
3918                                     '%(active)sfor "%(search_text)s"') % \
3919                                         {"active": active, "search_text": search_text}
3920                         else:
3921                                 opt_str = _('Searched All for "%s"') % (search_text)
3922                 else:
3923                         search_str = _("Searched")
3924                         if self.__doing_search():
3925                                 search_str = _("Searching...")
3926                         if self.last_active_publisher != None:
3927                                 active = "(" + self.last_active_publisher + ") "
3928                         opt_str = \
3929                                 _('%(search)s %(last_active)sfor "%(search_text)s"') \
3930                                 % {"search": search_str, "last_active" : active,
3931                                     "search_text" : search_text}
3932                 fmt_str = _("%(option_str)s:  %(number)d found %(time)s")
3933                 time_str = ""
3934                 if self.search_time_sec > 0:
3935                         time_str = _("in %d seconds") % self.search_time_sec
3936                 status_str = fmt_str % {"option_str" : opt_str, "number" :
3937                     len(self.application_list), "time" : time_str}
3938                 self.w_main_statusbar.push(0, status_str)
3939 
3940         def update_package_list(self, update_list):
3941                 if update_list == None and self.img_timestamp:
3942                         return
3943                 visible_repository = self.__get_visible_repository_name()
3944                 default_publisher = self.default_publisher
3945                 self.api_o.refresh()
3946                 if not self.img_timestamp:
3947                         self.img_timestamp = self.cache_o.get_index_timestamp()
3948                         self.__on_reload(None)
3949                         return
3950                 self.img_timestamp = self.cache_o.get_index_timestamp()
3951                 installed_icon = gui_misc.get_icon(self.icon_theme,
3952                     "status_installed")
3953                 visible_list = update_list.get(visible_repository)
3954                 if visible_list:
3955                         i = 0
3956                         while i < len(visible_list):
3957                                 visible_list[i] = gui_misc.get_pkg_name(
3958                                     visible_list[i])
3959                                 i +=  1
3960                         for row in self.application_list:
3961                                 if row[enumerations.NAME_COLUMN] in visible_list:
3962                                         pkg = row[enumerations.FMRI_COLUMN]
3963                                         pkg_stem = row[enumerations.STEM_COLUMN]
3964                                         self.__remove_pkg_stem_from_list(pkg_stem)
3965                                         if self.info_cache.has_key(pkg_stem):
3966                                                 del self.info_cache[pkg_stem]
3967                                         package_info = self.get_installed_version(
3968                                             self.api_o, pkg_stem)
3969                                         package_installed =  (package_info.state 
3970                                             == api.PackageInfo.INSTALLED)
3971                                         print pkg_stem, package_installed
3972                                         if package_installed:
3973                                                 row[enumerations.STATUS_COLUMN] = \
3974                                                     enumerations.INSTALLED
3975                                                 row[enumerations.STATUS_ICON_COLUMN] = \
3976                                                     installed_icon
3977                                         else:
3978                                                 row[enumerations.STATUS_COLUMN] = \
3979                                                     enumerations.NOT_INSTALLED
3980                                                 row[enumerations.STATUS_ICON_COLUMN] = \
3981                                                     None
3982                                         row[enumerations.MARK_COLUMN] = False
3983                         self.__dump_datamodels(visible_repository,
3984                                 self.application_list, self.category_list,
3985                                 self.section_list)
3986                 for publisher in update_list:
3987                         if publisher != visible_repository:
3988                                 pkg_list = update_list.get(publisher)
3989                                 for pkg in pkg_list:
3990                                         pkg_stem = None
3991                                         if publisher != default_publisher:
3992                                                 pkg_stem = "pkg://%s/%s" % \
3993                                                         (publisher, pkg)
3994                                         else:
3995                                                 pkg_stem = "pkg:/%s" % pkg
3996                                         if pkg_stem:
3997                                                 if self.info_cache.has_key(pkg_stem):
3998                                                         del self.info_cache[pkg_stem]
3999                                                 self.__remove_pkg_stem_from_list(pkg_stem)
4000                 self.__process_package_selection()
4001                 self.__enable_disable_selection_menus()
4002                 self.__enable_disable_install_remove()
4003                 self.update_statusbar()
4004                 Thread(target = self.__enable_disable_update_all).start()
4005 
4006         @staticmethod
4007         def __find_root_home_dir():
4008                 return_str = '/var/tmp'
4009                  
4010                 try:
4011                         lines = pwd.getpwnam('root')
4012                 except KeyError:
4013                         if debug:
4014                                 print "Error getting passwd database entry for root"
4015                         return return_str
4016                 try:
4017                         return_str = lines[5]
4018                 except IndexError:
4019                         if debug:
4020                                 print "Error getting home directory for root"
4021                 return return_str
4022 
4023         def restart_after_ips_update(self, be_name):
4024                 self.__main_application_quit(be_name)
4025 
4026         def shutdown_after_image_update(self):
4027                 info_str = _("The Update All action is now complete and "
4028                     "Package Manager will close.\n\nReview the posted release notes "
4029                     "before rebooting your system:\n\n"
4030                     )
4031                 self.w_ua_completed_release_label.set_text(info_str.strip('\n'))
4032 
4033                 info_str = misc.get_release_notes_url()
4034                 self.w_ua_completed_linkbutton.set_uri(info_str)
4035                 self.w_ua_completed_linkbutton.set_label(info_str)
4036                 self.release_notes_url = info_str
4037                 
4038                 self.w_ua_completed_dialog.set_title(_("Update All Complete"))
4039                 self.w_ua_completed_dialog.show()
4040 
4041 ###############################################################################
4042 #-----------------------------------------------------------------------------#
4043 # Main
4044 #-----------------------------------------------------------------------------#
4045 
4046 def main():
4047         gtk.main()
4048         return 0
4049 
4050 if __name__ == '__main__':
4051         debug = True
4052         debug_descriptions = False
4053         update_all_proceed = False
4054         ua_be_name = None
4055         app_path = None
4056         image_dir = None
4057         info_install_arg = None
4058         save_selected = _("Save selected...")
4059         save_selected_pkgs = _("Save selected packages...")
4060         reboot_needed = _("The installed package(s) require a reboot before "
4061             "installation can be completed.")
4062 
4063         try:
4064                 opts, args = getopt.getopt(sys.argv[1:], "hR:U:i:", \
4065                     ["help", "image-dir=", "update-all=", "info-install="])
4066         except getopt.error, msg:
4067                 print "%s, for help use --help" % msg
4068                 sys.exit(2)
4069 
4070         if os.path.isabs(sys.argv[0]):
4071                 app_path = sys.argv[0]
4072         else:
4073                 cmd = os.path.join(os.getcwd(), sys.argv[0])
4074                 app_path = os.path.realpath(cmd)
4075 
4076         for option, argument in opts:
4077                 if option in ("-h", "--help"):
4078                         print """\
4079 Use -R (--image-dir) to specify image directory.
4080 Use -U (--update-all) to proceed with Update All"""
4081                         sys.exit(0)
4082                 if option in ("-R", "--image-dir"):
4083                         image_dir = argument
4084                 if option in ("-U", "--update-all"):
4085                         update_all_proceed = True
4086                         ua_be_name = argument
4087                 if option in ("-i", "--info-install"):
4088                         info_install_arg = argument
4089 
4090         if image_dir == None:
4091                 try:
4092                         image_dir = os.environ["PKG_IMAGE"]
4093                 except KeyError:
4094                         image_dir = os.getcwd()
4095         try:
4096                 gtk.init_check()
4097         except RuntimeError, e:
4098                 print _("Unable to initialize gtk")
4099                 print str(e)
4100                 sys.exit(1)
4101 
4102         # Setup webinstall
4103         if info_install_arg or len(sys.argv) == 2:
4104                 webinstall = webinstall.Webinstall(image_dir)
4105                 if len(sys.argv) == 2:
4106                         info_install_arg = sys.argv[1]
4107                 webinstall.process_param(info_install_arg)
4108                 main()
4109                 sys.exit(0)
4110 
4111         # Setup packagemanager
4112         packagemanager = PackageManager()
4113         packagemanager.application_path = app_path
4114         packagemanager.image_dir_arg = image_dir
4115         packagemanager.update_all_proceed = update_all_proceed
4116         packagemanager.ua_be_name = ua_be_name
4117 
4118         while gtk.events_pending():
4119                 gtk.main_iteration(False)
4120 
4121         packagemanager.init_show_filter()
4122 
4123         packagemanager.process_package_list_start(image_dir)
4124 
4125         main()