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 2008 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.0    # 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 
  41 import getopt
  42 import os
  43 import sys
  44 import time
  45 import locale
  46 import socket
  47 import gettext
  48 from threading import Thread
  49 try:
  50         import gobject
  51         gobject.threads_init()
  52         import gtk
  53         import gtk.glade
  54         import pygtk
  55         pygtk.require("2.0")
  56 except ImportError:
  57         sys.exit(1)
  58 import pkg.client.image as image
  59 import pkg.client.progress as progress
  60 import pkg.misc as misc
  61 import pkg.portable as portable
  62 import pkg.gui.beadmin as beadm
  63 import pkg.gui.imageinfo as imageinfo
  64 import pkg.gui.installupdate as installupdate
  65 import pkg.gui.remove as remove
  66 import pkg.gui.enumerations as enumerations
  67 
  68 
  69 class PackageManager:
  70         def __init__(self):
  71                 self.image_o = None
  72                 socket.setdefaulttimeout(
  73                     int(os.environ.get("PKG_CLIENT_TIMEOUT", "30"))) # in seconds
  74 
  75                 # Override default MAX_TIMEOUT_COUNT if a value has been specified
  76                 # in the environment.
  77                 timeout_max = misc.MAX_TIMEOUT_COUNT
  78                 misc.MAX_TIMEOUT_COUNT = int(os.environ.get("PKG_TIMEOUT_MAX",
  79                     timeout_max))
  80                     
  81                 try:
  82                         self.application_dir = os.environ["PACKAGE_MANAGER_ROOT"]
  83                 except KeyError:
  84                         self.application_dir = "/"
  85                 locale.setlocale(locale.LC_ALL, '')
  86                 for module in (gettext, gtk.glade):
  87                         module.bindtextdomain("packagemanager", self.application_dir + \
  88                             "/usr/share/locale")
  89                         module.textdomain("packagemanager")
  90                 self._ = gettext.gettext
  91                 main_window_title = self._('Package Manager - revision 0.1')
  92                 self.user_rights = portable.is_admin()
  93                 self.cancelled = False                    # For background processes
  94                 self.image_directory = None
  95                 self.description_thread_running = False   # For background processes
  96                 self.pkginfo_thread = None                # For background processes
  97                 gtk.rc_parse('~/.gtkrc-1.2-gnome2')       # Load gtk theme
  98                 self.main_clipboard_text = None
  99                 self.ipkg_fmri = "SUNWipkg"
 100                 self.ipkggui_fmri = "SUNWipkg-gui"
 101                 self.progress_stop_timer_thread = False
 102                 self.progress_fraction_time_count = 0
 103                 self.progress_canceled = False
 104                 self.ips_uptodate = False
 105                 self.image_dir_arg = None
 106                 self.application_path = None
 107 
 108                 self.application_list = \
 109                     gtk.ListStore(
 110                         gobject.TYPE_BOOLEAN,     # enumerations.MARK_COLUMN
 111                         gtk.gdk.Pixbuf,           # enumerations.STATUS_ICON_COLUMN
 112                         gtk.gdk.Pixbuf,           # enumerations.ICON_COLUMN
 113                         gobject.TYPE_STRING,      # enumerations.NAME_COLUMN
 114                         gobject.TYPE_STRING,      # enumerations.INSTALLED_VERSION_COLUMN
 115                         gobject.TYPE_PYOBJECT,    # enumerations.INSTALLED_OBJECT_COLUMN
 116                         gobject.TYPE_STRING,      # enumerations.LATEST_AVAILABLE_COLUMN
 117                         gobject.TYPE_INT,         # enumerations.RATING_COLUMN
 118                         gobject.TYPE_STRING,      # enumerations.DESCRIPTION_COLUMN
 119                         gobject.TYPE_PYOBJECT,    # enumerations.PACKAGE_OBJECT_COLUMN
 120                         gobject.TYPE_PYOBJECT,    # enumerations.IMAGE_OBJECT_COLUMN
 121                         gobject.TYPE_BOOLEAN,     # enumerations.IS_VISIBLE_COLUMN
 122                         gobject.TYPE_PYOBJECT     # enumerations.CATEGORY_LIST_OBJECT
 123                         )
 124                 self.category_list = \
 125                     gtk.ListStore(
 126                         gobject.TYPE_INT,         # enumerations.CATEGORY_ID
 127                         gobject.TYPE_STRING,      # enumerations.CATEGORY_NAME
 128                         gobject.TYPE_STRING,      # enumerations.CATEGORY_DESCRIPTION
 129                         gtk.gdk.Pixbuf,           # enumerations.CATEGORY_ICON
 130                         gobject.TYPE_BOOLEAN,     # enumerations.CATEGORY_VISIBLE
 131                         gobject.TYPE_PYOBJECT,    # enumerations.SECTION_LIST_OBJECT
 132                         )
 133                 self.section_list = \
 134                     gtk.ListStore(
 135                         gobject.TYPE_INT,         # enumerations.SECTION_ID
 136                         gobject.TYPE_STRING,      # enumerations.SECTION_NAME
 137                         )
 138                 self.filter_list = \
 139                     gtk.ListStore(
 140                         gobject.TYPE_INT,         # enumerations.FILTER_ID
 141                         gobject.TYPE_STRING,      # enumerations.FILTER_NAME
 142                         )
 143                 self.repositories_list = \
 144                     gtk.ListStore(
 145                         gobject.TYPE_INT,         # enumerations.REPOSITORY_ID
 146                         gobject.TYPE_STRING,      # enumerations.REPOSITORY_NAME
 147                         )
 148 
 149                 self.application_list_filter = self.application_list.filter_new()
 150                 self.pr = progress.NullProgressTracker()
 151 
 152                 # Create Widgets and show gui
 153                 
 154                 self.gladefile = self.application_dir + \
 155                     "/usr/share/package-manager/packagemanager.glade"
 156                 w_tree_main = gtk.glade.XML(self.gladefile, "mainwindow")
 157                 w_tree_progress = gtk.glade.XML(self.gladefile, "progressdialog")
 158                 
 159                 self.w_main_window = w_tree_main.get_widget("mainwindow")
 160                 self.w_application_treeview = \
 161                     w_tree_main.get_widget("applicationtreeview")
 162                 self.w_categories_treeview = w_tree_main.get_widget("categoriestreeview")
 163                 self.w_generalinfo_textview = \
 164                     w_tree_main.get_widget("generalinfotextview")
 165                 self.w_installedfiles_textview = \
 166                     w_tree_main.get_widget("installedfilestextview")
 167                 self.w_dependencies_textview = \
 168                     w_tree_main.get_widget("dependenciestextview")
 169                 self.w_packagename_label = w_tree_main.get_widget("packagenamelabel")
 170                 self.w_shortdescription_label = \
 171                     w_tree_main.get_widget("shortdescriptionlabel")
 172                 self.w_searchentry_dialog = w_tree_main.get_widget("searchentry")
 173                 self.w_installupdate_button = \
 174                     w_tree_main.get_widget("install_update_button")
 175                 self.w_remove_button = w_tree_main.get_widget("remove_button")
 176                 self.w_updateall_button = w_tree_main.get_widget("update_all_button")
 177                 self.w_reload_button = w_tree_main.get_widget("reloadbutton")
 178                 self.w_repository_combobox = w_tree_main.get_widget("repositorycombobox")
 179                 self.w_sections_combobox = w_tree_main.get_widget("sectionscombobox")
 180                 self.w_filter_combobox = w_tree_main.get_widget("filtercombobox")
 181                 self.w_packageicon_image = w_tree_main.get_widget("packageimage")
 182                 self.w_main_statusbar = w_tree_main.get_widget("statusbar")
 183                 self.w_installupdate_menuitem = \
 184                     w_tree_main.get_widget("package_install_update")
 185                 self.w_remove_menuitem = w_tree_main.get_widget("package_remove")
 186                 self.w_updateall_menuitem = w_tree_main.get_widget("package_update_all")
 187                 self.w_cut_menuitem = w_tree_main.get_widget("edit_cut")
 188                 self.w_copy_menuitem = w_tree_main.get_widget("edit_copy")
 189                 self.w_paste_menuitem = w_tree_main.get_widget("edit_paste")
 190                 self.w_clear_menuitem = w_tree_main.get_widget("edit_clear")
 191                 self.w_selectall_menuitem = w_tree_main.get_widget("edit_select_all")
 192                 self.w_selectupdates_menuitem = \
 193                     w_tree_main.get_widget("edit_select_updates")
 194                 self.w_deselect_menuitem = w_tree_main.get_widget("edit_deselect")
 195                 self.w_main_clipboard = gtk.clipboard_get(gtk.gdk.SELECTION_CLIPBOARD)
 196 
 197                 self.w_progress_dialog = w_tree_progress.get_widget("progressdialog")
 198                 self.w_progress_dialog.set_title(self._("Update All"))
 199                 self.w_progressinfo_label = w_tree_progress.get_widget("progressinfo")
 200                 self.w_progressinfo_label.set_text(self._( \
 201                     "Checking SUNWipkg and SUNWipkg-gui versions\n\nPlease wait ..."))
 202                 self.w_progressbar = w_tree_progress.get_widget("progressbar")
 203                 self.w_progressbar.set_pulse_step(0.1)
 204                 self.w_progress_cancel = w_tree_progress.get_widget("progresscancel")
 205                 self.progress_canceled = False
 206 
 207                 self.__update_reload_button()
 208                 self.w_main_clipboard.request_text(self.__clipboard_text_received)
 209                 self.w_main_window.set_title(main_window_title)
 210 
 211                 try:
 212                         dic_mainwindow = \
 213                             {
 214                                 "on_mainwindow_delete_event": \
 215                                     self.__on_mainwindow_delete_event,
 216                                 "on_searchentry_changed":self.__on_searchentry_changed,
 217                                 "on_searchentry_focus_in_event": \
 218                                     self.__on_searchentry_focus_in,
 219                                 "on_searchentry_focus_out_event": \
 220                                     self.__on_searchentry_focus_out,
 221                                 "on_searchentry_event":self.__on_searchentry_event,
 222                                 "on_sectionscombobox_changed": \
 223                                     self.__on_sectionscombobox_changed,
 224                                 "on_filtercombobox_changed": \
 225                                     self.__on_filtercombobox_changed,
 226                                 "on_repositorycombobox_changed": \
 227                                     self.__on_repositorycombobox_changed,
 228                                 #menu signals
 229                                 "on_file_quit_activate":self.__on_file_quit_activate,
 230                                 "on_file_be_activate":self.__on_file_be_activate,
 231                                 "on_package_install_update_activate": \
 232                                     self.__on_install_update,
 233                                 "on_package_remove_activate":self.__on_remove,
 234                                 "on_help_about_activate":self.__on_help_about,
 235                                 "on_edit_paste_activate":self.__on_edit_paste,
 236                                 "on_edit_clear_activate":self.__on_clear_paste,
 237                                 "on_edit_copy_activate":self.__on_copy,
 238                                 "on_edit_cut_activate":self.__on_cut,
 239                                 "on_edit_select_all_activate":self.__on_select_all,
 240                                 "on_edit_select_updates_activate": \
 241                                     self.__on_select_updates,
 242                                 "on_edit_deselect_activate":self.__on_deselect,
 243                                 # XXX disabled until new API
 244                                 "on_package_update_all_activate":self.__on_update_all,
 245                                 #toolbar signals
 246                                 # XXX disabled until new API
 247                                 "on_update_all_button_clicked":self.__on_update_all,
 248                                 "on_reload_button_clicked":self.__on_reload,
 249                                 "on_install_update_button_clicked": \
 250                                     self.__on_install_update,
 251                                 "on_remove_button_clicked":self.__on_remove
 252                             }
 253                         dic_progress = \
 254                             {
 255                                 "on_cancel_progressdialog_clicked": \
 256                                     self.__on_cancel_progressdialog_clicked,
 257                             }
 258                         w_tree_main.signal_autoconnect(dic_mainwindow)
 259                         w_tree_progress.signal_autoconnect(dic_progress)
 260                 except AttributeError, error:
 261                         print self._( \
 262                             'GUI will not respond to any event! %s.' + \
 263                             'Check declare_signals()') \
 264                             % error
 265                             
 266                 self.package_selection = None
 267                 self.category_list_filter = None
 268                 self.in_setup = True
 269                 self.w_main_window.show_all()
 270 
 271         def __init_tree_views(self):
 272                 '''This function connects treeviews with their models and also applies
 273                 filters'''
 274                 ##APPLICATION MAIN TREEVIEW
 275                 application_list_sort = \
 276                     gtk.TreeModelSort(self.application_list_filter)
 277                 self.w_application_treeview.set_model(application_list_sort)
 278                 model = self.w_application_treeview.get_model()
 279                 toggle_renderer = gtk.CellRendererToggle()
 280                 toggle_renderer.connect('toggled', self.__active_pane_toggle, model)
 281                 column = gtk.TreeViewColumn("", toggle_renderer, \
 282                     active = enumerations.MARK_COLUMN)
 283                 column.set_sort_column_id(enumerations.MARK_COLUMN)
 284                 column.set_sort_indicator(True)
 285                 column.set_cell_data_func(toggle_renderer, self.cell_data_function, None)
 286                 self.w_application_treeview.append_column(column)
 287                 column = gtk.TreeViewColumn()
 288                 column.set_title("")
 289                 #Commented, since there was funny jumping of the icons
 290                 #column.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
 291                 render_pixbuf = gtk.CellRendererPixbuf()
 292                 column.pack_start(render_pixbuf, expand = False)
 293                 column.add_attribute(render_pixbuf, "pixbuf", \
 294                     enumerations.STATUS_ICON_COLUMN)
 295                 column.set_fixed_width(32)
 296                 column.set_cell_data_func(render_pixbuf, self.cell_data_function, None)
 297                 self.w_application_treeview.append_column(column)
 298                 column = gtk.TreeViewColumn()
 299                 column.set_title("")
 300                 #Commented, since there was funny jumping of the icons
 301                 #column.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
 302                 render_pixbuf = gtk.CellRendererPixbuf()
 303                 column.pack_start(render_pixbuf, expand = False)
 304                 column.add_attribute(render_pixbuf, "pixbuf", enumerations.ICON_COLUMN)
 305                 column.set_fixed_width(32)
 306                 column.set_cell_data_func(render_pixbuf, self.cell_data_function, None)
 307                 self.w_application_treeview.append_column(column)
 308                 name_renderer = gtk.CellRendererText()
 309                 column = gtk.TreeViewColumn(self._("Name"), name_renderer, \
 310                     text = enumerations.NAME_COLUMN)
 311                 column.set_sort_column_id(enumerations.NAME_COLUMN)
 312                 column.set_sort_indicator(True)
 313                 column.set_cell_data_func(name_renderer, self.cell_data_function, None)
 314                 self.w_application_treeview.append_column(column)
 315                 installed_version_renderer = gtk.CellRendererText()
 316                 column = gtk.TreeViewColumn(self._('Installed Version'), \
 317                     installed_version_renderer, \
 318                     text = enumerations.INSTALLED_VERSION_COLUMN)
 319                 column.set_sort_column_id(enumerations.INSTALLED_VERSION_COLUMN)
 320                 column.set_sort_indicator(True)
 321                 column.set_cell_data_func(installed_version_renderer, \
 322                     self.cell_data_function, None)
 323                 self.w_application_treeview.append_column(column)
 324                 latest_available_renderer = gtk.CellRendererText()
 325                 column = gtk.TreeViewColumn(self._('Latest Version'), \
 326                     latest_available_renderer, \
 327                     text = enumerations.LATEST_AVAILABLE_COLUMN)
 328                 column.set_sort_column_id(enumerations.LATEST_AVAILABLE_COLUMN)
 329                 column.set_sort_indicator(True)
 330                 column.set_cell_data_func(latest_available_renderer, \
 331                     self.cell_data_function, None)
 332                 self.w_application_treeview.append_column(column)
 333                 rating_renderer = gtk.CellRendererText()
 334                 column = gtk.TreeViewColumn(self._('Rating'), rating_renderer, \
 335                     text = enumerations.RATING_COLUMN)
 336                 column.set_cell_data_func(rating_renderer, self.cell_data_function, None)
 337                 description_renderer = gtk.CellRendererText()
 338                 column = gtk.TreeViewColumn(self._('Description'), \
 339                     description_renderer, text = enumerations.DESCRIPTION_COLUMN)
 340                 column.set_sort_column_id(enumerations.DESCRIPTION_COLUMN)
 341                 column.set_sort_indicator(True)
 342                 column.set_cell_data_func(description_renderer, \
 343                     self.cell_data_function, None)
 344                 self.w_application_treeview.append_column(column)
 345                 #Added selection listener
 346                 self.package_selection = self.w_application_treeview.get_selection()
 347                 self.package_selection.set_mode(gtk.SELECTION_SINGLE)
 348                 self.package_selection.connect("changed", \
 349                     self.__on_package_selection_changed, None)
 350                 ##CATEGORIES TREEVIEW
 351                 #enumerations.CATEGORY_NAME
 352                 self.category_list_filter = self.category_list.filter_new()
 353                 self.category_list_filter.set_visible_func(self.category_filter)
 354                 self.w_categories_treeview.set_model(self.category_list_filter)
 355                 enumerations.CATEGORY_NAME_renderer = gtk.CellRendererText()
 356                 column = gtk.TreeViewColumn(self._('Name'), \
 357                     enumerations.CATEGORY_NAME_renderer, \
 358                     text = enumerations.CATEGORY_NAME)
 359                 self.w_categories_treeview.append_column(column)
 360                 #Added selection listener
 361                 category_selection = self.w_categories_treeview.get_selection()
 362                 category_selection.set_mode(gtk.SELECTION_SINGLE)
 363                 category_selection.connect("changed", \
 364                     self.__on_category_selection_changed, None)
 365                 ##SECTION COMBOBOX
 366                 #enumerations.SECTION_NAME
 367                 self.w_sections_combobox.set_model(self.section_list)
 368                 cell = gtk.CellRendererText()
 369                 self.w_sections_combobox.pack_start(cell, True)
 370                 self.w_sections_combobox.add_attribute(cell, 'text', \
 371                     enumerations.SECTION_NAME)
 372                 self.w_sections_combobox.set_row_separator_func( \
 373                     self.combobox_id_separator)
 374                 ##FILTER COMBOBOX
 375                 #enumerations.FILTER_NAME
 376                 self.w_filter_combobox.set_model(self.filter_list)
 377                 cell = gtk.CellRendererText()
 378                 self.w_filter_combobox.pack_start(cell, True)
 379                 self.w_filter_combobox.add_attribute(cell, 'text', \
 380                     enumerations.FILTER_NAME)
 381                 self.w_filter_combobox.set_row_separator_func(self.combobox_id_separator)
 382                 ##FILTER COMBOBOX
 383                 #enumerations.FILTER_NAME
 384                 self.w_repository_combobox.set_model(self.repositories_list)
 385                 cell = gtk.CellRendererText()
 386                 self.w_repository_combobox.pack_start(cell, True)
 387                 self.w_repository_combobox.add_attribute(cell, 'text', \
 388                     enumerations.REPOSITORY_NAME)
 389                 self.w_repository_combobox.set_row_separator_func( \
 390                     self.combobox_id_separator)
 391                 self.w_filter_combobox.set_active(0)
 392 
 393         def __init_sections(self):
 394                 '''This function is for initializing sections combo box, also adds "All"
 395                 Category. It sets active section combobox entry "All"'''
 396                 self.section_list.append([0, self._('All'), ])
 397                 self.section_list.append([-1, "", ])
 398                 self.section_list.append([2, self._('Meta Packages'), ])
 399                 self.section_list.append([3, self._('Applications Desktop'), ])
 400                 self.section_list.append([4, self._('Applications Web-Based'), ])
 401                 self.section_list.append([5, self._('Operating System'), ])
 402                 self.section_list.append([6, self._('User Environment'), ])
 403                 self.section_list.append([7, self._('Web Infrastructure'), ])
 404 
 405         def __init_show_filter(self):
 406                 self.filter_list.append([0, self._('All Packages'), ])
 407                 self.filter_list.append([-1, "", ])
 408                 self.filter_list.append([2, self._('Installed Packages'), ])
 409                 self.filter_list.append([3, self._('Updates'), ])
 410                 self.filter_list.append([4, self._('Non-installed Packages'), ])
 411                 self.filter_list.append([-1, "", ])
 412                 # self.filter_list.append([self._('Locked Packages'), ])
 413                 # self.filter_list.append(["", ])
 414                 self.filter_list.append([6, self._('Selected Packages'), ])
 415 
 416         def __on_cancel_progressdialog_clicked(self, widget):
 417                 self.progress_canceled = True
 418                 self.progress_stop_timer_thread = True
 419 
 420         def __on_mainwindow_delete_event(self, widget, event):
 421                 ''' handler for delete event of the main window '''
 422                 if self.__check_if_something_was_changed() == True:
 423                         # XXX Change this to not quit and show dialog
 424                         # XXX if some changes were applied:
 425                         self.__main_application_quit()
 426                         return True
 427                 else:
 428                         self.__main_application_quit()
 429 
 430         def __on_file_quit_activate(self, widget):
 431                 ''' handler for quit menu event '''
 432                 self.__on_mainwindow_delete_event(None, None)
 433 
 434         def __on_file_be_activate(self, widget):
 435                 ''' handler for be menu event '''
 436                 beadm.Beadmin(self)
 437 
 438         def __on_searchentry_changed(self, widget):
 439                 '''On text search field changed we should refilter the main view'''
 440                 Thread(target = self.__on_searchentry_threaded, args = ()).start()
 441 
 442         def __on_searchentry_threaded(self):
 443                 gobject.idle_add(self.application_list_filter.refilter)
 444                 gobject.idle_add(self.__enable_disable_selection_menus)
 445 
 446         def __on_edit_paste(self, widget):
 447                 self.w_searchentry_dialog.insert_text(self.main_clipboard_text, \
 448                     self.w_searchentry_dialog.get_position())
 449 
 450         def __on_clear_paste(self, widget):
 451                 bounds = self.w_searchentry_dialog.get_selection_bounds()
 452                 self.w_searchentry_dialog.delete_text(bounds[0], bounds[1])
 453                 return
 454 
 455         def __on_copy(self, widget):
 456                 bounds = self.w_searchentry_dialog.get_selection_bounds()
 457                 text = self.w_searchentry_dialog.get_chars(bounds[0], bounds[1])
 458                 self.w_main_clipboard.set_text(text)
 459                 return
 460 
 461         def __on_cut(self, widget):
 462                 bounds = self.w_searchentry_dialog.get_selection_bounds()
 463                 text = self.w_searchentry_dialog.get_chars(bounds[0], bounds[1])
 464                 self.w_searchentry_dialog.delete_text(bounds[0], bounds[1])
 465                 self.w_main_clipboard.set_text(text)
 466                 return
 467 
 468         def __on_select_all(self, widget):
 469                 sort_filt_model = \
 470                     self.w_application_treeview.get_model() #gtk.TreeModelSort
 471                 filt_model = sort_filt_model.get_model() #gtk.TreeModelFilter
 472                 model = filt_model.get_model() #gtk.ListStore
 473                 iter_next = sort_filt_model.get_iter_first()
 474                 list_of_paths = []
 475                 while iter_next != None:
 476                         sorted_path = sort_filt_model.get_path(iter_next)
 477                         filtered_path = \
 478                             sort_filt_model.convert_path_to_child_path(sorted_path)
 479                         path = filt_model.convert_path_to_child_path(filtered_path)
 480                         list_of_paths.append(path)
 481                         iter_next = sort_filt_model.iter_next(iter_next)
 482                 for path in list_of_paths:
 483                         itr = model.get_iter(path)
 484                         model.set_value(itr, enumerations.MARK_COLUMN, True)
 485                 self.__enable_disable_selection_menus()
 486                 self.update_statusbar()
 487                 self.__enable_disable_install_update()
 488                 self.__enable_disable_remove()
 489 
 490         def __on_select_updates(self, widget):
 491                 sort_filt_model = \
 492                     self.w_application_treeview.get_model() #gtk.TreeModelSort
 493                 filt_model = sort_filt_model.get_model() #gtk.TreeModelFilter
 494                 model = filt_model.get_model() #gtk.ListStore
 495                 iter_next = sort_filt_model.get_iter_first()
 496                 list_of_paths = []
 497                 while iter_next != None:
 498                         sorted_path = sort_filt_model.get_path(iter_next)
 499                         filtered_iter = sort_filt_model.convert_iter_to_child_iter(None, \
 500                             iter_next)
 501                         app_iter = filt_model.convert_iter_to_child_iter(filtered_iter)
 502 
 503                         filtered_path = \
 504                             sort_filt_model.convert_path_to_child_path(sorted_path)
 505                         path = filt_model.convert_path_to_child_path(filtered_path)
 506                         if model.get_value(app_iter, \
 507                             enumerations.INSTALLED_VERSION_COLUMN):
 508                                 if  model.get_value(app_iter, \
 509                                     enumerations.LATEST_AVAILABLE_COLUMN):
 510                                         list_of_paths.append(path)
 511                         iter_next = sort_filt_model.iter_next(iter_next)
 512                 for path in list_of_paths:
 513                         itr = model.get_iter(path)
 514                         model.set_value(itr, enumerations.MARK_COLUMN, True)
 515                 self.__enable_disable_selection_menus()
 516                 self.update_statusbar()
 517                 self.__enable_disable_install_update()
 518                 self.__enable_disable_remove()
 519 
 520         def __on_deselect(self, widget):
 521                 sort_filt_model = \
 522                     self.w_application_treeview.get_model() #gtk.TreeModelSort
 523                 filt_model = sort_filt_model.get_model() #gtk.TreeModelFilter
 524                 model = filt_model.get_model() #gtk.ListStore
 525                 iter_next = sort_filt_model.get_iter_first()
 526                 list_of_paths = []
 527                 while iter_next != None:
 528                         sorted_path = sort_filt_model.get_path(iter_next)
 529                         filtered_iter = sort_filt_model.convert_iter_to_child_iter(None, \
 530                             iter_next)
 531                         app_iter = filt_model.convert_iter_to_child_iter(filtered_iter)
 532                         filtered_path = \
 533                             sort_filt_model.convert_path_to_child_path(sorted_path)
 534                         path = filt_model.convert_path_to_child_path(filtered_path)
 535                         if model.get_value(app_iter, enumerations.MARK_COLUMN):
 536                                 list_of_paths.append(path)
 537                         iter_next = sort_filt_model.iter_next(iter_next)
 538                 for path in list_of_paths:
 539                         itr = model.get_iter(path)
 540                         model.set_value(itr, enumerations.MARK_COLUMN, False)
 541                 self.__enable_disable_selection_menus()
 542                 self.update_statusbar()
 543                 self.__enable_disable_install_update()
 544                 self.__enable_disable_remove()
 545 
 546         def __on_searchentry_focus_in(self, widget, event):
 547                 self.w_paste_menuitem.set_sensitive(True)
 548 
 549         def __on_searchentry_focus_out(self, widget, event):
 550                 self.w_paste_menuitem.set_sensitive(False)
 551 
 552         def __on_searchentry_event(self, widget, event):
 553                 self.w_main_clipboard.request_text(self.__clipboard_text_received)
 554                 if widget.get_selection_bounds():
 555                         #enable selection functions
 556                         self.w_cut_menuitem.set_sensitive(True)
 557                         self.w_copy_menuitem.set_sensitive(True)
 558                         self.w_clear_menuitem.set_sensitive(True)
 559                 else:
 560                         self.w_cut_menuitem.set_sensitive(False)
 561                         self.w_copy_menuitem.set_sensitive(False)
 562                         self.w_clear_menuitem.set_sensitive(False)
 563 
 564         def __on_category_selection_changed(self, selection, widget):
 565                 '''This function is for handling category selection changes'''
 566                 self.application_list_filter.refilter()
 567                 self.__enable_disable_selection_menus()
 568 
 569         def __on_package_selection_changed(self, selection, widget):
 570                 '''This function is for handling package selection changes'''
 571                 model, itr = selection.get_selected()
 572                 if itr:
 573                         pkg = model.get_value(itr, enumerations.INSTALLED_OBJECT_COLUMN)
 574                         if not pkg:
 575                                 packages = model.get_value(itr, \
 576                                     enumerations.PACKAGE_OBJECT_COLUMN)
 577                                 pkg = max(packages)
 578                         self.pkginfo_thread = pkg
 579                         Thread(target = self.__show_package_info, \
 580                             args = (model, itr)).start()
 581 
 582         def __on_filtercombobox_changed(self, widget):
 583                 '''On filter combobox changed'''
 584                 self.application_list_filter.refilter()
 585                 self.__enable_disable_selection_menus()
 586 
 587         def __on_sectionscombobox_changed(self, widget):
 588                 '''On section combobox changed'''
 589                 selected_section = widget.get_active()
 590                 if selected_section == 0:
 591                         for category in self.category_list:
 592                                 category[enumerations.CATEGORY_VISIBLE] = True
 593                 else:
 594                         for category in self.category_list:
 595                                 if category[enumerations.CATEGORY_ID] == 0:
 596                                         category[enumerations.CATEGORY_VISIBLE] = True
 597                                 else:
 598                                         category_list = \
 599                                             category[enumerations.SECTION_LIST_OBJECT]
 600                                         if not category_list:
 601                                                 category[enumerations.CATEGORY_VISIBLE] \
 602                                                     = False
 603                                         else:
 604                                                 for section in category_list:
 605                                                         if section == selected_section:
 606                                                                 category[enumerations. \
 607                                                                     CATEGORY_VISIBLE] = \
 608                                                                     True
 609                                                         else:
 610                                                                 category[enumerations. \
 611                                                                     CATEGORY_VISIBLE] = \
 612                                                                     False
 613                 self.category_list_filter.refilter()
 614                 self.application_list_filter.refilter()
 615                 self.__enable_disable_selection_menus()
 616 
 617         def __on_repositorycombobox_changed(self, widget):
 618                 '''On repository combobox changed'''
 619                 if self.in_setup:
 620                         return
 621                 self.application_list_filter.refilter()
 622                 self.__enable_disable_selection_menus()
 623 
 624         def __on_install_update(self, widget):
 625                 installupdate.InstallUpdate(self.application_list, self, False)
 626 
 627         def __on_update_all(self, widget):
 628                 opensolaris_image = True
 629                 fmris, notfound = self.__installed_fmris_from_args(self.image_o, \
 630                     ["SUNWipkg", "SUNWcs"])
 631 
 632                 if notfound:
 633                         opensolaris_image = False
 634 
 635                 if opensolaris_image:
 636                         # Load the catalogs from the repository, its a long 
 637                         # running tasks so need a progress dialog
 638                         self.w_progress_dialog.set_title(self._("Update All"))
 639                         self.w_progressinfo_label.set_text(self._( \
 640                             "Checking SUNWipkg and SUNWipkg-gui versions\n" + \
 641                             "\nPlease wait ..."))
 642 
 643                         self.w_progress_dialog.show()
 644                         Thread(target = self.__progressdialog_progress_pulse).start()
 645                         Thread(target = self.__do_ips_uptodate_check).start()
 646                         self.w_progress_dialog.run()
 647                         
 648                         if self.progress_canceled:
 649                                 return
 650                 else:
 651                         self.ips_uptodate = True
 652                         
 653                 #2790: Make sure ipkg and ipkg-gui are up to date, if not update them and
 654                 # prompt user to restart
 655                 if not self.ips_uptodate:
 656                         # Prompt user
 657                         msgbox = gtk.MessageDialog(parent = self.w_main_window, \
 658                             buttons = gtk.BUTTONS_YES_NO, \
 659                             flags = gtk.DIALOG_MODAL, type = gtk.MESSAGE_QUESTION, \
 660                             message_format = self._("Newer versions of SUNWipkg and" + \
 661                             "SUNWipkg-gui are available " + "and\nmust be updated" + \
 662                             "before running Update All.\n\n Do you want to update" + \
 663                             "them now?"))
 664                         msgbox.set_title(self._("Update All"))
 665                         result = msgbox.run()
 666                         msgbox.destroy()
 667                         if result == gtk.RESPONSE_YES:
 668                                 pkg_list = [self.ipkg_fmri, self.ipkggui_fmri]
 669                                 installupdate.InstallUpdate({self.image_o:pkg_list}, \
 670                                     self, False, True)
 671                         else:
 672                                 msgbox = gtk.MessageDialog(parent = self.w_main_window, \
 673                                     buttons = gtk.BUTTONS_OK, \
 674                                     flags = gtk.DIALOG_MODAL, type = gtk.MESSAGE_INFO, \
 675                                     message_format = self._("Update All was not " + \
 676                                     "run.\n\n It can not be run until SUNWipkg and " + \
 677                                     "SUNWipkg-gui have been updated."))
 678                                 msgbox.set_title(self._("Update All"))
 679                                 result = msgbox.run()
 680                                 msgbox.destroy()
 681                 else:                        
 682                         pkg_list = [ ipkg.get_pkg_stem() for ipkg in \
 683                             self.image_o.gen_installed_pkgs() ]
 684                         installupdate.InstallUpdate({self.image_o:pkg_list}, self, \
 685                             True, False)
 686 
 687         def __on_help_about(self, widget):
 688                 wTreePlan = gtk.glade.XML(self.gladefile, "aboutdialog") 
 689                 aboutdialog = wTreePlan.get_widget("aboutdialog")
 690                 aboutdialog.connect("response", lambda x = None, \
 691                     y = None: aboutdialog.destroy())
 692                 aboutdialog.run()
 693 
 694         def __on_remove(self, widget):
 695                 remove.Remove(self.application_list, self)
 696 
 697         def __on_reload(self, widget):
 698                 if self.description_thread_running:
 699                         self.cancelled = True
 700                 self.__catalog_refresh()
 701                 self.process_package_list_start(self.image_directory)
 702                 self.category_list_filter.refilter()
 703                 self.application_list_filter.refilter()
 704                 self.__enable_disable_selection_menus()
 705                 self.update_statusbar()
 706                 self.__update_install_update_button(None, True)
 707                 self.__update_remove_button(None, True)
 708 
 709         def __clipboard_text_received(self, clipboard, text, data):
 710                 self.main_clipboard_text = text
 711                 return
 712 
 713         def __main_application_quit(self, restart_app = False):
 714                 '''quits the main gtk loop'''
 715                 self.cancelled = True
 716                 if self.in_setup:
 717                         return
 718                         
 719                 if restart_app:
 720                         if "image_dir_arg" in self.__dict__:
 721                                 gobject.spawn_async([self.application_path, "-R", \
 722                                     self.image_dir_arg])
 723                         else:
 724                                 gobject.spawn_async([self.application_path])
 725                 gtk.main_quit()
 726                 sys.exit(0)
 727                 return True
 728 
 729         def __check_if_something_was_changed(self):
 730                 ''' Returns True if any of the check boxes for package was changed, false
 731                 if not'''
 732                 for pkg in self.application_list:
 733                         if pkg[enumerations.MARK_COLUMN] == True:
 734                                 return True
 735                 return False
 736 
 737         def __setup_repositories_combobox(self, img):
 738                 if self.in_setup or img == None:
 739                         return
 740                         
 741                 repositories = img.catalogs
 742                 default_authority = img.get_default_authority()
 743                 self.repositories_list.clear()
 744                 i = 0
 745                 active = 0
 746                 for repo in repositories:
 747                         if cmp(repo, default_authority) == 0:
 748                                 active = i
 749 
 750                         self.repositories_list.append([i, repo, ])
 751                         i = i + 1
 752                 if default_authority:
 753                         self.w_repository_combobox.set_active(active)
 754                 else:
 755                         self.w_repository_combobox.set_active(0)
 756 
 757         def __active_pane_toggle(self, cell, path, model_sort):
 758                 '''Toggle function for column enumerations.MARK_COLUMN'''
 759                 applicationModel = model_sort.get_model()
 760                 applicationPath = model_sort.convert_path_to_child_path(path)
 761                 filterModel = applicationModel.get_model()
 762                 child_path = applicationModel.convert_path_to_child_path(applicationPath)
 763                 itr = filterModel.get_iter(child_path)
 764                 if itr:
 765                         modified = filterModel.get_value(itr, enumerations.MARK_COLUMN)
 766                         filterModel.set_value(itr, enumerations.MARK_COLUMN, \
 767                             not modified)
 768                         latest_available = filterModel.get_value(itr, \
 769                             enumerations.LATEST_AVAILABLE_COLUMN)
 770                         installed_available = filterModel.get_value(itr, \
 771                             enumerations.INSTALLED_VERSION_COLUMN)
 772                         self.update_statusbar()
 773                         self.__update_install_update_button(latest_available, modified)
 774                         self.__update_remove_button(installed_available, modified)
 775                         self.__enable_disable_selection_menus()
 776 
 777 
 778         def __update_install_update_button(self, latest_available, toggle_true):
 779                 if not toggle_true and self.user_rights:
 780                         if latest_available:
 781                                 self.w_installupdate_button.set_sensitive(True)
 782                                 self.w_installupdate_menuitem.set_sensitive(True)
 783                 else:
 784                         available = None
 785                         for row in self.application_list:
 786                                 if row[enumerations.MARK_COLUMN]:
 787                                         available = \
 788                                             row[enumerations.LATEST_AVAILABLE_COLUMN]
 789                                         if available:
 790                                                 return
 791                         if not available:
 792                                 self.w_installupdate_button.set_sensitive(False)
 793                                 self.w_installupdate_menuitem.set_sensitive(False)
 794 
 795         def __update_reload_button(self):
 796                 if self.user_rights:
 797                         self.w_reload_button.set_sensitive(True)
 798                 else:
 799                         self.w_reload_button.set_sensitive(False)
 800 
 801         def __update_remove_button(self, installed_available, toggle_true):
 802                 if not toggle_true and self.user_rights:
 803                         if installed_available:
 804                                 self.w_remove_button.set_sensitive(True)
 805                                 self.w_remove_menuitem.set_sensitive(True)
 806                 else:
 807                         available = None
 808                         for row in self.application_list:
 809                                 if row[enumerations.MARK_COLUMN]:
 810                                         installed = \
 811                                             row[enumerations.INSTALLED_VERSION_COLUMN]
 812                                         if installed:
 813                                                 return
 814                         if not available:
 815                                 self.w_remove_button.set_sensitive(False)
 816                                 self.w_remove_menuitem.set_sensitive(False)
 817 
 818         def __update_package_info(self, pkg, icon, installed, manifest):
 819                 if icon and icon != pkg:
 820                         self.w_packageicon_image.set_from_pixbuf(icon)
 821                 else:
 822                         self.w_packageicon_image.set_from_pixbuf( \
 823                             self.__get_pixbuf_from_path("/usr/share/package-manager/", \
 824                             "PM_package_36x"))
 825                 self.w_packagename_label.set_markup("<b>" + pkg.get_name() + "</b>")
 826                 instbuffer = self.w_installedfiles_textview.get_buffer()
 827                 depbuffer = self.w_dependencies_textview.get_buffer()
 828                 infobuffer = self.w_generalinfo_textview.get_buffer()
 829                 if not manifest:
 830                         self.w_shortdescription_label.set_text( \
 831                             self._("Fetching description..."))
 832                         instbuffer.set_text(self._("Fetching information..."))
 833                         depbuffer.set_text(self._("Fetching information..."))
 834                         infobuffer.set_text(self._("Fetching information..."))
 835                         return
 836                 if manifest == "NotAvailable":
 837                         self.w_shortdescription_label.set_text( \
 838                             self._("Description not available for this package..."))
 839                         instbuffer.set_text( \
 840                             self._("Files Details not available for this package..."))
 841                         depbuffer.set_text(self._( \
 842                             "Dependencies info not available for this package..."))
 843                         infobuffer.set_text( \
 844                             self._("Information not available for this package..."))
 845                         return
 846                 self.w_shortdescription_label.set_text(manifest.get("description", ""))
 847                 instbuffer.set_text(self._("Root: %s\n") % manifest.img.get_root())
 848                 depbuffer.set_text(self._("Dependencies:\n"))
 849                 if installed:
 850                         infobuffer.set_text( \
 851                             self._("Information for installed package:\n\n"))
 852                 else:
 853                         infobuffer.set_text( \
 854                             self._("Information for latest available package:\n\n"))
 855                 depiter = depbuffer.get_end_iter()
 856                 institer = instbuffer.get_end_iter()
 857                 infoiter = infobuffer.get_end_iter()
 858                 #Name: SUNWckr 
 859                 #FMRI: pkg://opensolaris.org/SUNWckr@0.5.11,5.11-0.75:20071114T203148Z
 860                 #Version: 0.5.11
 861                 #Branch: 0.75
 862                 #Packaging Date: 2007-11-14 20:31:48
 863                 #Size: 29369698
 864                 #Summary: Core Solaris Kernel (Root)
 865                 for a in manifest.actions:
 866                         if cmp(a.name, self.n_("depend")) == 0:
 867                                 #Remove "depend: " -> [8:]
 868                                 depbuffer.insert(depiter, "\t" + \
 869                                     self.__locale_distinguished_name(a)[8:]+"\n")
 870                         elif cmp(a.name,self.n_("dir")) == 0:
 871                                 instbuffer.insert(institer, "\t" + \
 872                                     self.__locale_distinguished_name(a)+"\n")
 873                         elif cmp(a.name,self.n_("file")) == 0:
 874                                 instbuffer.insert(institer, "\t" + \
 875                                     self.__locale_distinguished_name(a)+"\n")
 876                         elif cmp(a.name,self.n_("hardlink")) == 0:
 877                                 instbuffer.insert(institer, "\t" + \
 878                                     self.__locale_distinguished_name(a)+"\n")
 879                         elif cmp(a.name,self.n_("link")) == 0:
 880                                 instbuffer.insert(institer, "\t" + \
 881                                     self.__locale_distinguished_name(a)+"\n")
 882                         elif cmp(a.name,self.n_("legacy")) == 0:
 883                                 if cmp(a.attrlist(self.n_("pkg"))[0], \
 884                                     pkg.get_name()) == 0:
 885                                         desc = a.attrlist(self.n_("desc"))
 886                                         infobuffer.insert(infoiter, \
 887                                             self._("  Description:\t%s\n") % desc[0])
 888                         else:
 889                                 pass
 890                 infobuffer.insert(infoiter, self._("  Name:\t\t%s\n") % pkg.get_name())
 891                 infobuffer.insert(infoiter, self._("  FMRI:\t\t%s\n") % pkg.get_fmri())
 892                 infobuffer.insert(infoiter, self._("  Version:\t\t%s\n") % \
 893                     pkg.version.get_short_version())
 894                 infobuffer.insert(infoiter, self._("  Packaged:\t%s\n") % \
 895                     self.get_datetime(pkg.version))
 896 
 897         def __update_description(self, description, package):
 898                 '''workaround function'''
 899                 for pkg in self.application_list:
 900                         p = pkg[enumerations.PACKAGE_OBJECT_COLUMN][0]
 901                         if p == package:
 902                                 pkg[enumerations.DESCRIPTION_COLUMN] = description
 903                                 return
 904 
 905         def __show_package_info(self, model, itr):
 906                 img = model.get_value(itr, enumerations.IMAGE_OBJECT_COLUMN)
 907                 pkg = model.get_value(itr, enumerations.INSTALLED_OBJECT_COLUMN)
 908                 icon = model.get_value(itr, enumerations.INSTALLED_OBJECT_COLUMN)
 909                 if not pkg:
 910                         packages = model.get_value(itr, \
 911                             enumerations.PACKAGE_OBJECT_COLUMN)
 912                         pkg = max(packages)
 913                         gobject.idle_add(self.__update_package_info, pkg, icon, False, \
 914                             None)
 915                 else:
 916                         gobject.idle_add(self.__update_package_info, pkg, icon,
 917                             True, None)
 918                 man = None
 919                 try:
 920                         man = img.get_manifest(pkg, filtered = True)
 921                 except IOError:
 922                         man = "NotAvailable"
 923                 if cmp(self.pkginfo_thread, pkg) == 0:
 924                         if not pkg:
 925                                 gobject.idle_add(self.__update_package_info, pkg, icon, \
 926                                     False, man)
 927                         else:
 928                                 gobject.idle_add(self.__update_package_info, pkg, icon, \
 929                                     True, man)
 930                 else:
 931                         return
 932 
 933         # This function is ported from pkg.actions.generic.distinguished_name()
 934         def __locale_distinguished_name(self, action):
 935                 if action.key_attr == None:
 936                         return str(action)
 937                 return "%s: %s" % \
 938                     (self._(action.name), action.attrs.get(action.key_attr, "???"))
 939 
 940         def __application_filter(self, model, itr):
 941                 '''This function is used to filter content in the main 
 942                 application view'''
 943                 if self.in_setup or self.cancelled:
 944                         return False
 945                 # XXX Show filter, chenge text to integers 
 946                 selected_category = 0
 947                 selection = self.w_categories_treeview.get_selection()
 948                 category_model, category_iter = selection.get_selected()
 949                 if not category_iter:         #no category was selected, so select "All"
 950                         selection.select_path(0)
 951                         category_model, category_iter = selection.get_selected()
 952                 if category_iter:
 953                         selected_category = category_model.get_value(category_iter, \
 954                             enumerations.CATEGORY_ID)
 955                 category_list_iter = model.get_value(itr, \
 956                     enumerations.CATEGORY_LIST_OBJECT)
 957                 category = False
 958                 repository = self.__is_pkg_repository_visible(model, itr)
 959                 if category_list_iter:
 960                         sel = False
 961                         for category_iter in category_list_iter:
 962                                 if category != True:
 963                                         category = \
 964                                             self.category_filter(self.category_list, \
 965                                             category_iter)
 966                                 if selected_category != 0:
 967                                         if selected_category == \
 968                                             self.category_list.get_value(category_iter, \
 969                                             enumerations.CATEGORY_ID):
 970                                                 sel = True
 971                                         category = sel
 972                 else:
 973                         if selected_category == 0:
 974                                 selected_section = self.w_sections_combobox.get_active()
 975                                 if selected_section == 0:
 976                                         category = True
 977                 if (model.get_value(itr, enumerations.IS_VISIBLE_COLUMN) == False):
 978                         return False
 979                 if self.w_searchentry_dialog.get_text() == "":
 980                         return (repository & category & \
 981                             self.__is_package_filtered(model, itr))
 982                 if not model.get_value(itr, enumerations.NAME_COLUMN) == None:
 983                         if self.w_searchentry_dialog.get_text().lower() in \
 984                             model.get_value \
 985                             (itr, enumerations.NAME_COLUMN).lower():
 986                                 return (repository & category & \
 987                                     self.__is_package_filtered(model, itr))
 988                 if not model.get_value(itr, enumerations.DESCRIPTION_COLUMN) == None:
 989                         if self.w_searchentry_dialog.get_text().lower() in \
 990                             model.get_value \
 991                             (itr, enumerations.DESCRIPTION_COLUMN).lower():
 992                                 return (repository & category & \
 993                                     self.__is_package_filtered(model, itr))
 994                 else:
 995                         return False
 996 
 997         def __is_package_filtered(self, model, itr):
 998                 '''Function for filtercombobox'''
 999                 # XXX Instead of string comparison, we should do it through integers.
1000                 # XXX It should be faster and better for localisations.
1001                 filter_text = self.w_filter_combobox.get_active()
1002                 if filter_text == 0:
1003                         return True
1004                 elif filter_text == 2:
1005                         return model.get_value(itr, \
1006                             enumerations.INSTALLED_VERSION_COLUMN) != None
1007                 elif filter_text == 3:
1008                         return (model.get_value(itr, \
1009                             enumerations.INSTALLED_VERSION_COLUMN) != None) & \
1010                             (model.get_value(itr, \
1011                             enumerations.LATEST_AVAILABLE_COLUMN) != None)
1012                 elif filter_text == 4:
1013                         return not model.get_value(itr, \
1014                             enumerations.INSTALLED_VERSION_COLUMN) != None
1015                 elif filter_text == 6:
1016                         return model.get_value(itr, enumerations.MARK_COLUMN)
1017                 elif filter_text == 8:
1018                         # XXX Locked support
1019                         return False
1020 
1021 
1022         def __is_pkg_repository_visible(self, model, itr):
1023                 if len(self.repositories_list) <= 1:
1024                         return True
1025                 else:
1026                         auth_iter = self.w_repository_combobox.get_active_iter()
1027                         authority = self.repositories_list.get_value(auth_iter, \
1028                             enumerations.REPOSITORY_NAME)
1029                         packages = model.get_value(itr, \
1030                             enumerations.PACKAGE_OBJECT_COLUMN)
1031                         if not packages:
1032                                 return False
1033                         pkg = max(packages)
1034                         if cmp(pkg.get_authority(), authority) == 0:
1035                                 return True
1036                         else:
1037                                 return False
1038 
1039         def __do_ips_uptodate_check(self):
1040                 self.ips_uptodate = self.__ipkg_ipkgui_uptodate(self.image_o)
1041                 self.progress_stop_timer_thread = True
1042 
1043         def __ipkg_ipkgui_uptodate(self, img):
1044                 if not img.is_liveroot():
1045                         newimg = image.Image()
1046                         cmdpath = os.path.join(os.getcwd(), sys.argv[0])
1047                         cmdpath = os.path.realpath(cmdpath)
1048                         cmddir = os.path.dirname(os.path.realpath(cmdpath))
1049                         try:
1050                                 #
1051                                 # Find the path to ourselves, and use that
1052                                 # as a way to locate the image we're in.  It's
1053                                 # not perfect-- we could be in a developer's
1054                                 # workspace, for example.
1055                                 #
1056                                 newimg.find_root(cmddir)
1057                         except ValueError:
1058                                 # We can't answer in this case, so we return True to
1059                                 # let installation proceed.
1060                                 # TODO: log - msg(_("No image corresponding to '%s' was 
1061                                 # located. " \ "Proceeding.") % cmdpath)
1062                                 return True
1063                         newimg.load_config()
1064                         img = newimg
1065 
1066                 try:
1067                         img.retrieve_catalogs()
1068                 except image.CatalogRefreshException:
1069                         raise
1070                 # Reload catalog.  This picks up the update from retrieve_catalogs.
1071                 img.load_catalogs(self.pr)
1072  
1073                 try:
1074                         # We will use whatever the incorporation provides as the latest 
1075                         # version of ipkg and ipkg-gui
1076                         
1077                         img.make_install_plan([self.ipkg_fmri, self.ipkggui_fmri], \
1078                             self.pr, filters = [], noexecute = True)
1079                 except RuntimeError:
1080                         return True
1081 
1082                 if img.imageplan.nothingtodo():
1083                         return True                
1084                         
1085                 return False
1086 
1087 
1088         def __enable_disable_selection_menus(self):
1089                 
1090                 if self.in_setup:
1091                         return
1092                 self.__enable_disable_select_all()
1093                 self.__enable_disable_select_updates()
1094                 self.__enable_disable_deselect()
1095                 # XXX disabled until new API
1096                 self.__enable_disable_update_all()
1097 
1098         def __enable_disable_select_all(self):
1099                 
1100                 if self.in_setup:
1101                         return
1102                 if len(self.w_application_treeview.get_model()) > 0:
1103                         for row in self.w_application_treeview.get_model():
1104                                 if not row[enumerations.MARK_COLUMN]:
1105                                         self.w_selectall_menuitem.set_sensitive(True)
1106                                         return
1107                         self.w_selectall_menuitem.set_sensitive(False)
1108                 else:
1109                         self.w_selectall_menuitem.set_sensitive(False)
1110 
1111         def __enable_disable_install_update(self):
1112                 for row in self.application_list:
1113                         if row[enumerations.MARK_COLUMN]:
1114                                 if row[enumerations.LATEST_AVAILABLE_COLUMN] and \
1115                                     self.user_rights:
1116                                         self.w_installupdate_button.set_sensitive(True)
1117                                         self.w_installupdate_menuitem.set_sensitive(True)
1118                                         return
1119                 self.w_installupdate_button.set_sensitive(False)
1120                 self.w_installupdate_menuitem.set_sensitive(False)
1121 
1122         def __enable_disable_remove(self):
1123                 for row in self.application_list:
1124                         if row[enumerations.MARK_COLUMN]:
1125                                 if row[enumerations.INSTALLED_VERSION_COLUMN] and \
1126                                     self.user_rights:
1127                                         self.w_remove_button.set_sensitive(True)
1128                                         self.w_remove_menuitem.set_sensitive(True)
1129                                         return
1130                 self.w_remove_button.set_sensitive(False)
1131                 self.w_remove_menuitem.set_sensitive(False)
1132 
1133         def __enable_disable_select_updates(self):
1134                 for row in self.w_application_treeview.get_model():
1135                         if row[enumerations.INSTALLED_VERSION_COLUMN]:
1136                                 if row[enumerations.LATEST_AVAILABLE_COLUMN]:
1137                                         if not row[enumerations.MARK_COLUMN]:
1138                                                 self.w_selectupdates_menuitem. \
1139                                                     set_sensitive(True)
1140                                                 return
1141                 self.w_selectupdates_menuitem.set_sensitive(False)
1142                 return
1143 
1144         def __enable_disable_update_all(self):
1145                 for row in self.application_list:
1146                         if self.__is_pkg_repository_visible(self.application_list, \
1147                             row.iter):
1148                                 if self.application_list.get_value(row.iter, \
1149                                     enumerations.INSTALLED_VERSION_COLUMN):
1150                                         if self.application_list.get_value(row.iter, \
1151                                             enumerations.LATEST_AVAILABLE_COLUMN) and \
1152                                             self.user_rights:
1153                                                 self.w_updateall_menuitem. \
1154                                                     set_sensitive(True)
1155                                                 self.w_updateall_button. \
1156                                                     set_sensitive(True)
1157                                                 return
1158                 self.w_updateall_button.set_sensitive(False)
1159                 self.w_updateall_menuitem.set_sensitive(False)
1160 
1161         def __enable_disable_deselect(self):
1162                 for row in self.w_application_treeview.get_model():
1163                         if row[enumerations.MARK_COLUMN]:
1164                                 self.w_deselect_menuitem.set_sensitive(True)
1165                                 return
1166                 self.w_deselect_menuitem.set_sensitive(False)
1167                 return
1168 
1169 
1170         def __catalog_refresh(self):
1171                 """Update image's catalogs."""
1172                 images = self.__get_images_from_model()
1173                 full_refresh = False
1174                 for img in images:
1175                         # Ensure Image directory structure is valid.
1176                         if not os.path.isdir("%s/catalog" % img.imgdir):
1177                                 img.mkdirs()
1178                         # Loading catalogs allows us to perform incremental update
1179                         img.retrieve_catalogs(full_refresh)
1180 
1181         def __get_images_from_model(self):
1182                 images = []
1183                 for row in self.application_list:
1184                         img = row[enumerations.IMAGE_OBJECT_COLUMN]
1185                         if img:
1186                                 if not img in images:
1187                                         images.append(img)
1188                 return images 
1189 
1190         def __get_image_obj_from_directory(self, image_directory):
1191                 image_obj = image.Image()
1192                 dr = "/"
1193                 try:
1194                         image_obj.find_root(image_directory)
1195                         image_obj.load_config()
1196                         image_obj.load_catalogs(self.pr)
1197                 except ValueError:
1198                         print self._('%s is not valid image, trying root image') \
1199                             % image_directory 
1200                         try:
1201                                 dr = os.environ["PKG_IMAGE"]
1202                         except KeyError:
1203                                 print
1204                         try:
1205                                 image_obj.find_root(dr)
1206                                 image_obj.load_config()
1207                                 image_obj.load_catalogs(self.pr)
1208                         except ValueError:
1209                                 print self._('%s is not valid root image, return None') \
1210                                     % dr
1211                                 image_obj = None
1212                 return image_obj
1213 
1214 
1215 
1216         def __get_image_from_directory(self, image_obj, progressdialog_progress):
1217                 """ This method set up image from the given directory and
1218                 returns the image object or None"""
1219                 # XXX Convert timestamp to some nice date :)
1220                 self.application_list.clear()
1221                 self.category_list.clear()
1222                 self.application_list_filter.refilter()
1223                 try:
1224                         pkgs_known = [ pf[0] for pf in
1225                             sorted(image_obj.inventory(all_known = True)) ]
1226                 except image.InventoryException, e:
1227                         # Can't happen when all_known is true and no args,
1228                         # but here for completeness.
1229                         raise
1230                 #Only one instance of those icons should be in memory
1231                 update_available_icon = self.get_icon_pixbuf("new_update")
1232                 #Imageinfo for categories
1233                 imginfo = imageinfo.ImageInfo()
1234                 sectioninfo = imageinfo.ImageInfo()
1235                 catalogs = image_obj.catalogs
1236                 categories = {}
1237                 sections = {}
1238                 self.__setup_repositories_combobox(image_obj)
1239                 for cat in catalogs:
1240                         category = imginfo.read(self.application_dir + \
1241                             "/usr/share/package-manager/data/" + cat)
1242                         categories[cat] = category
1243                         section = sectioninfo.read(self.application_dir + \
1244                             "/usr/share/package-manager/data/" + cat + ".sections")
1245                         sections[cat] = section
1246                 # Speedup, instead of checking if the pkg is already in the list, 
1247                 # iterating through all elements, we will only compare to the previous
1248                 # package and if the package is the same (version difference) then we
1249                 # are adding to the first iterator for the set of those packages. 
1250                 # We can do that, since the list pkgs_known is sorted
1251                 # This will give a sppedup from 18sec to ~3!!!
1252                 p_pkg_iter = None
1253                 p_pkg = None
1254                 insert_count = 0
1255                 icon_path = self.application_dir + \
1256                     "/usr/share/package-manager/data/pixmaps/"
1257 
1258                 pkg_count = 0
1259                 progress_percent = INITIAL_PROGRESS_TOTAL_PERCENTAGE
1260                 total_pkg_count = len(pkgs_known)
1261                 progress_increment = \
1262                         total_pkg_count / PACKAGE_PROGRESS_TOTAL_INCREMENTS
1263 
1264                 self.progress_stop_timer_thread = True
1265                 while gtk.events_pending():
1266                         gtk.main_iteration(False)
1267                 for pkg in pkgs_known:
1268                         if pkg_count % progress_increment == 0:
1269                                 progress_percent += PACKAGE_PROGRESS_PERCENT_INCREMENT
1270                                 if progress_percent <= PACKAGE_PROGRESS_PERCENT_TOTAL:
1271                                         gobject.idle_add(progressdialog_progress,
1272                                             progress_percent, pkg_count, total_pkg_count)
1273                                 while gtk.events_pending():
1274                                         gtk.main_iteration(False)
1275                         pkg_count += 1
1276                         
1277                         #speedup hack, check only last package
1278                         already_in_model = \
1279                             self.check_if_pkg_have_row_in_model(pkg, p_pkg)
1280                         if not already_in_model:         #Create new row
1281                                 available_version = None
1282                                 version_installed = None
1283                                 status_icon = None
1284                                 fmris = [pkg, ]
1285                                 package_installed = \
1286                                     self.get_installed_version(image_obj, pkg)
1287                                 if package_installed:
1288                                         version_installed = \
1289                                             package_installed.version.get_short_version()
1290                                         #HACK, sometimes the package is installed but 
1291                                         #it's not in the pkgs_known
1292                                         if package_installed != pkg:
1293                                                 fmris.append(package_installed)
1294                                 else:
1295                                         dt = self.get_datetime(pkg.version)
1296                                         dt_str = (":%02d%02d") % (dt.month, dt.day)
1297                                         available_version = \
1298                                             pkg.version.get_short_version() + dt_str
1299                                 package_icon = self.__get_pixbuf_from_path(icon_path, \
1300                                     pkg.get_name())
1301                                 app = \
1302                                     [
1303                                         False, status_icon, package_icon, pkg.get_name(),
1304                                         version_installed, package_installed,
1305                                         available_version, -1, '...', fmris,
1306                                         image_obj, True, None
1307                                     ]
1308                                 # XXX Small hack, if this is not applied, first package 
1309                                 # is listed twice. Insert is ~0.5 sec faster than append
1310                                 if insert_count == 0:
1311                                         row_iter = self.application_list.append(app)
1312                                 else:
1313                                         row_iter = \
1314                                             self.application_list.insert(insert_count, \
1315                                             app)
1316                                 # XXX Do not iterate through all the catalogs. Package 
1317                                 # should know what is package fmri prefix?
1318                                 apc = self.__add_package_to_category
1319                                 for cat in categories:
1320                                         if cat in categories:
1321                                                 name = pkg.get_name()
1322                                                 if name in categories[cat]:
1323                                                         pkg_categories = \
1324                                                             categories[cat][ \
1325                                                             name]
1326                                                         for pcat in \
1327                                                             pkg_categories.split(","):
1328                                                                 if pcat:
1329                                                                         apc(self._( \
1330                                                                             pcat), None \
1331                                                                             , None, \
1332                                                                             row_iter)
1333                                 insert_count = insert_count + 1
1334                                 p_pkg_iter = row_iter
1335                                 p_pkg = pkg                  #The current become previous
1336                         else:
1337                                 # XXX check versions in here. For all installed/not 
1338                                 # installed:
1339                                 # if there is newer version, put it in the available 
1340                                 # field.
1341                                 #
1342                                 # XXXhack, since image_get_version_installed(pkg) is not 
1343                                 # working,as it should. For example package:
1344                                 # SUNWarc@0.5.11,5.11-0.79:20080205T152309Z
1345                                 # is not installed and it's newer version of installed
1346                                 # package:
1347                                 # SUNWarc@0.5.11,5.11-0.75:20071114T201151Z
1348                                 # the function returns only proper installed version for 
1349                                 # the older package and None for the newer.
1350                                 # The hack is a little bit slow since we are iterating 
1351                                 # for all known packages
1352                                 list_of_pkgs = \
1353                                     self.application_list.get_value(p_pkg_iter, \
1354                                     enumerations.PACKAGE_OBJECT_COLUMN)
1355                                 if pkg not in list_of_pkgs:
1356                                         list_of_pkgs.append(pkg)
1357                                 installed = self.application_list.get_value(p_pkg_iter, \
1358                                     enumerations.INSTALLED_OBJECT_COLUMN)
1359                                 latest = max(list_of_pkgs)
1360                                 dt = self.get_datetime(latest.version)
1361                                 dt_str = (":%02d%02d") % (dt.month, dt.day)
1362                                 if not installed:
1363                                         self.application_list.set_value(p_pkg_iter, \
1364                                             enumerations.LATEST_AVAILABLE_COLUMN, \
1365                                             latest.version.get_short_version() + \
1366                                             dt_str)
1367                                 else:
1368                                         if installed < latest:
1369                                                 self.application_list.set_value( \
1370                                                     p_pkg_iter, \
1371                                                     enumerations. \
1372                                                     LATEST_AVAILABLE_COLUMN, \
1373                                                     latest.version.get_short_version() + \
1374                                                     dt_str)
1375                                                 self.application_list.set_value(\
1376                                                     p_pkg_iter, \
1377                                                     enumerations.STATUS_ICON_COLUMN, \
1378                                                     update_available_icon)
1379                         # XXX How to get descriptions without manifest?
1380                         # XXX Downloading manifest is slow and can not work without 
1381                         # XXX Network connection
1382                         #if not image_obj.has_manifest(pkg):
1383                         #        image_obj.get_manifest(pkg)#verify(pkg, pr)
1384                         #installed_version = None
1385                         #package_iter = None #the iterator which points for other package
1386                 for authority in sections:
1387                         for section in sections[authority]:
1388                                 for category in sections[authority][section].split(","):
1389                                         self.__add_category_to_section(self._(category), \
1390                                             self._(section))
1391 
1392                 #1915 Sort the Categories into alphabetical order and prepend All Category
1393                 if len(self.category_list) > 0:
1394                         rows = [tuple(r) + (i,) for i, r in enumerate(self.category_list)]
1395                         rows.sort(self.__sort)
1396                         self.category_list.reorder([r[-1] for r in rows])
1397                 self.category_list.prepend([0, self._('All'), None, None, True, None])
1398 
1399                 gobject.idle_add(progressdialog_progress, PACKAGE_PROGRESS_PERCENT_TOTAL,
1400                         pkg_count, total_pkg_count)
1401 
1402         def __add_package_to_category(self, category_name, category_description, \
1403             category_icon, package):
1404                 if not package or category_name == self._('All'):
1405                         return
1406                 if not category_name:
1407                         return
1408                         # XXX check if needed
1409                         # category_name = self._('All')
1410                         # category_description = self._('All packages')
1411                         # category_icon = None
1412                 category_ref = None
1413                 for category in self.category_list:
1414                         if category[enumerations.CATEGORY_NAME] == category_name:
1415                                 category_ref = category.iter
1416                 if not category_ref:                       # Category not exists
1417                         category_ref = self.category_list.append([len( \
1418                             self.category_list), category_name, category_description, \
1419                             category_icon, True, None])
1420                 if category_ref:
1421                         if self.application_list.get_value(package, \
1422                             enumerations.CATEGORY_LIST_OBJECT):
1423                                 a = self.application_list.get_value(package, \
1424                                     enumerations.CATEGORY_LIST_OBJECT)
1425                                 a.append(category_ref)
1426                         else:
1427                                 category_list = []
1428                                 category_list.append(category_ref)
1429                                 self.application_list.set(package, \
1430                                     enumerations.CATEGORY_LIST_OBJECT, category_list)
1431 
1432         def __add_category_to_section(self, category_name, section_name):
1433                 '''Adds the section to section list in category. If there is no such 
1434                 section, than it is not added. If there was already section than it
1435                 is skipped. Sections must be case sensitive'''
1436                 if not category_name:
1437                         return
1438                 for section in self.section_list:
1439                         if section[enumerations.SECTION_NAME] == section_name:
1440                                 for category in self.category_list:
1441                                         if category[enumerations.CATEGORY_NAME] == \
1442                                             category_name:
1443                                                 if not category[ \
1444                                                     enumerations.SECTION_LIST_OBJECT]:
1445                                                         category[ \
1446                                                             enumerations. \
1447                                                             SECTION_LIST_OBJECT] = \
1448                                                             [section[ \
1449                                                             enumerations.SECTION_ID], ]
1450                                                 else:
1451                                                         if not section_name in \
1452                                                             category[ \
1453                                                             enumerations. \
1454                                                             SECTION_LIST_OBJECT]:
1455                                                                 category[enumerations. \
1456                                                                     SECTION_LIST_OBJECT \
1457                                                                     ].append(section[ \
1458                                                                     enumerations. \
1459                                                                     SECTION_ID])
1460 
1461         def __get_pixbuf_from_path(self, path, icon_name):
1462                 icon = icon_name.replace(' ', '_')
1463 
1464                 # Performance: Faster to check if files exist rather than catching
1465                 # exceptions when they do not. Picked up open failures using dtrace
1466                 png_exists = os.path.exists(self.application_dir + path + icon + ".png")
1467                 svg_exists = os.path.exists(self.application_dir + path + icon + ".svg")
1468                        
1469                 if not png_exists and not svg_exists:
1470                         return None
1471                 try:
1472                         return gtk.gdk.pixbuf_new_from_file( \
1473                             self.application_dir + path + icon + ".png")
1474                 except gobject.GError:
1475                         try:
1476                                 return gtk.gdk.pixbuf_new_from_file( \
1477                                     self.application_dir + path + icon + ".svg")
1478                         except gobject.GError:
1479                                 iconview = gtk.IconView()
1480                                 icon = iconview.render_icon(getattr(gtk, \
1481                                     "STOCK_MISSING_IMAGE"), \
1482                                     size = gtk.ICON_SIZE_MENU,
1483                                     detail = None)
1484                                 # XXX Could return image-we don't want to show ugly icon.
1485                                 return None
1486 
1487         def __installed_fmris_from_args(self, img, args):
1488                 found = []
1489                 notfound = []
1490                 try:
1491                         for m in img.inventory(args):
1492                                 found.append(m[0])
1493                 except image.InventoryException, e:
1494                         notfound = e.notfound
1495 
1496                 return found, notfound
1497 
1498         def __progressdialog_progress_pulse(self):
1499                 while not self.progress_stop_timer_thread:
1500                         gobject.idle_add(self.w_progressbar.pulse)
1501                         time.sleep(0.1)
1502                 gobject.idle_add(self.w_progress_dialog.hide)
1503                 self.progress_stop_timer_thread = False
1504                 
1505         # For initial setup before loading package entries allow 5% of progress bar
1506         # update it on a time base as we have no other way to judge progress at this point
1507         def __progressdialog_progress_time(self):
1508                 while not self.progress_stop_timer_thread and \
1509                         self.progress_fraction_time_count <= \
1510                             INITIAL_PROGRESS_TOTAL_PERCENTAGE:
1511                                 
1512                         gobject.idle_add(self.w_progressbar.set_fraction, \
1513                                 self.progress_fraction_time_count)
1514                         self.progress_fraction_time_count += \
1515                                 INITIAL_PROGRESS_TIME_PERCENTAGE
1516                         time.sleep(INITIAL_PROGRESS_TIME_INTERVAL)
1517                 self.progress_stop_timer_thread = False
1518                 self.progress_fraction_time_count = 0
1519 
1520         def __progressdialog_progress_percent(self, fraction, count, total):
1521                 gobject.idle_add(self.w_progressinfo_label.set_text, self._( \
1522                     "Processing package entries: %d of %d" % (count, total)  ))
1523                 gobject.idle_add(self.w_progressbar.set_fraction, fraction)
1524 
1525         def __setup_data_finished(self):
1526                 gobject.idle_add(self.w_progress_dialog.hide)
1527                 self.in_setup = False
1528       
1529 #-----------------------------------------------------------------------------#
1530 # Static Methods
1531 #-----------------------------------------------------------------------------#
1532 
1533         @staticmethod
1534         def n_(message): 
1535                 return message
1536 
1537         @staticmethod
1538         def __sort(a, b):
1539                 return cmp(a[1], b[1])
1540                 
1541         @staticmethod
1542         def cell_data_function(column, renderer, model, itr, data):
1543                 '''Function which sets the background colour to black if package is 
1544                 selected'''
1545                 if itr:
1546                         if model.get_value(itr, enumerations.MARK_COLUMN):
1547                                 renderer.set_property("cell-background", "#ffe5cc")
1548                                 renderer.set_property("cell-background-set", True)
1549                         else:
1550                                 renderer.set_property("cell-background-set", False)
1551 
1552         @staticmethod
1553         def combobox_separator(model, itr):
1554                 return model.get_value(itr, enumerations.FILTER_NAME) == ""
1555 
1556         @staticmethod
1557         def combobox_id_separator(model, itr):
1558                 return model.get_value(itr, 0) == -1
1559 
1560         @staticmethod
1561         def check_if_pkg_have_row_in_model(pkg, p_pkg):
1562                 """Returns True if package is already in model or False if not"""
1563                 if p_pkg:
1564                         if pkg.is_same_pkg(p_pkg):
1565                                 return True
1566                         else:
1567                                 return False
1568                 return False
1569 
1570         @staticmethod
1571         def category_filter(model, itr):
1572                 '''This function filters category in the main application view'''
1573                 return model.get_value(itr, enumerations.CATEGORY_VISIBLE)
1574 
1575         @staticmethod
1576         def get_datetime(version):
1577                 dt = None
1578                 try:
1579                         dt = version.get_datetime()
1580                 except AttributeError:
1581                         dt = version.get_timestamp()
1582                 return dt
1583 
1584         @staticmethod
1585         def get_installed_version(img, pkg):
1586                 if not img.has_version_installed(pkg):
1587                         return None
1588                 else:
1589                         img_ret = None
1590                         try:
1591                                 img_ret = img.get_version_installed(pkg)
1592                         except AttributeError:
1593                                 img_ret = img._get_version_installed(pkg)
1594                         return img_ret
1595 
1596         @staticmethod
1597         def get_manifest(img, package, filtered = True):
1598                 '''helper function'''
1599                 # XXX Should go to the  -> imageinfo.py
1600                 manifest = None
1601 
1602                 # 3087 shutdown time is too long when closing down soon after startup
1603                 if packagemanager.cancelled:
1604                         return manifest
1605                 try:
1606                         manifest = img.get_manifest(package, filtered)
1607                 except OSError:
1608                         # XXX It is possible here that the user doesn't have network con,
1609                         # XXX proper permissions to save manifest, should we do something 
1610                         # XXX and popup information dialog?
1611                         pass
1612                 except NameError:
1613                         pass
1614                 return manifest
1615 
1616         @staticmethod
1617         def update_desc(description, pkg, package):
1618                 p = pkg[enumerations.PACKAGE_OBJECT_COLUMN][0]
1619                 if p == package:
1620                         pkg[enumerations.DESCRIPTION_COLUMN] = description
1621                         return
1622 
1623 #-----------------------------------------------------------------------------#
1624 # Public Methods
1625 #-----------------------------------------------------------------------------#
1626         def setup_progressdialog_show(self):
1627                 self.w_progress_dialog.set_title(self._("Loading Repository Information"))
1628                 self.w_progressinfo_label.set_text(
1629                     self._( "Fetching package entries ..."))
1630                 self.w_progress_cancel.hide()
1631 
1632                 Thread(target = self.w_progress_dialog.run).start()
1633                 Thread(target = self.__progressdialog_progress_time).start()
1634         
1635         def init_sections(self):
1636                 self.__init_sections()                   #Initiates sections
1637 
1638         def process_package_list_start(self, image_directory):
1639                 self.image_directory = image_directory
1640                 # Create our image object based on image directory.
1641                 image_obj = self.__get_image_obj_from_directory(image_directory)
1642                 self.image_o = image_obj
1643                 
1644                 # Acquire image contents and update progress bar as you do so.
1645                 self.__get_image_from_directory(image_obj,
1646                         self.__progressdialog_progress_percent)
1647                 while gtk.events_pending():
1648                         gtk.main_iteration(False)
1649                         
1650         def init_package_view(self):
1651                 self.__init_show_filter()                
1652                 self.__setup_data_finished()
1653                 self.__init_tree_views()                 
1654 
1655                 self.w_filter_combobox.set_active(0)
1656                 self.w_sections_combobox.set_active(0)
1657                 self.application_list_filter.set_visible_func(self.__application_filter)
1658                 self.__setup_repositories_combobox(self.image_o)
1659 
1660         def get_icon_pixbuf(self, icon_name):
1661                 #2821: The get_icon_pixbuf should use PACKAGE_MANAGER_ROOT
1662                 return self.__get_pixbuf_from_path(self.application_dir + \
1663                     "/usr/share/icons/package-manager/", icon_name)
1664                 
1665         def get_manifests_for_packages(self):
1666                 ''' Function, which get's manifest for packages. If the manifest is not
1667                 locally tries to retrieve it. For installed packages gets manifest
1668                 for the particular version (local operation only), if the package is 
1669                 not installed than the newest one'''
1670                 self.description_thread_running = True
1671                 for pkg in self.application_list:
1672                         if self.cancelled:
1673                                 self.description_thread_running = False
1674                                 return
1675                         info = None
1676                         img = pkg[enumerations.IMAGE_OBJECT_COLUMN]
1677                         package = pkg[enumerations.PACKAGE_OBJECT_COLUMN][0]
1678                         if (img and package):
1679                                 version = img.has_version_installed(package)
1680                                 if version:
1681                                         version = self.get_installed_version(img, \
1682                                             package)
1683                                         man = self.get_manifest(img, version, \
1684                                             filtered = True)
1685                                         if man:
1686                                                 info = man.get("description", "")
1687                                 else:
1688                                         newest = max( \
1689                                             pkg[enumerations.PACKAGE_OBJECT_COLUMN])
1690                                         man = self.get_manifest(img, newest, \
1691                                             filtered = True)
1692                                         if man:
1693                                                 info = man.get("description", "")
1694                         # XXX workaround, this should be done nicer
1695                         gobject.idle_add(self.update_desc, info, pkg, package)
1696                         time.sleep(0.01)
1697                 self.description_thread_running = False
1698                 
1699         def update_statusbar(self):
1700                 '''Function which updates statusbar'''
1701                 installed = 0
1702                 selected = 0
1703                 broken = 0
1704                 for pkg in self.application_list:
1705                         if pkg[enumerations.INSTALLED_VERSION_COLUMN]:
1706                                 installed = installed + 1
1707                         if pkg[enumerations.MARK_COLUMN]:
1708                                 selected = selected + 1
1709                 listed_str = self._('%d packages listed') % len(self.application_list)
1710                 inst_str = self._('%d installed') % installed
1711                 sel_str = self._('%d selected') % selected
1712                 broken_str = self._('%d broken') % broken
1713                 self.w_main_statusbar.push(0, listed_str + ', ' + inst_str + ', ' + \
1714                     sel_str + ', ' + broken_str + '.')
1715 
1716 
1717         def update_package_list(self):
1718                 for row in self.application_list:
1719                         if row[enumerations.MARK_COLUMN]:
1720                                 img =  row[enumerations.IMAGE_OBJECT_COLUMN]
1721                                 pkg = row[enumerations.PACKAGE_OBJECT_COLUMN][0]
1722                                 package_installed = self.get_installed_version(img, pkg)
1723                                 version_installed = None
1724                                 if package_installed:
1725                                         version_installed = \
1726                                             package_installed.version.get_short_version()
1727                                 row[enumerations.MARK_COLUMN] = False
1728                                 row[enumerations.STATUS_ICON_COLUMN] = None
1729                                 row[enumerations.INSTALLED_VERSION_COLUMN] = \
1730                                     version_installed
1731                                 row[enumerations.INSTALLED_OBJECT_COLUMN] = \
1732                                     package_installed
1733                                 if not package_installed:
1734                                         pkg = max(row[enumerations.PACKAGE_OBJECT_COLUMN])
1735                                         dt = self.get_datetime(pkg.version)
1736                                         dt_str = (":%02d%02d") % (dt.month, dt.day)
1737                                         available_version = \
1738                                             pkg.version.get_short_version() + dt_str
1739                                         row[enumerations.LATEST_AVAILABLE_COLUMN] = \
1740                                             available_version
1741                                 else:
1742                                         row[enumerations.LATEST_AVAILABLE_COLUMN] = None
1743                 self.w_installupdate_button.set_sensitive(False)
1744                 self.w_installupdate_menuitem.set_sensitive(False)
1745                 self.w_remove_button.set_sensitive(False)
1746                 self.w_remove_menuitem.set_sensitive(False)
1747                 self.__enable_disable_selection_menus()
1748                 self.update_statusbar()
1749 
1750         def shutdown_after_ips_update(self):    
1751 
1752                 # 2790: As IPS and IPS-GUI have been updated the IPS GUI must be shutdown 
1753                 # and restarted
1754                 msgbox = gtk.MessageDialog(parent = self.w_main_window, \
1755                     buttons = gtk.BUTTONS_OK, \
1756                     flags = gtk.DIALOG_MODAL, type = gtk.MESSAGE_INFO, \
1757                     message_format = self._("SUNWipkg and SUNWipkg-gui have been" + \
1758                     "updated and Package Manager will now be restarted.\n\nAfter" + \
1759                     "restart select Update All to continue."))
1760                 msgbox.set_title(self._("Update All"))
1761                 msgbox.run()
1762                 msgbox.destroy()
1763                 self.__main_application_quit(restart_app = True)
1764 
1765         def shutdown_after_image_update(self):    
1766 
1767                 msgbox = gtk.MessageDialog(parent = self.w_main_window, \
1768                     buttons = gtk.BUTTONS_OK, \
1769                     flags = gtk.DIALOG_MODAL, type = gtk.MESSAGE_INFO, \
1770                     message_format = self._("Update All has completed and Package" + \
1771                     "Manager will now exit.\n\nPlease review posted release notes" + \
1772                     "before rebooting:\n\n" + \
1773                     "   http://opensolaris.org/os/project/indiana/resources/rn3/"))
1774                 msgbox.set_title(self._("Update All"))
1775                 msgbox.run()
1776                 msgbox.destroy()
1777                 self.__main_application_quit()
1778 
1779 ###############################################################################
1780 #-----------------------------------------------------------------------------#
1781 # Test functions
1782 #-----------------------------------------------------------------------------#
1783         def fill_with_fake_data(self):
1784                 '''test data for gui'''
1785                 app1 = [False, self.get_icon_pixbuf("locked"), \
1786                     self.get_icon_pixbuf("None"), "acc", None, None, None, 4, "desc6", \
1787                     "Object Name1", None, True, None]
1788                 app2 = [False, self.get_icon_pixbuf("update_available"), \
1789                     self.get_icon_pixbuf(self._('All')), "acc_gam", \
1790                     "2.3", None, "2.8", \
1791                     4, "desc7", "Object Name2", None, True, None]
1792                 app3 = [False, self.get_icon_pixbuf("None"), \
1793                     self.get_icon_pixbuf("Other"), "gam_grap", "2.3", None, None, 4, \
1794                     "desc8", "Object Name3", None, True, None]
1795                 app4 = [False, self.get_icon_pixbuf("update_locked"), \
1796                     self.get_icon_pixbuf("Office"), "grap_gam", "2.3", None, "2.8", 4, \
1797                     "desc9", "Object Name2", None, True, None]
1798                 app5 = [False, self.get_icon_pixbuf("update_available"), \
1799                     self.get_icon_pixbuf("None"), "grap", "2.3", None, "2.8", 4, \
1800                     "desc0", "Object Name3", None, True, None]
1801                 itr1 = self.application_list.append(app1)
1802                 itr2 = self.application_list.append(app2)
1803                 itr3 = self.application_list.append(app3)
1804                 itr4 = self.application_list.append(app4)
1805                 itr5 = self.application_list.append(app5)
1806                 #      self.__add_package_to_category(_("All"),None,None,None);
1807                 self.__add_package_to_category(self._("Accessories"), None, None, itr1)
1808                 self.__add_package_to_category(self._("Accessories"), None, None, itr2)
1809                 self.__add_package_to_category(self._("Games"), None, None, itr3)
1810                 self.__add_package_to_category(self._("Graphics"), None, None, itr3)
1811                 self.__add_package_to_category(self._("Games"), None, None, itr2)
1812                 self.__add_package_to_category(self._("Graphics"), None, None, itr4)
1813                 self.__add_package_to_category(self._("Games"), None, None, itr4)
1814                 self.__add_package_to_category(self._("Graphics"), None, None, itr5)
1815 
1816                 #     Category names until xdg is imported.
1817                 #     from xdg.DesktopEntry import *
1818                 #     entry = DesktopEntry ()
1819                 #     directory = '/usr/share/desktop-directories'
1820                 #     for root, dirs, files in os.walk (directory):
1821                 #       for name in files:
1822                 #       entry.parse (os.path.join (root, name))
1823                 #       self.__add_category_to_section (entry.getName (), \
1824                 #   self._('Applications Desktop'))
1825 
1826                 self.__add_category_to_section(self._("Accessories"), \
1827                     self._('Applications Desktop'))
1828                 self.__add_category_to_section(self._("Games"), \
1829                     self._('Applications Desktop'))
1830                 self.__add_category_to_section(self._("Graphics"), \
1831                     self._('Applications Desktop'))
1832                 self.__add_category_to_section(self._("Internet"), \
1833                     self._('Applications Desktop'))
1834                 self.__add_category_to_section(self._("Office"), \
1835                     self._('Applications Desktop'))
1836                 self.__add_category_to_section(self._("Sound & Video"), \
1837                     self._('Applications Desktop'))
1838                 self.__add_category_to_section(self._("System Tools"), \
1839                     self._('Applications Desktop'))
1840                 self.__add_category_to_section(self._("Universal Access"), \
1841                     self._('Applications Desktop'))
1842                 self.__add_category_to_section(self._("Developer Tools"), \
1843                     self._('Applications Desktop'))
1844                 self.__add_category_to_section(self._("Core"), self._('Operating System'))
1845                 self.__add_category_to_section(self._("Graphics"), \
1846                     self._('Operating System'))
1847                 self.__add_category_to_section(self._("Media"), \
1848                     self._('Operating System'))
1849                 #Can be twice :)
1850                 self.__add_category_to_section(self._("Developer Tools"), \
1851                     self._('Operating System'))
1852                 self.__add_category_to_section(self._("Office"), "Progs")
1853                 self.__add_category_to_section(self._("Office2"), "Progs")
1854                 self.__setup_repositories_combobox(self.image_o)
1855                 self.in_setup = False
1856 
1857 ###############################################################################
1858 #-----------------------------------------------------------------------------#
1859 # Main
1860 #-----------------------------------------------------------------------------#
1861 
1862 def main():
1863         gtk.main()
1864         return 0
1865 
1866 if __name__ == '__main__':
1867         packagemanager = PackageManager()
1868         passed_test_arg = False
1869         passed_imagedir_arg = False
1870 
1871         try:
1872                 opts, args = getopt.getopt(sys.argv[1:], "htR:", \
1873                     ["help", "test-gui", "image-dir="])
1874         except getopt.error, msg:
1875                 print "%s, for help use --help" % msg
1876                 sys.exit(2)
1877 
1878         cmd = os.path.join(os.getcwd(), sys.argv[0])
1879         cmd = os.path.realpath(cmd)
1880         packagemanager.application_path = cmd
1881 
1882         for option, argument in opts:
1883                 if option in ("-h", "--help"):
1884                         print """\
1885 Use -R (--image-dir) to specify image directory.
1886 Use -t (--test-gui) to work on fake data."""
1887                         sys.exit(0)
1888                 if option in ("-t", "--test-gui"):
1889                         passed_test_arg = True
1890                 if option in ("-R", "--image-dir"):
1891                         packagemanager.image_dir_arg = argument
1892                         image_dir = argument
1893                         passed_imagedir_arg = True
1894 
1895         if passed_test_arg and passed_imagedir_arg:
1896                 print "Options -R and -t can not be used together."
1897                 sys.exit(2)
1898         if not passed_imagedir_arg:
1899                 try:
1900                         image_dir = os.environ["PKG_IMAGE"]
1901                 except KeyError:
1902                         image_dir = os.getcwd()
1903 
1904         if not passed_test_arg:
1905                 packagemanager.setup_progressdialog_show()
1906                 packagemanager.init_sections()
1907                 packagemanager.process_package_list_start(image_dir)
1908         else:
1909                 packagemanager.init_sections()
1910                 packagemanager.fill_with_fake_data()
1911 
1912         packagemanager.init_package_view()        
1913         packagemanager.update_statusbar()
1914         while gtk.events_pending():
1915                 gtk.main_iteration(False)
1916         
1917         # Performance: Start this background thread after progress dialog thread has 
1918         # completed in init_package_view()->self.__setup_data_finished() or GUI will block
1919         if not passed_test_arg:
1920                 Thread(target = packagemanager.get_manifests_for_packages,
1921                         args = ()).start()
1922         main()