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