Ticket #1201: modelfilter_v2.patch

File modelfilter_v2.patch, 41.3 kB (added by asterix, 17 months ago)

some bugfixes with metacontacts

  • src/roster_window.py

     
    2323import os 
    2424import time 
    2525import urllib 
     26import threading 
    2627 
    2728import common.sleepy 
    2829import history_window 
     
    6768class RosterWindow: 
    6869        '''Class for main window of the GTK+ interface''' 
    6970 
    70         def get_account_iter(self, name): 
     71        def get_account_iter(self, name, model = None): 
    7172                ''' Returns a gtk.TreeIter of accounts in roster data model or None ''' 
    72                 model = self.tree.get_model() 
     73                if not model: 
     74                        model = self.tree.get_model() 
    7375                if model is None: 
    7476                        return 
    7577                account_iter = model.get_iter_root() 
    7678                if self.regroup: 
    7779                        return account_iter 
    7880                while account_iter: 
    79                         account_name = model[account_iter][C_ACCOUNT].decode('utf-8') 
    80                         if name == account_name: 
     81                        account_name = model[account_iter][C_ACCOUNT] 
     82                        if account_name and name == account_name.decode('utf-8'): 
    8183                                break 
    8284                        account_iter = model.iter_next(account_iter) 
    8385                return account_iter 
    8486 
    85         def get_group_iter(self, name, account): 
     87        def get_group_iter(self, name, account, model = None): 
    8688                ''' Returns a gtk.TreeIter of groups in roster data model or None ''' 
    87                 model = self.tree.get_model() 
    88                 root = self.get_account_iter(account) 
     89                if not model: 
     90                        model = self.tree.get_model() 
     91                root = self.get_account_iter(account, model) 
    8992                group_iter = model.iter_children(root) 
    9093                # C_NAME column contacts the pango escaped group name 
    9194                while group_iter: 
     
    9598                        group_iter = model.iter_next(group_iter) 
    9699                return group_iter 
    97100 
    98         def get_contact_iter(self, jid, account): 
     101        def get_contact_iter(self, jid, account, model = None): 
    99102                if jid == gajim.get_jid_from_account(account): 
    100103                        iter = self.get_self_contact_iter(account) 
    101104                        if iter: 
    102105                                return [iter] 
    103106                        else: 
    104107                                return [] 
    105                 model = self.tree.get_model() 
    106                 acct = self.get_account_iter(account) 
     108                if not model: 
     109                        model = self.tree.get_model() 
     110                acct = self.get_account_iter(account, model) 
    107111                found = [] 
    108112                if model is None: # when closing Gajim model can be none (async pbs?) 
    109113                        return found 
     
    111115                while group_iter: 
    112116                        contact_iter = model.iter_children(group_iter) 
    113117                        while contact_iter: 
    114                                 if jid == model[contact_iter][C_JID].decode('utf-8') and \ 
     118                                iter_jid = model[contact_iter][C_JID] 
     119                                if iter_jid and jid == iter_jid.decode('utf-8') and \ 
    115120                                        account == model[contact_iter][C_ACCOUNT].decode('utf-8'): 
    116121                                        found.append(contact_iter) 
    117122                                # find next contact iter 
     
    157162                        # show him 
    158163                        self.add_contact_to_roster(jid, account) 
    159164                        iters = self.get_contact_iter(jid, account) 
     165                        #FIXME: adding it doesn't mean it is visible 
     166                        if not iters: 
     167                                return 
    160168                        path = self.tree.get_model().get_path(iters[0]) 
    161169                if self.dragging or not gajim.config.get('scroll_roster_to_last_message'): 
    162170                        # do not change selection while DND'ing 
     
    171179        def add_account_to_roster(self, account): 
    172180                ''' Add an account to roster data model. ''' 
    173181                model = self.tree.get_model() 
     182                child_model = model.get_model() 
    174183                if self.get_account_iter(account): 
    175184                        return 
    176185 
    177186                # if we merge accounts... 
    178187                if self.regroup: 
    179188                        show = helpers.get_global_show() 
    180                         model.append(None, [self.jabber_state_images['16'][show], 
     189                        child_model.append(None, [self.jabber_state_images['16'][show], 
    181190                                _('Merged accounts'), 'account', '', 'all', None]) 
    182191                        self.draw_account(account) 
    183192                        return 
     
    191200 
    192201                our_jid = gajim.get_jid_from_account(account) 
    193202 
    194                 model.append(None, [self.jabber_state_images['16'][show], 
     203                child_model.append(None, [self.jabber_state_images['16'][show], 
    195204                        gobject.markup_escape_text(account), 
    196205                        'account', our_jid, account, tls_pixbuf]) 
    197206 
    198207        def draw_account(self, account): 
    199                 model = self.tree.get_model() 
    200                 iter = self.get_account_iter(account) 
     208                child_iter = self.get_account_iter(account, self.model) 
    201209                if self.regroup: 
    202210                        accounts = gajim.connections.keys() 
    203211                else: 
     
    226234                                                new_pixels += chr(128) 
    227235                                tls_pixbuf = gtk.gdk.pixbuf_new_from_data(new_pixels, colorspace, 
    228236                                        True, bps, width, height, rowstride) 
    229                         model[iter][C_SECPIXBUF] = tls_pixbuf 
     237                        self.model[child_iter][C_SECPIXBUF] = tls_pixbuf 
    230238                else: 
    231                         model[iter][C_SECPIXBUF] = None 
    232                 path = model.get_path(iter) 
     239                        self.model[child_iter][C_SECPIXBUF] = None 
     240                path = self.model.get_path(child_iter) 
    233241                account_name = account 
    234242                accounts = [account] 
    235243                if self.regroup: 
    236244                        account_name = _('Merged accounts') 
    237245                        accounts = [] 
    238                 if not self.tree.row_expanded(path) and model.iter_has_child(iter): 
     246                if not self.tree.row_expanded(path) and self.model.iter_has_child( 
     247                child_iter): 
    239248                        # account row not expanded 
    240249                        account_name = '[%s]' % account_name 
    241250                if (gajim.account_is_connected(account) or (self.regroup and \ 
     
    244253                        nbr_on, nbr_total = gajim.contacts.get_nb_online_total_contacts( 
    245254                                accounts = accounts) 
    246255                        account_name += ' (%s/%s)' % (repr(nbr_on),repr(nbr_total)) 
    247                 model[iter][C_NAME] = account_name 
     256                self.model[child_iter][C_NAME] = account_name 
    248257 
    249258        def remove_newly_added(self, jid, account): 
    250259                if jid in gajim.newly_added[account]: 
     
    257266                is False, because it has online children, so we need to show it. 
    258267                If add_children is True, we also add all children, even if they were not 
    259268                already drawn''' 
    260                 showOffline = gajim.config.get('showoffline') 
    261                 model = self.tree.get_model() 
     269                model = self.modelfilter 
     270                child_model = model.get_model() 
    262271                contact = gajim.contacts.get_first_contact_from_jid(account, jid) 
    263272                nb_events = gajim.events.get_nb_roster_events(account, contact.jid) 
    264273                # count events from all resources 
     
    275284                        self.add_self_contact(account) 
    276285                        return 
    277286                if gajim.jid_is_transport(contact.jid): 
    278                         # if jid is transport, check if we wanna show it in roster 
    279                         if not gajim.config.get('show_transports_group') and not nb_events: 
    280                                 return 
    281287                        contact.groups = [_('Transports')] 
    282                 elif not showOffline and not gajim.account_is_connected(account) and \ 
    283                 nb_events == 0: 
    284                         return 
    285288 
    286                 # XEP-0162 
    287                 hide = contact.is_hidden_from_roster() 
    288                 if hide and contact.sub != 'from': 
    289                         return 
    290289                observer = contact.is_observer() 
    291290                groupchat = contact.is_groupchat() 
    292291 
     
    295294                        tag = gajim.contacts.get_metacontacts_tag(account, jid) 
    296295                        if tag: 
    297296                                gajim.contacts.remove_metacontact(account, jid) 
     297                        contact.groups = [_('Observers')] 
    298298 
    299299                # family is [{'account': acct, 'jid': jid, 'priority': prio}, ] 
    300300                # 'priority' is optional 
     
    310310                                        continue 
    311311                                _jid = data['jid'] 
    312312 
    313                                 if self.get_contact_iter(_jid, _account): 
     313                                if self.get_contact_iter(_jid, _account, self.model): 
    314314                                        shown_family.append(data) 
     315 
    315316                                if _jid == jid and _account == account: 
    316317                                        our_data = data 
    317                         shown_family.append(our_data) 
    318318                        big_brother_data = gajim.contacts.get_metacontacts_big_brother( 
    319                                 shown_family) 
     319                                shown_family + [our_data]) 
    320320                        big_brother_jid = big_brother_data['jid'] 
    321321                        big_brother_account = big_brother_data['account'] 
    322322                        if big_brother_jid != jid or big_brother_account != account: 
    323323                                # We are adding a child contact 
    324                                 if contact.show in ('offline', 'error') and \ 
    325                                 not showOffline and len(gajim.events.get_events(account, jid)) == 0: 
     324                                parent_iters = self.get_contact_iter(big_brother_jid, 
     325                                        big_brother_account, self.model) 
     326                                if parent_iters: 
     327                                        name = contact.get_shown_name() 
     328                                        added_iters = [] 
     329                                        for child_i in parent_iters: 
     330                                                # we add some values here. see draw_contact for more 
     331                                                i_ = child_model.append(child_i, (None, name, 'contact', jid, 
     332                                                        account, None)) 
     333                                                added_iters.append(i_) 
     334                                        self.draw_contact(jid, account) 
     335                                        self.draw_avatar(added_iters) 
     336                                        self.draw_account(account) 
     337                                        # Redraw parent to change icon 
     338                                        self.draw_contact(big_brother_jid, big_brother_account) 
    326339                                        return 
    327                                 parent_iters = self.get_contact_iter(big_brother_jid, 
    328                                         big_brother_account) 
    329                                 name = contact.get_shown_name() 
    330                                 for i in parent_iters: 
    331                                         # we add some values here. see draw_contact for more 
    332                                         model.append(i, (None, name, 'contact', jid, account, None)) 
    333                                 self.draw_contact(jid, account) 
    334                                 self.draw_avatar(jid, account) 
    335                                 self.draw_account(account) 
    336                                 # Redraw parent to change icon 
    337                                 self.draw_contact(big_brother_jid, big_brother_account) 
    338                                 return 
    339340 
    340                 if (contact.show in ('offline', 'error') or hide) and \ 
    341                 not showOffline and (not _('Transports') in contact.groups or \ 
    342                 gajim.connections[account].connected < 2) and \ 
    343                 len(gajim.contacts.get_contacts(account, jid)) == 1 and nb_events == 0 and\ 
    344                 not _('Not in Roster') in contact.groups: 
    345                         return 
    346  
    347341                # Remove brother contacts that are already in roster to add them 
    348342                # under this iter 
    349343                for data in shown_family: 
     
    356350                        groups = [_('Observers')] 
    357351                elif not groups: 
    358352                        groups = [_('General')] 
     353                added_iters = [] 
    359354                for group in groups: 
    360355                        self.draw_group(group, account) 
    361                         iterG = self.get_group_iter(group, account) 
    362                         if not iterG: 
    363                                 IterAcct = self.get_account_iter(account) 
    364                                 iterG = model.append(IterAcct, [ 
     356                        child_iterG = self.get_group_iter(group, account, self.model) 
     357                        if not child_iterG: 
     358                                child_iterA = self.get_account_iter(account, self.model) 
     359                                child_iterG = self.model.append(child_iterA, [ 
    365360                                        self.jabber_state_images['16']['closed'], 
    366361                                        gobject.markup_escape_text(group), 'group', 
    367362                                        group, account, None]) 
    368363                                self.draw_group(group, account) 
    369                                 if model.iter_n_children(IterAcct) == 1: # We added the first one 
    370                                         self.draw_account(account) 
    371                         if group not in gajim.groups[account]: # It can probably never append 
     364                        try: 
     365                                iterG = model.convert_child_iter_to_iter(child_iterG) 
     366                        except RuntimeError: 
     367                                # group is not visible in filtered model 
     368                                iterG = None 
     369                        if group not in gajim.groups[account]: 
    372370                                if account + group in self.collapsed_rows: 
    373371                                        ishidden = False 
    374372                                else: 
    375373                                        ishidden = True 
    376374                                gajim.groups[account][group] = {'expand': ishidden} 
    377                         if not account in self.collapsed_rows: 
     375                        if iterG and not account in self.collapsed_rows: 
    378376                                self.tree.expand_row((model.get_path(iterG)[0]), False) 
    379377 
    380378                        typestr = 'contact' 
     
    385383 
    386384                        name = contact.get_shown_name() 
    387385                        # we add some values here. see draw_contact for more 
    388                         model.append(iterG, (None, name, typestr, contact.jid, account, None)) 
     386                        i_ = self.model.append(child_iterG, (None, name, typestr, contact.jid, 
     387                                account, None)) 
     388                        added_iters.append(i_) 
    389389 
    390390                        if gajim.groups[account][group]['expand']: 
    391                                 self.tree.expand_row(model.get_path(iterG), False) 
    392                 self.draw_contact(jid, account) 
    393                 self.draw_avatar(jid, account) 
     391                                #FIXME: why do we need to recall it? because we added a child? 
     392                                iterG = self.get_group_iter(group, account) 
     393                                if iterG: 
     394                                        self.tree.expand_row(model.get_path(iterG), False) 
     395                if not self.starting: 
     396                        self.draw_contact(jid, account) 
     397                        self.draw_avatar(added_iters) 
    394398                self.draw_account(account) 
    395399                # put the children under this iter 
    396400                for data in shown_family: 
     
    399403                        self.add_contact_to_roster(data['jid'], data['account']) 
    400404 
    401405        def draw_group(self, group, account): 
    402                 iter = self.get_group_iter(group, account) 
    403                 if not iter: 
     406                child_iter = self.get_group_iter(group, account, self.model) 
     407                if not child_iter: 
    404408                        return 
    405409                if self.regroup: 
    406410                        accounts = [] 
     
    413417                        nbr_on, nbr_total = gajim.contacts.get_nb_online_total_contacts( 
    414418                                accounts = accounts, groups = [group]) 
    415419                        text += ' (%s/%s)' % (repr(nbr_on), repr(nbr_total)) 
    416                 model = self.tree.get_model() 
    417                 model.set_value(iter, 1 , text) 
     420                self.model.set_value(child_iter, 1 , gobject.markup_escape_text(text)) 
    418421 
    419422        def add_to_not_in_the_roster(self, account, jid, nick = '', resource = ''): 
    420423                ''' add jid to group "not in the roster", he MUST not be in roster yet, 
     
    453456                return contact 
    454457 
    455458        def get_self_contact_iter(self, account): 
    456                 model = self.tree.get_model() 
    457459                iterAcct = self.get_account_iter(account) 
    458                 iter = model.iter_children(iterAcct) 
     460                iter = self.modelfilter.iter_children(iterAcct) 
    459461                if not iter: 
    460462                        return None 
    461                 if model[iter][C_TYPE] == 'self_contact': 
     463                if self.modelfilter[iter][C_TYPE] == 'self_contact': 
    462464                        return iter 
    463465                return None 
    464466 
    465467        def add_self_contact(self, account): 
     468                return 
    466469                jid = gajim.get_jid_from_account(account) 
    467                 if self.get_self_contact_iter(account): 
     470                self_contact_iter = self.get_self_contact_iter(account) 
     471                if self_contact_iter: 
    468472                        self.draw_contact(jid, account) 
    469                         self.draw_avatar(jid, account) 
     473                        child_iter = self.modelfilter.convert_iter_to_child_iter( 
     474                                self_contact_iter) 
     475                        self.draw_avatar(child_iter) 
    470476                        return 
    471477 
    472478                contact = gajim.contacts.get_first_contact_from_jid(account, jid) 
    473479                if not contact: 
    474480                        return 
    475                 showOffline = gajim.config.get('showoffline') 
    476                 if (contact.show in ('offline', 'error')) and not showOffline and \ 
    477                         len(gajim.events.get_events(account, jid)) == 0: 
    478                         return 
    479481 
    480482                model = self.tree.get_model() 
    481                 iterAcct = self.get_account_iter(account) 
    482                 model.append(iterAcct, (None, gajim.nicks[account], 'self_contact', jid, 
    483                         account, None)) 
     483                iterA = self.get_account_iter(account) 
     484                child_model = model.get_model() 
     485                child_iterA = model.convert_iter_to_child_iter(iterA) 
     486                i_ = child_model.append(child_iterA, (None, gajim.nicks[account], 
     487                        'self_contact', jid, account, None)) 
    484488                self.draw_contact(jid, account) 
    485                 self.draw_avatar(jid, account) 
     489                self.draw_avatar([i_]) 
    486490 
    487491        def add_transport_to_roster(self, account, transport): 
    488492                c = gajim.contacts.create_contact(jid = transport, name = transport, 
     
    497501                        return 
    498502                if contact.jid in gajim.newly_added[account]: 
    499503                        return 
    500                 if gajim.jid_is_transport(contact.jid) and gajim.account_is_connected( 
    501                 account) and gajim.config.get('show_transports_group'): 
    502                         # It's an agent and we show them 
    503                         return 
    504504                if contact.jid in gajim.to_be_removed[account]: 
    505505                        gajim.to_be_removed[account].remove(contact.jid) 
     506                        # FIXME: refilter only this contact 
     507#                       for iter in self.get_contact_iter(contact.jid, account, self.model): 
     508#                               path = self.model.get_path(iter) 
     509                                # doesn't work 
     510#                               self.model.row_has_child_toggled(path, iter) 
     511                        self.modelfilter.refilter() 
    506512 
     513#               hide = contact.is_hidden_from_roster() 
     514# 
     515#               show_offline = gajim.config.get('showoffline') 
     516#               show_transports = gajim.config.get('show_transports_group') 
     517# 
     518#               nb_events = 0 
     519#               jid_list = [contact.jid] 
     520#               if contact.get_full_jid() != contact.jid: 
     521#                       jid_list.append(contact.get_full_jid()) 
     522#               for jid in jid_list: 
     523#                       # dont't count printed_chat messages 
     524#                       nb_events += gajim.events.get_nb_roster_events(account, jid, ['chat']) 
     525# 
     526#               if (_('Transports') in contact.groups and not show_transports) or \ 
     527#               ((contact.show in ('offline', 'error') or hide) and not show_offline and \ 
     528#               (not _('Transports') in contact.groups or \ 
     529#               gajim.account_is_disconnected(account))) and nb_events == 0: 
     530#               else: 
     531#                       self.draw_contact(contact.jid, account) 
    507532 
    508                 hide = contact.is_hidden_from_roster() 
    509  
    510                 show_offline = gajim.config.get('showoffline') 
    511                 show_transports = gajim.config.get('show_transports_group') 
    512  
    513                 nb_events = 0 
    514                 jid_list = [contact.jid] 
    515                 if contact.get_full_jid() != contact.jid: 
    516                         jid_list.append(contact.get_full_jid()) 
    517                 for jid in jid_list: 
    518                         # dont't count printed_chat messages 
    519                         nb_events += gajim.events.get_nb_roster_events(account, jid, ['chat']) 
    520  
    521                 if (_('Transports') in contact.groups and not show_transports) or \ 
    522                 ((contact.show in ('offline', 'error') or hide) and not show_offline and \ 
    523                 (not _('Transports') in contact.groups or \ 
    524                 gajim.account_is_disconnected(account))) and nb_events == 0: 
    525                         self.remove_contact(contact, account) 
    526                 else: 
    527                         self.draw_contact(contact.jid, account) 
    528  
    529533        def remove_contact(self, contact, account): 
    530534                '''Remove a contact from the roster''' 
    531535                if contact.jid in gajim.to_be_removed[account]: 
    532536                        return 
    533                 model = self.tree.get_model() 
    534                 iters = self.get_contact_iter(contact.jid, account) 
     537                # look for iters in all (even not shown) iters 
     538                iters = self.get_contact_iter(contact.jid, account, self.model) 
    535539                if not iters: 
    536540                        return 
    537                 parent_iter = model.iter_parent(iters[0]) 
    538                 parent_type = model[parent_iter][C_TYPE] 
     541                parent_iter = self.model.iter_parent(iters[0]) 
     542                parent_type = self.model[parent_iter][C_TYPE] 
    539543                # remember children to re-add them 
    540544                children = [] 
    541                 child_iter = model.iter_children(iters[0]) 
    542                 while child_iter: 
    543                         c_jid = model[child_iter][C_JID].decode('utf-8') 
    544                         c_account = model[child_iter][C_ACCOUNT].decode('utf-8') 
     545                iterC = self.model.iter_children(iters[0]) 
     546                while iterC: 
     547                        c_jid = self.model[iterC][C_JID].decode('utf-8') 
     548                        c_account = self.model[iterC][C_ACCOUNT].decode('utf-8') 
    545549                        children.append((c_jid, c_account)) 
    546                         child_iter = model.iter_next(child_iter) 
     550                        iterC = self.model.iter_next(iterC) 
    547551 
    548552                # Remove iters and group iter if they are empty 
    549553                for i in iters: 
    550                         parent_i = model.iter_parent(i) 
    551                         model.remove(i) 
     554                        parent_i = self.model.iter_parent(i) 
     555                        self.model.remove(i) 
    552556                        if parent_type == 'group': 
    553                                 group = model[parent_i][C_JID].decode('utf-8') 
    554                                 if model.iter_n_children(parent_i) == 0: 
    555                                         model.remove(parent_i) 
    556                                         # We need to check all contacts, even offline contacts 
    557                                         for jid in gajim.contacts.get_jid_list(account): 
    558                                                 if group in gajim.contacts.get_contact_with_highest_priority( 
    559                                                         account, jid).groups: 
    560                                                         break 
    561                                         else: 
    562                                                 if gajim.groups[account].has_key(group): 
    563                                                         del gajim.groups[account][group] 
     557                                group = self.model[parent_i][C_JID].decode('utf-8') 
     558                                if self.model.iter_n_children(parent_i) == 0: 
     559                                        self.model.remove(parent_i) 
     560                                        if gajim.groups[account].has_key(group): 
     561                                                del gajim.groups[account][group] 
    564562                                else: 
    565563                                        self.draw_group(group, account) 
    566564 
     
    569567                        self.add_contact_to_roster(child[0], child[1]) 
    570568                # redraw parent 
    571569                if parent_type == 'contact': 
    572                         parent_jid = model[parent_iter][C_JID].decode('utf-8') 
    573                         parent_account = model[parent_iter][C_ACCOUNT].decode('utf-8') 
     570                        parent_jid = self.model[parent_iter][C_JID].decode('utf-8') 
     571                        parent_account = self.model[parent_iter][C_ACCOUNT].decode('utf-8') 
    574572                        self.draw_contact(parent_jid, parent_account) 
    575573 
    576574        def get_appropriate_state_images(self, jid, size = '16', 
    577                 icon_name = 'online'): 
     575        icon_name = 'online'): 
    578576                '''check jid and return the appropriate state images dict for 
    579577                the demanded size. icon_name is taken into account when jid is from 
    580578                transport: transport iconset doesn't contain all icons, so we fall back 
     
    589587        def draw_contact(self, jid, account, selected = False, focus = False): 
    590588                '''draw the correct state image, name BUT not avatar''' 
    591589                # focus is about if the roster window has toplevel-focus or not 
    592                 model = self.tree.get_model() 
    593                 iters = self.get_contact_iter(jid, account) 
    594                 if len(iters) == 0: 
     590                child_iters = self.get_contact_iter(jid, account, self.model) 
     591                if len(child_iters) == 0: 
    595592                        return 
    596593                contact_instances = gajim.contacts.get_contacts(account, jid) 
    597594                contact = gajim.contacts.get_highest_prio_contact_from_contacts( 
     
    639636                if self.regroup: 
    640637                        add_acct = False 
    641638                        # look through all contacts of all accounts 
    642                         for account_iter in gajim.connections: 
    643                                 if account_iter == account: # useless to add accout name