Ticket #1201: modelfilter.2.patch

File modelfilter.2.patch, 41.7 kB (added by asterix, 14 months ago)
  • src/roster_window.py

     
    3030import sys 
    3131import time 
    3232import urllib 
     33import threading 
    3334 
    3435import common.sleepy 
    3536import history_window 
     
    8081class RosterWindow: 
    8182        '''Class for main window of the GTK+ interface''' 
    8283 
    83         def get_account_iter(self, name): 
     84        def get_account_iter(self, name, model = None): 
    8485                ''' Returns a gtk.TreeIter of accounts in roster data model or None ''' 
    85                 model = self.tree.get_model() 
     86                if not model: 
     87                        model = self.tree.get_model() 
    8688                if model is None: 
    8789                        return 
    8890                account_iter = model.get_iter_root() 
    8991                if self.regroup: 
    9092                        return account_iter 
    9193                while account_iter: 
    92                         account_name = model[account_iter][C_ACCOUNT].decode('utf-8') 
    93                         if name == account_name: 
     94                        account_name = model[account_iter][C_ACCOUNT] 
     95                        if account_name and name == account_name.decode('utf-8'): 
    9496                                break 
    9597                        account_iter = model.iter_next(account_iter) 
    9698                return account_iter 
    9799 
    98         def get_group_iter(self, name, account): 
     100        def get_group_iter(self, name, account, model = None): 
    99101                ''' Returns a gtk.TreeIter of groups in roster data model or None ''' 
    100                 model = self.tree.get_model() 
    101                 root = self.get_account_iter(account) 
     102                if not model: 
     103                        model = self.tree.get_model() 
     104                root = self.get_account_iter(account, model) 
    102105                group_iter = model.iter_children(root) 
    103106                # C_NAME column contacts the pango escaped group name 
    104107                while group_iter: 
     
    108111                        group_iter = model.iter_next(group_iter) 
    109112                return group_iter 
    110113 
    111         def get_contact_iter(self, jid, account): 
     114        def get_contact_iter(self, jid, account, model = None): 
    112115                if jid == gajim.get_jid_from_account(account): 
    113116                        iter = self.get_self_contact_iter(account) 
    114117                        if iter: 
    115118                                return [iter] 
    116119                        else: 
    117120                                return [] 
    118                 model = self.tree.get_model() 
    119                 acct = self.get_account_iter(account) 
     121                if not model: 
     122                        model = self.tree.get_model() 
     123                acct = self.get_account_iter(account, model) 
    120124                found = [] 
    121125                if model is None: # when closing Gajim model can be none (async pbs?) 
    122126                        return found 
     
    124128                while group_iter: 
    125129                        contact_iter = model.iter_children(group_iter) 
    126130                        while contact_iter: 
    127                                 if jid == model[contact_iter][C_JID].decode('utf-8') and \ 
     131                                iter_jid = model[contact_iter][C_JID] 
     132                                if iter_jid and jid == iter_jid.decode('utf-8') and \ 
    128133                                        account == model[contact_iter][C_ACCOUNT].decode('utf-8'): 
    129134                                        found.append(contact_iter) 
    130135                                # find next contact iter 
     
    170175                        # show him 
    171176                        self.add_contact_to_roster(jid, account) 
    172177                        iters = self.get_contact_iter(jid, account) 
     178                        #FIXME: adding it doesn't mean it is visible 
     179                        if not iters: 
     180                                return 
    173181                        path = self.tree.get_model().get_path(iters[0]) 
    174182                if self.dragging or not gajim.config.get('scroll_roster_to_last_message'): 
    175183                        # do not change selection while DND'ing 
     
    184192        def add_account_to_roster(self, account): 
    185193                ''' Add an account to roster data model. ''' 
    186194                model = self.tree.get_model() 
     195                child_model = model.get_model() 
    187196                if self.get_account_iter(account): 
    188197                        return 
    189198 
    190199                # if we merge accounts... 
    191200                if self.regroup: 
    192201                        show = helpers.get_global_show() 
    193                         model.append(None, [self.jabber_state_images['16'][show], 
     202                        child_model.append(None, [self.jabber_state_images['16'][show], 
    194203                                _('Merged accounts'), 'account', '', 'all', None]) 
    195204                        self.draw_account(account) 
    196205                        return 
     
    204213 
    205214                our_jid = gajim.get_jid_from_account(account) 
    206215 
    207                 model.append(None, [self.jabber_state_images['16'][show], 
     216                child_model.append(None, [self.jabber_state_images['16'][show], 
    208217                        gobject.markup_escape_text(account), 
    209218                        'account', our_jid, account, tls_pixbuf]) 
    210219 
    211220        def draw_account(self, account): 
    212                 model = self.tree.get_model() 
    213                 iter = self.get_account_iter(account) 
     221                child_iter = self.get_account_iter(account, self.model) 
    214222                if self.regroup: 
    215223                        accounts = gajim.connections.keys() 
    216224                else: 
     
    239247                                                new_pixels += chr(128) 
    240248                                tls_pixbuf = gtk.gdk.pixbuf_new_from_data(new_pixels, colorspace, 
    241249                                        True, bps, width, height, rowstride) 
    242                         model[iter][C_SECPIXBUF] = tls_pixbuf 
     250                        self.model[child_iter][C_SECPIXBUF] = tls_pixbuf 
    243251                else: 
    244                         model[iter][C_SECPIXBUF] = None 
    245                 path = model.get_path(iter) 
     252                        self.model[child_iter][C_SECPIXBUF] = None 
     253                path = self.model.get_path(child_iter) 
    246254                account_name = account 
    247255                accounts = [account] 
    248256                if self.regroup: 
    249257                        account_name = _('Merged accounts') 
    250258                        accounts = [] 
    251                 if not self.tree.row_expanded(path) and model.iter_has_child(iter): 
     259                if not self.tree.row_expanded(path) and self.model.iter_has_child( 
     260                child_iter): 
    252261                        # account row not expanded 
    253262                        account_name = '[%s]' % account_name 
    254263                if (gajim.account_is_connected(account) or (self.regroup and \ 
     
    257266                        nbr_on, nbr_total = gajim.contacts.get_nb_online_total_contacts( 
    258267                                accounts = accounts) 
    259268                        account_name += ' (%s/%s)' % (repr(nbr_on),repr(nbr_total)) 
    260                 model[iter][C_NAME] = account_name 
     269                self.model[child_iter][C_NAME] = account_name 
    261270 
    262271        def remove_newly_added(self, jid, account): 
    263272                if jid in gajim.newly_added[account]: 
     
    270279                is False, because it has online children, so we need to show it. 
    271280                If add_children is True, we also add all children, even if they were not 
    272281                already drawn''' 
    273                 showOffline = gajim.config.get('showoffline') 
    274                 model = self.tree.get_model() 
     282                model = self.modelfilter 
     283                child_model = model.get_model() 
    275284                contact = gajim.contacts.get_first_contact_from_jid(account, jid) 
    276285                nb_events = gajim.events.get_nb_roster_events(account, contact.jid) 
    277286                # count events from all resources 
     
    289298                                self.add_self_contact(account) 
    290299                        return 
    291300                if gajim.jid_is_transport(contact.jid): 
    292                         # if jid is transport, check if we wanna show it in roster 
    293                         if not gajim.config.get('show_transports_group') and not nb_events: 
    294                                 return 
    295301                        contact.groups = [_('Transports')] 
    296                 elif not showOffline and not gajim.account_is_connected(account) and \ 
    297                 nb_events == 0: 
    298                         return 
    299302 
    300                 # XEP-0162 
    301                 hide = contact.is_hidden_from_roster() 
    302                 if hide and contact.sub != 'from': 
    303                         return 
    304303                observer = contact.is_observer() 
    305304                groupchat = contact.is_groupchat() 
    306305 
     
    309308                        tag = gajim.contacts.get_metacontacts_tag(account, jid) 
    310309                        if tag: 
    311310                                gajim.contacts.remove_metacontact(account, jid) 
     311                        contact.groups = [_('Observers')] 
    312312 
    313313                # family is [{'account': acct, 'jid': jid, 'priority': prio}, ] 
    314314                # 'priority' is optional 
     
    324324                                        continue 
    325325                                _jid = data['jid'] 
    326326 
    327                                 if self.get_contact_iter(_jid, _account): 
     327                                if self.get_contact_iter(_jid, _account, self.model): 
    328328                                        shown_family.append(data) 
    329329                                if _jid == jid and _account == account: 
    330330                                        our_data = data 
     
    335335                        big_brother_account = big_brother_data['account'] 
    336336                        if big_brother_jid != jid or big_brother_account != account: 
    337337                                # We are adding a child contact 
    338                                 if contact.show in ('offline', 'error') and \ 
    339                                 not showOffline and len(gajim.events.get_events(account, jid)) == 0: 
     338                                parent_iters = self.get_contact_iter(big_brother_jid, 
     339                                        big_brother_account, self.model) 
     340                                if parent_iters: 
     341                                        name = contact.get_shown_name() 
     342                                        added_iters = [] 
     343                                        for child_i in parent_iters: 
     344                                                # we add some values here. see draw_contact for more 
     345                                                i_ = child_model.append(child_i, (None, name, 'contact', jid, 
     346                                                        account, None)) 
     347                                                added_iters.append(i_) 
     348                                        self.draw_contact(jid, account) 
     349                                        self.draw_avatar(added_iters) 
     350                                        self.draw_account(account) 
     351                                        # Redraw parent to change icon 
     352                                        self.draw_contact(big_brother_jid, big_brother_account) 
    340353                                        return 
    341                                 parent_iters = self.get_contact_iter(big_brother_jid, 
    342                                         big_brother_account) 
    343                                 name = contact.get_shown_name() 
    344                                 for i in parent_iters: 
    345                                         # we add some values here. see draw_contact for more 
    346                                         model.append(i, (None, name, 'contact', jid, account, None)) 
    347                                 self.draw_contact(jid, account) 
    348                                 self.draw_avatar(jid, account) 
    349                                 self.draw_account(account) 
    350                                 # Redraw parent to change icon 
    351                                 self.draw_contact(big_brother_jid, big_brother_account) 
    352                                 return 
    353354 
    354                 if (contact.show in ('offline', 'error') or hide) and \ 
    355                 not showOffline and (not _('Transports') in contact.groups or \ 
    356                 gajim.connections[account].connected < 2) and \ 
    357                 len(gajim.contacts.get_contacts(account, jid)) == 1 and nb_events == 0 and\ 
    358                 not _('Not in Roster') in contact.groups: 
    359                         return 
    360  
    361355                # Remove brother contacts that are already in roster to add them 
    362356                # under this iter 
    363357                for data in shown_family: 
     
    370364                        groups = [_('Observers')] 
    371365                elif not groups: 
    372366                        groups = [_('General')] 
     367                added_iters = [] 
    373368                for group in groups: 
    374369                        self.draw_group(group, account) 
    375                         iterG = self.get_group_iter(group, account) 
    376                         if not iterG: 
    377                                 IterAcct = self.get_account_iter(account) 
    378                                 iterG = model.append(IterAcct, [ 
     370                        child_iterG = self.get_group_iter(group, account, self.model) 
     371                        if not child_iterG: 
     372                                child_iterA = self.get_account_iter(account, self.model) 
     373                                child_iterG = self.model.append(child_iterA, [ 
    379374                                        self.jabber_state_images['16']['closed'], 
    380375                                        gobject.markup_escape_text(group), 'group', 
    381376                                        group, account, None]) 
    382377                                self.draw_group(group, account) 
    383                                 if model.iter_n_children(IterAcct) == 1: # We added the first one 
    384                                         self.draw_account(account) 
    385                         if group not in gajim.groups[account]: # It can probably never append 
     378                        try: 
     379                                iterG = model.convert_child_iter_to_iter(child_iterG) 
     380                        except RuntimeError: 
     381                                # group is not visible in filtered model 
     382                                iterG = None 
     383                        if group not in gajim.groups[account]: 
    386384                                if account + group in self.collapsed_rows: 
    387385                                        ishidden = False 
    388386                                else: 
    389387                                        ishidden = True 
    390388                                gajim.groups[account][group] = {'expand': ishidden} 
    391                         if not account in self.collapsed_rows: 
     389                        if iterG and not account in self.collapsed_rows: 
    392390                                self.tree.expand_row((model.get_path(iterG)[0]), False) 
    393391 
    394392                        typestr = 'contact' 
     
    399397 
    400398                        name = contact.get_shown_name() 
    401399                        # we add some values here. see draw_contact for more 
    402                         model.append(iterG, (None, name, typestr, contact.jid, account, None)) 
     400                        i_ = self.model.append(child_iterG, (None, name, typestr, contact.jid, 
     401                                account, None)) 
     402                        added_iters.append(i_) 
    403403 
    404404                        if gajim.groups[account][group]['expand']: 
    405                                 self.tree.expand_row(model.get_path(iterG), False) 
    406                 self.draw_contact(jid, account) 
    407                 self.draw_avatar(jid, account) 
     405                                #FIXME: why do we need to recall it? because we added a child? 
     406                                iterG = self.get_group_iter(group, account) 
     407                                if iterG: 
     408                                        self.tree.expand_row(model.get_path(iterG), False) 
     409                if not self.starting: 
     410                        self.draw_contact(jid, account) 
     411                        self.draw_avatar(added_iters) 
    408412                self.draw_account(account) 
    409413                # put the children under this iter 
    410414                for data in shown_family: 
     
    413417                        self.add_contact_to_roster(data['jid'], data['account']) 
    414418 
    415419        def draw_group(self, group, account): 
    416                 iter = self.get_group_iter(group, account) 
    417                 if not iter: 
     420                child_iter = self.get_group_iter(group, account, self.model) 
     421                if not child_iter: 
    418422                        return 
    419423                if self.regroup: 
    420424                        accounts = [] 
     
    427431                        nbr_on, nbr_total = gajim.contacts.get_nb_online_total_contacts( 
    428432                                accounts = accounts, groups = [group]) 
    429433                        text += ' (%s/%s)' % (repr(nbr_on), repr(nbr_total)) 
    430                 model = self.tree.get_model() 
    431                 model.set_value(iter, 1 , text) 
     434                self.model.set_value(child_iter, 1 , gobject.markup_escape_text(text)) 
    432435 
    433436        def add_to_not_in_the_roster(self, account, jid, nick = '', resource = ''): 
    434437                ''' add jid to group "not in the roster", he MUST not be in roster yet, 
     
    467470                return contact 
    468471 
    469472        def get_self_contact_iter(self, account): 
    470                 model = self.tree.get_model() 
    471473                iterAcct = self.get_account_iter(account) 
    472                 iter = model.iter_children(iterAcct) 
     474                iter = self.modelfilter.iter_children(iterAcct) 
    473475                if not iter: 
    474476                        return None 
    475                 if model[iter][C_TYPE] == 'self_contact': 
     477                if self.modelfilter[iter][C_TYPE] == 'self_contact': 
    476478                        return iter 
    477479                return None 
    478480 
    479481        def add_self_contact(self, account): 
     482                return 
    480483                jid = gajim.get_jid_from_account(account) 
    481                 if self.get_self_contact_iter(account): 
     484                self_contact_iter = self.get_self_contact_iter(account) 
     485                if self_contact_iter: 
    482486                        self.draw_contact(jid, account) 
    483                         self.draw_avatar(jid, account) 
     487                        child_iter = self.modelfilter.convert_iter_to_child_iter( 
     488                                self_contact_iter) 
     489                        self.draw_avatar(child_iter) 
    484490                        return 
    485491 
    486492                contact = gajim.contacts.get_first_contact_from_jid(account, jid) 
    487493                if not contact: 
    488494                        return 
    489                 showOffline = gajim.config.get('showoffline') 
    490                 if (contact.show in ('offline', 'error')) and not showOffline and \ 
    491                         len(gajim.events.get_events(account, jid)) == 0: 
    492                         return 
    493495 
    494496                model = self.tree.get_model() 
    495                 iterAcct = self.get_account_iter(account) 
    496                 model.append(iterAcct, (None, gajim.nicks[account], 'self_contact', jid, 
    497                         account, None)) 
     497                iterA = self.get_account_iter(account) 
     498                child_model = model.get_model() 
     499                child_iterA = model.convert_iter_to_child_iter(iterA) 
     500                i_ = child_model.append(child_iterA, (None, gajim.nicks[account], 
     501                        'self_contact', jid, account, None)) 
    498502                self.draw_contact(jid, account) 
    499                 self.draw_avatar(jid, account) 
     503                self.draw_avatar([i_]) 
    500504 
    501505        def add_transport_to_roster(self, account, transport): 
    502506                c = gajim.contacts.create_contact(jid = transport, name = transport, 
     
    511515                        return 
    512516                if contact.jid in gajim.newly_added[account]: 
    513517                        return 
    514                 if gajim.jid_is_transport(contact.jid) and gajim.account_is_connected( 
    515                 account) and gajim.config.get('show_transports_group'): 
    516                         # It's an agent and we show them 
    517                         return 
    518518                if contact.jid in gajim.to_be_removed[account]: 
    519519                        gajim.to_be_removed[account].remove(contact.jid) 
     520                        # FIXME: refilter only this contact 
     521#                       for iter in self.get_contact_iter(contact.jid, account, self.model): 
     522#                               path = self.model.get_path(iter) 
     523                                # doesn't work 
     524#                               self.model.row_has_child_toggled(path, iter) 
     525                        self.modelfilter.refilter() 
    520526 
     527#               hide = contact.is_hidden_from_roster() 
     528# 
     529#               show_offline = gajim.config.get('showoffline') 
     530#               show_transports = gajim.config.get('show_transports_group') 
     531# 
     532#               nb_events = 0 
     533#               jid_list = [contact.jid] 
     534#               if contact.get_full_jid() != contact.jid: 
     535#                       jid_list.append(contact.get_full_jid()) 
     536#               for jid in jid_list: 
     537#                       # dont't count printed_chat messages 
     538#                       nb_events += gajim.events.get_nb_roster_events(account, jid, ['chat']) 
     539# 
     540#               if (_('Transports') in contact.groups and not show_transports) or \ 
     541#               ((contact.show in ('offline', 'error') or hide) and not show_offline and \ 
     542#               (not _('Transports') in contact.groups or \ 
     543#               gajim.account_is_disconnected(account))) and nb_events == 0: 
     544#               else: 
     545#                       self.draw_contact(contact.jid, account) 
    521546 
    522                 hide = contact.is_hidden_from_roster() 
    523  
    524                 show_offline = gajim.config.get('showoffline') 
    525                 show_transports = gajim.config.get('show_transports_group') 
    526  
    527                 nb_events = 0 
    528                 jid_list = [contact.jid] 
    529                 if contact.get_full_jid() != contact.jid: 
    530                         jid_list.append(contact.get_full_jid()) 
    531                 for jid in jid_list: 
    532                         # dont't count printed_chat messages 
    533                         nb_events += gajim.events.get_nb_roster_events(account, jid, ['chat']) 
    534  
    535                 if (_('Transports') in contact.groups and not show_transports) or \ 
    536                 ((contact.show in ('offline', 'error') or hide) and not show_offline and \ 
    537                 (not _('Transports') in contact.groups or \ 
    538                 gajim.account_is_disconnected(account))) and nb_events == 0: 
    539                         self.remove_contact(contact, account) 
    540                 else: 
    541                         self.draw_contact(contact.jid, account) 
    542  
    543547        def remove_contact(self, contact, account): 
    544548                '''Remove a contact from the roster''' 
    545549                if contact.jid in gajim.to_be_removed[account]: 
    546550                        return 
    547                 model = self.tree.get_model() 
    548                 iters = self.get_contact_iter(contact.jid, account) 
     551                # look for iters in all (even not shown) iters 
     552                iters = self.get_contact_iter(contact.jid, account, self.model) 
    549553                if not iters: 
    550554                        return 
    551                 parent_iter = model.iter_parent(iters[0]) 
    552                 parent_type = model[parent_iter][C_TYPE] 
     555                parent_iter = self.model.iter_parent(iters[0]) 
     556                parent_type = self.model[parent_iter][C_TYPE] 
    553557                # remember children to re-add them 
    554558                children = [] 
    555                 child_iter = model.iter_children(iters[0]) 
    556                 while child_iter: 
    557                         c_jid = model[child_iter][C_JID].decode('utf-8') 
    558                         c_account = model[child_iter][C_ACCOUNT].decode('utf-8') 
     559                iterC = self.model.iter_children(iters[0]) 
     560                while iterC: 
     561                        c_jid = self.model[iterC][C_JID].decode('utf-8') 
     562                        c_account = self.model[iterC][C_ACCOUNT].decode('utf-8') 
    559563                        children.append((c_jid, c_account)) 
    560                         child_iter = model.iter_next(child_iter) 
     564                        iterC = self.model.iter_next(iterC) 
    561565 
    562566                # Remove iters and group iter if they are empty 
    563567                for i in iters: 
    564                         parent_i = model.iter_parent(i) 
    565                         model.remove(i) 
     568                        parent_i = self.model.iter_parent(i) 
     569                        self.model.remove(i) 
    566570                        if parent_type == 'group': 
    567                                 group = model[parent_i][C_JID].decode('utf-8') 
    568                                 if model.iter_n_children(parent_i) == 0: 
    569                                         model.remove(parent_i) 
    570                                         # We need to check all contacts, even offline contacts 
    571                                         for jid in gajim.contacts.get_jid_list(account): 
    572                                                 if group in gajim.contacts.get_contact_with_highest_priority( 
    573                                                         account, jid).groups: 
    574                                                         break 
    575                                         else: 
    576                                                 if gajim.groups[account].has_key(group): 
    577                                                         del gajim.groups[account][group] 
     571                                group = self.model[parent_i][C_JID].decode('utf-8') 
     572                                if self.model.iter_n_children(parent_i) == 0: 
     573                                        self.model.remove(parent_i) 
     574                                        if gajim.groups[account].has_key(group): 
     575                                                del gajim.groups[account][group] 
    578576                                else: 
    579577                                        self.draw_group(group, account) 
    580578 
     
    583581                        self.add_contact_to_roster(child[0], child[1]) 
    584582                # redraw parent 
    585583                if parent_type == 'contact': 
    586                         parent_jid = model[parent_iter][C_JID].decode('utf-8') 
    587                         parent_account = model[parent_iter][C_ACCOUNT].decode('utf-8') 
     584                        parent_jid = self.model[parent_iter][C_JID].decode('utf-8') 
     585                        parent_account = self.model[parent_iter][C_ACCOUNT].decode('utf-8') 
    588586                        self.draw_contact(parent_jid, parent_account) 
    589587 
    590588        def get_appropriate_state_images(self, jid, size = '16', 
    591                 icon_name = 'online'): 
     589        icon_name = 'online'): 
    592590                '''check jid and return the appropriate state images dict for 
    593591                the demanded size. icon_name is taken into account when jid is from 
    594592                transport: transport iconset doesn't contain all icons, so we fall back 
     
    603601        def draw_contact(self, jid, account, selected = False, focus = False): 
    604602                '''draw the correct state image, name BUT not avatar''' 
    605603                # focus is about if the roster window has toplevel-focus or not 
    606                 model = self.tree.get_model() 
    607                 iters = self.get_contact_iter(jid, account) 
    608                 if len(iters) == 0: 
     604                child_iters = self.get_contact_iter(jid, account, self.model) 
     605                if len(child_iters) == 0: 
    609606                        return 
    610607                contact_instances = gajim.contacts.get_contacts(account, jid) 
    611608                contact = gajim.contacts.get_highest_prio_contact_from_contacts( 
     
    653650                if self.regroup: 
    654651                        add_acct = False 
    655652                        # look through all contacts of all accounts 
    656                         for account_iter in gajim.connections: 
    657                                 if account_iter == account: # useless to add accout name 
     653                        for account_ in gajim.connections: 
     654                                if account_ == account: # useless to add accout name 
    658655                                        continue 
    659                                 for jid_iter in gajim.contacts.get_jid_list(account_iter): 
     656                                for jid_&nbs