예제 #1
0
    def update_order(self):
        'Sends order to the sorter.'

        if hasattr(self, 'new_sorter'):
            order = deepcopy(self.order['contacts'])
            order['__groups__'] = self.order['groups']
            on_thread('sorter').call(self.new_sorter.set_contact_order, order)
예제 #2
0
    def search(self, s, cb = None):
        if not hasattr(self, 'new_sorter'):
            return
        assert isinstance(s, basestring)
        self._search_by = s
        self.reconfig_sorter(rebuild=False)
        self.rebuild_now()

        if cb is not None:
            on_thread('sorter').call(lambda: wx.CallAfter(cb, self._search_results))
예제 #3
0
    def _on_account_offline(self, src):
        '''
        Notifies the buddylist sorter than an account is now offline.
        '''
        sorter = getattr(self.profile.blist, 'new_sorter', None)
        if sorter is None:
            return

        if is_im_account(src) or src is self.profile:
            log.info('informing the sorter that (%r, %r) went offline', src.username, src.protocol)
            on_thread('sorter').call(sorter.removeAccount, src.username, src.protocol)
예제 #4
0
    def remove(self, mc, contact, explode=True, cleanup=True):
        if isinstance(mc, int):
            mcname = self.idstr(mc)
            if mc not in self:
                return
            contacts = self[mc].buddies
        else:
            mcname = mc.name
            contacts = mc.mcinfo.buddies

        log.info('removing %r from metacontact %r', contact, mcname)

        cd = contact_dict(contact)

        for d in list(contacts):
            if cd['name'] == d.name and cd['service'] == d.service:
                contacts.remove(d)

        # Contact inherits certain properties from the MetaContact.
        get, set = self.blist.get_contact_info, self.blist.set_contact_info
        sms, email = get(mcname, 'sms'), get(mcname, 'email')

        contact_obj = self.blist.contact_for_id(contact) if isinstance(
            contact, basestring) else contact

        def tolist(s):
            if isinstance(s, basestring): return [s]

        # "inherit" email addresses and sms numbers from the metacontact.
        if sms:
            new_sms = removedupes((tolist(get(mcname, 'sms')) or []) + sms)
            set(contact_obj, 'sms', new_sms)
        if email:
            new_email = removedupes((tolist(get(mcname, 'email')) or []) +
                                    email)
            set(contact_obj, 'email', new_email)

        info('removed %r from %r', contact, mc)
        if hasattr(self.blist, 'new_sorter'):
            on_thread('sorter').call(self.blist.new_sorter.removeContact,
                                     mcname)
        self.rebuild_buddy_mapping()
        self.blist._info_changed()

        if explode and len(contacts) == 1:
            self.remove(mc, contacts[0], True)
            self.remove_mc_entry(mc)
        elif explode and len(contacts) == 0:
            pass
        else:
            if cleanup:
                self.blist.rebuild()
예제 #5
0
    def remove(self, mc, contact, explode = True, cleanup = True):
        if isinstance(mc, int):
            mcname = self.idstr(mc)
            if mc not in self:
                return
            contacts = self[mc].buddies
        else:
            mcname = mc.name
            contacts = mc.mcinfo.buddies

        log.info('removing %r from metacontact %r', contact, mcname)


        cd = contact_dict(contact)

        for d in list(contacts):
            if cd['name'] == d.name and cd['service'] == d.service:
                contacts.remove(d)

        # Contact inherits certain properties from the MetaContact.
        get, set = self.blist.get_contact_info, self.blist.set_contact_info
        sms, email = get(mcname, 'sms'), get(mcname, 'email')

        contact_obj = self.blist.contact_for_id(contact) if isinstance(contact, basestring) else contact
        def tolist(s):
            if isinstance(s, basestring): return [s]

        # "inherit" email addresses and sms numbers from the metacontact.
        if sms:
            new_sms = removedupes((tolist(get(mcname, 'sms')) or []) + sms)
            set(contact_obj, 'sms', new_sms)
        if email:
            new_email = removedupes((tolist(get(mcname, 'email')) or []) + email)
            set(contact_obj, 'email', new_email)

        info('removed %r from %r', contact, mc)
        if hasattr(self.blist, 'new_sorter'):
            on_thread('sorter').call(self.blist.new_sorter.removeContact, mcname)
        self.rebuild_buddy_mapping()
        self.blist._info_changed()

        if explode and len(contacts) == 1:
            self.remove(mc, contacts[0], True)
            self.remove_mc_entry(mc)
        elif explode and len(contacts) == 0:
            pass
        else:
            if cleanup:
                self.blist.rebuild()
예제 #6
0
    def rebuild(self, *a):
        'Triggers a full buddylist update.'

        if on_thread('sorter').now:
            # sorter thread should never trigger a rebuild
            return

        self.dirty = True
예제 #7
0
    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
예제 #8
0
    def set_new(self, contacts, hidden_contacts):
        if self[:] != contacts or self.hidden != hidden_contacts:
            self[:] = contacts
            self.hidden[:] = hidden_contacts
            self.meta_dirty = True

            # when the contents of a MetaContact changes, the sorter needs to invalidate
            # it's knowledge of it
            sorter = getattr(self.manager.blist, 'new_sorter', None)
            if sorter is not None:
                def invalidate_sorter_contact():
                    sorter.removeContact(self.name)

                if on_thread('sorter').now:
                    # if called from resort->collect, this is already true,
                    invalidate_sorter_contact()
                else: # but sometimes we call it on the console for testing
                    on_thread('sorter').call(invalidate_sorter_contact)
예제 #9
0
    def set_new(self, contacts, hidden_contacts):
        if self[:] != contacts or self.hidden != hidden_contacts:
            self[:] = contacts
            self.hidden[:] = hidden_contacts
            self.meta_dirty = True

            # when the contents of a MetaContact changes, the sorter needs to invalidate
            # it's knowledge of it
            sorter = getattr(self.manager.blist, 'new_sorter', None)
            if sorter is not None:

                def invalidate_sorter_contact():
                    sorter.removeContact(self.name)

                if on_thread('sorter').now:
                    # if called from resort->collect, this is already true,
                    invalidate_sorter_contact()
                else:  # but sometimes we call it on the console for testing
                    on_thread('sorter').call(invalidate_sorter_contact)
예제 #10
0
    def _setup_blist_sorter(self):
        if hasattr(self, 'new_sorter'):
            return

        blist.set_group_type((DGroup, Group, MockGroup))
        self.new_sorter = blist.BuddyListSorter()
        self.update_order()

        # link prefs
        cb = self._on_blist_sort_pref
        link = profile.prefs.link
        for prefname in ('buddylist.fakeroot_name',
                         'buddylist.show_offline',
                         'buddylist.group_offline',
                         'buddylist.show_mobile',
                         'buddylist.hide_offline_groups',
                         'buddylist.sortby'):
            link(prefname, cb)

        cb()
        assert on_thread('sorter').now
        self._reconfig_sorter(False)
예제 #11
0
    def get_sorter(self):
        # TODO
        return 'New sorter diagnostic needs to happen on the sorter thread; plz impl on_thread("sorter").blocking_call kthx'

        sorter = profile.blist.new_sorter

        from util.threads.bgthread import on_thread
        def later():
            s = ''.join(['expanded root:\n\n',
                         sorter.dump_root(),
                         '\n\ngathered tree:\n\n',
                         sorter.dump_gather()])

            s += '\n\npython tree:\n\n'

            from contacts.buddyliststore import dump_elem_tree
            root = sorter._gather()
            try:
                s += dump_elem_tree(root)
            finally:
                sorter._done_gather(root)

        # TODO: blocking_call not implemented
        return on_thread('sorter').blocking_call(later)
예제 #12
0
    def update_data(self, data):
        """
        Updates this store's current state with incoming data from the network.

        data should be a mapping containing 'metacontacts', 'order', and 'info'
        structures (see comment at top of file)
        """
        rebuild = False

        # This method needs to substitute some defaultdicts for the normal
        # dictionaries that come back from the server.

        # Metacontact information

        #if data['metacontacts']
        mc_dict = data.get('metacontacts', {})
        if not isinstance(mc_dict, dict):
            log.critical('invalid metacontacts dictionary')
            mc_dict = {}

        # Contact information like SMS numbers and email addresses.
        self.info = defaultdict(dict)

        si = self.info
        if 'info' in data:
            for (k, v) in data['info'].iteritems():
                if isinstance(k, str):
                    cmpk = k.decode('utf8')
                else:
                    cmpk = k

                if not isinstance(cmpk, unicode):
                    continue

                if cmpk.startswith('Meta') or any((cmpk.endswith('_' + prot)
                                                   for prot in protocols.iterkeys())):
                    if any(v.values()):
                        si[k] = v

            for c, v in si.iteritems():
                for attr in ('email', 'sms'):
                    if attr in v:
                        self.contact_info_changed(c, attr, v[attr])

        self.metacontacts = MetaContactManager(self, mc_dict)
        if hasattr(self, 'new_sorter'):
            on_thread('sorter').call(self.new_sorter.removeAllContacts)
        rebuild = True

        # Manual ordering of groups
        try:
            self.order = deepcopy(data['order'])
            self.order['groups'] = list(oset(self.order['groups']))
            contacts = self._filtered_contacts()
            self.order['contacts'] = defaultdict(list)
            self.order['contacts'].update(contacts)
        except Exception:
            log.critical('error receiving order')
            self._init_order()

        # note: loading tofrom data from the network is deprecated. this data
        # now goes out to disk. see save/load_local_data
        if 'tofrom' in data and isinstance(data['tofrom'], dict) and \
            'im' in data['tofrom'] and 'email' in data['tofrom']:
            self.dispatch.set_tofrom(deepcopy(data['tofrom']))

        if rebuild:
            self.rebuild()

        self.update_order()