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 length of the description
41 MAX_INFO_CACHE_LIMIT = 100 # Max number of package descriptions to cache
42 TYPE_AHEAD_DELAY = 600 # Time of the last type in search box after which search is performed
43
44 CLIENT_API_VERSION = 4
45 PKG_CLIENT_NAME = "packagemanager"
46
47 import getopt
48 import os
49 import sys
50 import time
51 import locale
52 import urlparse
53 import socket
54 import gettext
55 from threading import Thread
56 from urllib2 import HTTPError, URLError
57
58 try:
59 import gobject
60 import gnome
61 gobject.threads_init()
62 import gtk
63 import gtk.glade
64 import pygtk
65 pygtk.require("2.0")
66 except ImportError:
67 sys.exit(1)
68 import pkg.client.history as history
69 import pkg.client.image as image
70 import pkg.client.progress as progress
71 import pkg.client.api_errors as api_errors
72 import pkg.client.api as api
73 import pkg.client.retrieve as retrieve
74 import pkg.portable as portable
75 import pkg.gui.repository as repository
76 import pkg.gui.beadmin as beadm
77 import pkg.gui.imageinfo as imageinfo
78 import pkg.gui.installupdate as installupdate
79 import pkg.gui.enumerations as enumerations
80 from pkg.client import global_settings
81
82 # Put _() in the global namespace
83 import __builtin__
84 __builtin__._ = gettext.gettext
85
86 class PackageManager:
87 def __init__(self):
88 self.api_o = None
89 socket.setdefaulttimeout(
256 }
257 dic_progress = \
258 {
259 "on_cancel_progressdialog_clicked": \
260 self.__on_cancel_progressdialog_clicked,
261 }
262 w_tree_main.signal_autoconnect(dic_mainwindow)
263 w_tree_progress.signal_autoconnect(dic_progress)
264 except AttributeError, error:
265 print self._( \
266 'GUI will not respond to any event! %s.' + \
267 'Check declare_signals()') \
268 % error
269
270 self.package_selection = None
271 self.category_list_filter = None
272 self.application_list_filter = None
273 self.application_refilter_id = 0
274 self.in_setup = True
275 self.w_main_window.show_all()
276
277 @staticmethod
278 def __get_new_application_liststore():
279 return gtk.ListStore(
280 gobject.TYPE_BOOLEAN, # enumerations.MARK_COLUMN
281 gtk.gdk.Pixbuf, # enumerations.STATUS_ICON_COLUMN
282 gtk.gdk.Pixbuf, # enumerations.ICON_COLUMN
283 gobject.TYPE_STRING, # enumerations.NAME_COLUMN
284 gobject.TYPE_STRING, # enumerations.INSTALLED_VERSION_COLUMN
285 gobject.TYPE_PYOBJECT, # enumerations.INSTALLED_OBJECT_COLUMN
286 gobject.TYPE_STRING, # enumerations.LATEST_AVAILABLE_COLUMN
287 gobject.TYPE_INT, # enumerations.RATING_COLUMN
288 gobject.TYPE_STRING, # enumerations.DESCRIPTION_COLUMN
289 gobject.TYPE_PYOBJECT, # enumerations.PACKAGE_OBJECT_COLUMN
290 gobject.TYPE_BOOLEAN, # enumerations.IS_VISIBLE_COLUMN
291 gobject.TYPE_PYOBJECT # enumerations.CATEGORY_LIST_OBJECT
292 )
293
294 @staticmethod
295 def __get_new_category_liststore():
296 return gtk.ListStore(
297 gobject.TYPE_INT, # enumerations.CATEGORY_ID
298 gobject.TYPE_STRING, # enumerations.CATEGORY_NAME
299 gobject.TYPE_STRING, # enumerations.CATEGORY_DESCRIPTION
300 gtk.gdk.Pixbuf, # enumerations.CATEGORY_ICON
301 gobject.TYPE_BOOLEAN, # enumerations.CATEGORY_VISIBLE
302 gobject.TYPE_PYOBJECT, # enumerations.SECTION_LIST_OBJECT
303 )
304
305 @staticmethod
306 def __get_new_section_liststore():
307 return gtk.ListStore(
308 gobject.TYPE_INT, # enumerations.SECTION_ID
309 gobject.TYPE_STRING, # enumerations.SECTION_NAME
310 )
311
359 column = gtk.TreeViewColumn(self._("Name"), name_renderer, \
360 text = enumerations.NAME_COLUMN)
361 column.set_resizable(True)
362 column.set_sort_column_id(enumerations.NAME_COLUMN)
363 column.set_sort_indicator(True)
364 column.set_cell_data_func(name_renderer, self.cell_data_function, None)
365 self.w_application_treeview.append_column(column)
366 column = gtk.TreeViewColumn()
367 column.set_title(self._("Status"))
368 #Commented, since there was funny jumping of the icons
369 #column.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
370 render_pixbuf = gtk.CellRendererPixbuf()
371 column.pack_start(render_pixbuf, expand = True)
372 column.add_attribute(render_pixbuf, "pixbuf", \
373 enumerations.STATUS_ICON_COLUMN)
374 column.set_fixed_width(32)
375 column.set_sort_column_id(enumerations.STATUS_ICON_COLUMN)
376 column.set_sort_indicator(True)
377 column.set_cell_data_func(render_pixbuf, self.cell_data_function, None)
378 self.w_application_treeview.append_column(column)
379 installed_version_renderer = gtk.CellRendererText()
380 column = gtk.TreeViewColumn(self._('Installed Version'), \
381 installed_version_renderer, \
382 text = enumerations.INSTALLED_VERSION_COLUMN)
383 column.set_sort_column_id(enumerations.INSTALLED_VERSION_COLUMN)
384 column.set_sort_indicator(True)
385 column.set_cell_data_func(installed_version_renderer, \
386 self.cell_data_function, None)
387 latest_available_renderer = gtk.CellRendererText()
388 column = gtk.TreeViewColumn(self._('Latest Version'), \
389 latest_available_renderer, \
390 text = enumerations.LATEST_AVAILABLE_COLUMN)
391 column.set_sort_column_id(enumerations.LATEST_AVAILABLE_COLUMN)
392 column.set_sort_indicator(True)
393 column.set_cell_data_func(latest_available_renderer, \
394 self.cell_data_function, None)
395 rating_renderer = gtk.CellRendererText()
396 column = gtk.TreeViewColumn(self._('Rating'), rating_renderer, \
397 text = enumerations.RATING_COLUMN)
398 column.set_cell_data_func(rating_renderer, self.cell_data_function, None)
399 description_renderer = gtk.CellRendererText()
400 column = gtk.TreeViewColumn(self._('Description'), \
401 description_renderer, text = enumerations.DESCRIPTION_COLUMN)
402 column.set_resizable(True)
403 column.set_sort_column_id(enumerations.DESCRIPTION_COLUMN)
404 column.set_sort_indicator(True)
405 column.set_cell_data_func(description_renderer, \
406 self.cell_data_function, None)
407 self.w_application_treeview.append_column(column)
408 #Added selection listener
409 self.package_selection = self.w_application_treeview.get_selection()
410
411 ##CATEGORIES TREEVIEW
412 #enumerations.CATEGORY_NAME
413 category_list_filter = category_list.filter_new()
414 enumerations.CATEGORY_NAME_renderer = gtk.CellRendererText()
415 column = gtk.TreeViewColumn(self._('Name'), \
416 enumerations.CATEGORY_NAME_renderer, \
417 text = enumerations.CATEGORY_NAME)
418 self.w_categories_treeview.append_column(column)
463 category_list_filter.set_visible_func(self.category_filter)
464 toggle_renderer.connect('toggled', self.__active_pane_toggle, \
465 application_list_sort)
466 category_selection.connect("changed", \
467 self.__on_category_selection_changed, None)
468 self.package_selection.set_mode(gtk.SELECTION_SINGLE)
469 self.package_selection.connect("changed", \
470 self.__on_package_selection_changed, None)
471 self.first_run = False
472
473 def __disconnect_models(self):
474 self.w_application_treeview.set_model(None)
475 self.w_categories_treeview.set_model(None)
476 self.w_repository_combobox.set_model(None)
477 self.w_sections_combobox.set_model(None)
478 self.w_filter_combobox.set_model(None)
479
480 @staticmethod
481 def __status_sort_func(treemodel, iter1, iter2, user_data=None):
482 get_val = treemodel.get_value
483 lat1 = get_val(iter1, enumerations.LATEST_AVAILABLE_COLUMN)
484 ins1 = get_val(iter1, enumerations.INSTALLED_VERSION_COLUMN)
485 lat2 = get_val(iter2, enumerations.LATEST_AVAILABLE_COLUMN)
486 ins2 = get_val(iter2, enumerations.INSTALLED_VERSION_COLUMN)
487 if ins1 and not ins2:
488 return -1
489 if ins2 and not ins1:
490 return 1
491 if lat1 and not lat2:
492 return -1
493 if lat2 and not lat1:
494 return 1
495 return 0
496
497 @staticmethod
498 def __remove_treeview_columns(treeview):
499 columns = treeview.get_columns()
500 if columns:
501 for column in columns:
502 treeview.remove_column(column)
503
504 def __init_sections(self):
505 '''This function is for initializing sections combo box, also adds "All"
506 Category. It sets active section combobox entry "All"'''
507 self.section_list.append([0, self._('All'), ])
508 self.section_list.append([-1, "", ])
509 self.section_list.append([2, self._('Meta Packages'), ])
510 self.section_list.append([3, self._('Applications'), ])
511 self.section_list.append([4, self._('Desktop (GNOME)'), ])
512 self.section_list.append([5, self._('Development'), ])
513 self.section_list.append([6, self._('Distributions'), ])
514 self.section_list.append([7, self._('Drivers'), ])
515 self.section_list.append([8, self._('System'), ])
537 # XXX if some changes were applied:
538 self.__main_application_quit()
539 return True
540 else:
541 self.__main_application_quit()
542
543 def __on_file_quit_activate(self, widget):
544 ''' handler for quit menu event '''
545 self.__on_mainwindow_delete_event(None, None)
546
547 def __on_edit_repositories_activate(self, widget):
548 ''' handler for repository menu event '''
549 repository.Repository(self)
550
551 def __on_file_be_activate(self, widget):
552 ''' handler for be menu event '''
553 beadm.Beadmin(self)
554
555 def __on_searchentry_changed(self, widget):
556 '''On text search field changed we should refilter the main view'''
557 if self.application_refilter_id != 0:
558 gobject.source_remove(self.application_refilter_id)
559 self.application_refilter_id = 0
560 if self.w_searchentry_dialog.get_text() == "":
561 self.application_refilter_id = \
562 gobject.idle_add(self.__application_refilter)
563 else:
564 self.application_refilter_id = \
565 gobject.timeout_add(TYPE_AHEAD_DELAY, self.__application_refilter)
566
567 def __application_refilter(self):
568 self.application_list_filter.refilter()
569 gobject.idle_add(self.__enable_disable_selection_menus)
570 self.application_refilter_id = 0
571 return False
572
573 def __on_edit_paste(self, widget):
574 self.w_searchentry_dialog.insert_text(self.main_clipboard_text, \
575 self.w_searchentry_dialog.get_position())
576
577 def __on_clear_paste(self, widget):
578 bounds = self.w_searchentry_dialog.get_selection_bounds()
579 self.w_searchentry_dialog.delete_text(bounds[0], bounds[1])
580 return
581
582 def __on_copy(self, widget):
583 bounds = self.w_searchentry_dialog.get_selection_bounds()
584 text = self.w_searchentry_dialog.get_chars(bounds[0], bounds[1])
585 self.w_main_clipboard.set_text(text)
626 self.__enable_disable_install_update()
627 self.__enable_disable_remove()
628
629 def __on_select_updates(self, widget):
630 sort_filt_model = \
631 self.w_application_treeview.get_model() #gtk.TreeModelSort
632 filt_model = sort_filt_model.get_model() #gtk.TreeModelFilter
633 model = filt_model.get_model() #gtk.ListStore
634 iter_next = sort_filt_model.get_iter_first()
635 list_of_paths = []
636 while iter_next != None:
637 sorted_path = sort_filt_model.get_path(iter_next)
638 filtered_iter = sort_filt_model.convert_iter_to_child_iter(None, \
639 iter_next)
640 app_iter = filt_model.convert_iter_to_child_iter(filtered_iter)
641
642 filtered_path = \
643 sort_filt_model.convert_path_to_child_path(sorted_path)
644 path = filt_model.convert_path_to_child_path(filtered_path)
645 if model.get_value(app_iter, \
646 enumerations.INSTALLED_VERSION_COLUMN):
647 if model.get_value(app_iter, \
648 enumerations.LATEST_AVAILABLE_COLUMN):
649 list_of_paths.append(path)
650 iter_next = sort_filt_model.iter_next(iter_next)
651 for path in list_of_paths:
652 itr = model.get_iter(path)
653 model.set_value(itr, enumerations.MARK_COLUMN, True)
654 self.__enable_disable_selection_menus()
655 self.update_statusbar()
656 self.__enable_disable_install_update()
657 self.__enable_disable_remove()
658
659 def __on_deselect(self, widget):
660 sort_filt_model = \
661 self.w_application_treeview.get_model() #gtk.TreeModelSort
662 filt_model = sort_filt_model.get_model() #gtk.TreeModelFilter
663 model = filt_model.get_model() #gtk.ListStore
664 iter_next = sort_filt_model.get_iter_first()
665 list_of_paths = []
666 while iter_next != None:
667 sorted_path = sort_filt_model.get_path(iter_next)
668 filtered_iter = sort_filt_model.convert_iter_to_child_iter(None, \
685 def __on_searchentry_focus_in(self, widget, event):
686 self.w_paste_menuitem.set_sensitive(True)
687
688 def __on_searchentry_focus_out(self, widget, event):
689 self.w_paste_menuitem.set_sensitive(False)
690
691 def __on_searchentry_event(self, widget, event):
692 self.w_main_clipboard.request_text(self.__clipboard_text_received)
693 if widget.get_selection_bounds():
694 #enable selection functions
695 self.w_cut_menuitem.set_sensitive(True)
696 self.w_copy_menuitem.set_sensitive(True)
697 self.w_clear_menuitem.set_sensitive(True)
698 else:
699 self.w_cut_menuitem.set_sensitive(False)
700 self.w_copy_menuitem.set_sensitive(False)
701 self.w_clear_menuitem.set_sensitive(False)
702
703 def __on_category_selection_changed(self, selection, widget):
704 '''This function is for handling category selection changes'''
705 self.application_list_filter.refilter()
706 self.__enable_disable_selection_menus()
707
708 def __on_package_selection_changed(self, selection, widget):
709 '''This function is for handling package selection changes'''
710 model, itr = selection.get_selected()
711 if itr:
712 self.pkginfo_thread += 1
713 self.selected_pkgname = \
714 model.get_value(itr, enumerations.NAME_COLUMN)
715 Thread(target = self.__show_package_info, \
716 args = (model, itr, self.pkginfo_thread)).start()
717 if self.w_info_notebook.get_current_page() == 3:
718 self.__on_notebook_change(None, None, 3)
719
720
721 def __on_filtercombobox_changed(self, widget):
722 '''On filter combobox changed'''
723 if self.in_setup:
724 return
725 self.application_list_filter.refilter()
726 self.__enable_disable_selection_menus()
727
728 def __on_sectionscombobox_changed(self, widget):
729 '''On section combobox changed'''
730 if self.in_setup:
731 return
732 selected_section = widget.get_active()
733 if selected_section == 0:
734 for category in self.category_list:
735 category[enumerations.CATEGORY_VISIBLE] = True
736 else:
737 for category in self.category_list:
738 if category[enumerations.CATEGORY_ID] == 0:
739 category[enumerations.CATEGORY_VISIBLE] = True
740 else:
741 category_list = \
742 category[enumerations.SECTION_LIST_OBJECT]
743 if not category_list:
744 category[enumerations.CATEGORY_VISIBLE] \
745 = False
746 else:
747 for section in category_list:
748 if section == selected_section:
749 category[enumerations. \
750 CATEGORY_VISIBLE] = \
751 True
752 else:
753 category[enumerations. \
754 CATEGORY_VISIBLE] = \
755 False
756 self.category_list_filter.refilter()
757 self.application_list_filter.refilter()
758 self.__enable_disable_selection_menus()
759
760 def __on_repositorycombobox_changed(self, widget):
761 '''On repository combobox changed'''
762 if self.in_setup:
763 return
764 self.application_list_filter.refilter()
765 self.__enable_disable_selection_menus()
766
767 def __on_install_update(self, widget):
768 self.api_o.reset()
769 install_update = []
770 for row in self.application_list:
771 if row[enumerations.MARK_COLUMN]:
772 install_update.append(row[\
773 enumerations.NAME_COLUMN])
774 installupdate.InstallUpdate(install_update, self, \
775 self.api_o, ips_update = False, \
776 action = enumerations.INSTALL_UPDATE)
777
778 def __on_update_all(self, widget):
779 opensolaris_image = True
780 self.progress_stop_timer_thread = False
781 notfound = self.__installed_fmris_from_args(self.api_o, \
782 ["SUNWipkg", "SUNWcs"])
783
784 if notfound:
785 opensolaris_image = False
786
787 if opensolaris_image:
788 # Load the catalogs from the repository, its a long
789 # running tasks so need a progress dialog
790 self.w_progress_dialog.set_title(self._("Update All"))
791 self.w_progressinfo_label.set_text(self._( \
792 "Checking SUNWipkg and SUNWipkg-gui versions\n" \
793 "\nPlease wait ..."))
837 action = enumerations.IMAGE_UPDATE)
838
839 def __on_help_about(self, widget):
840 wTreePlan = gtk.glade.XML(self.gladefile, "aboutdialog")
841 aboutdialog = wTreePlan.get_widget("aboutdialog")
842 aboutdialog.connect("response", lambda x = None, \
843 y = None: aboutdialog.destroy())
844 aboutdialog.run()
845
846 def __on_help_help(self, widget):
847 props = { gnome.PARAM_APP_DATADIR : self.application_dir + \
848 '/usr/share/package-manager/help' }
849 gnome.program_init('package-manager', '0.1', properties=props)
850 gnome.help_display('package-manager')
851
852 def __on_remove(self, widget):
853 self.api_o.reset()
854 remove_list = []
855 for pkg in self.application_list:
856 if pkg[enumerations.MARK_COLUMN] and \
857 pkg[enumerations.INSTALLED_VERSION_COLUMN]:
858 remove_list.append(\
859 pkg[enumerations.NAME_COLUMN])
860 installupdate.InstallUpdate(remove_list, self, \
861 self.api_o, ips_update = False, \
862 action = enumerations.REMOVE)
863
864 def __on_reload(self, widget):
865 if self.description_thread_running:
866 self.cancelled = True
867 self.in_setup = True
868 self.w_progress_dialog.set_title(self._("Refreshing catalogs"))
869 self.w_progressinfo_label.set_text(self._("Refreshing catalogs..."))
870 self.progress_stop_timer_thread = False
871 Thread(target = self.__progressdialog_progress_pulse).start()
872 self.w_progress_dialog.show()
873 self.__disconnect_models()
874 Thread(target = self.__catalog_refresh).start()
875
876 def __catalog_refresh_done(self):
877 self.progress_stop_timer_thread = True
878 #Let the progress_pulse finish. This should be done other way, but at
879 #The moment this works fine
926
927 repositories_list.append([i, repo, ])
928 i = i + 1
929 self.w_repository_combobox.set_model(repositories_list)
930 if default_authority:
931 self.w_repository_combobox.set_active(active)
932 else:
933 self.w_repository_combobox.set_active(0)
934
935 def __active_pane_toggle(self, cell, path, model_sort):
936 '''Toggle function for column enumerations.MARK_COLUMN'''
937 applicationModel = model_sort.get_model()
938 applicationPath = model_sort.convert_path_to_child_path(path)
939 filterModel = applicationModel.get_model()
940 child_path = applicationModel.convert_path_to_child_path(applicationPath)
941 itr = filterModel.get_iter(child_path)
942 if itr:
943 modified = filterModel.get_value(itr, enumerations.MARK_COLUMN)
944 filterModel.set_value(itr, enumerations.MARK_COLUMN, \
945 not modified)
946 latest_available = filterModel.get_value(itr, \
947 enumerations.LATEST_AVAILABLE_COLUMN)
948 installed_available = filterModel.get_value(itr, \
949 enumerations.INSTALLED_VERSION_COLUMN)
950 self.update_statusbar()
951 self.__update_install_update_button(latest_available, modified)
952 self.__update_remove_button(installed_available, modified)
953 self.__enable_disable_selection_menus()
954
955
956 def __update_install_update_button(self, latest_available, toggle_true):
957 if not toggle_true and self.user_rights:
958 if latest_available:
959 self.w_installupdate_button.set_sensitive(True)
960 self.w_installupdate_menuitem.set_sensitive(True)
961 else:
962 available = None
963 for row in self.application_list:
964 if row[enumerations.MARK_COLUMN]:
965 available = \
966 row[enumerations.LATEST_AVAILABLE_COLUMN]
967 if available:
968 return
969 if not available:
970 self.w_installupdate_button.set_sensitive(False)
971 self.w_installupdate_menuitem.set_sensitive(False)
972
973 def __update_reload_button(self):
974 if self.user_rights:
975 self.w_reload_button.set_sensitive(True)
976 else:
977 self.w_reload_button.set_sensitive(False)
978
979 def __update_remove_button(self, installed_available, toggle_true):
980 if not toggle_true and self.user_rights:
981 if installed_available:
982 self.w_remove_button.set_sensitive(True)
983 self.w_remove_menuitem.set_sensitive(True)
984 else:
985 available = None
986 for row in self.application_list:
987 if row[enumerations.MARK_COLUMN]:
988 installed = \
989 row[enumerations.INSTALLED_VERSION_COLUMN]
990 if installed:
991 return
992 if not available:
993 self.w_remove_button.set_sensitive(False)
994 self.w_remove_menuitem.set_sensitive(False)
995
996 def __show_fetching_package_info(self, pkg, icon):
997 pkg_name = pkg.get_name()
998 if icon and icon != pkg:
999 self.w_packageicon_image.set_from_pixbuf(icon)
1000 else:
1001 self.w_packageicon_image.set_from_pixbuf( \
1002 self.__get_pixbuf_from_path("/usr/share/package-manager/", \
1003 "PM_package_36x"))
1004 self.w_packagename_label.set_markup("<b>" + pkg_name + "</b>")
1005
1006 if self.__setting_from_cache(pkg_name):
1007 return
1008
1009 self.w_shortdescription_label.set_text( \
1010 self._("Fetching description..."))
1011 instbuffer = self.w_installedfiles_textview.get_buffer()
1012 depbuffer = self.w_dependencies_textview.get_buffer()
1013 infobuffer = self.w_generalinfo_textview.get_buffer()
1014 instbuffer.set_text(self._("Fetching information..."))
1015 depbuffer.set_text(self._("Fetching information..."))
1016 infobuffer.set_text(self._("Fetching information..."))
1017 return
1018
1019 def __setting_from_cache(self, pkg_name):
1020 if len(self.info_cache) > MAX_INFO_CACHE_LIMIT:
1021 self.info_cache = {}
1022
1023 if self.info_cache.has_key(pkg_name):
1024 self.w_shortdescription_label.set_text(\
1025 self.info_cache[pkg_name][0])
1026 instbuffer = self.w_installedfiles_textview.get_buffer()
1027 depbuffer = self.w_dependencies_textview.get_buffer()
1028 infobuffer = self.w_generalinfo_textview.get_buffer()
1029 infobuffer.set_text(self.info_cache[pkg_name][1])
1030 instbuffer.set_text(self.info_cache[pkg_name][2])
1031 depbuffer.set_text(self.info_cache[pkg_name][3])
1032 return True
1033 else:
1034 return False
1035
1036 def __update_package_info(self, pkg, icon, installed, pkg_info):
1037 pkg_name = pkg.get_name()
1038 if icon and icon != pkg:
1039 self.w_packageicon_image.set_from_pixbuf(icon)
1040 else:
1041 self.w_packageicon_image.set_from_pixbuf( \
1042 self.__get_pixbuf_from_path("/usr/share/package-manager/", \
1043 "PM_package_36x"))
1044 self.w_packagename_label.set_markup("<b>" + pkg_name + "</b>")
1045
1046 if self.__setting_from_cache(pkg_name):
1047 return
1048
1049 instbuffer = self.w_installedfiles_textview.get_buffer()
1050 depbuffer = self.w_dependencies_textview.get_buffer()
1051 infobuffer = self.w_generalinfo_textview.get_buffer()
1052
1053 if not pkg_info:
1054 self.w_shortdescription_label.set_text( \
1055 self._("Description not available for this package..."))
1056 instbuffer.set_text( \
1057 self._("Files Details not available for this package..."))
1058 depbuffer.set_text(self._( \
1059 "Dependencies info not available for this package..."))
1060 infobuffer.set_text( \
1061 self._("Information not available for this package..."))
1062 return
1063 description = pkg_info.summary
1064 #XXX long term need to have something more robust here for multi byte
1065 if len(description) > MAX_DESC_LEN:
1066 description = description[:MAX_DESC_LEN] + " ..."
1087 if pkg_info.files:
1088 inst_str += ''.join(["\t%s\n" % x for x in pkg_info.files])
1089 if pkg_info.hardlinks:
1090 inst_str += ''.join(["\t%s\n" % x for x in pkg_info.hardlinks])
1091 if pkg_info.links:
1092 inst_str += ''.join(["\t%s\n" % x for x in pkg_info.links])
1093
1094 if description:
1095 info_str += self._(" Description:\t%s\n") % description
1096 info_str += self._(" Name:\t\t%s\n") % pkg_name
1097 info_str += self._(" FMRI:\t\t%s\n") % pkg.get_fmri()
1098 info_str += self._(" Version:\t\t%s\n") % \
1099 pkg.version.get_short_version()
1100 info_str += self._(" Packaged:\t%s\n") % \
1101 self.get_datetime(pkg.version)
1102
1103 infobuffer.set_text(info_str)
1104 instbuffer.set_text(inst_str)
1105 depbuffer.set_text(dep_str)
1106
1107 self.info_cache[pkg_name] = \
1108 (description, info_str, inst_str, dep_str)
1109
1110 def __update_package_license(self, licenses):
1111 lic = ""
1112 lic_u = ""
1113 if licenses == None:
1114 lic_u = self._("Not available")
1115 else:
1116 for licens in licenses:
1117 lic += licens.get_text()
1118 lic += "\n"
1119 try:
1120 lic_u = unicode(lic, "utf-8")
1121 except UnicodeDecodeError:
1122 lic_u += ""
1123 licbuffer = self.w_license_textview.get_buffer()
1124 licbuffer.set_text(lic_u)
1125
1126 def __update_description(self, description, package):
1127 '''workaround function'''
1128 for pkg in self.application_list:
1129 p = pkg[enumerations.PACKAGE_OBJECT_COLUMN][0]
1130 if p == package:
1131 pkg[enumerations.DESCRIPTION_COLUMN] = description
1132 return
1133
1134 def __show_package_licenses(self, th_no):
1135 #XXX revisit this and replace with gobject.timer_add() instead of sleep
1136 # sleep for a little time, this is done for the users who are
1137 # fast browsing the list of the packages.
1138 time.sleep(1)
1139 if th_no != self.pkginfo_thread:
1140 return
1141 if self.selected_pkgname == None:
1142 gobject.idle_add(self.__update_package_license, \
1143 None)
1144 return
1145 info = self.api_o.info([self.selected_pkgname], True, True)
1146 pkgs_info = None
1147 package_info = None
1148 no_licenses = 0
1149 if info:
1150 pkgs_info = info[0]
1151 if pkgs_info:
1152 package_info = pkgs_info[0]
1153 if package_info:
1160 gobject.idle_add(self.__update_package_license, \
1161 package_info.licenses)
1162 else:
1163 return
1164
1165 def __get_pkg_info(self, pkg_name, installed):
1166 info = self.api_o.info([pkg_name], installed, get_licenses=False, \
1167 get_action_info=True)
1168 pkgs_info = None
1169 package_info = None
1170 if info:
1171 pkgs_info = info[0]
1172 if pkgs_info:
1173 package_info = pkgs_info[0]
1174 if package_info:
1175 return package_info
1176 else:
1177 return
1178
1179 def __show_package_info(self, model, itr, th_no):
1180 pkg = model.get_value(itr, enumerations.INSTALLED_OBJECT_COLUMN)
1181 icon = model.get_value(itr, enumerations.INSTALLED_OBJECT_COLUMN)
1182 installed = False
1183 if not pkg:
1184 packages = model.get_value(itr, \
1185 enumerations.PACKAGE_OBJECT_COLUMN)
1186 pkg = max(packages)
1187 gobject.idle_add( \
1188 self.__show_fetching_package_info, pkg, icon)
1189 else:
1190 gobject.idle_add( \
1191 self.__show_fetching_package_info, pkg, icon)
1192 installed = True
1193
1194 if self.info_cache.has_key(pkg.get_name()):
1195 return
1196
1197 # sleep for a little time, this is done for the users which are
1198 # fast browsing the list of the packages.
1199 time.sleep(1)
1200 if th_no != self.pkginfo_thread:
1201 return
1202 man = None
1203 img = self.api_o.img
1204 img.history.operation_name = "info"
1205
1206 pkg_info = self.__get_pkg_info(pkg.get_name(), installed)
1207 if th_no == self.pkginfo_thread:
1208 if not pkg:
1209 gobject.idle_add(self.__update_package_info, pkg, icon, \
1210 installed, pkg_info)
1211 else:
1212 gobject.idle_add(self.__update_package_info, pkg, icon, \
1213 installed, pkg_info)
1214 img.history.operation_result = \
1215 history.RESULT_SUCCEEDED
1216 else:
1217 img.history.operation_result = \
1218 history.RESULT_SUCCEEDED
1219 return
1220
1221 # This function is ported from pkg.actions.generic.distinguished_name()
1222 def __locale_distinguished_name(self, action):
1223 if action.key_attr == None:
1224 return str(action)
1225 return "%s: %s" % \
1226 (self._(action.name), action.attrs.get(action.key_attr, "???"))
1227
1228 def __application_filter(self, model, itr):
1229 '''This function is used to filter content in the main
1230 application view'''
1231 if self.in_setup or self.cancelled:
1232 return False
1233 # XXX Show filter, chenge text to integers
1234 selected_category = 0
1235 selection = self.w_categories_treeview.get_selection()
1236 category_model, category_iter = selection.get_selected()
1237 if not category_iter: #no category was selected, so select "All"
1238 selection.select_path(0)
1239 category_model, category_iter = selection.get_selected()
1240 if category_iter:
1241 selected_category = category_model.get_value(category_iter, \
1242 enumerations.CATEGORY_ID)
1243 category_list_iter = model.get_value(itr, \
1244 enumerations.CATEGORY_LIST_OBJECT)
1245 category = False
1246 repo = self.__is_pkg_repository_visible(model, itr)
1247 if category_list_iter:
1248 sel = False
1249 for category_iter in category_list_iter:
1250 if category != True:
1251 category = \
1252 self.category_filter(self.category_list, \
1253 category_iter)
1254 if selected_category != 0:
1255 if selected_category == \
1256 self.category_list.get_value(category_iter, \
1257 enumerations.CATEGORY_ID):
1258 sel = True
1259 category = sel
1260 else:
1261 if selected_category == 0:
1262 selected_section = self.w_sections_combobox.get_active()
1263 if selected_section == 0:
1264 category = True
1272 model.get_value \
1273 (itr, enumerations.NAME_COLUMN).lower():
1274 return (repo & category & \
1275 self.__is_package_filtered(model, itr))
1276 if not model.get_value(itr, enumerations.DESCRIPTION_COLUMN) == None:
1277 if self.w_searchentry_dialog.get_text().lower() in \
1278 model.get_value \
1279 (itr, enumerations.DESCRIPTION_COLUMN).lower():
1280 return (repo & category & \
1281 self.__is_package_filtered(model, itr))
1282 else:
1283 return False
1284
1285 def __is_package_filtered(self, model, itr):
1286 '''Function for filtercombobox'''
1287 # XXX Instead of string comparison, we should do it through integers.
1288 # XXX It should be faster and better for localisations.
1289 filter_text = self.w_filter_combobox.get_active()
1290 if filter_text == 0:
1291 return True
1292 elif filter_text == 2:
1293 return model.get_value(itr, \
1294 enumerations.INSTALLED_VERSION_COLUMN) != None
1295 elif filter_text == 3:
1296 return (model.get_value(itr, \
1297 enumerations.INSTALLED_VERSION_COLUMN) != None) & \
1298 (model.get_value(itr, \
1299 enumerations.LATEST_AVAILABLE_COLUMN) != None)
1300 elif filter_text == 4:
1301 return not model.get_value(itr, \
1302 enumerations.INSTALLED_VERSION_COLUMN) != None
1303 elif filter_text == 6:
1304 return model.get_value(itr, enumerations.MARK_COLUMN)
1305 elif filter_text == 8:
1306 # XXX Locked support
1307 return False
1308
1309
1310 def __is_pkg_repository_visible(self, model, itr):
1311 if len(self.repositories_list) <= 1:
1312 return True
1313 else:
1314 auth_iter = self.w_repository_combobox.get_active_iter()
1315 authority = self.repositories_list.get_value(auth_iter, \
1316 enumerations.REPOSITORY_NAME)
1317 packages = model.get_value(itr, \
1318 enumerations.PACKAGE_OBJECT_COLUMN)
1319 if not packages:
1320 return False
1321 pkg = max(packages)
1322 if cmp(pkg.get_authority(), authority) == 0:
1323 return True
1324 else:
1325 return False
1326
1327 def __do_ips_uptodate_check(self):
1328 ret = self.__catalog_refresh(False)
1329 if ret != -1:
1330 self.ips_uptodate = self.__ipkg_ipkgui_uptodate()
1331 else:
1332 self.progress_canceled = True
1333 self.progress_stop_timer_thread = True
1334
1335 def __ipkg_ipkgui_uptodate(self):
1336 self.api_o.reset()
1337 list_of_packages = [self.ipkg_fmri, self.ipkggui_fmri]
1338 ret = True
1339 try:
1340 upgrade_needed, cre = self.api_o.plan_install(
1341 list_of_packages, filters = [])
1358 self.__enable_disable_deselect()
1359 # XXX disabled until new API
1360 self.__enable_disable_update_all()
1361
1362 def __enable_disable_select_all(self):
1363
1364 if self.in_setup:
1365 return
1366 if len(self.w_application_treeview.get_model()) > 0:
1367 for row in self.w_application_treeview.get_model():
1368 if not row[enumerations.MARK_COLUMN]:
1369 self.w_selectall_menuitem.set_sensitive(True)
1370 return
1371 self.w_selectall_menuitem.set_sensitive(False)
1372 else:
1373 self.w_selectall_menuitem.set_sensitive(False)
1374
1375 def __enable_disable_install_update(self):
1376 for row in self.application_list:
1377 if row[enumerations.MARK_COLUMN]:
1378 if row[enumerations.LATEST_AVAILABLE_COLUMN] and \
1379 self.user_rights:
1380 self.w_installupdate_button.set_sensitive(True)
1381 self.w_installupdate_menuitem.set_sensitive(True)
1382 return
1383 self.w_installupdate_button.set_sensitive(False)
1384 self.w_installupdate_menuitem.set_sensitive(False)
1385
1386 def __enable_disable_remove(self):
1387 for row in self.application_list:
1388 if row[enumerations.MARK_COLUMN]:
1389 if row[enumerations.INSTALLED_VERSION_COLUMN] and \
1390 self.user_rights:
1391 self.w_remove_button.set_sensitive(True)
1392 self.w_remove_menuitem.set_sensitive(True)
1393 return
1394 self.w_remove_button.set_sensitive(False)
1395 self.w_remove_menuitem.set_sensitive(False)
1396
1397 def __enable_disable_select_updates(self):
1398 for row in self.w_application_treeview.get_model():
1399 if row[enumerations.INSTALLED_VERSION_COLUMN]:
1400 if row[enumerations.LATEST_AVAILABLE_COLUMN]:
1401 if not row[enumerations.MARK_COLUMN]:
1402 self.w_selectupdates_menuitem. \
1403 set_sensitive(True)
1404 return
1405 self.w_selectupdates_menuitem.set_sensitive(False)
1406 return
1407
1408 def __enable_disable_update_all(self):
1409 for row in self.application_list:
1410 if self.__is_pkg_repository_visible(self.application_list, \
1411 row.iter):
1412 if self.application_list.get_value(row.iter, \
1413 enumerations.INSTALLED_VERSION_COLUMN):
1414 if self.application_list.get_value(row.iter, \
1415 enumerations.LATEST_AVAILABLE_COLUMN) and \
1416 self.user_rights:
1417 self.w_updateall_menuitem. \
1418 set_sensitive(True)
1419 self.w_updateall_button. \
1420 set_sensitive(True)
1421 return
1422 self.w_updateall_button.set_sensitive(False)
1423 self.w_updateall_menuitem.set_sensitive(False)
1424
1425 def __enable_disable_deselect(self):
1426 for row in self.w_application_treeview.get_model():
1427 if row[enumerations.MARK_COLUMN]:
1428 self.w_deselect_menuitem.set_sensitive(True)
1429 return
1430 self.w_deselect_menuitem.set_sensitive(False)
1431 return
1432
1433
1434 def __catalog_refresh(self, reload_gui=True):
1435 """Update image's catalogs."""
1436 full_refresh = True
1437 try:
1438 self.api_o.refresh(full_refresh)
1439 self.api_o.img.load_catalogs(self.pr)
1440 except api_errors.UnrecognizedAuthorityException:
1441 # In current implementation, this will never happen
1442 # We are not refrehsing specific authority
1443 self.__catalog_refresh_done()
1444 raise
1445 except api_errors.PermissionsException, pe:
1446 #Error will already have been reported in
1447 #Manage Repository dialog
1448 self.__catalog_refresh_done()
1449 return -1
1450 except api_errors.CatalogRefreshException, cre:
1451 total = cre.total
1452 succeeded = cre.succeeded
1453 ermsg = self._("Network problem.\n\n")
1454 ermsg += self._("Details:\n")
1455 ermsg += "%s/%s" % (succeeded, total)
1456 ermsg += self._(" catalogs successfully updated:\n")
1457 for auth, err in cre.failed:
1458 if isinstance(err, HTTPError):
1459 ermsg += " %s: %s - %s\n" % \
1460 (err.filename, err.code, err.msg)
1461 elif isinstance(err, URLError):
1462 if err.args[0][0] == 8:
1463 ermsg += " %s: %s\n" % \
1464 (urlparse.urlsplit(
1465 auth["origin"])[1].split(":")[0],
1483 None, gtk.MESSAGE_INFO)
1484 self.__catalog_refresh_done()
1485 return -1
1486
1487 except api_errors.UnrecognizedAuthorityException:
1488 self.__catalog_refresh_done()
1489 raise
1490 except Exception:
1491 self.__catalog_refresh_done()
1492 raise
1493 if reload_gui:
1494 self.__catalog_refresh_done()
1495 return 0
1496
1497 def __get_image_from_directory(self, api_o, progressdialog_progress):
1498 """ This method set up image from the given directory and
1499 returns the image object or None"""
1500 application_list = self.__get_new_application_liststore()
1501 category_list = self.__get_new_category_liststore()
1502 repositories_list = self.__get_new_repositories_liststore()
1503
1504 try:
1505 pkgs_known = [ pf[0] for pf in
1506 sorted(api_o.img.inventory(all_known = True)) ]
1507 except api_errors.InventoryException:
1508 # Can't happen when all_known is true and no args,
1509 # but here for completeness.
1510 err = self._("Error occured while getting list of packages")
1511 gobject.idle_add(self.w_progress_dialog.hide)
1512 gobject.idle_add(self.error_occured, err)
1513 return
1514
1515 #Only one instance of those icons should be in memory
1516 update_available_icon = self.get_icon_pixbuf("status_newupdate")
1517 installed_icon = self.get_icon_pixbuf("status_installed")
1518 #Imageinfo for categories
1519 imginfo = imageinfo.ImageInfo()
1520 sectioninfo = imageinfo.ImageInfo()
1521 catalogs = api_o.img.catalogs
1522 categories = {}
1523 sections = {}
1524 share_path = "/usr/share/package-manager/data/"
1525 for cat in catalogs:
1526 category = imginfo.read(self.application_dir + \
1527 share_path + cat)
1528 if len(category) == 0:
1529 category = imginfo.read(self.application_dir + \
1530 share_path + "opensolaris.org")
1531 categories[cat] = category
1532 section = sectioninfo.read(self.application_dir + \
1533 share_path + cat + ".sections")
1534 if len(section) == 0:
1535 section = sectioninfo.read(self.application_dir + \
1536 share_path + "opensolaris.org.sections")
1537 sections[cat] = section
1538 # Speedup, instead of checking if the pkg is already in the list,
1539 # iterating through all elements, we will only compare to the previous
1540 # package and if the package is the same (version difference) then we
1541 # are adding to the first iterator for the set of those packages.
1542 # We can do that, since the list pkgs_known is sorted
1543 # This will give a sppedup from 18sec to ~3!!!
1544 p_pkg_iter = None
1545 p_pkg = None
1546 insert_count = 0
1547 icon_path = self.application_dir + \
1548 "/usr/share/package-manager/data/pixmaps/"
1549
1550 pkg_count = 0
1551 progress_percent = INITIAL_PROGRESS_TOTAL_PERCENTAGE
1552 total_pkg_count = len(pkgs_known)
1553 progress_increment = \
1554 total_pkg_count / PACKAGE_PROGRESS_TOTAL_INCREMENTS
1555
1556 self.progress_stop_timer_thread = True
1557 while gtk.events_pending():
1558 gtk.main_iteration(False)
1559 for pkg in pkgs_known:
1560 if progress_increment > 0 and pkg_count % progress_increment == 0:
1561 progress_percent += PACKAGE_PROGRESS_PERCENT_INCREMENT
1562 if progress_percent <= PACKAGE_PROGRESS_PERCENT_TOTAL:
1563 progressdialog_progress(progress_percent, \
1564 pkg_count, total_pkg_count)
1565 while gtk.events_pending():
1566 gtk.main_iteration(False)
1567 pkg_count += 1
1568
1569 #speedup hack, check only last package
1570 already_in_model = \
1571 self.check_if_pkg_have_row_in_model(pkg, p_pkg)
1572 if not already_in_model: #Create new row
1573 available_version = None
1574 version_installed = None
1575 status_icon = None
1576 fmris = [pkg, ]
1577 package_installed = \
1578 self.get_installed_version(api_o, pkg)
1579 if package_installed:
1580 version_installed = \
1581 package_installed.version.get_short_version()
1582 #HACK, sometimes the package is installed but
1583 #it's not in the pkgs_known
1584 status_icon = installed_icon
1585 if package_installed != pkg:
1586 fmris.append(package_installed)
1587 else:
1588 dt = self.get_datetime(pkg.version)
1589 dt_str = (":%02d%02d") % (dt.month, dt.day)
1590 available_version = \
1591 pkg.version.get_short_version() + dt_str
1592 package_icon = self.__get_pixbuf_from_path(icon_path, \
1593 pkg.get_name())
1594 app = \
1595 [
1596 False, status_icon, package_icon, pkg.get_name(),
1597 version_installed, package_installed,
1598 available_version, -1, '...', fmris,
1599 True, None
1600 ]
1601 # XXX Small hack, if this is not applied, first package
1602 # is listed twice. Insert is ~0.5 sec faster than append
1603 if insert_count == 0:
1604 row_iter = application_list.append(app)
1605 else:
1606 row_iter = \
1607 application_list.insert(insert_count, \
1608 app)
1609 # XXX Do not iterate through all the catalogs. Package
1610 # should know what is package fmri prefix?
1611 apc = self.__add_package_to_category
1612 app_ls = application_list
1613 for cat in categories:
1614 if cat in categories:
1615 name = pkg.get_name()
1616 if name in categories[cat]:
1617 pkg_categories = \
1618 categories[cat][ \
1619 name]
1620 for pcat in \
1621 pkg_categories.split(","):
1622 if pcat:
1623 apc(self._( \
1624 pcat), None \
1625 , None, \
1626 row_iter, \
1627 app_ls, \
1628 category_list)
1629 insert_count = insert_count + 1
1630 p_pkg_iter = row_iter
1631 p_pkg = pkg #The current become previous
1632 else:
1633 # XXX check versions in here. For all installed/not
1634 # installed:
1635 # if there is newer version, put it in the available
1636 # field.
1637 #
1638 # XXXhack, since image_get_version_installed(pkg) is not
1639 # working,as it should. For example package:
1640 # SUNWarc@0.5.11,5.11-0.79:20080205T152309Z
1641 # is not installed and it's newer version of installed
1642 # package:
1643 # SUNWarc@0.5.11,5.11-0.75:20071114T201151Z
1644 # the function returns only proper installed version for
1645 # the older package and None for the newer.
1646 # The hack is a little bit slow since we are iterating
1647 # for all known packages
1648 list_of_pkgs = \
1649 application_list.get_value(p_pkg_iter, \
1650 enumerations.PACKAGE_OBJECT_COLUMN)
1651 if pkg not in list_of_pkgs:
1652 list_of_pkgs.append(pkg)
1653 installed = application_list.get_value(p_pkg_iter, \
1654 enumerations.INSTALLED_OBJECT_COLUMN)
1655 latest = max(list_of_pkgs)
1656 dt = self.get_datetime(latest.version)
1657 dt_str = (":%02d%02d") % (dt.month, dt.day)
1658 if not installed:
1659 application_list.set_value(p_pkg_iter, \
1660 enumerations.LATEST_AVAILABLE_COLUMN, \
1661 latest.version.get_short_version() + \
1662 dt_str)
1663 else:
1664 if installed < latest:
1665 application_list.set_value( \
1666 p_pkg_iter, \
1667 enumerations. \
1668 LATEST_AVAILABLE_COLUMN, \
1669 latest.version.get_short_version() + \
1670 dt_str)
1671 application_list.set_value(\
1672 p_pkg_iter, \
1673 enumerations.STATUS_ICON_COLUMN, \
1674 update_available_icon)
1675 # XXX How to get descriptions without manifest?
1676 # XXX Downloading manifest is slow and can not work without
1677 # XXX Network connection
1678 #if not image_obj.has_manifest(pkg):
1679 # image_obj.get_manifest(pkg)#verify(pkg, pr)
1680 #installed_version = None
1681 #package_iter = None #the iterator which points for other package
1682 for authority in sections:
1683 for section in sections[authority]:
1684 for category in sections[authority][section].split(","):
1685 self.__add_category_to_section(self._(category), \
1686 self._(section), category_list)
1687
1688 #1915 Sort the Categories into alphabetical order and prepend All Category
1689 if len(category_list) > 0:
1690 rows = [tuple(r) + (i,) for i, r in enumerate(category_list)]
1691 rows.sort(self.__sort)
1692 r = []
1693 category_list.reorder([r[-1] for r in rows])
1694 category_list.prepend([0, self._('All'), None, None, True, None])
1695
1696 progressdialog_progress(PACKAGE_PROGRESS_PERCENT_TOTAL, pkg_count, \
1697 total_pkg_count)
1698 gobject.idle_add(self.process_package_list_end, api_o, \
1699 application_list, category_list, repositories_list)
1700
1701 def __add_package_to_category(self, category_name, category_description, \
1702 category_icon, package, application_list, category_list):
1703 if not package or category_name == self._('All'):
1704 return
1705 if not category_name:
1706 return
1707 # XXX check if needed
1708 # category_name = self._('All')
1709 # category_description = self._('All packages')
1710 # category_icon = None
1711 category_ref = None
1712 for category in category_list:
1713 if category[enumerations.CATEGORY_NAME] == category_name:
1714 category_ref = category.iter
1715 if not category_ref: # Category not exists
1716 category_ref = category_list.append([len( \
1717 category_list)+1, category_name, category_description, \
1718 category_icon, True, None])
1719 if category_ref:
1720 if application_list.get_value(package, \
1721 enumerations.CATEGORY_LIST_OBJECT):
1722 a = application_list.get_value(package, \
1723 enumerations.CATEGORY_LIST_OBJECT)
1724 a.append(category_ref)
1725 else:
1726 category_list = []
1727 category_list.append(category_ref)
1728 application_list.set(package, \
1729 enumerations.CATEGORY_LIST_OBJECT, category_list)
1730
1731 def __add_category_to_section(self, category_name, section_name, category_list):
1732 '''Adds the section to section list in category. If there is no such
1733 section, than it is not added. If there was already section than it
1734 is skipped. Sections must be case sensitive'''
1735 if not category_name:
1736 return
1737 for section in self.section_list:
1738 if section[enumerations.SECTION_NAME] == section_name:
1739 for category in category_list:
1740 if category[enumerations.CATEGORY_NAME] == \
1741 category_name:
1742 if not category[ \
1743 enumerations.SECTION_LIST_OBJECT]:
1744 category[ \
1745 enumerations. \
1746 SECTION_LIST_OBJECT] = \
1747 [section[ \
1748 enumerations.SECTION_ID], ]
1749 else:
1854 @staticmethod
1855 def cell_data_function(column, renderer, model, itr, data):
1856 '''Function which sets the background colour to black if package is
1857 selected'''
1858 if itr:
1859 if model.get_value(itr, enumerations.MARK_COLUMN):
1860 renderer.set_property("cell-background", "#ffe5cc")
1861 renderer.set_property("cell-background-set", True)
1862 else:
1863 renderer.set_property("cell-background-set", False)
1864
1865 @staticmethod
1866 def combobox_separator(model, itr):
1867 return model.get_value(itr, enumerations.FILTER_NAME) == ""
1868
1869 @staticmethod
1870 def combobox_id_separator(model, itr):
1871 return model.get_value(itr, 0) == -1
1872
1873 @staticmethod
1874 def check_if_pkg_have_row_in_model(pkg, p_pkg):
1875 """Returns True if package is already in model or False if not"""
1876 if p_pkg:
1877 if pkg.is_same_pkg(p_pkg):
1878 return True
1879 else:
1880 return False
1881 return False
1882
1883 @staticmethod
1884 def category_filter(model, itr):
1885 '''This function filters category in the main application view'''
1886 return model.get_value(itr, enumerations.CATEGORY_VISIBLE)
1887
1888 @staticmethod
1889 def get_datetime(version):
1890 dt = None
1891 try:
1892 dt = version.get_datetime()
1893 except AttributeError:
1894 dt = version.get_timestamp()
1895 return dt
1896
1897 @staticmethod
1898 def get_installed_version(api_o, pkg):
1899 return api_o.img.get_version_installed(pkg)
1900
1901 @staticmethod
1902 def get_manifest(img, package, filtered = True):
1903 '''helper function'''
1928 # Public Methods
1929 #-----------------------------------------------------------------------------#
1930 def setup_progressdialog_show(self):
1931 self.w_progress_dialog.set_title(self._("Loading Repository Information"))
1932 self.w_progressinfo_label.set_text(
1933 self._( "Fetching package entries ..."))
1934 self.w_progress_cancel.hide()
1935 self.w_progress_dialog.show()
1936 Thread(target = self.__progressdialog_progress_time).start()
1937
1938 def init_sections(self):
1939 self.__init_sections() #Initiates sections
1940
1941 def init_show_filter(self):
1942 self.__init_show_filter() #Initiates filter
1943
1944 def reload_packages(self):
1945 self.api_o = self.__get_api_object(self.image_directory, self.pr)
1946 self.__on_reload(None)
1947
1948 def process_package_list_start(self, image_directory):
1949 self.cancelled = True
1950 self.setup_progressdialog_show()
1951 while gtk.events_pending():
1952 gtk.main_iteration(False)
1953 self.image_directory = image_directory
1954 # Create our image object based on image directory.
1955 api_o = self.__get_api_object(image_directory, self.pr)
1956 api_o.img.load_catalogs(self.pr)
1957 self.api_o = api_o
1958 # Acquire image contents and update progress bar as you do so.
1959 Thread(target = self.__get_image_from_directory, args = (api_o,
1960 self.__progressdialog_progress_percent)).start()
1961
1962 @staticmethod
1963 def __get_api_object(img_dir, progtrack):
1964 api_o = None
1965 try:
1966 api_o = api.ImageInterface(img_dir, \
1967 CLIENT_API_VERSION, \
1991 self.w_progress_dialog.hide()
1992
1993 def __get_manifests_thread(self):
1994 Thread(target = self.get_manifests_for_packages,
1995 args = ()).start()
1996
1997 def get_icon_pixbuf(self, icon_name):
1998 #2821: The get_icon_pixbuf should use PACKAGE_MANAGER_ROOT
1999 return self.__get_pixbuf_from_path(self.application_dir + \
2000 "/usr/share/icons/package-manager/", icon_name)
2001
2002 def get_manifests_for_packages(self):
2003 ''' Function, which get's manifest for packages. If the manifest is not
2004 locally tries to retrieve it. For installed packages gets manifest
2005 for the particular version (local operation only), if the package is
2006 not installed than the newest one'''
2007 time.sleep(3)
2008 count = 0
2009 self.description_thread_running = True
2010 img = self.api_o.img
2011 img.history.operation_name = "info"
2012 for pkg in self.application_list:
2013 if self.cancelled:
2014 self.description_thread_running = False
2015 return
2016 info = None
2017 img = self.api_o.img
2018 package = pkg[enumerations.INSTALLED_OBJECT_COLUMN]
2019 if (img and package):
2020 man = self.get_manifest(img, package, filtered = True)
2021 if man:
2022 info = man.get("description", "")
2023 elif img:
2024 newest = max( \
2025 pkg[enumerations.PACKAGE_OBJECT_COLUMN])
2026 man = self.get_manifest(img, newest, \
2027 filtered = True)
2028 if man:
2029 info = man.get("description", "")
2030 gobject.idle_add(self.update_desc, info, pkg)
2031 count += 1
2032 if count % 2 == 0:
2033 time.sleep(0.001)
2034 img.history.operation_name = "info"
2035 img = self.api_o.img
2036 img.history.operation_result = history.RESULT_SUCCEEDED
2037 self.description_thread_running = False
2038
2039 def update_statusbar(self):
2040 '''Function which updates statusbar'''
2041 installed = 0
2042 selected = 0
2043 broken = 0
2044 for pkg in self.application_list:
2045 if pkg[enumerations.INSTALLED_VERSION_COLUMN]:
2046 installed = installed + 1
2047 if pkg[enumerations.MARK_COLUMN]:
2048 selected = selected + 1
2049 listed_str = self._('%d packages listed') % len(self.application_list)
2050 inst_str = self._('%d installed') % installed
2051 sel_str = self._('%d selected') % selected
2052 broken_str = self._('%d broken') % broken
2053 self.w_main_statusbar.push(0, listed_str + ', ' + inst_str + ', ' + \
2054 sel_str + ', ' + broken_str + '.')
2055
2056
2057 def update_package_list(self, update_list):
2058 img = self.api_o.img
2059 img.clear_pkg_state()
2060 img.load_catalogs(self.pr)
2061 installed_icon = self.get_icon_pixbuf("status_installed")
2062 for row in self.application_list:
2063 status_icon = None
2064 if row[enumerations.MARK_COLUMN] or \
2065 row[enumerations.NAME_COLUMN] in update_list:
2066 pkg = row[enumerations.PACKAGE_OBJECT_COLUMN][0]
2067 package_installed = \
2068 self.get_installed_version(self.api_o, pkg)
2069 version_installed = None
2070 if package_installed:
2071 status_icon = installed_icon
2072 version_installed = \
2073 package_installed.version.get_short_version()
2074 row[enumerations.MARK_COLUMN] = False
2075 row[enumerations.INSTALLED_VERSION_COLUMN] = \
2076 version_installed
2077 row[enumerations.INSTALLED_OBJECT_COLUMN] = \
2078 package_installed
2079 row[enumerations.STATUS_ICON_COLUMN] = \
2080 status_icon
2081 if not package_installed:
2082 pkg = max(row[enumerations.PACKAGE_OBJECT_COLUMN])
2083 dt = self.get_datetime(pkg.version)
2084 dt_str = (":%02d%02d") % (dt.month, dt.day)
2085 available_version = \
2086 pkg.version.get_short_version() + dt_str
2087 row[enumerations.LATEST_AVAILABLE_COLUMN] = \
2088 available_version
2089 else:
2090 row[enumerations.LATEST_AVAILABLE_COLUMN] = None
2091 self.w_installupdate_button.set_sensitive(False)
2092 self.w_installupdate_menuitem.set_sensitive(False)
2093 self.w_remove_button.set_sensitive(False)
2094 self.w_remove_menuitem.set_sensitive(False)
2095 self.__enable_disable_selection_menus()
2096 self.update_statusbar()
2097
2098 def shutdown_after_ips_update(self):
2099
2100 # 2790: As IPS and IPS-GUI have been updated the IPS GUI must be shutdown
2101 # and restarted
2102 msgbox = gtk.MessageDialog(parent = self.w_main_window, \
2103 buttons = gtk.BUTTONS_OK, \
2104 flags = gtk.DIALOG_MODAL, type = gtk.MESSAGE_INFO, \
2105 message_format = self._("SUNWipkg and SUNWipkg-gui have been " \
2106 "updated and Package Manager will now be restarted.\n\nAfter " \
2107 "restart select Update All to continue."))
2108 msgbox.set_title(self._("Update All"))
2109 msgbox.run()
2110 msgbox.destroy()
|
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 length of the description
41 MAX_INFO_CACHE_LIMIT = 100 # Max number of package descriptions to cache
42 TYPE_AHEAD_DELAY = 600 # The last type in search box after which search is performed
43
44 CLIENT_API_VERSION = 4
45 PKG_CLIENT_NAME = "packagemanager"
46
47 import getopt
48 import os
49 import sys
50 import time
51 import locale
52 import urlparse
53 import socket
54 import gettext
55 from threading import Thread
56 from urllib2 import HTTPError, URLError
57
58 try:
59 import gobject
60 import gnome
61 gobject.threads_init()
62 import gtk
63 import gtk.glade
64 import pygtk
65 pygtk.require("2.0")
66 except ImportError:
67 sys.exit(1)
68 import pkg.client.history as history
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 # Put _() in the global namespace
82 import __builtin__
83 __builtin__._ = gettext.gettext
84
85 class PackageManager:
86 def __init__(self):
87 self.api_o = None
88 socket.setdefaulttimeout(
255 }
256 dic_progress = \
257 {
258 "on_cancel_progressdialog_clicked": \
259 self.__on_cancel_progressdialog_clicked,
260 }
261 w_tree_main.signal_autoconnect(dic_mainwindow)
262 w_tree_progress.signal_autoconnect(dic_progress)
263 except AttributeError, error:
264 print self._( \
265 'GUI will not respond to any event! %s.' + \
266 'Check declare_signals()') \
267 % error
268
269 self.package_selection = None
270 self.category_list_filter = None
271 self.application_list_filter = None
272 self.application_refilter_id = 0
273 self.in_setup = True
274 self.w_main_window.show_all()
275 gdk_win = self.w_main_window.get_window()
276 self.gdk_window = gtk.gdk.Window(gdk_win, gtk.gdk.screen_width(),
277 gtk.gdk.screen_height(), gtk.gdk.WINDOW_CHILD, 0, gtk.gdk.INPUT_ONLY)
278 gdk_cursor = gtk.gdk.Cursor(gtk.gdk.WATCH)
279 self.gdk_window.set_cursor(gdk_cursor)
280
281 @staticmethod
282 def __get_new_application_liststore():
283 return gtk.ListStore(
284 gobject.TYPE_BOOLEAN, # enumerations.MARK_COLUMN
285 gtk.gdk.Pixbuf, # enumerations.STATUS_ICON_COLUMN
286 gtk.gdk.Pixbuf, # enumerations.ICON_COLUMN
287 gobject.TYPE_STRING, # enumerations.NAME_COLUMN
288 gobject.TYPE_STRING, # enumerations.DESCRIPTION_COLUMN
289 gobject.TYPE_INT, # enumerations.STATUS_COLUMN
290 gobject.TYPE_PYOBJECT, # enumerations.FMRI_COLUMN
291 gobject.TYPE_STRING, # enumerations.STEM_COLUMN
292 gobject.TYPE_STRING, # enumerations.DISPLAY_NAME_COLUMN
293 gobject.TYPE_BOOLEAN, # enumerations.IS_VISIBLE_COLUMN
294 gobject.TYPE_PYOBJECT # enumerations.CATEGORY_LIST_COLUMN
295 )
296
297 @staticmethod
298 def __get_new_category_liststore():
299 return gtk.ListStore(
300 gobject.TYPE_INT, # enumerations.CATEGORY_ID
301 gobject.TYPE_STRING, # enumerations.CATEGORY_NAME
302 gobject.TYPE_STRING, # enumerations.CATEGORY_DESCRIPTION
303 gtk.gdk.Pixbuf, # enumerations.CATEGORY_ICON
304 gobject.TYPE_BOOLEAN, # enumerations.CATEGORY_VISIBLE
305 gobject.TYPE_PYOBJECT, # enumerations.SECTION_LIST_OBJECT
306 )
307
308 @staticmethod
309 def __get_new_section_liststore():
310 return gtk.ListStore(
311 gobject.TYPE_INT, # enumerations.SECTION_ID
312 gobject.TYPE_STRING, # enumerations.SECTION_NAME
313 )
314
362 column = gtk.TreeViewColumn(self._("Name"), name_renderer, \
363 text = enumerations.NAME_COLUMN)
364 column.set_resizable(True)
365 column.set_sort_column_id(enumerations.NAME_COLUMN)
366 column.set_sort_indicator(True)
367 column.set_cell_data_func(name_renderer, self.cell_data_function, None)
368 self.w_application_treeview.append_column(column)
369 column = gtk.TreeViewColumn()
370 column.set_title(self._("Status"))
371 #Commented, since there was funny jumping of the icons
372 #column.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
373 render_pixbuf = gtk.CellRendererPixbuf()
374 column.pack_start(render_pixbuf, expand = True)
375 column.add_attribute(render_pixbuf, "pixbuf", \
376 enumerations.STATUS_ICON_COLUMN)
377 column.set_fixed_width(32)
378 column.set_sort_column_id(enumerations.STATUS_ICON_COLUMN)
379 column.set_sort_indicator(True)
380 column.set_cell_data_func(render_pixbuf, self.cell_data_function, None)
381 self.w_application_treeview.append_column(column)
382 description_renderer = gtk.CellRendererText()
383 column = gtk.TreeViewColumn(self._('Description'), \
384 description_renderer, text = enumerations.DESCRIPTION_COLUMN)
385 column.set_resizable(True)
386 column.set_sort_column_id(enumerations.DESCRIPTION_COLUMN)
387 column.set_sort_indicator(True)
388 column.set_cell_data_func(description_renderer, \
389 self.cell_data_function, None)
390 self.w_application_treeview.append_column(column)
391 #Added selection listener
392 self.package_selection = self.w_application_treeview.get_selection()
393
394 ##CATEGORIES TREEVIEW
395 #enumerations.CATEGORY_NAME
396 category_list_filter = category_list.filter_new()
397 enumerations.CATEGORY_NAME_renderer = gtk.CellRendererText()
398 column = gtk.TreeViewColumn(self._('Name'), \
399 enumerations.CATEGORY_NAME_renderer, \
400 text = enumerations.CATEGORY_NAME)
401 self.w_categories_treeview.append_column(column)
446 category_list_filter.set_visible_func(self.category_filter)
447 toggle_renderer.connect('toggled', self.__active_pane_toggle, \
448 application_list_sort)
449 category_selection.connect("changed", \
450 self.__on_category_selection_changed, None)
451 self.package_selection.set_mode(gtk.SELECTION_SINGLE)
452 self.package_selection.connect("changed", \
453 self.__on_package_selection_changed, None)
454 self.first_run = False
455
456 def __disconnect_models(self):
457 self.w_application_treeview.set_model(None)
458 self.w_categories_treeview.set_model(None)
459 self.w_repository_combobox.set_model(None)
460 self.w_sections_combobox.set_model(None)
461 self.w_filter_combobox.set_model(None)
462
463 @staticmethod
464 def __status_sort_func(treemodel, iter1, iter2, user_data=None):
465 get_val = treemodel.get_value
466 status1 = get_val(iter1, enumerations.STATUS_COLUMN)
467 status2 = get_val(iter2, enumerations.STATUS_COLUMN)
468 return cmp(status1, status2)
469
470 @staticmethod
471 def __remove_treeview_columns(treeview):
472 columns = treeview.get_columns()
473 if columns:
474 for column in columns:
475 treeview.remove_column(column)
476
477 def __init_sections(self):
478 '''This function is for initializing sections combo box, also adds "All"
479 Category. It sets active section combobox entry "All"'''
480 self.section_list.append([0, self._('All'), ])
481 self.section_list.append([-1, "", ])
482 self.section_list.append([2, self._('Meta Packages'), ])
483 self.section_list.append([3, self._('Applications'), ])
484 self.section_list.append([4, self._('Desktop (GNOME)'), ])
485 self.section_list.append([5, self._('Development'), ])
486 self.section_list.append([6, self._('Distributions'), ])
487 self.section_list.append([7, self._('Drivers'), ])
488 self.section_list.append([8, self._('System'), ])
510 # XXX if some changes were applied:
511 self.__main_application_quit()
512 return True
513 else:
514 self.__main_application_quit()
515
516 def __on_file_quit_activate(self, widget):
517 ''' handler for quit menu event '''
518 self.__on_mainwindow_delete_event(None, None)
519
520 def __on_edit_repositories_activate(self, widget):
521 ''' handler for repository menu event '''
522 repository.Repository(self)
523
524 def __on_file_be_activate(self, widget):
525 ''' handler for be menu event '''
526 beadm.Beadmin(self)
527
528 def __on_searchentry_changed(self, widget):
529 '''On text search field changed we should refilter the main view'''
530 self.set_busy_cursor()
531 if self.application_refilter_id != 0:
532 gobject.source_remove(self.application_refilter_id)
533 self.application_refilter_id = 0
534 if self.w_searchentry_dialog.get_text() == "":
535 self.application_refilter_id = \
536 gobject.idle_add(self.__application_refilter)
537 else:
538 self.application_refilter_id = \
539 gobject.timeout_add(TYPE_AHEAD_DELAY,
540 self.__application_refilter)
541
542 def __application_refilter(self):
543 self.application_list_filter.refilter()
544 gobject.idle_add(self.__enable_disable_selection_menus)
545 self.application_refilter_id = 0
546 return False
547
548 def __on_edit_paste(self, widget):
549 self.w_searchentry_dialog.insert_text(self.main_clipboard_text, \
550 self.w_searchentry_dialog.get_position())
551
552 def __on_clear_paste(self, widget):
553 bounds = self.w_searchentry_dialog.get_selection_bounds()
554 self.w_searchentry_dialog.delete_text(bounds[0], bounds[1])
555 return
556
557 def __on_copy(self, widget):
558 bounds = self.w_searchentry_dialog.get_selection_bounds()
559 text = self.w_searchentry_dialog.get_chars(bounds[0], bounds[1])
560 self.w_main_clipboard.set_text(text)
601 self.__enable_disable_install_update()
602 self.__enable_disable_remove()
603
604 def __on_select_updates(self, widget):
605 sort_filt_model = \
606 self.w_application_treeview.get_model() #gtk.TreeModelSort
607 filt_model = sort_filt_model.get_model() #gtk.TreeModelFilter
608 model = filt_model.get_model() #gtk.ListStore
609 iter_next = sort_filt_model.get_iter_first()
610 list_of_paths = []
611 while iter_next != None:
612 sorted_path = sort_filt_model.get_path(iter_next)
613 filtered_iter = sort_filt_model.convert_iter_to_child_iter(None, \
614 iter_next)
615 app_iter = filt_model.convert_iter_to_child_iter(filtered_iter)
616
617 filtered_path = \
618 sort_filt_model.convert_path_to_child_path(sorted_path)
619 path = filt_model.convert_path_to_child_path(filtered_path)
620 if model.get_value(app_iter, \
621 enumerations.STATUS_COLUMN) == enumerations.UPDATABLE:
622 list_of_paths.append(path)
623 iter_next = sort_filt_model.iter_next(iter_next)
624 for path in list_of_paths:
625 itr = model.get_iter(path)
626 model.set_value(itr, enumerations.MARK_COLUMN, True)
627 self.__enable_disable_selection_menus()
628 self.update_statusbar()
629 self.__enable_disable_install_update()
630 self.__enable_disable_remove()
631
632 def __on_deselect(self, widget):
633 sort_filt_model = \
634 self.w_application_treeview.get_model() #gtk.TreeModelSort
635 filt_model = sort_filt_model.get_model() #gtk.TreeModelFilter
636 model = filt_model.get_model() #gtk.ListStore
637 iter_next = sort_filt_model.get_iter_first()
638 list_of_paths = []
639 while iter_next != None:
640 sorted_path = sort_filt_model.get_path(iter_next)
641 filtered_iter = sort_filt_model.convert_iter_to_child_iter(None, \
658 def __on_searchentry_focus_in(self, widget, event):
659 self.w_paste_menuitem.set_sensitive(True)
660
661 def __on_searchentry_focus_out(self, widget, event):
662 self.w_paste_menuitem.set_sensitive(False)
663
664 def __on_searchentry_event(self, widget, event):
665 self.w_main_clipboard.request_text(self.__clipboard_text_received)
666 if widget.get_selection_bounds():
667 #enable selection functions
668 self.w_cut_menuitem.set_sensitive(True)
669 self.w_copy_menuitem.set_sensitive(True)
670 self.w_clear_menuitem.set_sensitive(True)
671 else:
672 self.w_cut_menuitem.set_sensitive(False)
673 self.w_copy_menuitem.set_sensitive(False)
674 self.w_clear_menuitem.set_sensitive(False)
675
676 def __on_category_selection_changed(self, selection, widget):
677 '''This function is for handling category selection changes'''
678 self.set_busy_cursor()
679 gobject.idle_add(self.__application_refilter)
680
681 def __on_package_selection_changed(self, selection, widget):
682 '''This function is for handling package selection changes'''
683 model, itr = selection.get_selected()
684 if itr:
685 self.pkginfo_thread += 1
686 self.selected_pkgname = \
687 model.get_value(itr, enumerations.NAME_COLUMN)
688 Thread(target = self.__show_package_info, \
689 args = (model, itr, self.pkginfo_thread)).start()
690 if self.w_info_notebook.get_current_page() == 3:
691 self.__on_notebook_change(None, None, 3)
692
693
694 def __on_filtercombobox_changed(self, widget):
695 '''On filter combobox changed'''
696 if self.in_setup:
697 return
698 self.set_busy_cursor()
699 gobject.idle_add(self.__application_refilter)
700
701 def __on_sectionscombobox_changed(self, widget):
702 '''On section combobox changed'''
703 if self.in_setup:
704 return
705 selected_section = widget.get_active()
706 if selected_section == 0:
707 for category in self.category_list:
708 category[enumerations.CATEGORY_VISIBLE] = True
709 else:
710 for category in self.category_list:
711 if category[enumerations.CATEGORY_ID] == 0:
712 category[enumerations.CATEGORY_VISIBLE] = True
713 else:
714 category_list = \
715 category[enumerations.SECTION_LIST_OBJECT]
716 if not category_list:
717 category[enumerations.CATEGORY_VISIBLE] \
718 = False
719 else:
720 for section in category_list:
721 if section == selected_section:
722 category[enumerations. \
723 CATEGORY_VISIBLE] = \
724 True
725 else:
726 category[enumerations. \
727 CATEGORY_VISIBLE] = \
728 False
729 self.set_busy_cursor()
730 self.category_list_filter.refilter()
731 gobject.idle_add(self.__application_refilter)
732
733 def __on_repositorycombobox_changed(self, widget):
734 '''On repository combobox changed'''
735 if self.in_setup:
736 return
737 self.set_busy_cursor()
738 gobject.idle_add(self.__application_refilter)
739
740 def __on_install_update(self, widget):
741 self.api_o.reset()
742 install_update = []
743 for row in self.application_list:
744 if row[enumerations.MARK_COLUMN] and \
745 row[enumerations.STATUS_COLUMN] == \
746 enumerations.NOT_INSTALLED or \
747 row[enumerations.STATUS_COLUMN] == enumerations.UPDATABLE:
748 install_update.append(row[\
749 enumerations.STEM_COLUMN])
750 installupdate.InstallUpdate(install_update, self, \
751 self.api_o, ips_update = False, \
752 action = enumerations.INSTALL_UPDATE)
753
754 def __on_update_all(self, widget):
755 opensolaris_image = True
756 self.progress_stop_timer_thread = False
757 notfound = self.__installed_fmris_from_args(self.api_o, \
758 ["SUNWipkg", "SUNWcs"])
759
760 if notfound:
761 opensolaris_image = False
762
763 if opensolaris_image:
764 # Load the catalogs from the repository, its a long
765 # running tasks so need a progress dialog
766 self.w_progress_dialog.set_title(self._("Update All"))
767 self.w_progressinfo_label.set_text(self._( \
768 "Checking SUNWipkg and SUNWipkg-gui versions\n" \
769 "\nPlease wait ..."))
813 action = enumerations.IMAGE_UPDATE)
814
815 def __on_help_about(self, widget):
816 wTreePlan = gtk.glade.XML(self.gladefile, "aboutdialog")
817 aboutdialog = wTreePlan.get_widget("aboutdialog")
818 aboutdialog.connect("response", lambda x = None, \
819 y = None: aboutdialog.destroy())
820 aboutdialog.run()
821
822 def __on_help_help(self, widget):
823 props = { gnome.PARAM_APP_DATADIR : self.application_dir + \
824 '/usr/share/package-manager/help' }
825 gnome.program_init('package-manager', '0.1', properties=props)
826 gnome.help_display('package-manager')
827
828 def __on_remove(self, widget):
829 self.api_o.reset()
830 remove_list = []
831 for pkg in self.application_list:
832 if pkg[enumerations.MARK_COLUMN] and \
833 pkg[enumerations.STATUS_COLUMN] == enumerations.INSTALLED or \
834 pkg[enumerations.STATUS_COLUMN] == enumerations.UPDATABLE:
835 remove_list.append(\
836 pkg[enumerations.STEM_COLUMN])
837 installupdate.InstallUpdate(remove_list, self, \
838 self.api_o, ips_update = False, \
839 action = enumerations.REMOVE)
840
841 def __on_reload(self, widget):
842 if self.description_thread_running:
843 self.cancelled = True
844 self.in_setup = True
845 self.w_progress_dialog.set_title(self._("Refreshing catalogs"))
846 self.w_progressinfo_label.set_text(self._("Refreshing catalogs..."))
847 self.progress_stop_timer_thread = False
848 Thread(target = self.__progressdialog_progress_pulse).start()
849 self.w_progress_dialog.show()
850 self.__disconnect_models()
851 Thread(target = self.__catalog_refresh).start()
852
853 def __catalog_refresh_done(self):
854 self.progress_stop_timer_thread = True
855 #Let the progress_pulse finish. This should be done other way, but at
856 #The moment this works fine
903
904 repositories_list.append([i, repo, ])
905 i = i + 1
906 self.w_repository_combobox.set_model(repositories_list)
907 if default_authority:
908 self.w_repository_combobox.set_active(active)
909 else:
910 self.w_repository_combobox.set_active(0)
911
912 def __active_pane_toggle(self, cell, path, model_sort):
913 '''Toggle function for column enumerations.MARK_COLUMN'''
914 applicationModel = model_sort.get_model()
915 applicationPath = model_sort.convert_path_to_child_path(path)
916 filterModel = applicationModel.get_model()
917 child_path = applicationModel.convert_path_to_child_path(applicationPath)
918 itr = filterModel.get_iter(child_path)
919 if itr:
920 modified = filterModel.get_value(itr, enumerations.MARK_COLUMN)
921 filterModel.set_value(itr, enumerations.MARK_COLUMN, \
922 not modified)
923 pkg_status = filterModel.get_value(itr, \
924 enumerations.STATUS_COLUMN)
925 self.update_statusbar()
926 self.__update_install_update_button(pkg_status, modified)
927 self.__update_remove_button(pkg_status, modified)
928 self.__enable_disable_selection_menus()
929
930
931 def __update_install_update_button(self, pkg_status, toggle_true):
932 if not toggle_true and self.user_rights:
933 if pkg_status == enumerations.NOT_INSTALLED or \
934 pkg_status == enumerations.UPDATABLE:
935 self.w_installupdate_button.set_sensitive(True)
936 self.w_installupdate_menuitem.set_sensitive(True)
937 return
938 elif self.user_rights:
939 instup_button = self.w_installupdate_button
940 instup_menu = self.w_installupdate_menuitem
941 for row in self.application_list:
942 if row[enumerations.MARK_COLUMN]:
943 status = row[enumerations.STATUS_COLUMN]
944 if status == enumerations.NOT_INSTALLED or \
945 status == enumerations.UPDATABLE:
946 instup_button.set_sensitive(True)
947 instup_menu.set_sensitive(True)
948 return
949 else:
950 self.w_installupdate_button.set_sensitive(False)
951 self.w_installupdate_menuitem.set_sensitive(False)
952
953 def __update_reload_button(self):
954 if self.user_rights:
955 self.w_reload_button.set_sensitive(True)
956 else:
957 self.w_reload_button.set_sensitive(False)
958
959 def __update_remove_button(self, pkg_status, toggle_true):
960 if not toggle_true and self.user_rights:
961 if pkg_status == enumerations.INSTALLED or \
962 pkg_status == enumerations.UPDATABLE:
963 self.w_remove_button.set_sensitive(True)
964 self.w_remove_menuitem.set_sensitive(True)
965 return
966 elif self.user_rights:
967 for row in self.application_list:
968 if row[enumerations.MARK_COLUMN]:
969 status = row[enumerations.STATUS_COLUMN]
970 if status == enumerations.INSTALLED or \
971 status == enumerations.UPDATABLE:
972 self.w_remove_button.set_sensitive(True)
973 self.w_remove_menuitem.set_sensitive(True)
974 return
975 else:
976 self.w_remove_button.set_sensitive(False)
977 self.w_remove_menuitem.set_sensitive(False)
978
979 def __show_fetching_package_info(self, pkg, icon):
980 pkg_name = pkg.get_name()
981 if icon and icon != pkg:
982 self.w_packageicon_image.set_from_pixbuf(icon)
983 else:
984 self.w_packageicon_image.set_from_pixbuf( \
985 self.__get_pixbuf_from_path("/usr/share/package-manager/", \
986 "PM_package_36x"))
987 self.w_packagename_label.set_markup("<b>" + pkg_name + "</b>")
988
989 pkg_stem = pkg.get_pkg_stem()
990 if self.__setting_from_cache(pkg_stem):
991 return
992
993 self.w_shortdescription_label.set_text( \
994 self._("Fetching description..."))
995 instbuffer = self.w_installedfiles_textview.get_buffer()
996 depbuffer = self.w_dependencies_textview.get_buffer()
997 infobuffer = self.w_generalinfo_textview.get_buffer()
998 instbuffer.set_text(self._("Fetching information..."))
999 depbuffer.set_text(self._("Fetching information..."))
1000 infobuffer.set_text(self._("Fetching information..."))
1001 return
1002
1003 def __setting_from_cache(self, pkg_stem):
1004 if len(self.info_cache) > MAX_INFO_CACHE_LIMIT:
1005 self.info_cache = {}
1006
1007 if self.info_cache.has_key(pkg_stem):
1008 self.w_shortdescription_label.set_text(\
1009 self.info_cache[pkg_stem][0])
1010 instbuffer = self.w_installedfiles_textview.get_buffer()
1011 depbuffer = self.w_dependencies_textview.get_buffer()
1012 infobuffer = self.w_generalinfo_textview.get_buffer()
1013 infobuffer.set_text(self.info_cache[pkg_stem][1])
1014 instbuffer.set_text(self.info_cache[pkg_stem][2])
1015 depbuffer.set_text(self.info_cache[pkg_stem][3])
1016 return True
1017 else:
1018 return False
1019
1020 def __update_package_info(self, pkg, icon, installed, pkg_info):
1021 pkg_name = pkg.get_name()
1022 pkg_stem = pkg.get_pkg_stem()
1023 if icon and icon != pkg:
1024 self.w_packageicon_image.set_from_pixbuf(icon)
1025 else:
1026 self.w_packageicon_image.set_from_pixbuf( \
1027 self.__get_pixbuf_from_path("/usr/share/package-manager/", \
1028 "PM_package_36x"))
1029 self.w_packagename_label.set_markup("<b>" + pkg_name + "</b>")
1030
1031 if self.__setting_from_cache(pkg_stem):
1032 return
1033
1034 instbuffer = self.w_installedfiles_textview.get_buffer()
1035 depbuffer = self.w_dependencies_textview.get_buffer()
1036 infobuffer = self.w_generalinfo_textview.get_buffer()
1037
1038 if not pkg_info:
1039 self.w_shortdescription_label.set_text( \
1040 self._("Description not available for this package..."))
1041 instbuffer.set_text( \
1042 self._("Files Details not available for this package..."))
1043 depbuffer.set_text(self._( \
1044 "Dependencies info not available for this package..."))
1045 infobuffer.set_text( \
1046 self._("Information not available for this package..."))
1047 return
1048 description = pkg_info.summary
1049 #XXX long term need to have something more robust here for multi byte
1050 if len(description) > MAX_DESC_LEN:
1051 description = description[:MAX_DESC_LEN] + " ..."
1072 if pkg_info.files:
1073 inst_str += ''.join(["\t%s\n" % x for x in pkg_info.files])
1074 if pkg_info.hardlinks:
1075 inst_str += ''.join(["\t%s\n" % x for x in pkg_info.hardlinks])
1076 if pkg_info.links:
1077 inst_str += ''.join(["\t%s\n" % x for x in pkg_info.links])
1078
1079 if description:
1080 info_str += self._(" Description:\t%s\n") % description
1081 info_str += self._(" Name:\t\t%s\n") % pkg_name
1082 info_str += self._(" FMRI:\t\t%s\n") % pkg.get_fmri()
1083 info_str += self._(" Version:\t\t%s\n") % \
1084 pkg.version.get_short_version()
1085 info_str += self._(" Packaged:\t%s\n") % \
1086 self.get_datetime(pkg.version)
1087
1088 infobuffer.set_text(info_str)
1089 instbuffer.set_text(inst_str)
1090 depbuffer.set_text(dep_str)
1091
1092 self.info_cache[pkg_stem] = \
1093 (description, info_str, inst_str, dep_str)
1094
1095 def __update_package_license(self, licenses):
1096 lic = ""
1097 lic_u = ""
1098 if licenses == None:
1099 lic_u = self._("Not available")
1100 else:
1101 for licens in licenses:
1102 lic += licens.get_text()
1103 lic += "\n"
1104 try:
1105 lic_u = unicode(lic, "utf-8")
1106 except UnicodeDecodeError:
1107 lic_u += ""
1108 licbuffer = self.w_license_textview.get_buffer()
1109 licbuffer.set_text(lic_u)
1110
1111 def __show_package_licenses(self, th_no):
1112 #XXX revisit this and replace with gobject.timer_add() instead of sleep
1113 # sleep for a little time, this is done for the users who are
1114 # fast browsing the list of the packages.
1115 time.sleep(1)
1116 if th_no != self.pkginfo_thread:
1117 return
1118 if self.selected_pkgname == None:
1119 gobject.idle_add(self.__update_package_license, \
1120 None)
1121 return
1122 info = self.api_o.info([self.selected_pkgname], True, True)
1123 pkgs_info = None
1124 package_info = None
1125 no_licenses = 0
1126 if info:
1127 pkgs_info = info[0]
1128 if pkgs_info:
1129 package_info = pkgs_info[0]
1130 if package_info:
1137 gobject.idle_add(self.__update_package_license, \
1138 package_info.licenses)
1139 else:
1140 return
1141
1142 def __get_pkg_info(self, pkg_name, installed):
1143 info = self.api_o.info([pkg_name], installed, get_licenses=False, \
1144 get_action_info=True)
1145 pkgs_info = None
1146 package_info = None
1147 if info:
1148 pkgs_info = info[0]
1149 if pkgs_info:
1150 package_info = pkgs_info[0]
1151 if package_info:
1152 return package_info
1153 else:
1154 return
1155
1156 def __show_package_info(self, model, itr, th_no):
1157 installed = False
1158 pkg = model.get_value(itr, enumerations.FMRI_COLUMN)
1159 status = model.get_value(itr, enumerations.STATUS_COLUMN)
1160 if status == enumerations.UPDATABLE or status == enumerations.INSTALLED:
1161 installed = True
1162 gobject.idle_add( \
1163 self.__show_fetching_package_info, pkg, pkg)
1164
1165 if self.info_cache.has_key(pkg.get_pkg_stem()):
1166 return
1167
1168 # sleep for a little time, this is done for the users which are
1169 # fast browsing the list of the packages.
1170 time.sleep(1)
1171 if th_no != self.pkginfo_thread:
1172 return
1173 img = self.api_o.img
1174 img.history.operation_name = "info"
1175
1176 pkg_info = self.__get_pkg_info(pkg.get_name(), installed)
1177 if th_no == self.pkginfo_thread:
1178 if not pkg:
1179 gobject.idle_add(self.__update_package_info, pkg, pkg, \
1180 installed, pkg_info)
1181 else:
1182 gobject.idle_add(self.__update_package_info, pkg, pkg, \
1183 installed, pkg_info)
1184 img.history.operation_result = \
1185 history.RESULT_SUCCEEDED
1186 else:
1187 img.history.operation_result = \
1188 history.RESULT_SUCCEEDED
1189 return
1190
1191 # This function is ported from pkg.actions.generic.distinguished_name()
1192 def __locale_distinguished_name(self, action):
1193 if action.key_attr == None:
1194 return str(action)
1195 return "%s: %s" % \
1196 (self._(action.name), action.attrs.get(action.key_attr, "???"))
1197
1198 def __application_filter(self, model, itr):
1199 '''This function is used to filter content in the main
1200 application view'''
1201 if self.in_setup or self.cancelled:
1202 return False
1203 # XXX Show filter, chenge text to integers
1204 selected_category = 0
1205 selection = self.w_categories_treeview.get_selection()
1206 category_model, category_iter = selection.get_selected()
1207 if not category_iter: #no category was selected, so select "All"
1208 selection.select_path(0)
1209 category_model, category_iter = selection.get_selected()
1210 if category_iter:
1211 selected_category = category_model.get_value(category_iter, \
1212 enumerations.CATEGORY_ID)
1213 category_list_iter = model.get_value(itr, \
1214 enumerations.CATEGORY_LIST_COLUMN)
1215 category = False
1216 repo = self.__is_pkg_repository_visible(model, itr)
1217 if category_list_iter:
1218 sel = False
1219 for category_iter in category_list_iter:
1220 if category != True:
1221 category = \
1222 self.category_filter(self.category_list, \
1223 category_iter)
1224 if selected_category != 0:
1225 if selected_category == \
1226 self.category_list.get_value(category_iter, \
1227 enumerations.CATEGORY_ID):
1228 sel = True
1229 category = sel
1230 else:
1231 if selected_category == 0:
1232 selected_section = self.w_sections_combobox.get_active()
1233 if selected_section == 0:
1234 category = True
1242 model.get_value \
1243 (itr, enumerations.NAME_COLUMN).lower():
1244 return (repo & category & \
1245 self.__is_package_filtered(model, itr))
1246 if not model.get_value(itr, enumerations.DESCRIPTION_COLUMN) == None:
1247 if self.w_searchentry_dialog.get_text().lower() in \
1248 model.get_value \
1249 (itr, enumerations.DESCRIPTION_COLUMN).lower():
1250 return (repo & category & \
1251 self.__is_package_filtered(model, itr))
1252 else:
1253 return False
1254
1255 def __is_package_filtered(self, model, itr):
1256 '''Function for filtercombobox'''
1257 # XXX Instead of string comparison, we should do it through integers.
1258 # XXX It should be faster and better for localisations.
1259 filter_text = self.w_filter_combobox.get_active()
1260 if filter_text == 0:
1261 return True
1262 status = model.get_value(itr, enumerations.STATUS_COLUMN)
1263 if filter_text == 2:
1264 return (status == enumerations.INSTALLED or status == \
1265 enumerations.UPDATABLE)
1266 elif filter_text == 3:
1267 return status == enumerations.UPDATABLE
1268 elif filter_text == 4:
1269 return status == enumerations.NOT_INSTALLED
1270 elif filter_text == 6:
1271 return model.get_value(itr, enumerations.MARK_COLUMN)
1272 elif filter_text == 8:
1273 # XXX Locked support
1274 return False
1275
1276
1277 def __is_pkg_repository_visible(self, model, itr):
1278 if len(self.repositories_list) <= 1:
1279 return True
1280 else:
1281 auth_iter = self.w_repository_combobox.get_active_iter()
1282 authority = self.repositories_list.get_value(auth_iter, \
1283 enumerations.REPOSITORY_NAME)
1284 pkg = model.get_value(itr, \
1285 enumerations.FMRI_COLUMN)
1286 if not pkg:
1287 return False
1288 if cmp(pkg.get_authority(), authority) == 0:
1289 return True
1290 else:
1291 return False
1292
1293 def __do_ips_uptodate_check(self):
1294 ret = self.__catalog_refresh(False)
1295 if ret != -1:
1296 self.ips_uptodate = self.__ipkg_ipkgui_uptodate()
1297 else:
1298 self.progress_canceled = True
1299 self.progress_stop_timer_thread = True
1300
1301 def __ipkg_ipkgui_uptodate(self):
1302 self.api_o.reset()
1303 list_of_packages = [self.ipkg_fmri, self.ipkggui_fmri]
1304 ret = True
1305 try:
1306 upgrade_needed, cre = self.api_o.plan_install(
1307 list_of_packages, filters = [])
1324 self.__enable_disable_deselect()
1325 # XXX disabled until new API
1326 self.__enable_disable_update_all()
1327
1328 def __enable_disable_select_all(self):
1329
1330 if self.in_setup:
1331 return
1332 if len(self.w_application_treeview.get_model()) > 0:
1333 for row in self.w_application_treeview.get_model():
1334 if not row[enumerations.MARK_COLUMN]:
1335 self.w_selectall_menuitem.set_sensitive(True)
1336 return
1337 self.w_selectall_menuitem.set_sensitive(False)
1338 else:
1339 self.w_selectall_menuitem.set_sensitive(False)
1340
1341 def __enable_disable_install_update(self):
1342 for row in self.application_list:
1343 if row[enumerations.MARK_COLUMN]:
1344 status = row[enumerations.STATUS_COLUMN]
1345 if self.user_rights and \
1346 (status == enumerations.UPDATABLE or
1347 status == enumerations.NOT_INSTALLED):
1348 self.w_installupdate_button.set_sensitive(True)
1349 self.w_installupdate_menuitem.set_sensitive(True)
1350 return
1351 self.w_installupdate_button.set_sensitive(False)
1352 self.w_installupdate_menuitem.set_sensitive(False)
1353
1354 def __enable_disable_remove(self):
1355 for row in self.application_list:
1356 if row[enumerations.MARK_COLUMN]:
1357 status = row[enumerations.STATUS_COLUMN]
1358 if self.user_rights and \
1359 (status == enumerations.UPDATABLE or
1360 status == enumerations.INSTALLED):
1361 self.w_remove_button.set_sensitive(True)
1362 self.w_remove_menuitem.set_sensitive(True)
1363 return
1364 self.w_remove_button.set_sensitive(False)
1365 self.w_remove_menuitem.set_sensitive(False)
1366
1367 def __enable_disable_select_updates(self):
1368 for row in self.w_application_treeview.get_model():
1369 if row[enumerations.STATUS_COLUMN] == enumerations.UPDATABLE:
1370 if not row[enumerations.MARK_COLUMN]:
1371 self.w_selectupdates_menuitem. \
1372 set_sensitive(True)
1373 return
1374 self.w_selectupdates_menuitem.set_sensitive(False)
1375 return
1376
1377 def __enable_disable_update_all(self):
1378 for row in self.application_list:
1379 if self.__is_pkg_repository_visible(self.application_list, \
1380 row.iter):
1381 if self.application_list.get_value(row.iter, \
1382 enumerations.STATUS_COLUMN) == \
1383 enumerations.UPDATABLE and self.user_rights:
1384 self.w_updateall_menuitem. \
1385 set_sensitive(True)
1386 self.w_updateall_button. \
1387 set_sensitive(True)
1388 return
1389 self.w_updateall_button.set_sensitive(False)
1390 self.w_updateall_menuitem.set_sensitive(False)
1391 self.unset_busy_cursor()
1392
1393 def __enable_disable_deselect(self):
1394 for row in self.w_application_treeview.get_model():
1395 if row[enumerations.MARK_COLUMN]:
1396 self.w_deselect_menuitem.set_sensitive(True)
1397 return
1398 self.w_deselect_menuitem.set_sensitive(False)
1399 return
1400
1401
1402 def __catalog_refresh(self, reload_gui=True):
1403 """Update image's catalogs."""
1404 full_refresh = True
1405 try:
1406 self.api_o.refresh(full_refresh)
1407 self.api_o.img.load_catalogs(self.pr)
1408 except api_errors.UnrecognizedAuthorityException:
1409 # In current implementation, this will never happen
1410 # We are not refrehsing specific authority
1411 self.__catalog_refresh_done()
1412 raise
1413 except api_errors.PermissionsException:
1414 #Error will already have been reported in
1415 #Manage Repository dialog
1416 self.__catalog_refresh_done()
1417 return -1
1418 except api_errors.CatalogRefreshException, cre:
1419 total = cre.total
1420 succeeded = cre.succeeded
1421 ermsg = self._("Network problem.\n\n")
1422 ermsg += self._("Details:\n")
1423 ermsg += "%s/%s" % (succeeded, total)
1424 ermsg += self._(" catalogs successfully updated:\n")
1425 for auth, err in cre.failed:
1426 if isinstance(err, HTTPError):
1427 ermsg += " %s: %s - %s\n" % \
1428 (err.filename, err.code, err.msg)
1429 elif isinstance(err, URLError):
1430 if err.args[0][0] == 8:
1431 ermsg += " %s: %s\n" % \
1432 (urlparse.urlsplit(
1433 auth["origin"])[1].split(":")[0],
1451 None, gtk.MESSAGE_INFO)
1452 self.__catalog_refresh_done()
1453 return -1
1454
1455 except api_errors.UnrecognizedAuthorityException:
1456 self.__catalog_refresh_done()
1457 raise
1458 except Exception:
1459 self.__catalog_refresh_done()
1460 raise
1461 if reload_gui:
1462 self.__catalog_refresh_done()
1463 return 0
1464
1465 def __get_image_from_directory(self, api_o, progressdialog_progress):
1466 """ This method set up image from the given directory and
1467 returns the image object or None"""
1468 application_list = self.__get_new_application_liststore()
1469 category_list = self.__get_new_category_liststore()
1470 repositories_list = self.__get_new_repositories_liststore()
1471 authority = api_o.img.get_default_authority()
1472 most_recent = {}
1473 installed = []
1474 try:
1475 pkgs_known = api_o.img.inventory(all_known=True)
1476 for pfmri, state in pkgs_known:
1477 if state["state"] == "installed":
1478 installed.append((pfmri, state))
1479 hv = pfmri.get_pkg_stem(include_pkg=False)
1480 if hv in most_recent:
1481 stored_pfmri, stored_state = \
1482 most_recent[hv]
1483 if pfmri.is_successor(stored_pfmri):
1484 most_recent[hv] = (pfmri, state)
1485 else:
1486 most_recent[hv] = (pfmri, state)
1487 pkgs_known = installed + most_recent.values()
1488
1489 # This method is necessary because fmri.__cmp__ does
1490 # not provide the desired ordering. It uses the same
1491 # ordering on package names as fmri.__cmp__ but it
1492 # reverse sorts on version, so that 98 comes before 97.
1493 # Also, authorities are taken into account so that
1494 # preferred authorities come before others. Finally,
1495 # authorties are presented in alphabetical order.
1496 def __fmri_cmp((f1, s1), (f2, s2)):
1497 t = cmp(f1.pkg_name, f2.pkg_name)
1498 if t != 0:
1499 return t
1500 t = cmp(f2, f1)
1501 if t != 0:
1502 return t
1503 if f1.preferred_authority():
1504 return -1
1505 if f2.preferred_authority():
1506 return 1
1507 return cmp(f1.get_authority(),
1508 f2.get_authority())
1509
1510 pkgs_known.sort(cmp=__fmri_cmp)
1511 except api_errors.InventoryException:
1512 # Can't happen when all_known is true and no args,
1513 # but here for completeness.
1514 err = self._("Error occured while getting list of packages")
1515 gobject.idle_add(self.w_progress_dialog.hide)
1516 gobject.idle_add(self.error_occured, err)
1517 return
1518
1519 #Only one instance of those icons should be in memory
1520 update_available_icon = self.get_icon_pixbuf("status_newupdate")
1521 installed_icon = self.get_icon_pixbuf("status_installed")
1522 #Imageinfo for categories
1523 imginfo = imageinfo.ImageInfo()
1524 sectioninfo = imageinfo.ImageInfo()
1525 catalogs = api_o.img.catalogs
1526 categories = {}
1527 sections = {}
1528 share_path = "/usr/share/package-manager/data/"
1529 for cat in catalogs:
1530 category = imginfo.read(self.application_dir +
1531 share_path + cat)
1532 if len(category) == 0:
1533 category = imginfo.read(self.application_dir +
1534 share_path + "opensolaris.org")
1535 categories[cat] = category
1536 section = sectioninfo.read(self.application_dir +
1537 share_path + cat + ".sections")
1538 if len(section) == 0:
1539 section = sectioninfo.read(self.application_dir +
1540 share_path + "opensolaris.org.sections")
1541 sections[cat] = section
1542 icon_path = self.application_dir + \
1543 "/usr/share/package-manager/data/pixmaps/"
1544 pkg_count = 0
1545 progress_percent = INITIAL_PROGRESS_TOTAL_PERCENTAGE
1546 total_pkg_count = len(pkgs_known)
1547 progress_increment = \
1548 total_pkg_count / PACKAGE_PROGRESS_TOTAL_INCREMENTS
1549 self.progress_stop_timer_thread = True
1550 while gtk.events_pending():
1551 gtk.main_iteration(False)
1552 prev_pfmri_str = ""
1553 prev_state = None
1554 for pkg, state in pkgs_known:
1555 if prev_pfmri_str and \
1556 prev_pfmri_str == pkg.get_short_fmri() and \
1557 prev_state == state:
1558 continue
1559 prev_pfmri_str = pkg.get_short_fmri()
1560 prev_state = state
1561
1562 if progress_increment > 0 and pkg_count % progress_increment == 0:
1563 progress_percent += PACKAGE_PROGRESS_PERCENT_INCREMENT
1564 if progress_percent <= PACKAGE_PROGRESS_PERCENT_TOTAL:
1565 progressdialog_progress(progress_percent,
1566 pkg_count, total_pkg_count)
1567 while gtk.events_pending():
1568 gtk.main_iteration(False)
1569
1570 status_icon = None
1571 pkg_name = pkg.get_name()
1572 pkg_stem = pkg.get_pkg_stem()
1573 package_icon = self.__get_pixbuf_from_path(icon_path, pkg_name)
1574 pkg_state = enumerations.NOT_INSTALLED
1575 if state["state"] == "installed":
1576 pkg_state = enumerations.INSTALLED
1577 if state["upgradable"] == True:
1578 status_icon = update_available_icon
1579 pkg_state = enumerations.UPDATABLE
1580 else:
1581 status_icon = installed_icon
1582 app = \
1583 [
1584 False, status_icon, package_icon, pkg_name,
1585 '...', pkg_state, pkg, pkg_stem, None, True, None
1586 ]
1587 row_iter = application_list.insert(pkg_count, app)
1588 pkg_count += 1
1589 apc = self.__add_package_to_category
1590 app_ls = application_list
1591 for cat in categories:
1592 if cat in categories:
1593 if pkg_name in categories[cat]:
1594 pkg_categories = categories[cat][pkg_name]
1595 for pcat in pkg_categories.split(","):
1596 if pcat:
1597 apc(self._(pcat), None,
1598 None, row_iter,
1599 app_ls, category_list)
1600 for authority in sections:
1601 for section in sections[authority]:
1602 for category in sections[authority][section].split(","):
1603 self.__add_category_to_section(self._(category),
1604 self._(section), category_list)
1605
1606 #1915 Sort the Categories into alphabetical order and prepend All Category
1607 if len(category_list) > 0:
1608 rows = [tuple(r) + (i,) for i, r in enumerate(category_list)]
1609 rows.sort(self.__sort)
1610 r = []
1611 category_list.reorder([r[-1] for r in rows])
1612 category_list.prepend([0, self._('All'), None, None, True, None])
1613
1614 progressdialog_progress(PACKAGE_PROGRESS_PERCENT_TOTAL, total_pkg_count,
1615 total_pkg_count)
1616 gobject.idle_add(self.process_package_list_end, api_o,
1617 application_list, category_list, repositories_list)
1618 return
1619
1620 def __add_package_to_category(self, category_name, category_description, \
1621 category_icon, package, application_list, category_list):
1622 if not package or category_name == self._('All'):
1623 return
1624 if not category_name:
1625 return
1626 # XXX check if needed
1627 # category_name = self._('All')
1628 # category_description = self._('All packages')
1629 # category_icon = None
1630 category_ref = None
1631 for category in category_list:
1632 if category[enumerations.CATEGORY_NAME] == category_name:
1633 category_ref = category.iter
1634 if not category_ref: # Category not exists
1635 category_ref = category_list.append([len( \
1636 category_list)+1, category_name, category_description, \
1637 category_icon, True, None])
1638 if category_ref:
1639 if application_list.get_value(package, \
1640 enumerations.CATEGORY_LIST_COLUMN):
1641 a = application_list.get_value(package, \
1642 enumerations.CATEGORY_LIST_COLUMN)
1643 a.append(category_ref)
1644 else:
1645 category_list = []
1646 category_list.append(category_ref)
1647 application_list.set(package, \
1648 enumerations.CATEGORY_LIST_COLUMN, category_list)
1649
1650 def __add_category_to_section(self, category_name, section_name, category_list):
1651 '''Adds the section to section list in category. If there is no such
1652 section, than it is not added. If there was already section than it
1653 is skipped. Sections must be case sensitive'''
1654 if not category_name:
1655 return
1656 for section in self.section_list:
1657 if section[enumerations.SECTION_NAME] == section_name:
1658 for category in category_list:
1659 if category[enumerations.CATEGORY_NAME] == \
1660 category_name:
1661 if not category[ \
1662 enumerations.SECTION_LIST_OBJECT]:
1663 category[ \
1664 enumerations. \
1665 SECTION_LIST_OBJECT] = \
1666 [section[ \
1667 enumerations.SECTION_ID], ]
1668 else:
1773 @staticmethod
1774 def cell_data_function(column, renderer, model, itr, data):
1775 '''Function which sets the background colour to black if package is
1776 selected'''
1777 if itr:
1778 if model.get_value(itr, enumerations.MARK_COLUMN):
1779 renderer.set_property("cell-background", "#ffe5cc")
1780 renderer.set_property("cell-background-set", True)
1781 else:
1782 renderer.set_property("cell-background-set", False)
1783
1784 @staticmethod
1785 def combobox_separator(model, itr):
1786 return model.get_value(itr, enumerations.FILTER_NAME) == ""
1787
1788 @staticmethod
1789 def combobox_id_separator(model, itr):
1790 return model.get_value(itr, 0) == -1
1791
1792 @staticmethod
1793 def category_filter(model, itr):
1794 '''This function filters category in the main application view'''
1795 return model.get_value(itr, enumerations.CATEGORY_VISIBLE)
1796
1797 @staticmethod
1798 def get_datetime(version):
1799 dt = None
1800 try:
1801 dt = version.get_datetime()
1802 except AttributeError:
1803 dt = version.get_timestamp()
1804 return dt
1805
1806 @staticmethod
1807 def get_installed_version(api_o, pkg):
1808 return api_o.img.get_version_installed(pkg)
1809
1810 @staticmethod
1811 def get_manifest(img, package, filtered = True):
1812 '''helper function'''
1837 # Public Methods
1838 #-----------------------------------------------------------------------------#
1839 def setup_progressdialog_show(self):
1840 self.w_progress_dialog.set_title(self._("Loading Repository Information"))
1841 self.w_progressinfo_label.set_text(
1842 self._( "Fetching package entries ..."))
1843 self.w_progress_cancel.hide()
1844 self.w_progress_dialog.show()
1845 Thread(target = self.__progressdialog_progress_time).start()
1846
1847 def init_sections(self):
1848 self.__init_sections() #Initiates sections
1849
1850 def init_show_filter(self):
1851 self.__init_show_filter() #Initiates filter
1852
1853 def reload_packages(self):
1854 self.api_o = self.__get_api_object(self.image_directory, self.pr)
1855 self.__on_reload(None)
1856
1857 def set_busy_cursor(self):
1858 self.gdk_window.show()
1859
1860 def unset_busy_cursor(self):
1861 self.gdk_window.hide()
1862
1863 def process_package_list_start(self, image_directory):
1864 self.cancelled = True
1865 self.setup_progressdialog_show()
1866 while gtk.events_pending():
1867 gtk.main_iteration(False)
1868 self.image_directory = image_directory
1869 # Create our image object based on image directory.
1870 api_o = self.__get_api_object(image_directory, self.pr)
1871 api_o.img.load_catalogs(self.pr)
1872 self.api_o = api_o
1873 # Acquire image contents and update progress bar as you do so.
1874 Thread(target = self.__get_image_from_directory, args = (api_o,
1875 self.__progressdialog_progress_percent)).start()
1876
1877 @staticmethod
1878 def __get_api_object(img_dir, progtrack):
1879 api_o = None
1880 try:
1881 api_o = api.ImageInterface(img_dir, \
1882 CLIENT_API_VERSION, \
1906 self.w_progress_dialog.hide()
1907
1908 def __get_manifests_thread(self):
1909 Thread(target = self.get_manifests_for_packages,
1910 args = ()).start()
1911
1912 def get_icon_pixbuf(self, icon_name):
1913 #2821: The get_icon_pixbuf should use PACKAGE_MANAGER_ROOT
1914 return self.__get_pixbuf_from_path(self.application_dir + \
1915 "/usr/share/icons/package-manager/", icon_name)
1916
1917 def get_manifests_for_packages(self):
1918 ''' Function, which get's manifest for packages. If the manifest is not
1919 locally tries to retrieve it. For installed packages gets manifest
1920 for the particular version (local operation only), if the package is
1921 not installed than the newest one'''
1922 time.sleep(3)
1923 count = 0
1924 self.description_thread_running = True
1925 img = self.api_o.img
1926 for pkg in self.application_list:
1927 if self.cancelled:
1928 self.description_thread_running = False
1929 return
1930 info = None
1931 package = pkg[enumerations.FMRI_COLUMN]
1932 if (img and package):
1933 man = self.get_manifest(img, package, filtered = True)
1934 if man:
1935 info = man.get("description", "")
1936 gobject.idle_add(self.update_desc, info, pkg)
1937 count += 1
1938 if count % 2 == 0:
1939 time.sleep(0.001)
1940 img.history.operation_name = "info"
1941 img.history.operation_result = history.RESULT_SUCCEEDED
1942 self.description_thread_running = False
1943
1944 def update_statusbar(self):
1945 '''Function which updates statusbar'''
1946 installed = 0
1947 selected = 0
1948 broken = 0
1949 for pkg_row in self.application_list:
1950 if pkg_row[enumerations.STATUS_COLUMN] == enumerations.INSTALLED \
1951 or pkg_row[enumerations.STATUS_COLUMN] == \
1952 enumerations.UPDATABLE:
1953 installed = installed + 1
1954 if pkg_row[enumerations.MARK_COLUMN]:
1955 selected = selected + 1
1956 listed_str = self._('%d packages listed') % len(self.application_list)
1957 inst_str = self._('%d installed') % installed
1958 sel_str = self._('%d selected') % selected
1959 broken_str = self._('%d broken') % broken
1960 self.w_main_statusbar.push(0, listed_str + ', ' + inst_str + ', ' + \
1961 sel_str + ', ' + broken_str + '.')
1962
1963
1964 def update_package_list(self, update_list):
1965 img = self.api_o.img
1966 img.clear_pkg_state()
1967 img.load_catalogs(self.pr)
1968 installed_icon = self.get_icon_pixbuf("status_installed")
1969 for row in self.application_list:
1970 if row[enumerations.NAME_COLUMN] in update_list:
1971 pkg = row[enumerations.FMRI_COLUMN]
1972 pkg_stem = row[enumerations.STEM_COLUMN]
1973 package_installed = \
1974 self.get_installed_version(self.api_o, pkg)
1975 if package_installed:
1976 inst_stem = package_installed.get_pkg_stem()
1977 if inst_stem == pkg_stem:
1978 row[enumerations.STATUS_COLUMN] = \
1979 enumerations.INSTALLED
1980 row[enumerations.STATUS_ICON_COLUMN] = \
1981 installed_icon
1982 else:
1983 row[enumerations.STATUS_COLUMN] = \
1984 enumerations.NOT_INSTALLED
1985 row[enumerations.STATUS_ICON_COLUMN] = \
1986 None
1987 row[enumerations.MARK_COLUMN] = False
1988 self.w_installupdate_button.set_sensitive(False)
1989 self.w_installupdate_menuitem.set_sensitive(False)
1990 self.w_remove_button.set_sensitive(False)
1991 self.w_remove_menuitem.set_sensitive(False)
1992 self.__enable_disable_selection_menus()
1993 self.update_statusbar()
1994
1995 def shutdown_after_ips_update(self):
1996
1997 # 2790: As IPS and IPS-GUI have been updated the IPS GUI must be shutdown
1998 # and restarted
1999 msgbox = gtk.MessageDialog(parent = self.w_main_window, \
2000 buttons = gtk.BUTTONS_OK, \
2001 flags = gtk.DIALOG_MODAL, type = gtk.MESSAGE_INFO, \
2002 message_format = self._("SUNWipkg and SUNWipkg-gui have been " \
2003 "updated and Package Manager will now be restarted.\n\nAfter " \
2004 "restart select Update All to continue."))
2005 msgbox.set_title(self._("Update All"))
2006 msgbox.run()
2007 msgbox.destroy()
|