--- old/src/packagemanager.py Fri Jul 3 15:36:57 2009 +++ new/src/packagemanager.py Fri Jul 3 15:36:56 2009 @@ -45,8 +45,6 @@ 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" @@ -270,6 +268,7 @@ 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 @@ -675,7 +674,7 @@ 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): @@ -762,22 +761,20 @@ % (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) @@ -785,26 +782,28 @@ 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() @@ -1015,7 +1014,8 @@ ) 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() @@ -1023,7 +1023,7 @@ 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() @@ -1040,6 +1040,7 @@ 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) @@ -1088,7 +1089,8 @@ 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: @@ -1116,7 +1118,8 @@ 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 @@ -1316,6 +1319,9 @@ 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 @@ -1372,10 +1378,11 @@ if desc == '...': fmri = sort_filt_model.get_value(sf_itr, enumerations.FMRI_COLUMN) - 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 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: self.__set_accessible_status(sort_filt_model, sf_itr) start += 1 @@ -1422,6 +1429,10 @@ 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 @@ -1734,38 +1745,56 @@ 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: @@ -1774,10 +1803,7 @@ 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" @@ -1792,15 +1818,18 @@ 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: @@ -1812,8 +1841,17 @@ 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 @@ -2080,14 +2118,16 @@ 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) @@ -2428,12 +2468,22 @@ 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=[]): + print "__get_application_categories_lists: ", self.visible_repository if not self.visible_repository: self.visible_repository = self.__get_active_publisher() + print "** __get_application_categories_lists: ", self.visible_repository application_list = self.__get_new_application_liststore() category_list = self.__get_new_category_liststore() section_list = self.__get_new_section_liststore() @@ -2464,8 +2514,12 @@ 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 @@ -2478,6 +2532,18 @@ 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(): @@ -2616,7 +2682,11 @@ 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, @@ -3810,48 +3880,61 @@ 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} + + if not self.in_search_mode: + installed = 0 + self.selected = 0 + sel = 0 + if self.application_list == None: + return + 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 \ + 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) self.w_main_statusbar.push(0, status_str) return - installed = 0 - self.selected = 0 - sel = 0 - if self.application_list == None: - return - 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 \ - 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) + + # 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): @@ -3965,7 +4048,7 @@ return 0 if __name__ == '__main__': - debug = False + debug = True debug_descriptions = False update_all_proceed = False ua_be_name = None