def safe_metacontacts(self, rootgroups, use_cached=False): default = lambda: DGroup('Root', [], [], []) if use_cached: try: return self.collected_metacontacts except AttributeError: pass try: self.collected_metacontacts = metacontacts = self.metacontacts.collect(*rootgroups) except Exception: # If there was an exception collecting metacontacts, # just proceed. print_exc() metacontacts = DGroup('Root', [], [], []) return metacontacts
def resort(self, mock = False): assert on_thread('sorter').now rootgroups = [display_copy(g) for g in self.rootgroups if isinstance(g, GroupTypes)] self.personalities = self.track_personalities(rootgroups) metacontacts = self.safe_metacontacts(rootgroups) # Always collect metacontacts, but exit early here if sorting is paused. if self.sorting_paused:# or not profile.prefs_loaded: return metrics.event('Buddylist Sort') self._setup_blist_sorter() # invalidate all sorter knowledge of contacts. # results in more CPU usage, but until we put metacontact combining into the sorter # this might be necessary. self.new_sorter.removeAllContacts() newroots = rootgroups[:] + [metacontacts] for i, root in enumerate(newroots): root.name = "Root" + str(i) root._root = True root = DGroup('none', [], [], newroots) if mock: self.mock_root = make_mocklist(root) self.new_sorter.set_root(root) view = get_view_from_sorter(self.new_sorter) if getattr(self, '_search_by', ''): if len(view) > 0: contacts_group = view[0] # don't allow renaming, etc of the search "Contacts" group contacts_group._disallow_actions = True num_contacts = len(contacts_group) else: num_contacts = -1 self._search_results = self._search_results[1], num_contacts else: if pref('buddylist.hide_offline_dependant', False, bool): hide_offline_groups = not pref('buddylist.show_offline') and pref('buddylist.hide_offline_groups') else: hide_offline_groups = pref('buddylist.hide_offline_groups') if hide_offline_groups: view[:] = filter((lambda g: not offline_nonempty_group_re.match(g.display_string)), view) for g in view: remove_duplicate_contacts(g) self.add_search_entries(view) hooks.notify('buddylist.sorted', view) return view
def display_copy(group): 'Turns Groups into DGroups.' elems = [] for elem in group: if isinstance(elem, Group): elems.append(display_copy(elem)) else: elems.append(elem) return DGroup(group.name, [group.protocol], [group.id], elems)
def use_sorter(self, sorter): rootgroups = [display_copy(g) for g in self.rootgroups if isinstance(g, GroupTypes)] newroots = rootgroups[:] + [self.safe_metacontacts(rootgroups, use_cached=True)] for i, root in enumerate(newroots): root.name = "Root" + str(i) root._root = True root = DGroup('none', [], [], newroots) sorter.set_root(root) view = get_view_from_sorter(sorter) for g in view: remove_duplicate_contacts(g) return view
def __init__(self, conn_accts): Observable.__init__(self) self.dirty = False self.sorting_paused = True #self._listen_for_pref_load() self.rebuild_timer = wx.PyTimer(self.rebuild_later) self.rebuild_timer.StartRepeating(500) # Holds the final view that goes into the TreeList. self.view = DGroup('__root__', [], []) self.info = {} # Rootgroups are the "protocol" rootgroups with the original, # unmodified versions of the buddy list structure for each account self.rootgroups = [] self.base_attrs = frozenset([None, 'alias', 'status', 'status_message', 'icon', 'icon_hash', 'entering', 'leaving', 'idle', 'away','mobile']) self.attrs = set(self.base_attrs) # conn_accts must be an observable list of connected accounts conn_accts.add_observer(self.on_connections_changed) self.metacontacts = MetaContactManager(self) self._init_order() self.contact_info_changed = Delegate() self.dispatch = ContactDispatcher() self.caches = dict(tofrom = DiskCache('im_history.dat', validator = validate_tofrom)) self.load_local_data() # save local to/from data on exit hooks.register('digsby.app.exit', self.save_local_data) self._search_by = u'' self._search_results = (0, 0) # number of contacts found in last two searches #todo: make then_bys based on a pref self.sort_models = sort_model.build_models( then_bys = 1, obj = self) self.sbw = sort_model.SortByWatcher(self.sort_models)
def collect(self, *roots): ''' For contacts which are in metacontacts, remove them from the original protocol groups and add them to a new group. Returns that new group full of DGroups holding MetaContacts. ''' # Remove meta contacts mc_root = DGroup('Root', protocols=[], ids=[]) b2m = self.buddies_to_metas # = = defaultdict(set) #map buddy description to set of metas groupnames = oset() # For each protocol root group cs = defaultdict(list) mc_gnames = self.groupnames metacontact_objs = self.metacontact_objs def maybe_remove_contact(contact, group): if (contact.name.lower(), contact.service) in b2m: for meta in b2m[(contact.name.lower(), contact.service)]: cs[meta.id].append(contact) group.remove(contact) return True return False from contacts.Group import GroupTypes for root in roots: # Find the corresponding group for group in list(root): gflag = False if group is root: continue if isinstance(group, GroupTypes): for elem in list(group): gflag |= maybe_remove_contact(elem, group) if gflag and (group.name not in groupnames): groupnames.add(group.name) else: # contact elem = group if maybe_remove_contact(elem, root): groupnames.add(get_fakeroot_name()) assert not set(cs.keys()) - set(self.keys()) for id in self.iterkeys(): elems = cs[id] order = [b.tag for b in self[id].buddies] elems = list( sorted(elems, key=lambda elem: order.index( (elem.name.lower(), elem.service)))) out = [] hidden = [] for tag in order: online = False while elems and (elems[0].name.lower(), elems[0].service) == tag: b = elems.pop(0) if not online: out.append(b) online = True else: hidden.append(b) if not online: old = [ o for o in metacontact_objs[id] if (isinstance(o, OfflineBuddy) and (o.name.lower(), o.service) == tag) ] if old: out.append(old[0]) else: out.append(OfflineBuddy(*tag)) metacontact_objs[id].set_new(out, hidden) groups = {} for m in metacontact_objs.itervalues(): if any(not isinstance(b, OfflineBuddy) for b in m): for gname in self[m.id].groups: try: g = groups[gname[0]] except KeyError: groups[gname[0]] = g = DGroup(gname[0]) g.append(m) glen = len(groups) nextroot = DGroup('Root') for gname in groupnames: if gname in groups: nextroot.append(groups.pop(gname)) for gname in set(g[0] for g in mc_gnames) - set(groupnames): if gname in groups: nextroot.append(groups.pop(gname)) mc_root.extend(nextroot) # assert len(nextroot) == glen return mc_root
def inflate_groups(grouppath): 'Returns a DGroup tree given a sequence of names.' return [] if not grouppath else \ DGroup(grouppath[0], protocols = None, ids = None, *inflate_groups(grouppath[1:]))