Print this page
*** NO COMMENTS ***

@@ -43,12 +43,10 @@
 NOTEBOOK_START_PAGE = 1                   # Main View Start page index
 INFO_NOTEBOOK_LICENSE_PAGE = 3            # License Tab index
 SHOW_INFO_DELAY = 600       # Delay before showing selected pacakge information
 SHOW_LICENSE_DELAY = 600    # Delay before showing license information
 SEARCH_STR_FORMAT = "<%s>"
-SEARCH_LIMIT = 100                        # Maximum number of results shown for
-                                          # api search
 MIN_APP_WIDTH = 750                       # Minimum application width
 MIN_APP_HEIGHT = 500                     # Minimum application height
 INITIAL_APP_WIDTH_PREFERENCES = "/apps/packagemanager/preferences/initial_app_width"
 INITIAL_APP_HEIGHT_PREFERENCES = "/apps/packagemanager/preferences/initial_app_height"
 INITIAL_APP_HPOS_PREFERENCES = "/apps/packagemanager/preferences/initial_app_hposition"

@@ -268,10 +266,11 @@
                 self.visible_repository = None
                 self.visible_repository_uptodate = False
                 self.last_active_publisher = None
                 self.search_start = 0
                 self.search_time_sec = 0
+                self.current_search_publisher = None
                 self.section_list = None
                 self.filter_list = self.__get_new_filter_liststore()
                 self.application_list = None
                 self.a11y_application_treeview = None
                 self.a11y_categories_treeview = None

@@ -673,11 +672,11 @@
                             [-1, _("All Repositories Search Results"), ])
                 else:
                         self.repositories_list.remove(
                             self.repositories_list.get_iter_first())
                 self.w_repository_combobox.set_model(self.repositories_list)
-                self.visible_repository = None
+                #self.visible_repository = None
 
 
         def __link_load_blank(self):
                 self.document.clear()
                 self.document.open_stream('text/html')

@@ -760,53 +759,53 @@
                     "<font color='#0000FF'>Warning: Unable to "
                     "load Start Page:<br>%s</font></body></html>"
                     % (start_page_url)))
                 self.document.close_stream()
 
-        def __parse_api_search_error(self, error):
+        def __process_api_search_error(self, error):
                 self.current_repos_with_search_errors = []
-                if "failed_servers" in error.__dict__ and len(error.failed_servers) > 0:
-                        #TBD we should not have to parse the error output
-                        rem_str = " doesn't speak a known version of search operation"
-                        timeout_str = "urlopen error timed out"
-                        repos = []
-                        for err in error.failed_servers:
-                                err_str = str(err[1])
-                                if rem_str in err_str:
-                                        repo = err_str.replace(rem_str,"")
-                                        self.current_repos_with_search_errors.append(repo)
-                                elif timeout_str in err_str:
-                                        repo = err[0].repositories[0].origins[0].uri
-                                        self.current_repos_with_search_errors.append(repo)
 
+                for pub, err in error.failed_servers:
+                        self.current_repos_with_search_errors.append(
+                            (pub, _("failed to respond"), err))
+                for pub in error.invalid_servers:
+                        self.current_repos_with_search_errors.append(
+                            (pub, _("invalid response"),
+                                _("A valid response was not returned.")))
+                for pub, err in error.unsupported_servers:
+                        self.current_repos_with_search_errors.append(
+                            (pub, _("unsupported search"), err))
+
         def __on_infosearch_button_clicked(self, widget):
                 self.__handle_api_search_error(True)
 
         def __handle_api_search_error(self, show_all=False):
                 if len(self.current_repos_with_search_errors) == 0:
                         self.w_infosearch_frame.hide()
                         return
-                else:
-                        self.w_infosearch_button.set_size_request(26, 22)
-                        self.w_infosearch_frame.show()
 
-                repo_pubs = self.__get_repo_publishers()
                 repo_count = 0
-                for url in self.current_repos_with_search_errors:
-                        if show_all or (url not in self.gconf_not_show_repos):
+                for pub, err_type, err_str in self.current_repos_with_search_errors:
+                        if show_all or (pub not in self.gconf_not_show_repos):
                                 repo_count += 1
                 if repo_count == 0:
+                        self.w_infosearch_frame.hide()
                         return
 
+                self.w_infosearch_button.set_size_request(26, 22)
+                self.w_infosearch_frame.show()
                 infobuffer = self.api_search_error_textview.get_buffer()
                 infobuffer.set_text("")
                 textiter = infobuffer.get_end_iter()
-                for url in self.current_repos_with_search_errors:
-                        if show_all or (url not in self.gconf_not_show_repos):
+                for pub, err_type, err_str in self.current_repos_with_search_errors:
+
+                        if show_all or (pub not in self.gconf_not_show_repos):
                                 infobuffer.insert_with_tags_by_name(textiter,
-                                        "%s" % repo_pubs[url], "bold")
-                                infobuffer.insert(textiter, " (%s)\n" % url)
+                                    "%(pub)s (%(err_type)s)\n" % {"pub": pub,
+                                    "err_type": err_type}, "bold")
+                                infobuffer.insert(textiter, "%s\n" % (err_str))
+
                 self.api_search_checkbox.set_active(False)
                 self.api_search_error_dialog.show()
                 self.api_search_button.grab_focus()
 
         def __get_repo_publishers(self):

@@ -1013,19 +1012,20 @@
                         gobject.TYPE_INT,         # enumerations.REPOSITORY_ID
                         gobject.TYPE_STRING,      # enumerations.REPOSITORY_NAME
                         )
 
         def __init_application_tree_view(self, application_list,
-            application_list_filter, application_list_sort):
+            application_list_filter, application_list_sort,
+            application_sort_column):
                 ##APPLICATION MAIN TREEVIEW
                 if application_list_filter == None:
                         application_list_filter = application_list.filter_new()
                 if application_list_sort == None:
                         application_list_sort = \
                             gtk.TreeModelSort(application_list_filter)
                         application_list_sort.set_sort_column_id(
-                            enumerations.NAME_COLUMN, gtk.SORT_ASCENDING)
+                            application_sort_column, gtk.SORT_ASCENDING)
                         application_list_sort.set_sort_func(
                             enumerations.STATUS_ICON_COLUMN, self.__status_sort_func)
                 toggle_renderer = gtk.CellRendererToggle()
 
                 column = gtk.TreeViewColumn("", toggle_renderer, \

@@ -1038,10 +1038,11 @@
                 self.w_application_treeview.append_column(column)
                 name_renderer = gtk.CellRendererText()
                 column = gtk.TreeViewColumn(_("Name"), name_renderer,
                     text = enumerations.NAME_COLUMN)
                 column.set_resizable(True)
+                column.set_min_width(150)
                 column.set_sort_column_id(enumerations.NAME_COLUMN)
                 column.set_sort_indicator(True)
                 column.set_cell_data_func(name_renderer, self.cell_data_function, None)
                 column.connect_after('clicked',
                     self.__application_treeview_column_sorted, None)

@@ -1086,11 +1087,12 @@
                 toggle_renderer.connect('toggled', self.__active_pane_toggle,
                     application_list_sort)
 
         def __init_tree_views(self, application_list, category_list, 
             section_list, application_list_filter = None, 
-            application_list_sort = None):
+            application_list_sort = None, 
+            application_sort_column = enumerations.NAME_COLUMN):
                 '''This function connects treeviews with their models and also applies
                 filters'''
                 if category_list == None:
                         self.w_application_treeview.set_model(None)
                         self.__remove_treeview_columns(self.w_application_treeview)

@@ -1114,11 +1116,12 @@
                         else:
                                 self.set_section = 0
 
                 if application_list != None:
                         self.__init_application_tree_view(application_list,
-                            application_list_filter, application_list_sort)
+                            application_list_filter, application_list_sort, 
+                            application_sort_column)
 
                 if self.first_run:
                         # When vadj changes we need to set image descriptions
                         # on visible status icons. This catches moving the scroll bars
                         # and scrolling up and down using keyboard.

@@ -1314,10 +1317,13 @@
         def __set_visible_status(self, check_range = True):
                 self.visible_status_id = 0
                 if self.w_main_view_notebook.get_current_page() != \
                     NOTEBOOK_PACKAGE_LIST_PAGE:
                         return
+                if self.__doing_search():
+                        return
+
                 a11y_enabled = False
                 if self.a11y_application_treeview.get_n_accessible_children() != 0:
                         a11y_enabled = True
 
                 visible_range = self.w_application_treeview.get_visible_range()

@@ -1370,10 +1376,11 @@
                         # Only Fetch description for packages without a
                         # description
                         if desc == '...':
                                 fmri = sort_filt_model.get_value(sf_itr,
                                     enumerations.FMRI_COLUMN)
+                                if fmri != None:
                                 pkg_stem = fmri.get_pkg_stem(
                                     include_scheme = True)
                                 pkg_stems_and_itr_to_fetch[pkg_stem] = \
                                     model.get_string_from_iter(app_itr)
                         if a11y_enabled:

@@ -1420,10 +1427,14 @@
                         print "FETCHED PKGS: \n%s" % pkg_descriptions_for_update
                 gobject.idle_add(self.__update_description_from_iter,
                     pkg_descriptions_for_update, orig_model)
 
         def __update_description_from_iter(self, pkg_descriptions_for_update, orig_model):
+                #If doing a search abandon description updates
+                if self.__doing_search():
+                        return
+
                 sort_filt_model = \
                     self.w_application_treeview.get_model() #gtk.TreeModelSort
                 filt_model = sort_filt_model.get_model() #gtk.TreeModelFilter
                 model = filt_model.get_model() #gtk.ListStore
 

@@ -1732,54 +1743,69 @@
                         else:
                                 pub = self.api_o.get_preferred_publisher()
                         origin_uri = self.__get_origin_uri(pub.selected_repository)
                         servers.append({"origin": origin_uri})
                 if debug:
-                        print "pargs:", pargs
-                        print "servers:", servers
+                        print "Search: pargs %s servers: %s" % (pargs, servers)
                         
+                #TBD If we ever search just Installed pkgs should allow for a local search
                 case_sensitive = False
+                return_actions = True
                 searches.append(self.api_o.remote_search(
-                    [api.Query(" ".join(pargs), case_sensitive, True, None, None)],
+                    [api.Query(" ".join(pargs), case_sensitive, return_actions)],
                     servers=servers))
-                result_tuple = {}
+                if debug:
+                        print "Search Args: %s : cs: %s : retact: %s" % \
+                                ("".join(pargs), case_sensitive, return_actions)
+
+                last_name = ""
+                self.current_search_publisher = None
+
+                # Sorting results by Name gives best overall appearance and flow
+                sort_col = enumerations.NAME_COLUMN
                 try:
                         for query_num, publisher, (v, return_type, tmp) in \
                             itertools.chain(*searches):
-                                if v == 1 and \
-                                    return_type == api.Query.RETURN_PACKAGES:
-                                        repo = None
-                                        if publisher is not None \
-                                            and "prefix" in publisher:
-                                                repo = publisher["prefix"]
-                                        name = fmri.PkgFmri(str(tmp)).get_name()
-                                        result_tuple[(name, repo)] = -1
-                                        if len(result_tuple) == SEARCH_LIMIT:
-                                                break
-                                else:
-                                        # We are not interested in this error
+                                if v < 1 or return_type != api.Query.RETURN_PACKAGES:
                                         gobject.idle_add(self.w_progress_dialog.hide)
                                         self.__process_after_search_failure()
                                         return
+
+                                pub = None
+                                if publisher is not None \
+                                    and "prefix" in publisher:
+                                        pub = publisher["prefix"]
+                                name = fmri.PkgFmri(str(tmp)).get_name()
+                                if last_name != name:
+                                        if debug:
+                                                print "Result Name: %s (%s)" % (name, pub)
+                                        a_res = name, pub
+                                        result.append(a_res)
+                                        #Ignore Status when fetching
+                                        application_list = \
+                                                self.__get_min_list_from_search(result)
+                                        self.current_search_publisher = pub
+                                        self.in_setup = True
+                                        gobject.idle_add(self.__init_tree_views, 
+                                            application_list, None, None, None, None,
+                                            sort_col)
+                                last_name = name
                                 self.pylintstub = query_num
                 except api_errors.ProblematicSearchServers, ex:
-                        self.__parse_api_search_error(ex)
+                        self.__process_api_search_error(ex)
                         gobject.idle_add(self.w_progress_dialog.hide)
                         gobject.idle_add(self.__handle_api_search_error)
-                        if len(result_tuple) == 0:
+                        if len(result) == 0:
                                 self.__process_after_search_with_zero_results()
                                 return
                 except Exception, ex:
                         # We are not interested in this error
                         gobject.idle_add(self.w_progress_dialog.hide)
                         self.__process_after_search_failure()
                         return
                 if debug:
-                        print "Number of search results:", len(result_tuple)
-                for name, repo in result_tuple:
-                        a_res = name, repo
-                        result.append(a_res)
+                        print "Number of search results:", len(result)
                 if len(result) == 0:
                         if debug:
                                 print "No search results"
                         self.__process_after_search_with_zero_results()
                         return

@@ -1790,19 +1816,22 @@
                 while self.catalog_loaded == False:
                         if times == 0:
                                 break
                         time.sleep(1)
                         times -= 1
+
+                #Now fetch full result set with Status
                 self.in_setup = True
-                application_list = self.__get_list_from_search(result)
+                application_list = self.__get_full_list_from_search(result)
+                gobject.idle_add(self.__init_tree_views, application_list, None, None, \
+                    None, None, sort_col)
+
                 if self.search_start > 0:
                         self.search_time_sec = int(time.time() - self.search_start)
+                        if debug:
+                                print "Search time: %d (sec)" % self.search_time_sec
                 self.search_start = 0
-                gobject.idle_add(self.__set_empty_details_panel)
-                gobject.idle_add(self.__set_main_view_package_list)
-                gobject.idle_add(self.__init_tree_views, application_list,
-                    None, None)
 
         def __process_after_search_with_zero_results(self):
                 if self.search_start > 0:
                         self.search_time_sec = int(time.time() - self.search_start)
                 self.search_start = 0

@@ -1810,12 +1839,21 @@
                 application_list = self.__get_new_application_liststore()
                 gobject.idle_add(self.__set_empty_details_panel)
                 gobject.idle_add(self.__set_main_view_package_list)
                 gobject.idle_add(self.__init_tree_views, application_list, None, None)
 
-        def __get_list_from_search(self, search_result):
+        def __get_min_list_from_search(self, search_result):
                 application_list = self.__get_new_application_liststore()
+                for name, publisher in search_result:
+                        application_list.append(
+                            [False, None, name, '...', enumerations.NOT_INSTALLED, None, 
+                            "pkg://" + publisher + "/" + name, None, True, None, 
+                            publisher])
+                return application_list
+
+        def __get_full_list_from_search(self, search_result):
+                application_list = self.__get_new_application_liststore()
                 self.__add_pkgs_to_list_from_search(search_result,
                     application_list)
                 return application_list
 
         def __add_pkgs_to_list_from_search(self, search_result,

@@ -2078,18 +2116,20 @@
 
         def __on_api_search_checkbox_toggled(self, widget):
                 active = self.api_search_checkbox.get_active()
                 if len(self.current_repos_with_search_errors) > 0:
                         if active:
-                                for url in self.current_repos_with_search_errors:
-                                        if url not in self.gconf_not_show_repos:
-                                                self.gconf_not_show_repos += url + ","
+                                for pub, err_type, err_str in \
+                                        self.current_repos_with_search_errors:
+                                        if pub not in self.gconf_not_show_repos:
+                                                self.gconf_not_show_repos += pub + ","
                         else:
-                                for url in self.current_repos_with_search_errors:
+                                for pub, err_type, err_str in \
+                                        self.current_repos_with_search_errors:
                                         self.gconf_not_show_repos = \
                                             self.gconf_not_show_repos.replace(
-                                            url + ",", "")
+                                            pub + ",", "")
                         try:
                                 self.client.set_string(API_SEARCH_ERROR_PREFERENCES,
                                     self.gconf_not_show_repos)
                         except GError:
                                 pass

@@ -2426,13 +2466,21 @@
 
         def __setup_publisher(self, publishers=[]):
                 self.saved_filter_combobox_active = self.initial_show_filter
                 application_list, category_list , section_list = \
                     self.__get_application_categories_lists(publishers)
+                self.__unset_saved()
                 gobject.idle_add(self.__init_tree_views, application_list,
                     category_list, section_list)
 
+        def __unset_saved(self):
+                self.saved_application_list = None
+                self.saved_application_list_filter = None
+                self.saved_application_list_sort = None
+                self.saved_category_list = None
+                self.saved_section_list = None
+
         def __get_application_categories_lists(self, publishers=[]):
                 if not self.visible_repository:
                         self.visible_repository = self.__get_active_publisher()
                 application_list = self.__get_new_application_liststore()
                 category_list = self.__get_new_category_liststore()

@@ -2462,12 +2510,16 @@
                                 category_list.prepend([0, _('All'), None, None, False,
                                     True, None])
                         if self.application_list and self.category_list and \
                             not self.visible_repository_uptodate:
                                 if self.visible_repository:
+                                        dump_list = self.application_list
+                                        if self.saved_application_list != None:
+                                                dump_list = \
+                                                    self.saved_application_list
                                         self.__dump_datamodels(self.visible_repository,
-                                            self.application_list, self.category_list,
+                                            dump_list, self.category_list,
                                             self.section_list)
                         self.visible_repository = self.__get_active_publisher()
                         self.visible_repository_uptodate = uptodate
                 return application_list, category_list, section_list
 

@@ -2476,10 +2528,22 @@
                         return self.cache_o.check_if_cache_uptodate(publisher)
                 return False
 
         def __dump_datamodels(self, publisher, application_list, category_list,
             section_list):
+                #Consistency check - only dump models if publisher passed in matches 
+                #publisher in application list
+                if application_list == None:
+                        return
+                app_pub = application_list[0][enumerations.AUTHORITY_COLUMN]
+                if publisher != app_pub:
+                        if debug:
+                                print "ERROR: __dump_data_models(): INCONSISTENT " \
+                                        "pub %s != app_list_pub %s" % \
+                                        (publisher,  app_pub)
+                        return
+
                 if self.cache_o:
                         if self.img_timestamp == \
                             self.cache_o.get_index_timestamp():
                                 Thread(target = self.cache_o.dump_datamodels,
                                     args = (publisher, application_list, category_list,

@@ -2614,11 +2678,15 @@
                                 gobject.spawn_async([self.application_path, "-R",
                                     self.image_dir_arg, "-U", be_name])
                         else:
                                 gobject.spawn_async([self.application_path,
                                     "-U", be_name])
-                elif not self.in_search_mode:
+                elif self.in_search_mode:
+                        self.__dump_datamodels(self.visible_repository,
+                            self.saved_application_list, self.category_list,
+                            self.section_list)
+                else:
                         visible_repository = self.__get_visible_repository_name()
                         self.__dump_datamodels(visible_repository,
                                 self.application_list, self.category_list,
                                 self.section_list)
 

@@ -3808,31 +3876,12 @@
                 '''Function which updates statusbar'''
                 if self.statusbar_message_id > 0:
                         self.w_main_statusbar.remove(0, self.statusbar_message_id)
                         self.statusbar_message_id = 0
                 search_text = self.w_searchentry.get_text()
-                if self.in_search_mode:
-                        if self.is_search_all:
-                                opt_str = _('Searched All for "%s"') % (search_text)
-                        else:
-                                opt_str = \
-                                        _('Searched %(last_active)s '
-                                            'for "%(search_text)s"') \
-                                        % {"last_active" : self.last_active_publisher,
-                                            "search_text" : search_text}
-                        if len(self.application_list) == SEARCH_LIMIT:
-                                fmt_str = _("%(option_str)s:  first %(number)d "
-                                    "found %(time)s")
-                        else:
-                                fmt_str = _("%(option_str)s:  %(number)d found %(time)s")
-                        time_str = ""
-                        if self.search_time_sec > 0:
-                                time_str = _("in %d seconds") % self.search_time_sec
-                        status_str = fmt_str % {"option_str" : opt_str,
-                            "number" : len(self.application_list), "time" : time_str}
-                        self.w_main_statusbar.push(0, status_str)
-                        return
+
+                if not self.in_search_mode:
                 installed = 0
                 self.selected = 0
                 sel = 0
                 if self.application_list == None:
                         return

@@ -3839,23 +3888,55 @@
                 visible_repository = self.__get_visible_repository_name()
                 pkgs = self.selected_pkgs.get(visible_repository)
                 if pkgs:
                         self.selected = len(pkgs)
                 for pkg_row in self.application_list:
-                        if pkg_row[enumerations.STATUS_COLUMN] == enumerations.INSTALLED \
+                                if pkg_row[enumerations.STATUS_COLUMN] == \
+                                        enumerations.INSTALLED \
                             or pkg_row[enumerations.STATUS_COLUMN] == \
                             enumerations.UPDATABLE:
                                 installed = installed + 1
                         if pkg_row[enumerations.MARK_COLUMN]:
                                 sel = sel + 1
                 listed_str = _('%d listed') % len(self.application_list)
                 sel_str = _('%d selected') % sel
                 inst_str = _('%d installed') % installed
-                status_str = _("%s: %s , %s, %s.") % (visible_repository, listed_str,
-                        inst_str, sel_str)
+                        status_str = _("%s: %s , %s, %s.") % (visible_repository,
+                            listed_str, inst_str, sel_str)
                 self.w_main_statusbar.push(0, status_str)
+                        return
 
+                # In Search Mode
+                active = ""
+                if self.is_search_all:
+                        if self.__doing_search():
+                                if self.current_search_publisher != None:
+                                        active = "(" + self.current_search_publisher + \
+                                                ") "
+                                opt_str = _('Searching... '
+                                    '%(active)sfor "%(search_text)s"') % \
+                                        {"active": active, "search_text": search_text}
+                        else:
+                                opt_str = _('Searched All for "%s"') % (search_text)
+                else:
+                        search_str = _("Searched")
+                        if self.__doing_search():
+                                search_str = _("Searching...")
+                        if self.last_active_publisher != None:
+                                active = "(" + self.last_active_publisher + ") "
+                        opt_str = \
+                                _('%(search)s %(last_active)sfor "%(search_text)s"') \
+                                % {"search": search_str, "last_active" : active,
+                                    "search_text" : search_text}
+                fmt_str = _("%(option_str)s:  %(number)d found %(time)s")
+                time_str = ""
+                if self.search_time_sec > 0:
+                        time_str = _("in %d seconds") % self.search_time_sec
+                status_str = fmt_str % {"option_str" : opt_str, "number" :
+                    len(self.application_list), "time" : time_str}
+                self.w_main_statusbar.push(0, status_str)
+
         def update_package_list(self, update_list):
                 if update_list == None and self.img_timestamp:
                         return
                 visible_repository = self.__get_visible_repository_name()
                 default_publisher = self.default_publisher