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                 if not self.visible_repository:
2484                         self.visible_repository = self.__get_active_publisher()
2485                 application_list = self.__get_new_application_liststore()
2486                 category_list = self.__get_new_category_liststore()
2487                 section_list = self.__get_new_section_liststore()
2488                 first_loop = True
2489                 for publisher in publishers:
2490                         uptodate = False
2491                         try:
2492                                 uptodate = self.__check_if_cache_uptodate(publisher)
2493                                 if uptodate:
2494                                         self.__add_pkgs_to_lists_from_cache(publisher,
2495                                             application_list, category_list,
2496                                             section_list)
2497                         except (UnpicklingError, EOFError, IOError):
2498                                 #Most likely cache is corrupted, silently load list
2499                                 #from api.
2500                                 application_list = self.__get_new_application_liststore()
2501                                 category_list = self.__get_new_category_liststore()
2502                                 uptodate = False
2503                         if not uptodate:
2504                                 if first_loop == True:
2505                                         first_loop = False
2506                                         gobject.idle_add(self.setup_progressdialog_show)
2507                                 self.api_o.refresh(pubs=[publisher])
2508                                 self.__add_pkgs_to_lists_from_api(publisher,
2509                                     application_list, category_list, section_list)
2510                                 category_list.prepend([0, _('All'), None, None, False,
2511                                     True, None])
2512                         if self.application_list and self.category_list and \
2513                             not self.visible_repository_uptodate:
2514                                 if self.visible_repository:
2515                                         dump_list = self.application_list
2516                                         if self.saved_application_list != None:
2517                                                 dump_list = \
2518                                                     self.saved_application_list
2519                                         self.__dump_datamodels(self.visible_repository,
2520                                             dump_list, self.category_list,
2521                                             self.section_list)
2522                         self.visible_repository = self.__get_active_publisher()
2523                         self.visible_repository_uptodate = uptodate
2524                 return application_list, category_list, section_list
2525 
2526         def __check_if_cache_uptodate(self, publisher):
2527                 if self.cache_o:
2528                         return self.cache_o.check_if_cache_uptodate(publisher)
2529                 return False
2530 
2531         def __dump_datamodels(self, publisher, application_list, category_list,
2532             section_list):
2533                 #Consistency check - only dump models if publisher passed in matches 
2534                 #publisher in application list
2535                 if application_list == None:
2536                         return
2537                 app_pub = application_list[0][enumerations.AUTHORITY_COLUMN]
2538                 if publisher != app_pub:
2539                         if debug:
2540                                 print "ERROR: __dump_data_models(): INCONSISTENT " \
2541                                         "pub %s != app_list_pub %s" % \
2542                                         (publisher,  app_pub)
2543                         return
2544 
2545                 if self.cache_o:
2546                         if self.img_timestamp == \
2547                             self.cache_o.get_index_timestamp():
2548                                 Thread(target = self.cache_o.dump_datamodels,
2549                                     args = (publisher, application_list, category_list,
2550                                     section_list)).start()
2551                         else:
2552                                 self.__remove_cache()
2553 
2554         def __remove_cache(self):
2555                 model = self.w_repository_combobox.get_model()
2556                 for publisher in model:
2557                         pub_name = publisher[1]
2558                         if pub_name and pub_name != _("Add..."):
2559                                 Thread(target = self.cache_o.remove_datamodel,
2560                                     args = [publisher[1]]).start()
2561 
2562         def __on_install_update(self, widget):
2563                 self.api_o.reset()
2564                 install_update = []
2565                 if self.selected == 0:
2566                         model, itr = self.package_selection.get_selected()
2567                         if itr:
2568                                 install_update.append(
2569                                     model.get_value(itr, enumerations.STEM_COLUMN))
2570                 else:
2571                         visible_repository = self.__get_visible_repository_name()
2572                         pkgs = self.selected_pkgs.get(visible_repository)
2573                         if pkgs:
2574                                 for pkg_stem in pkgs:
2575                                         status = pkgs.get(pkg_stem)
2576                                         if status == enumerations.NOT_INSTALLED or \
2577                                             status == enumerations.UPDATABLE:
2578                                                 install_update.append(pkg_stem)
2579 
2580                 if self.img_timestamp != self.cache_o.get_index_timestamp():
2581                         self.img_timestamp = None
2582                         self.__remove_cache()
2583 
2584                 installupdate.InstallUpdate(install_update, self, \
2585                     self.api_o, ips_update = False, \
2586                     action = enumerations.INSTALL_UPDATE)
2587 
2588         def __on_update_all(self, widget):
2589                 self.api_o.reset()
2590                 installupdate.InstallUpdate([], self,
2591                     self.api_o, ips_update = False,
2592                     action = enumerations.IMAGE_UPDATE, be_name = self.ua_be_name,
2593                     parent_name = _("Package Manager"),
2594                     pkg_list = ["SUNWipkg", "SUNWipkg-gui"],
2595                     main_window = self.w_main_window)
2596                 return
2597 
2598         def __on_ua_completed_linkbutton_clicked(self, widget):
2599                 try:
2600                         gnome.url_show(self.release_notes_url)
2601                 except gobject.GError:
2602                         self.error_occurred(_("Unable to navigate to:\n\t%s") % 
2603                             self.release_notes_url)
2604 
2605         def __on_help_about(self, widget):
2606                 wTreePlan = gtk.glade.XML(self.gladefile, "aboutdialog")
2607                 aboutdialog = wTreePlan.get_widget("aboutdialog")
2608                 aboutdialog.connect("response", lambda x = None, \
2609                     y = None: aboutdialog.destroy())
2610                 aboutdialog.run()
2611 
2612         def __on_help_help(self, widget):
2613                 gui_misc.display_help(self.application_dir)
2614 
2615         def __on_remove(self, widget):
2616                 self.api_o.reset()
2617                 remove_list = []
2618                 if self.selected == 0:
2619                         model, itr = self.package_selection.get_selected()
2620                         if itr:
2621                                 remove_list.append(
2622                                     model.get_value(itr, enumerations.STEM_COLUMN))
2623                 else:
2624                         visible_repository = self.__get_visible_repository_name()
2625                         pkgs = self.selected_pkgs.get(visible_repository)
2626                         if pkgs:
2627                                 for pkg_stem in pkgs:
2628                                         status = pkgs.get(pkg_stem)
2629                                         if status == enumerations.INSTALLED or \
2630                                             status == enumerations.UPDATABLE:
2631                                                 remove_list.append(pkg_stem)
2632 
2633                 if self.img_timestamp != self.cache_o.get_index_timestamp():
2634                         self.img_timestamp = None
2635                         self.__remove_cache()
2636 
2637                 installupdate.InstallUpdate(remove_list, self,
2638                     self.api_o, ips_update = False,
2639                     action = enumerations.REMOVE)
2640 
2641         def __on_reload(self, widget):
2642                 if self.description_thread_running:
2643                         self.cancelled = True
2644                 if self.in_search_mode or self.is_search_all:
2645                         self.__unset_search(False)
2646                 self.__set_empty_details_panel()
2647                 self.in_setup = True
2648                 self.visible_repository = None
2649                 if widget != None:
2650                         self.__remove_cache()
2651                 self.w_progress_dialog.set_title(_("Refreshing catalogs"))
2652                 self.w_progressinfo_label.set_text(_("Refreshing catalogs..."))
2653                 self.progress_stop_timer_thread = False
2654                 Thread(target = self.__progressdialog_progress_pulse).start()
2655                 self.w_progress_dialog.show()
2656                 self.w_progress_cancel.hide()
2657                 self.__disconnect_models()
2658                 self.in_reload = True
2659                 Thread(target = self.__catalog_refresh).start()
2660 
2661         def __catalog_refresh_done(self):
2662                 self.progress_stop_timer_thread = True
2663                 #Let the progress_pulse finish. This should be done other way, but at
2664                 #The moment this works fine
2665                 time.sleep(0.2)
2666                 gobject.idle_add(self.w_progress_cancel.show)
2667                 gobject.idle_add(self.process_package_list_start,
2668                     self.image_directory)
2669 
2670         def __main_application_quit(self, be_name = None):
2671                 '''quits the main gtk loop'''
2672                 self.cancelled = True
2673                 if self.in_setup:
2674                         return
2675 
2676                 if be_name:
2677                         if self.image_dir_arg:
2678                                 gobject.spawn_async([self.application_path, "-R",
2679                                     self.image_dir_arg, "-U", be_name])
2680                         else:
2681                                 gobject.spawn_async([self.application_path,
2682                                     "-U", be_name])
2683                 elif self.in_search_mode:
2684                         self.__dump_datamodels(self.visible_repository,
2685                             self.saved_application_list, self.category_list,
2686                             self.section_list)
2687                 else:
2688                         visible_repository = self.__get_visible_repository_name()
2689                         self.__dump_datamodels(visible_repository,
2690                                 self.application_list, self.category_list,
2691                                 self.section_list)
2692 
2693                 width, height = self.w_main_window.get_size()
2694                 hpos = self.w_main_hpaned.get_position()
2695                 vpos = self.w_main_vpaned.get_position()
2696                 try:
2697                         self.client.set_int(INITIAL_APP_WIDTH_PREFERENCES, width)
2698                         self.client.set_int(INITIAL_APP_HEIGHT_PREFERENCES, height)
2699                         self.client.set_int(INITIAL_APP_HPOS_PREFERENCES, hpos)
2700                         self.client.set_int(INITIAL_APP_VPOS_PREFERENCES, vpos)
2701                 except GError:
2702                         pass
2703 
2704                 self.w_main_window.hide()
2705                 while gtk.events_pending():
2706                         gtk.main_iteration(False)
2707                 gtk.main_quit()
2708                 sys.exit(0)
2709                 return True
2710 
2711         def __check_if_something_was_changed(self):
2712                 ''' Returns True if any of the check boxes for package was changed, false
2713                 if not'''
2714                 if self.application_list:
2715                         for pkg in self.application_list:
2716                                 if pkg[enumerations.MARK_COLUMN] == True:
2717                                         return True
2718                 return False
2719 
2720         def __setup_repositories_combobox(self, api_o, repositories_list):
2721                 self.__disconnect_repository_model()
2722                 default_pub = api_o.get_preferred_publisher().prefix
2723                 if self.default_publisher != default_pub:
2724                         self.__clear_pkg_selections()
2725                         self.default_publisher = default_pub
2726                 selected_repos = []
2727                 enabled_repos = []
2728                 for repo in self.selected_pkgs:
2729                         selected_repos.append(repo)
2730                 i = 0
2731                 active = 0
2732                 for pub in api_o.get_publishers():
2733                         if pub.disabled:
2734                                 continue
2735                         prefix = pub.prefix
2736                         if cmp(prefix, self.default_publisher) == 0:
2737                                 active = i
2738                         repositories_list.append([i, prefix, ])
2739                         enabled_repos.append(prefix)
2740                         i = i + 1
2741                 repositories_list.append([-1, "", ])
2742                 repositories_list.append([-1, _("Add..."), ])
2743                 pkgs_to_remove = []
2744                 for repo_name in selected_repos:
2745                         if repo_name not in enabled_repos:
2746                                 pkg_stems = self.selected_pkgs.get(repo_name)
2747                                 for pkg_stem in pkg_stems:
2748                                         pkgs_to_remove.append(pkg_stem)
2749                 for pkg_stem in pkgs_to_remove:
2750                         self.__remove_pkg_stem_from_list(pkg_stem)
2751                 self.w_repository_combobox.set_model(repositories_list)
2752                 if self.default_publisher:
2753                         self.w_repository_combobox.set_active(active)
2754                 else:
2755                         self.w_repository_combobox.set_active(0)
2756 
2757         def __active_pane_toggle(self, cell, path, model_sort):
2758                 '''Toggle function for column enumerations.MARK_COLUMN'''
2759                 applicationModel = model_sort.get_model()
2760                 applicationPath = model_sort.convert_path_to_child_path(path)
2761                 filterModel = applicationModel.get_model()
2762                 child_path = applicationModel.convert_path_to_child_path(applicationPath)
2763                 itr = filterModel.get_iter(child_path)
2764                 if itr:
2765                         modified = filterModel.get_value(itr, enumerations.MARK_COLUMN)
2766                         filterModel.set_value(itr, enumerations.MARK_COLUMN,
2767                             not modified)
2768                         pkg_status = filterModel.get_value(itr,
2769                             enumerations.STATUS_COLUMN)
2770                         pkg_stem = filterModel.get_value(itr, enumerations.STEM_COLUMN)
2771                         if modified:
2772                                 self.__remove_pkg_stem_from_list(pkg_stem)
2773                         else:
2774                                 self.__add_pkg_stem_to_list(pkg_stem, pkg_status)
2775                         self.update_statusbar()
2776                         self.__enable_disable_selection_menus()
2777 
2778         def __update_reload_button(self):
2779                 if self.user_rights:
2780                         self.w_reload_button.set_sensitive(True)
2781                 else:
2782                         self.w_reload_button.set_sensitive(False)
2783 
2784         def __add_pkg_stem_to_list(self, stem, status):
2785                 publisher = self.__get_active_publisher()
2786                 if self.selected_pkgs.get(publisher) == None:
2787                         self.selected_pkgs[publisher] = {}
2788                 self.selected_pkgs.get(publisher)[stem] = status
2789                 if status == enumerations.NOT_INSTALLED or \
2790                     status == enumerations.UPDATABLE:
2791                         if self.to_install_update.get(publisher) == None:
2792                                 self.to_install_update[publisher] = 1
2793                         else:
2794                                 self.to_install_update[publisher] += 1
2795                 if status == enumerations.UPDATABLE or status == enumerations.INSTALLED:
2796                         if self.to_remove.get(publisher) == None:
2797                                 self.to_remove[publisher] = 1
2798                         else:
2799                                 self.to_remove[publisher] += 1
2800                 self.__update_tooltips()
2801 
2802         def __update_tooltips(self):
2803                 to_remove = None
2804                 to_install = None
2805                 no_iter = 0
2806                 for publisher in self.to_remove:
2807                         packages = self.to_remove.get(publisher)
2808                         if packages > 0:
2809                                 if no_iter == 0:
2810                                         to_remove = _("Selected for Removal:")
2811                                 to_remove += "\n   %s: %d" % (publisher, packages)
2812                                 no_iter += 1
2813                 no_iter = 0
2814                 for publisher in self.to_install_update:
2815                         packages = self.to_install_update.get(publisher)
2816                         if packages > 0:
2817                                 if no_iter == 0:
2818                                         to_install = _("Selected for Install/Update:")
2819                                 to_install += "\n   %s: %d" % (publisher, packages)
2820                                 no_iter += 1
2821                 if not to_install:
2822                         to_install = _("Select packages by marking the checkbox "
2823                             "and click to Install/Update.")
2824                 self.w_installupdate_button.set_tooltip(self.install_button_tooltip,
2825                     to_install)
2826                 if not to_remove:
2827                         to_remove = _("Select packages by marking the checkbox "
2828                             "and click to Remove selected.")
2829                 self.w_remove_button.set_tooltip(self.remove_button_tooltip, to_remove)
2830 
2831         def __remove_pkg_stem_from_list(self, stem):
2832                 remove_pub = []
2833                 for publisher in self.selected_pkgs:
2834                         pkgs = self.selected_pkgs.get(publisher)
2835                         status = None
2836                         if stem in pkgs:
2837                                 status = pkgs.pop(stem)
2838                         if status == enumerations.NOT_INSTALLED or \
2839                             status == enumerations.UPDATABLE:
2840                                 if self.to_install_update.get(publisher) == None:
2841                                         self.to_install_update[publisher] = 0
2842                                 else:
2843                                         self.to_install_update[publisher] -= 1
2844                         if status == enumerations.UPDATABLE or \
2845                             status == enumerations.INSTALLED:
2846                                 if self.to_remove.get(publisher) == None:
2847                                         self.to_remove[publisher] = 0
2848                                 else:
2849                                         self.to_remove[publisher] -= 1
2850                         if len(pkgs) == 0:
2851                                 remove_pub.append(publisher)
2852                 for publisher in remove_pub:
2853                         self.selected_pkgs.pop(publisher)
2854                 self.__update_tooltips()
2855 
2856         def __clear_pkg_selections(self):
2857                 # We clear the selections as the preffered repository was changed
2858                 # and pkg stems are not valid.
2859                 remove_pub = []
2860                 for publisher in self.selected_pkgs:
2861                         stems = self.selected_pkgs.get(publisher)
2862                         for pkg_stem in stems:
2863                                 remove_pub.append(pkg_stem)
2864                 for pkg_stem in remove_pub:
2865                         self.__remove_pkg_stem_from_list(pkg_stem)
2866 
2867         def __set_empty_details_panel(self):
2868                 self.showing_empty_details = True
2869                 if self.show_info_id != 0:
2870                         gobject.source_remove(self.show_info_id)
2871                         self.show_info_id = 0
2872                 if self.show_licenses_id != 0:
2873                         gobject.source_remove(self.show_licenses_id)
2874                         self.show_licenses_id = 0
2875                 pkg_name = _("Package Name")
2876                 self.w_packagename_label.set_markup("<b>" + pkg_name + "</b>")
2877                 self.w_general_info_label.set_markup("<b>" + pkg_name + "</b>")
2878                 self.w_installedfiles_textview.get_buffer().set_text("")
2879                 self.w_dependencies_textview.get_buffer().set_text("")
2880                 self.w_generalinfo_textview.get_buffer().set_text("")
2881                 self.w_license_textview.get_buffer().set_text("")
2882                 return
2883 
2884         def __show_fetching_package_info(self, pkg):
2885                 pkg_name = pkg.get_name()
2886                 self.w_packagename_label.set_markup("<b>" + pkg_name + "</b>")
2887                 self.w_general_info_label.set_markup("<b>" + pkg_name + "</b>")
2888 
2889                 pkg_stem = pkg.get_pkg_stem()
2890                 if self.__setting_from_cache(pkg_stem):
2891                         return
2892 
2893                 self.w_shortdescription_label.set_text(
2894                     _("Fetching description..."))
2895                 instbuffer = self.w_installedfiles_textview.get_buffer()
2896                 depbuffer = self.w_dependencies_textview.get_buffer()
2897                 infobuffer = self.w_generalinfo_textview.get_buffer()
2898                 fetching_text = _("Fetching information...")
2899                 instbuffer.set_text(fetching_text)
2900                 depbuffer.set_text(fetching_text)
2901                 infobuffer.set_text(fetching_text)
2902                 return
2903 
2904         def __setting_from_cache(self, pkg_stem):
2905                 if len(self.info_cache) > MAX_INFO_CACHE_LIMIT:
2906                         self.info_cache = {}
2907 
2908                 if self.info_cache.has_key(pkg_stem):
2909                         self.w_shortdescription_label.set_text(
2910                             self.info_cache[pkg_stem][0])
2911                         instbuffer = self.w_installedfiles_textview.get_buffer()
2912                         depbuffer = self.w_dependencies_textview.get_buffer()
2913                         infobuffer = self.w_generalinfo_textview.get_buffer()
2914                         infobuffer.set_text(self.info_cache[pkg_stem][1])
2915                         instbuffer.set_text(self.info_cache[pkg_stem][2])
2916                         depbuffer.set_text(self.info_cache[pkg_stem][3])
2917                         return True
2918                 else:
2919                         return False
2920 
2921         def __update_package_info(self, pkg, local_info, remote_info, info_id):
2922                 if self.showing_empty_details or (info_id != 
2923                     self.last_show_info_id):
2924                         return
2925                 pkg_name = pkg.get_name()
2926                 pkg_stem = pkg.get_pkg_stem()
2927                 self.w_packagename_label.set_markup("<b>" + pkg_name + "</b>")
2928                 self.w_general_info_label.set_markup("<b>" + pkg_name + "</b>")
2929                 installed = True
2930 
2931                 if self.__setting_from_cache(pkg_stem):
2932                         return
2933 
2934                 instbuffer = self.w_installedfiles_textview.get_buffer()
2935                 depbuffer = self.w_dependencies_textview.get_buffer()
2936                 infobuffer = self.w_generalinfo_textview.get_buffer()
2937 
2938                 if not local_info and not remote_info:
2939                         network_str = \
2940                             _("\nThis might be caused by network problem "
2941                             "while accessing the repository.")
2942                         self.w_shortdescription_label.set_text(
2943                             _("Description not available for this package...") +
2944                             network_str)
2945                         instbuffer.set_text( \
2946                             _("Files Details not available for this package...") +
2947                             network_str)
2948                         depbuffer.set_text(_(
2949                             "Dependencies info not available for this package...") +
2950                             network_str)
2951                         infobuffer.set_text(
2952                             _("Information not available for this package...") +
2953                             network_str)
2954                         return
2955 
2956                 if not local_info:
2957                         # Package is not installed
2958                         local_info = remote_info
2959                         installed = False
2960 
2961                 if not remote_info:
2962                         remote_info = local_info
2963                         installed = True
2964 
2965                 description = local_info.summary
2966                 #XXX long term need to have something more robust here for multi byte
2967                 if len(description) > MAX_DESC_LEN:
2968                         description = description[:MAX_DESC_LEN] + " ..."
2969                 self.w_shortdescription_label.set_text(description)
2970                 inst_str = _("Root: %s\n") % self.api_o.img.get_root()
2971                 dep_str = _("Dependencies:\n")
2972 
2973                 if local_info.dependencies:
2974                         dep_str += ''.join(
2975                             ["\t%s\n" % x for x in local_info.dependencies])
2976                 if local_info.dirs:
2977                         inst_str += ''.join(["\t%s\n" % x for x in local_info.dirs])
2978                 if local_info.files:
2979                         inst_str += ''.join(["\t%s\n" % x for x in local_info.files])
2980                 if local_info.hardlinks:
2981                         inst_str += ''.join(["\t%s\n" % x for x in local_info.hardlinks])
2982                 if local_info.links:
2983                         inst_str += ''.join(["\t%s\n" % x for x in local_info.links])
2984                 info_str = ""
2985                 labs = {}
2986                 labs["sum"] = _("Summary:\t\t")
2987                 labs["size"] = _("Size:\t\t\t")
2988                 labs["cat"] = _("Category:\t\t")
2989                 labs["ins"] = _("Installed Version:\t")
2990                 labs["lat"] = _("Latest Version:\t")
2991                 labs["pkg_date"] = _("Packaging Date:\t")
2992                 labs["fmri"] = _("FMRI:\t\t\t")
2993                 labs["repository"] = _("Repository:\t\t")
2994                 max_len = 0
2995                 for lab in labs:
2996                         if len(labs[lab]) > max_len:
2997                                 max_len = len(labs[lab])
2998                 categories = _("None")
2999                 if local_info.category_info_list:
3000                         verbose = len(local_info.category_info_list) > 1
3001                         categories = ""
3002                         categories += local_info.category_info_list[0].__str__(verbose)
3003                         if len(local_info.category_info_list) > 1:
3004                                 for ci in local_info.category_info_list[1:]:
3005                                         categories += ", " + ci.__str__(verbose)
3006                 summary = _("None")
3007                 if local_info.summary:
3008                         summary = local_info.summary
3009                 info_str += "  %s %s" % (labs["sum"], summary)
3010                 info_str += "\n  %s %s" % (labs["size"],
3011                     misc.bytes_to_str(local_info.size))
3012                 info_str += "\n  %s %s" % (labs["cat"], categories)
3013                 if installed:
3014                         info_str += "\n  %s %s,%s-%s" % (labs["ins"], local_info.version,
3015                             local_info.build_release, local_info.branch)
3016                 info_str += "\n  %s %s,%s-%s" % (labs["lat"], remote_info.version,
3017                     remote_info.build_release, remote_info.branch)
3018                 info_str += "\n  %s %s" % (labs["pkg_date"], local_info.packaging_date)
3019                 info_str += "\n  %s %s" % (labs["fmri"], local_info.fmri)
3020                 info_str += "\n  %s %s" % (labs["repository"], local_info.publisher)
3021                 infobuffer.set_text(info_str)
3022                 instbuffer.set_text(inst_str)
3023                 depbuffer.set_text(dep_str)
3024                 self.info_cache[pkg_stem] = \
3025                     (description, info_str, inst_str, dep_str)
3026 
3027         def __update_package_license(self, licenses, license_id):
3028                 if self.showing_empty_details or (license_id !=
3029                     self.last_show_licenses_id):
3030                         return
3031                 lic = ""
3032                 lic_u = ""
3033                 if licenses == None:
3034                         lic_u = _("Not available")
3035                 else:
3036                         for licens in licenses:
3037                                 lic += licens.get_text()
3038                                 lic += "\n"
3039                         try:
3040                                 lic_u = unicode(lic, "utf-8")
3041                         except UnicodeDecodeError:
3042                                 lic_u += ""
3043                 licbuffer = self.w_license_textview.get_buffer()
3044                 licbuffer.set_text(lic_u)
3045 
3046         def __show_licenses(self):
3047                 self.show_licenses_id = 0
3048                 if self.catalog_loaded == False:
3049                         return
3050                 Thread(target = self.__show_package_licenses,
3051                     args = (self.selected_pkgstem, self.last_show_licenses_id,)).start()
3052 
3053         def __show_package_licenses(self, selected_pkgstem, license_id):
3054                 if selected_pkgstem == None:
3055                         gobject.idle_add(self.__update_package_license, None,
3056                             self.last_show_licenses_id)
3057                         return
3058                 info = None
3059                 try:
3060                         info = self.api_o.info([selected_pkgstem],
3061                             True, frozenset([api.PackageInfo.LICENSES]))
3062                 except (api_errors.TransportError):
3063                         pass
3064                 if self.showing_empty_details or (license_id != 
3065                     self.last_show_licenses_id):
3066                         return
3067                 if not info or (info and len(info.get(0)) == 0):
3068                         try:
3069                         # Get license from remote
3070                                 info = self.api_o.info([selected_pkgstem],
3071                                     False, frozenset([api.PackageInfo.LICENSES]))
3072                         except (api_errors.TransportError):
3073                                 pass
3074                 if self.showing_empty_details or (license_id != 
3075                     self.last_show_licenses_id):
3076                         return
3077                 pkgs_info = None
3078                 package_info = None
3079                 no_licenses = 0
3080                 if info:
3081                         pkgs_info = info[0]
3082                 if pkgs_info:
3083                         package_info = pkgs_info[0]
3084                 if package_info:
3085                         no_licenses = len(package_info.licenses)
3086                 if no_licenses == 0:
3087                         gobject.idle_add(self.__update_package_license, None, 
3088                             license_id)
3089                         return
3090                 else:
3091                         gobject.idle_add(self.__update_package_license,
3092                             package_info.licenses, license_id)
3093 
3094         def __get_pkg_info(self, pkg_stem, local):
3095                 info = None
3096                 try:
3097                         info = self.api_o.info([pkg_stem], local,
3098                             api.PackageInfo.ALL_OPTIONS -
3099                             frozenset([api.PackageInfo.LICENSES]))
3100                 except (api_errors.TransportError):
3101                         return info
3102                 pkgs_info = None
3103                 package_info = None
3104                 if info:
3105                         pkgs_info = info[0]
3106                 if pkgs_info:
3107                         package_info = pkgs_info[0]
3108                 if package_info:
3109                         return package_info
3110                 else:
3111                         return None
3112 
3113         def __show_info(self, model, path):
3114                 self.show_info_id = 0
3115                 if self.catalog_loaded == False:
3116                         self.selected_model = model
3117                         self.selected_path = path
3118                         return
3119                 if not (model and path):
3120                         return
3121                 if self.selected_model != None:
3122                         if (self.selected_model != model or
3123                             self.selected_path != path):
3124                         # This can happen after catalogs are loaded in
3125                         # enable_disable_update_all and a different
3126                         # package is selected before enable_disable_update_all
3127                         # calls __show_info. We set these variable to None
3128                         # so that when __show_info is called it does nothing.
3129                                 self.selected_model = None
3130                                 self.selected_path = None
3131 
3132                 itr = model.get_iter(path)
3133                 pkg = model.get_value(itr, enumerations.FMRI_COLUMN)
3134                 pkg_stem = model.get_value(itr, enumerations.STEM_COLUMN)
3135                 pkg_status = model.get_value(itr, enumerations.STATUS_COLUMN)
3136                 if self.info_cache.has_key(pkg_stem):
3137                         return
3138                 Thread(target = self.__show_package_info,
3139                     args = (pkg, pkg_stem, pkg_status, self.last_show_info_id)).start()
3140 
3141         def __show_package_info(self, pkg, pkg_stem, pkg_status, info_id):
3142                 self.api_o.log_operation_start("info")
3143                 local_info = None
3144                 remote_info = None
3145                 if not self.showing_empty_details and (info_id ==
3146                     self.last_show_info_id) and (pkg_status ==
3147                     enumerations.INSTALLED or pkg_status ==
3148                     enumerations.UPDATABLE):
3149                         local_info = self.__get_pkg_info(pkg_stem, True)
3150                 if not self.showing_empty_details and (info_id ==
3151                     self.last_show_info_id) and (pkg_status ==
3152                     enumerations.NOT_INSTALLED or pkg_status ==
3153                     enumerations.UPDATABLE):
3154                         remote_info = self.__get_pkg_info(pkg_stem, False)
3155                 if not self.showing_empty_details and (info_id ==
3156                     self.last_show_info_id):
3157                         gobject.idle_add(self.__update_package_info, pkg,
3158                             local_info, remote_info, info_id)
3159                 self.api_o.log_operation_end()
3160                 return
3161 
3162         # This function is ported from pkg.actions.generic.distinguished_name()
3163         @staticmethod
3164         def __locale_distinguished_name(action):
3165                 if action.key_attr == None:
3166                         return str(action)
3167                 return "%s: %s" % \
3168                     (_(action.name), action.attrs.get(action.key_attr, "???"))
3169 
3170         def __application_filter(self, model, itr):
3171                 '''This function is used to filter content in the main
3172                 application view'''
3173                 if self.in_setup or self.cancelled:
3174                         return False
3175                 filter_id = self.w_filter_combobox.get_active()
3176                 if filter_id == enumerations.FILTER_SELECTED:
3177                         return model.get_value(itr, enumerations.MARK_COLUMN)
3178                 # XXX Show filter, chenge text to integers
3179                 selected_category = 0
3180                 category_selection = self.w_categories_treeview.get_selection()
3181                 category_model, category_iter = category_selection.get_selected()
3182                 if category_iter:
3183                         selected_category = category_model.get_value(category_iter,
3184                             enumerations.CATEGORY_ID)
3185                 category_list = model.get_value(itr, enumerations.CATEGORY_LIST_COLUMN)
3186                 selected_section = self.w_sections_combobox.get_active()
3187                 category = False
3188                 if selected_section == 0 and selected_category == 0:
3189                         #For section "All" and category "All" always true
3190                         category = True
3191                 elif selected_category != 0:
3192                         if category_list and selected_category in category_list:
3193                                 category = True
3194                 elif category_list:
3195                         #The selected category is "All" so we need to check
3196                         #If the package belongs to one of the visible categories
3197                         for visible_category in category_model:
3198                                 visible_id = visible_category[enumerations.CATEGORY_ID]
3199                                 if visible_id in category_list:
3200                                         category = True
3201                                         break
3202                 if (model.get_value(itr, enumerations.IS_VISIBLE_COLUMN) == False):
3203                         return False
3204                 return (category &
3205                     self.__is_package_filtered(model, itr, filter_id))
3206 
3207         @staticmethod
3208         def __is_package_filtered(model, itr, filter_id):
3209                 '''Function for filtercombobox'''
3210                 if filter_id == enumerations.FILTER_ALL:
3211                         return True
3212                 status = model.get_value(itr, enumerations.STATUS_COLUMN)
3213                 if filter_id == enumerations.FILTER_INSTALLED:
3214                         return (status == enumerations.INSTALLED or status == \
3215                             enumerations.UPDATABLE)
3216                 elif filter_id == enumerations.FILTER_UPDATES:
3217                         return status == enumerations.UPDATABLE
3218                 elif filter_id == enumerations.FILTER_NOT_INSTALLED:
3219                         return status == enumerations.NOT_INSTALLED
3220 
3221         def __is_pkg_repository_visible(self, model, itr):
3222                 if len(self.repositories_list) <= 1:
3223                         return True
3224                 else:
3225                         visible_repository = self.__get_visible_repository_name()
3226                         pkg = model.get_value(itr, enumerations.FMRI_COLUMN)
3227                         if not pkg:
3228                                 return False
3229                         if cmp(pkg.get_publisher(), visible_repository) == 0:
3230                                 return True
3231                         else:
3232                                 return False
3233 
3234         def __get_visible_repository_name(self):
3235                 pub_iter = self.w_repository_combobox.get_active_iter()
3236                 if pub_iter == None:
3237                         return None
3238                 visible = self.repositories_list.get_value(pub_iter, \
3239                     enumerations.REPOSITORY_NAME)
3240                 return visible
3241 
3242         def __enable_disable_selection_menus(self):
3243                 if self.in_setup:
3244                         return
3245                 self.__enable_disable_select_updates()
3246                 if not self.__doing_search():
3247                         self.unset_busy_cursor()
3248 
3249         def __enable_disable_select_all(self):
3250                 if self.in_setup:
3251                         return
3252                 if len(self.w_application_treeview.get_model()) > 0:
3253                         for row in self.w_application_treeview.get_model():
3254                                 if not row[enumerations.MARK_COLUMN]:
3255                                         self.w_selectall_menuitem.set_sensitive(True)
3256                                         return
3257                         self.w_selectall_menuitem.set_sensitive(False)
3258                 else:
3259                         self.w_selectall_menuitem.set_sensitive(False)
3260 
3261         def __enable_disable_install_remove(self):
3262                 if not self.user_rights:
3263                         self.w_installupdate_button.set_sensitive(False)
3264                         self.w_installupdate_menuitem.set_sensitive(False)
3265                         self.w_remove_button.set_sensitive(False)
3266                         self.w_remove_menuitem.set_sensitive(False)
3267                         return
3268                 selected_removal = self.__enable_if_selected_for_removal()
3269                 selected_install_update = self.__enable_if_selected_for_install_update()
3270                 if selected_removal or selected_install_update:
3271                         return
3272                 remove = False
3273                 install = False
3274                 if self.selected == 0:
3275                         model, itr = self.package_selection.get_selected()
3276                         if itr:
3277                                 status = \
3278                                        model.get_value(itr, enumerations.STATUS_COLUMN)
3279                                 if status == enumerations.NOT_INSTALLED:
3280                                         remove = False
3281                                         install = True
3282                                 elif status == enumerations.UPDATABLE:
3283                                         remove = True
3284                                         install = True
3285                                 elif status == enumerations.INSTALLED:
3286                                         remove = True
3287                                         install = False
3288                                 self.w_installupdate_button.set_sensitive(install)
3289                                 self.w_installupdate_menuitem.set_sensitive(install)
3290                                 self.w_remove_button.set_sensitive(remove)
3291                                 self.w_remove_menuitem.set_sensitive(remove)
3292 
3293         def __enable_if_selected_for_removal(self):
3294                 sensitive = False
3295                 visible_repository = self.__get_visible_repository_name()
3296                 selected = self.to_remove.get(visible_repository)
3297                 if selected > 0:
3298                         sensitive = True
3299                 self.w_remove_button.set_sensitive(sensitive)
3300                 self.w_remove_menuitem.set_sensitive(sensitive)
3301                 return sensitive
3302 
3303         def __enable_if_selected_for_install_update(self):
3304                 sensitive = False
3305                 visible_repository = self.__get_visible_repository_name()
3306                 selected = self.to_install_update.get(visible_repository)
3307                 if selected > 0:
3308                         sensitive = True
3309                 self.w_installupdate_button.set_sensitive(sensitive)
3310                 self.w_installupdate_menuitem.set_sensitive(sensitive)
3311                 return sensitive
3312 
3313         def __enable_disable_select_updates(self):
3314                 for row in self.w_application_treeview.get_model():
3315                         if row[enumerations.STATUS_COLUMN] == enumerations.UPDATABLE:
3316                                 if not row[enumerations.MARK_COLUMN]:
3317                                         self.w_selectupdates_menuitem. \
3318                                             set_sensitive(True)
3319                                         return
3320                 self.w_selectupdates_menuitem.set_sensitive(False)
3321                 return
3322 
3323         def __get_inventory_list(self, pargs, all_known, all_versions):
3324                 self.__image_activity_lock.acquire()
3325                 try:
3326                         res = misc.get_inventory_list(self.api_o.img, 
3327                             pargs, all_known, all_versions)
3328                 finally:
3329                         self.__image_activity_lock.release()
3330                 return res
3331 
3332         def __enable_disable_update_all(self):
3333                 #XXX Api to provide fast information if there are some updates
3334                 #available within image
3335                 gobject.idle_add(self.w_updateall_button.set_sensitive, False)
3336                 gobject.idle_add(self.w_updateall_menuitem.set_sensitive, False)
3337                 update_available = self.__check_if_updates_available()
3338                 gobject.idle_add(self.__g_enable_disable_update_all, update_available)
3339                 gobject.idle_add(self.__show_info_after_catalog_load)
3340                 return False
3341 
3342         def __show_info_after_catalog_load(self):
3343                 self.__show_info(self.selected_model, self.selected_path)
3344                 self.selected_model = None
3345                 self.selected_path = None
3346                 if (self.w_info_notebook.get_current_page() == 
3347                     INFO_NOTEBOOK_LICENSE_PAGE and
3348                     not self.showing_empty_details):
3349                         self.__show_licenses()
3350 
3351         def __check_if_updates_available(self):
3352                 try:
3353                         self.catalog_loaded = False
3354                         self.api_o.refresh()
3355                         self.catalog_loaded = True
3356                         res = self.__get_inventory_list([], False, False)
3357                         for pfmri, state in res:
3358                                 if state["upgradable"]:
3359                                         self.pylintstub = pfmri
3360                                         return True
3361 
3362                 except api_errors.InventoryException:
3363                         gobject.idle_add(self.__set_empty_details_panel)
3364                         return False
3365                 return False
3366 
3367         def __g_enable_disable_update_all(self, update_available):
3368                 self.w_updateall_button.set_sensitive(update_available)
3369                 self.w_updateall_menuitem.set_sensitive(update_available)
3370                 self.__enable_disable_install_remove()
3371 
3372         def __enable_disable_deselect(self):
3373                 if self.w_application_treeview.get_model():
3374                         for row in self.w_application_treeview.get_model():
3375                                 if row[enumerations.MARK_COLUMN]:
3376                                         self.w_deselect_menuitem.set_sensitive(True)
3377                                         return
3378                 self.w_deselect_menuitem.set_sensitive(False)
3379                 return
3380 
3381         def __catalog_refresh(self, reload_gui=True):
3382                 """Update image's catalogs."""
3383                 try:
3384                         # Since the user requested the refresh, perform it
3385                         # immediately for all publishers.
3386                         self.api_o.refresh(immediate=True)
3387                         # Refresh will load the catalogs.
3388                         self.catalog_loaded = True
3389                 except api_errors.PublisherError:
3390                         # In current implementation, this will never happen
3391                         # We are not refreshing specific publisher
3392                         self.__catalog_refresh_done()
3393                         raise
3394                 except api_errors.PermissionsException:
3395                         #Error will already have been reported in
3396                         #Manage Repository dialog
3397                         self.__catalog_refresh_done()
3398                         return -1
3399                 except api_errors.CatalogRefreshException, cre:
3400                         total = cre.total
3401                         succeeded = cre.succeeded
3402                         ermsg = _("Network problem.\n\n")
3403                         ermsg += _("Details:\n")
3404                         ermsg += "%s/%s" % (succeeded, total)
3405                         ermsg += _(" catalogs successfully updated:\n")
3406                         for pub, err in cre.failed:
3407                                 if isinstance(err, HTTPError):
3408                                         ermsg += "   %s: %s - %s\n" % \
3409                                             (err.filename, err.code, err.msg)
3410                                 elif isinstance(err, URLError):
3411                                         if err.args[0][0] == 8:
3412                                                 ermsg += "    %s: %s\n" % \
3413                                                     (urlparse.urlsplit(
3414                                                         pub["origin"])[1].split(":")[0],
3415                                                     err.args[0][1])
3416                                         else:
3417                                                 if isinstance(err.args[0], \
3418                                                     socket.timeout):
3419                                                         ermsg += "    %s: %s\n" % \
3420                                                             (pub["origin"], "timeout")
3421                                                 else:
3422                                                         ermsg += "    %s: %s\n" % \
3423                                                             (pub["origin"], \
3424                                                             err.args[0][1])
3425                                 elif "data" in err.__dict__ and err.data:
3426                                         ermsg += err.data
3427                                 else:
3428                                         ermsg += _("Unknown error")
3429                                         ermsg += "\n"
3430 
3431                         gobject.idle_add(self.error_occurred, ermsg,
3432                             None, gtk.MESSAGE_INFO)
3433                         self.__catalog_refresh_done()
3434                         return -1
3435                 except api_errors.InvalidDepotResponseException, idrex:
3436                         err = str(idrex)
3437                         gobject.idle_add(self.error_occurred, err,
3438                             None, gtk.MESSAGE_INFO)
3439                         self.__catalog_refresh_done()
3440                         return -1
3441                 except api_errors.PublisherError:
3442                         self.__catalog_refresh_done()
3443                         raise
3444                 except Exception:
3445                         self.__catalog_refresh_done()
3446                         raise
3447                 if reload_gui:
3448                         self.__catalog_refresh_done()
3449                 return 0
3450 
3451         def __add_pkgs_to_lists_from_cache(self, publisher, application_list,
3452             category_list, section_list):
3453                 if self.cache_o:
3454                         self.cache_o.load_application_list(publisher, application_list,
3455                             self.selected_pkgs)
3456                         self.cache_o.load_category_list(publisher, category_list)
3457                         self.cache_o.load_section_list(publisher, section_list)
3458 
3459         def __add_pkgs_to_lists_from_api(self, publisher, application_list,
3460             category_list, section_list):
3461                 """ This method set up image from the given directory and
3462                 returns the image object or None"""
3463                 pargs = []
3464                 pargs.append("pkg://" + publisher + "/*")
3465                 try:
3466                         pkgs_known = self.__get_inventory_list(pargs,
3467                             True, True)
3468                 except api_errors.InventoryException:
3469                         # This can happen if the repository does not
3470                         # contain any packages
3471                         err = _("Selected repository does not contain any packages.")
3472                         gobject.idle_add(self.w_progress_dialog.hide)
3473                         gobject.idle_add(self.error_occurred, err, None,
3474                             gtk.MESSAGE_INFO)
3475                         self.unset_busy_cursor()
3476                         pkgs_known = []
3477 
3478                 return self.__add_pkgs_to_lists(pkgs_known, application_list,
3479                     category_list, section_list)
3480 
3481         def __add_pkgs_to_lists(self, pkgs_known, application_list,
3482             category_list, section_list):
3483                 if section_list != None:
3484                         self.__init_sections(section_list)
3485                 #Only one instance of those icons should be in memory
3486                 update_available_icon = gui_misc.get_icon(self.icon_theme,
3487                     "status_newupdate")
3488                 installed_icon = gui_misc.get_icon(self.icon_theme,
3489                     "status_installed")
3490                 update_for_category_icon = \
3491                     self.get_icon_pixbuf_from_glade_dir("legend_newupdate")
3492                 #Imageinfo for categories
3493                 imginfo = imageinfo.ImageInfo()
3494                 sectioninfo = imageinfo.ImageInfo()
3495                 pubs = [p.prefix for p in self.api_o.get_publishers()]
3496                 categories = {}
3497                 sections = {}
3498                 share_path = "/usr/share/package-manager/data/"
3499                 for pub in pubs:
3500                         category = imginfo.read(self.application_dir +
3501                             share_path + pub)
3502                         if len(category) == 0:
3503                                 category = imginfo.read(self.application_dir +
3504                                     share_path + "opensolaris.org")
3505                         categories[pub] = category
3506                         section = sectioninfo.read(self.application_dir +
3507                             share_path + pub + ".sections")
3508                         if len(section) == 0:
3509                                 section = sectioninfo.read(self.application_dir +
3510                                     share_path + "opensolaris.org.sections")
3511                         sections[pub] = section
3512                 pkg_count = 0
3513                 pkg_add = 0
3514                 progress_percent = INITIAL_PROGRESS_TOTAL_PERCENTAGE
3515                 total_pkg_count = len(pkgs_known)
3516                 progress_increment = \
3517                         total_pkg_count / PACKAGE_PROGRESS_TOTAL_INCREMENTS
3518                 self.progress_stop_timer_thread = True
3519                 while gtk.events_pending():
3520                         gtk.main_iteration(False)
3521                 prev_stem = ""
3522                 prev_pfmri_str = ""
3523                 next_app = None
3524                 pkg_name = None
3525                 pkg_publisher = None
3526                 prev_state = None
3527                 category_icon = None
3528                 for pkg, state in pkgs_known:
3529                         if prev_pfmri_str and \
3530                             prev_pfmri_str == pkg.get_short_fmri() and \
3531                             prev_state == state:
3532                                 pkg_count += 1
3533                                 continue
3534                         if prev_stem and \
3535                             prev_stem == pkg.get_pkg_stem() and \
3536                             prev_state["state"] == "known" and \
3537                             state["state"] == "installed":
3538                                 pass
3539                         elif next_app != None:
3540                                 self.__add_package_to_list(next_app,
3541                                     application_list,
3542                                     pkg_add, pkg_name,
3543                                     category_icon,
3544                                     categories, category_list, pkg_publisher)
3545                                 pkg_add += 1
3546                         prev_stem = pkg.get_pkg_stem()
3547                         prev_pfmri_str = pkg.get_short_fmri()
3548                         prev_state = state
3549 
3550                         if progress_increment > 0 and pkg_count % progress_increment == 0:
3551                                 progress_percent += PACKAGE_PROGRESS_PERCENT_INCREMENT
3552                                 if progress_percent <= PACKAGE_PROGRESS_PERCENT_TOTAL:
3553                                         self.__progressdialog_progress_percent(
3554                                             progress_percent, pkg_count, total_pkg_count)
3555                                 while gtk.events_pending():
3556                                         gtk.main_iteration(False)
3557 
3558                         status_icon = None
3559                         category_icon = None
3560                         pkg_name = pkg.get_name()
3561                         pkg_name = gui_misc.get_pkg_name(pkg_name)
3562                         pkg_stem = pkg.get_pkg_stem()
3563                         pkg_publisher = pkg.get_publisher()
3564                         pkg_state = enumerations.NOT_INSTALLED
3565                         if state["state"] == "installed":
3566                                 pkg_state = enumerations.INSTALLED
3567                                 if state["upgradable"] == True:
3568                                         status_icon = update_available_icon
3569                                         category_icon = update_for_category_icon
3570                                         pkg_state = enumerations.UPDATABLE
3571                                 else:
3572                                         status_icon = installed_icon
3573                         marked = False
3574                         if not self.is_search_all:
3575                                 pkgs = self.selected_pkgs.get(pkg_publisher)
3576                                 if pkgs != None:
3577                                         if pkg_stem in pkgs:
3578                                                 marked = True
3579                         next_app = \
3580                             [
3581                                 marked, status_icon, pkg_name, '...', pkg_state,
3582                                 pkg, pkg_stem, None, True, None, pkg_publisher
3583                             ]
3584                         pkg_count += 1
3585 
3586                 if next_app:
3587                         self.__add_package_to_list(next_app, application_list, 
3588                             pkg_add, pkg_name, category_icon, categories, 
3589                             category_list, pkg_publisher)
3590                         pkg_add += 1
3591                 if category_list != None:
3592                         self.__add_categories_to_sections(sections,
3593                             category_list, section_list)
3594                 self.__progressdialog_progress_percent(PACKAGE_PROGRESS_PERCENT_TOTAL,
3595                     total_pkg_count, total_pkg_count)
3596                 return
3597 
3598         def __add_categories_to_sections(self, sections, category_list, section_list):
3599                 for publisher in sections:
3600                         for section in sections[publisher]:
3601                                 for category in sections[publisher][section].split(","):
3602                                         self.__add_category_to_section(_(category),
3603                                             _(section), category_list, section_list)
3604 
3605                 #1915 Sort the Categories into alphabetical order and prepend All Category
3606                 if len(category_list) > 0:
3607                         rows = [tuple(r) + (i,) for i, r in enumerate(category_list)]
3608                         rows.sort(self.__sort)
3609                         r = []
3610                         category_list.reorder([r[-1] for r in rows])
3611                 return
3612 
3613         def __add_package_to_list(self, app, application_list, pkg_add,
3614             pkg_name, category_icon, categories, category_list, publisher):
3615                 row_iter = application_list.insert(pkg_add, app)
3616                 if category_list == None:
3617                         return
3618                 cat_pub = categories.get(publisher)
3619                 if pkg_name in cat_pub:
3620                         pkg_categories = cat_pub.get(pkg_name)
3621                         for pcat in pkg_categories.split(","):
3622                                 self.__add_package_to_category(_(pcat), None,
3623                                     category_icon, row_iter, application_list,
3624                                     category_list)
3625 
3626         @staticmethod
3627         def __add_package_to_category(category_name, category_description,
3628             category_icon, package, application_list, category_list):
3629                 if not package or category_name == _('All'):
3630                         return
3631                 if not category_name:
3632                         return
3633                 category_id = None
3634                 icon_visible = False
3635                 if category_icon:
3636                         icon_visible = True
3637                 for category in category_list:
3638                         if category[enumerations.CATEGORY_NAME] == category_name:
3639                                 category_id = category[enumerations.CATEGORY_ID]
3640                                 if category_icon:
3641                                         category[enumerations.CATEGORY_ICON] = \
3642                                             category_icon
3643                                         category[enumerations.CATEGORY_ICON_VISIBLE] = \
3644                                             icon_visible
3645                                 break
3646                 if not category_id:                       # Category not exists
3647                         category_id = len(category_list) + 1
3648                         category_list.append([category_id, category_name,
3649                             category_description, category_icon, icon_visible,
3650                             True, None])
3651                 if application_list.get_value(package,
3652                     enumerations.CATEGORY_LIST_COLUMN):
3653                         a = application_list.get_value(package,
3654                             enumerations.CATEGORY_LIST_COLUMN)
3655                         a.append(category_id)
3656                 else:
3657                         category_list = []
3658                         category_list.append(category_id)
3659                         application_list.set(package,
3660                             enumerations.CATEGORY_LIST_COLUMN, category_list)
3661 
3662         @staticmethod
3663         def __add_category_to_section(category_name, section_name, category_list,
3664             section_list):
3665                 '''Adds the section to section list in category. If there is no such
3666                 section, than it is not added. If there was already section than it
3667                 is skipped. Sections must be case sensitive'''
3668                 if not category_name:
3669                         return
3670                 for section in section_list:
3671                         if section[enumerations.SECTION_NAME] == section_name:
3672                                 section_id = section[enumerations.SECTION_ID]
3673                                 for category in category_list:
3674                                         if category[enumerations.CATEGORY_NAME] == \
3675                                             category_name:
3676                                                 section_lst = category[ \
3677                                                     enumerations.SECTION_LIST_OBJECT]
3678                                                 section[enumerations.SECTION_ENABLED] = \
3679                                                     True
3680                                                 if not section_lst:
3681                                                         category[ \
3682                                                     enumerations.SECTION_LIST_OBJECT] = \
3683                                                             [section_id, ]
3684                                                 else:
3685                                                         if not section_name in \
3686                                                             section_lst:
3687                                                                 section_lst.append(
3688                                                                     section_id)
3689 
3690         def __progressdialog_progress_pulse(self):
3691                 while not self.progress_stop_timer_thread:
3692                         gobject.idle_add(self.w_progressbar.pulse)
3693                         time.sleep(0.1)
3694                 gobject.idle_add(self.w_progress_dialog.hide)
3695                 self.progress_stop_timer_thread = False
3696 
3697         # For initial setup before loading package entries allow 5% of progress bar
3698         # update it on a time base as we have no other way to judge progress at this point
3699         def __progressdialog_progress_time(self):
3700                 while not self.progress_stop_timer_thread and \
3701                         self.progress_fraction_time_count <= \
3702                             INITIAL_PROGRESS_TOTAL_PERCENTAGE:
3703 
3704                         gobject.idle_add(self.w_progressbar.set_fraction,
3705                             self.progress_fraction_time_count)
3706                         self.progress_fraction_time_count += \
3707                                 INITIAL_PROGRESS_TIME_PERCENTAGE
3708                         time.sleep(INITIAL_PROGRESS_TIME_INTERVAL)
3709                 self.progress_stop_timer_thread = False
3710                 self.progress_fraction_time_count = 0
3711 
3712         def __progressdialog_progress_percent(self, fraction, count, total):
3713                 gobject.idle_add(self.w_progressinfo_label.set_text, _(
3714                     "Processing package entries: %d of %d") % (count, total)  )
3715                 gobject.idle_add(self.w_progressbar.set_fraction, fraction)
3716 
3717         def error_occurred(self, error_msg, msg_title=None, msg_type=gtk.MESSAGE_ERROR):
3718                 if msg_title:
3719                         title = msg_title
3720                 else:
3721                         title = _("Package Manager")
3722                 gui_misc.error_occurred(self.w_main_window, error_msg,
3723                     title, msg_type, use_markup=True)
3724 
3725 
3726                 msgbox = gtk.MessageDialog(parent =
3727                     self.w_main_window,
3728                     buttons = gtk.BUTTONS_CLOSE,
3729                     flags = gtk.DIALOG_MODAL,
3730                     type = msg_type,
3731                     message_format = None)
3732                 msgbox.set_property('text', error_msg)
3733                 title = None
3734                 if msg_title:
3735                         title = msg_title
3736                 else:
3737                         title = _("Package Manager")
3738                 msgbox.set_title(title)
3739                 msgbox.run()
3740                 msgbox.destroy()
3741 
3742 #-----------------------------------------------------------------------------#
3743 # Static Methods
3744 #-----------------------------------------------------------------------------#
3745 
3746         #@staticmethod
3747         #def N_(message):
3748         #        return message
3749 
3750         @staticmethod
3751         def __sort(a, b):
3752                 return cmp(a[1], b[1])
3753 
3754         @staticmethod
3755         def cell_data_function(column, renderer, model, itr, data):
3756                 '''Function which sets the background colour to black if package is
3757                 selected'''
3758                 if itr:
3759                         if model.get_value(itr, enumerations.MARK_COLUMN):
3760                                 renderer.set_property("cell-background", "#ffe5cc")
3761                                 renderer.set_property("cell-background-set", True)
3762                         else:
3763                                 renderer.set_property("cell-background-set", False)
3764 
3765         @staticmethod
3766         def combobox_separator(model, itr):
3767                 return model.get_value(itr, enumerations.FILTER_NAME) == ""
3768 
3769         @staticmethod
3770         def combobox_id_separator(model, itr):
3771                 return model.get_value(itr, 0) == -1 and \
3772                     model.get_value(itr, 1) == ""
3773 
3774         @staticmethod
3775         def category_filter(model, itr):
3776                 '''This function filters category in the main application view'''
3777                 return model.get_value(itr, enumerations.CATEGORY_VISIBLE)
3778 
3779         @staticmethod
3780         def get_datetime(version):
3781                 dt = None
3782                 try:
3783                         dt = version.get_datetime()
3784                 except AttributeError:
3785                         dt = version.get_timestamp()
3786                 return dt
3787 
3788         @staticmethod
3789         def get_installed_version(api_o, pkg):
3790                 info = api_o.info([pkg], False, frozenset(
3791                     [api.PackageInfo.STATE, api.PackageInfo.IDENTITY]))
3792                 found = info[api.ImageInterface.INFO_FOUND]
3793                 try:
3794                         version = found[0]
3795                 except IndexError:
3796                         version = None
3797                 return version
3798 
3799 #-----------------------------------------------------------------------------#
3800 # Public Methods
3801 #-----------------------------------------------------------------------------#
3802         def setup_progressdialog_show(self):
3803                 self.w_progress_dialog.set_title(_("Loading Repository Information"))
3804                 self.w_progressinfo_label.set_text(
3805                     _( "Fetching package entries ..."))
3806                 self.w_progress_cancel.hide()
3807                 self.w_progress_dialog.show()
3808                 Thread(target = self.__progressdialog_progress_time).start()
3809 
3810         def setup_progressdialog_hide(self):
3811                 self.progress_stop_timer_thread = True
3812                 self.w_progress_dialog.hide()
3813 
3814         def init_show_filter(self):
3815                 self.__init_show_filter()                #Initiates filter
3816 
3817         def reload_packages(self):
3818                 self.api_o = gui_misc.get_api_object(self.image_directory, 
3819                     self.pr, self.w_main_window)
3820                 self.cache_o = self.__get_cache_obj(self.icon_theme, 
3821                     self.application_dir, self.api_o)
3822                 self.__on_reload(None)
3823 
3824         def set_busy_cursor(self):
3825                 self.gdk_window.show()
3826 
3827         def unset_busy_cursor(self):
3828                 self.gdk_window.hide()
3829 
3830         def process_package_list_start(self, image_directory):
3831                 self.image_directory = image_directory
3832                 if not self.api_o:
3833                         self.api_o = gui_misc.get_api_object(image_directory, 
3834                             self.pr, self.w_main_window)
3835                         self.cache_o = self.__get_cache_obj(self.icon_theme,
3836                             self.application_dir, self.api_o)
3837                         self.img_timestamp = self.cache_o.get_index_timestamp()
3838                 self.repositories_list = self.__get_new_repositories_liststore()
3839                 self.__setup_repositories_combobox(self.api_o, self.repositories_list)
3840 
3841         @staticmethod
3842         def __get_cache_obj(icon_theme, application_dir, api_o):
3843                 cache_o = cache.CacheListStores(icon_theme, application_dir,
3844                     api_o)
3845                 return cache_o
3846 
3847         def process_package_list_end(self):
3848                 self.__set_first_category_text()
3849                 self.in_startpage_startup = False
3850                 if self.update_all_proceed:
3851                 # TODO: Handle situation where only SUNWipkg/SUNWipg-gui have been updated
3852                 # in update all: bug 6357
3853                         self.__on_update_all(None)
3854                         self.update_all_proceed = False
3855                 self.setup_progressdialog_hide()
3856                 self.__enable_disable_install_remove()
3857                 self.update_statusbar()
3858                 self.in_setup = False
3859                 self.cancelled = False
3860                 if self.set_section != 0 or \
3861                     self.set_show_filter != enumerations.FILTER_ALL:
3862                         self.__application_refilter()
3863                 else:
3864                         self.unset_busy_cursor()
3865                 
3866                 if self.first_run or self.in_reload:
3867                         Thread(target = self.__enable_disable_update_all).start()
3868                 self.first_run = False
3869                 self.in_reload = False
3870 
3871         def get_icon_pixbuf_from_glade_dir(self, icon_name):
3872                 return gui_misc.get_pixbuf_from_path(self.application_dir +
3873                     "/usr/share/package-manager/", icon_name)
3874 
3875         def update_statusbar(self):
3876                 '''Function which updates statusbar'''
3877                 if self.statusbar_message_id > 0:
3878                         self.w_main_statusbar.remove(0, self.statusbar_message_id)
3879                         self.statusbar_message_id = 0
3880                 search_text = self.w_searchentry.get_text()
3881 
3882                 if not self.in_search_mode:
3883                         installed = 0
3884                         self.selected = 0
3885                         sel = 0
3886                         if self.application_list == None:
3887                                 return
3888                         visible_repository = self.__get_visible_repository_name()
3889                         pkgs = self.selected_pkgs.get(visible_repository)
3890                         if pkgs:
3891                                 self.selected = len(pkgs)
3892                         for pkg_row in self.application_list:
3893                                 if pkg_row[enumerations.STATUS_COLUMN] == \
3894                                         enumerations.INSTALLED \
3895                                         or pkg_row[enumerations.STATUS_COLUMN] == \
3896                                     enumerations.UPDATABLE:
3897                                         installed = installed + 1
3898                                 if pkg_row[enumerations.MARK_COLUMN]:
3899                                         sel = sel + 1
3900                         listed_str = _('%d listed') % len(self.application_list)
3901                         sel_str = _('%d selected') % sel
3902                         inst_str = _('%d installed') % installed
3903                         status_str = _("%s: %s , %s, %s.") % (visible_repository,
3904                             listed_str, inst_str, sel_str)
3905                         self.w_main_statusbar.push(0, status_str)
3906                         return
3907 
3908                 # In Search Mode
3909                 active = ""
3910                 if self.is_search_all:
3911                         if self.__doing_search():
3912                                 if self.current_search_publisher != None:
3913                                         active = "(" + self.current_search_publisher + \
3914                                                 ") "
3915                                 opt_str = _('Searching... '
3916                                     '%(active)sfor "%(search_text)s"') % \
3917                                         {"active": active, "search_text": search_text}
3918                         else:
3919                                 opt_str = _('Searched All for "%s"') % (search_text)
3920                 else:
3921                         search_str = _("Searched")
3922                         if self.__doing_search():
3923                                 search_str = _("Searching...")
3924                         if self.last_active_publisher != None:
3925                                 active = "(" + self.last_active_publisher + ") "
3926                         opt_str = \
3927                                 _('%(search)s %(last_active)sfor "%(search_text)s"') \
3928                                 % {"search": search_str, "last_active" : active,
3929                                     "search_text" : search_text}
3930                 fmt_str = _("%(option_str)s:  %(number)d found %(time)s")
3931                 time_str = ""
3932                 if self.search_time_sec > 0:
3933                         time_str = _("in %d seconds") % self.search_time_sec
3934                 status_str = fmt_str % {"option_str" : opt_str, "number" :
3935                     len(self.application_list), "time" : time_str}
3936                 self.w_main_statusbar.push(0, status_str)
3937 
3938         def update_package_list(self, update_list):
3939                 if update_list == None and self.img_timestamp:
3940                         return
3941                 visible_repository = self.__get_visible_repository_name()
3942                 default_publisher = self.default_publisher
3943                 self.api_o.refresh()
3944                 if not self.img_timestamp:
3945                         self.img_timestamp = self.cache_o.get_index_timestamp()
3946                         self.__on_reload(None)
3947                         return
3948                 self.img_timestamp = self.cache_o.get_index_timestamp()
3949                 installed_icon = gui_misc.get_icon(self.icon_theme,
3950                     "status_installed")
3951                 visible_list = update_list.get(visible_repository)
3952                 if visible_list:
3953                         i = 0
3954                         while i < len(visible_list):
3955                                 visible_list[i] = gui_misc.get_pkg_name(
3956                                     visible_list[i])
3957                                 i +=  1
3958                         for row in self.application_list:
3959                                 if row[enumerations.NAME_COLUMN] in visible_list:
3960                                         pkg = row[enumerations.FMRI_COLUMN]
3961                                         pkg_stem = row[enumerations.STEM_COLUMN]
3962                                         self.__remove_pkg_stem_from_list(pkg_stem)
3963                                         if self.info_cache.has_key(pkg_stem):
3964                                                 del self.info_cache[pkg_stem]
3965                                         package_info = self.get_installed_version(
3966                                             self.api_o, pkg_stem)
3967                                         package_installed =  (package_info.state 
3968                                             == api.PackageInfo.INSTALLED)
3969                                         print pkg_stem, package_installed
3970                                         if package_installed:
3971                                                 row[enumerations.STATUS_COLUMN] = \
3972                                                     enumerations.INSTALLED
3973                                                 row[enumerations.STATUS_ICON_COLUMN] = \
3974                                                     installed_icon
3975                                         else:
3976                                                 row[enumerations.STATUS_COLUMN] = \
3977                                                     enumerations.NOT_INSTALLED
3978                                                 row[enumerations.STATUS_ICON_COLUMN] = \
3979                                                     None
3980                                         row[enumerations.MARK_COLUMN] = False
3981                         self.__dump_datamodels(visible_repository,
3982                                 self.application_list, self.category_list,
3983                                 self.section_list)
3984                 for publisher in update_list:
3985                         if publisher != visible_repository:
3986                                 pkg_list = update_list.get(publisher)
3987                                 for pkg in pkg_list:
3988                                         pkg_stem = None
3989                                         if publisher != default_publisher:
3990                                                 pkg_stem = "pkg://%s/%s" % \
3991                                                         (publisher, pkg)
3992                                         else:
3993                                                 pkg_stem = "pkg:/%s" % pkg
3994                                         if pkg_stem:
3995                                                 if self.info_cache.has_key(pkg_stem):
3996                                                         del self.info_cache[pkg_stem]
3997                                                 self.__remove_pkg_stem_from_list(pkg_stem)
3998                 self.__process_package_selection()
3999                 self.__enable_disable_selection_menus()
4000                 self.__enable_disable_install_remove()
4001                 self.update_statusbar()
4002                 Thread(target = self.__enable_disable_update_all).start()
4003 
4004         @staticmethod
4005         def __find_root_home_dir():
4006                 return_str = '/var/tmp'
4007                  
4008                 try:
4009                         lines = pwd.getpwnam('root')
4010                 except KeyError:
4011                         if debug:
4012                                 print "Error getting passwd database entry for root"
4013                         return return_str
4014                 try:
4015                         return_str = lines[5]
4016                 except IndexError:
4017                         if debug:
4018                                 print "Error getting home directory for root"
4019                 return return_str
4020 
4021         def restart_after_ips_update(self, be_name):
4022                 self.__main_application_quit(be_name)
4023 
4024         def shutdown_after_image_update(self):
4025                 info_str = _("The Update All action is now complete and "
4026                     "Package Manager will close.\n\nReview the posted release notes "
4027                     "before rebooting your system:\n\n"
4028                     )
4029                 self.w_ua_completed_release_label.set_text(info_str.strip('\n'))
4030 
4031                 info_str = misc.get_release_notes_url()
4032                 self.w_ua_completed_linkbutton.set_uri(info_str)
4033                 self.w_ua_completed_linkbutton.set_label(info_str)
4034                 self.release_notes_url = info_str
4035                 
4036                 self.w_ua_completed_dialog.set_title(_("Update All Complete"))
4037                 self.w_ua_completed_dialog.show()
4038 
4039 ###############################################################################
4040 #-----------------------------------------------------------------------------#
4041 # Main
4042 #-----------------------------------------------------------------------------#
4043 
4044 def main():
4045         gtk.main()
4046         return 0
4047 
4048 if __name__ == '__main__':
4049         debug = False
4050         debug_descriptions = False
4051         update_all_proceed = False
4052         ua_be_name = None
4053         app_path = None
4054         image_dir = None
4055         info_install_arg = None
4056         save_selected = _("Save selected...")
4057         save_selected_pkgs = _("Save selected packages...")
4058         reboot_needed = _("The installed package(s) require a reboot before "
4059             "installation can be completed.")
4060 
4061         try:
4062                 opts, args = getopt.getopt(sys.argv[1:], "hR:U:i:", \
4063                     ["help", "image-dir=", "update-all=", "info-install="])
4064         except getopt.error, msg:
4065                 print "%s, for help use --help" % msg
4066                 sys.exit(2)
4067 
4068         if os.path.isabs(sys.argv[0]):
4069                 app_path = sys.argv[0]
4070         else:
4071                 cmd = os.path.join(os.getcwd(), sys.argv[0])
4072                 app_path = os.path.realpath(cmd)
4073 
4074         for option, argument in opts:
4075                 if option in ("-h", "--help"):
4076                         print """\
4077 Use -R (--image-dir) to specify image directory.
4078 Use -U (--update-all) to proceed with Update All"""
4079                         sys.exit(0)
4080                 if option in ("-R", "--image-dir"):
4081                         image_dir = argument
4082                 if option in ("-U", "--update-all"):
4083                         update_all_proceed = True
4084                         ua_be_name = argument
4085                 if option in ("-i", "--info-install"):
4086                         info_install_arg = argument
4087 
4088         if image_dir == None:
4089                 try:
4090                         image_dir = os.environ["PKG_IMAGE"]
4091                 except KeyError:
4092                         image_dir = os.getcwd()
4093         try:
4094                 gtk.init_check()
4095         except RuntimeError, e:
4096                 print _("Unable to initialize gtk")
4097                 print str(e)
4098                 sys.exit(1)
4099 
4100         # Setup webinstall
4101         if info_install_arg or len(sys.argv) == 2:
4102                 webinstall = webinstall.Webinstall(image_dir)
4103                 if len(sys.argv) == 2:
4104                         info_install_arg = sys.argv[1]
4105                 webinstall.process_param(info_install_arg)
4106                 main()
4107                 sys.exit(0)
4108 
4109         # Setup packagemanager
4110         packagemanager = PackageManager()
4111         packagemanager.application_path = app_path
4112         packagemanager.image_dir_arg = image_dir
4113         packagemanager.update_all_proceed = update_all_proceed
4114         packagemanager.ua_be_name = ua_be_name
4115 
4116         while gtk.events_pending():
4117                 gtk.main_iteration(False)
4118 
4119         packagemanager.init_show_filter()
4120 
4121         packagemanager.process_package_list_start(image_dir)
4122 
4123         main()