root/branches/gajim_0.6.1/plugins/gtkgui/roster_window.py

Revision 978, 47.8 kB (checked in by nk, 4 years ago)

pkgbuild ready for 0.6.1, fix in systray

Line 
1##      plugins/gtkgui/roster_window.py
2##
3## Gajim Team:
4##      - Yann Le Boulanger <asterix@lagaule.org>
5##      - Vincent Hanquez <tab@snarc.org>
6##      - Nikos Kouremenos <kourem@gmail.com>
7##
8##      Copyright (C) 2003-2005 Gajim Team
9##
10## This program is free software; you can redistribute it and/or modify
11## it under the terms of the GNU General Public License as published
12## by the Free Software Foundation; version 2 only.
13##
14## This program is distributed in the hope that it will be useful,
15## but WITHOUT ANY WARRANTY; without even the implied warranty of
16## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17## GNU General Public License for more details.
18##
19
20import gtk
21import gtk.glade
22import pango
23import gobject
24import os
25import Queue
26import common.sleepy
27
28from tabbed_chat_window import *
29from groupchat_window import *
30from history_window import *
31from gtkgui import CellRendererImage, User
32from dialogs import *
33from config import *
34
35from common import i18n
36
37_ = i18n._
38APP = i18n.APP
39gtk.glade.bindtextdomain(APP, i18n.DIR)
40gtk.glade.textdomain(APP)
41
42GTKGUI_GLADE='plugins/gtkgui/gtkgui.glade'
43
44class Roster_window:
45        """Class for main window of gtkgui plugin"""
46
47        def get_account_iter(self, name):
48                if self.regroup:
49                        return None
50                model = self.tree.get_model()
51                fin = False
52                account = model.get_iter_root()
53                if not account:
54                        return None
55                while not fin:
56                        account_name = model.get_value(account, 3)
57                        if name == account_name:
58                                return account
59                        account = model.iter_next(account)
60                        if not account:
61                                fin = True
62                return None
63
64        def get_group_iter(self, name, account):
65                model = self.tree.get_model()
66                root = self.get_account_iter(account)
67                fin = False
68                group = model.iter_children(root)
69                if not group:
70                        fin = True
71                while not fin:
72                        group_name = model.get_value(group, 3)
73                        if name == group_name:
74                                return group
75                        group = model.iter_next(group)
76                        if not group:
77                                fin = True
78                return None
79
80        def get_user_iter(self, jid, account):
81                model = self.tree.get_model()
82                acct = self.get_account_iter(account)
83                found = []
84                fin = False
85                group = model.iter_children(acct)
86                if not group:
87                        return found
88                while not fin:
89                        fin2 = False
90                        user = model.iter_children(group)
91                        if not user:
92                                fin2=True
93                        while not fin2:
94                                if jid == model.get_value(user, 3):
95                                        found.append(user)
96                                user = model.iter_next(user)
97                                if not user:
98                                        fin2 = True
99                        group = model.iter_next(group)
100                        if not group:
101                                fin = True
102                return found
103
104        def add_account_to_roster(self, account):
105                if self.regroup:
106                        return
107                model = self.tree.get_model()
108                if self.get_account_iter(account):
109                        return
110                statuss = ['offline', 'connecting', 'online', 'away', 'xa', 'dnd',\
111                        'invisible']
112                status = statuss[self.plugin.connected[account]]
113                model.append(None, (self.pixbufs[status], account, 'account', account,\
114                        account, False))
115
116        def add_user_to_roster(self, jid, account):
117                """Add a user to the roster and add groups if they aren't in roster"""
118                showOffline = self.plugin.config['showoffline']
119                if not self.contacts[account].has_key(jid):
120                        return
121                users = self.contacts[account][jid]
122                user = users[0]
123                if user.jid.find("@") <= 0:
124                        user.groups = ['Agents']
125                elif user.groups == []:
126                        user.groups.append('General')
127
128                if (user.show == 'offline' or user.show == 'error') and not showOffline\
129                        and not 'Agents' in user.groups and \
130                        not self.plugin.queues[account].has_key(user.jid):
131                        return
132
133                model = self.tree.get_model()
134                for g in user.groups:
135                        iterG = self.get_group_iter(g, account)
136                        if not iterG:
137                                IterAcct = self.get_account_iter(account)
138                                iterG = model.append(IterAcct, \
139                                        (self.pixbufs['closed'], g, 'group', \
140                                        g, account, False))
141                        if not self.groups[account].has_key(g): #It can probably never append
142                                if account+g in self.hidden_lines:
143                                        self.groups[account][g] = {'expand': False}
144                                else:
145                                        self.groups[account][g] = {'expand': True}
146                        if not account in self.hidden_lines and not self.plugin.config['mergeaccounts']:
147                                self.tree.expand_row((model.get_path(iterG)[0]), False)
148
149                        typestr = 'user'
150                        if g == 'Agents':
151                                typestr = 'agent'
152
153                        model.append(iterG, (self.pixbufs[user.show], \
154                                user.name, typestr, user.jid, account, False))
155                       
156                        if self.groups[account][g]['expand']:
157                                self.tree.expand_row(model.get_path(iterG), False)
158                self.redraw_jid(jid, account)
159       
160        def remove_user(self, user, account):
161                """Remove a user from the roster"""
162                model = self.tree.get_model()
163                for i in self.get_user_iter(user.jid, account):
164                        parent_i = model.iter_parent(i)
165                        group = model.get_value(parent_i, 3)
166                        model.remove(i)
167                        if model.iter_n_children(parent_i) == 0:
168                                model.remove(parent_i)
169                                # We need to check all contacts, even offline contacts
170                                group_empty = True
171                                for jid in self.contacts[account]:
172                                        if group in self.contacts[account][jid][0].groups:
173                                                group_empty = False
174                                                break
175                                if group_empty:
176                                        del self.groups[account][group]
177
178        def redraw_jid(self, jid, account):
179                """draw the correct pixbuf and name"""
180                model = self.tree.get_model()
181                iters = self.get_user_iter(jid, account)
182                if len(iters) == 0:
183                        return
184                users = self.contacts[account][jid]
185                name = users[0].name
186                if len(users) > 1:
187                        name += " (" + str(len(users)) + ")"
188                prio = 0
189                user = users[0]
190                for u in users:
191                        if u.priority > prio:
192                                prio = u.priority
193                                user = u
194                for iter in iters:
195                        if self.plugin.queues[account].has_key(jid):
196                                img = self.pixbufs['message']
197                        else:
198                                if user.sub != 'both':
199                                        if user.ask == 'subscribe':
200                                                img = self.pixbufs['requested']
201                                        else:
202                                                img = self.pixbufs['not in the roster']
203                                else:
204                                        img = self.pixbufs[user.show]
205                        model.set_value(iter, 0, img)
206                        model.set_value(iter, 1, name)
207       
208        def make_menu(self):
209                """create the main_window's menus"""
210                # try to avoid WIDGET_REALIZED_FOR_EVENT failed which freezes gajim
211                new_message_menuitem = self.xml.get_widget('new_message_menuitem')
212                join_gc_menuitem = self.xml.get_widget('join_gc_menuitem')
213                add_new_contact_menuitem  = self.xml.get_widget('add_new_contact_menuitem')
214                service_disco_menuitem  = self.xml.get_widget('service_disco_menuitem')
215                if self.add_new_contact_handler_id:
216                        add_new_contact_menuitem.handler_disconnect(self.add_new_contact_handler_id)
217                        self.add_new_contact_handler_id = None
218                if self.service_disco_handler_id:
219                        service_disco_menuitem.handler_disconnect(\
220                                self.service_disco_handler_id)
221                        self.service_disco_handler_id = None
222                if self.join_gc_handler_id:
223                        join_gc_menuitem.handler_disconnect(self.join_gc_handler_id)
224                        self.join_gc_handler_id = None
225                if self.new_message_menuitem_handler_id:
226                        new_message_menuitem.handler_disconnect(\
227                                self.new_message_menuitem_handler_id)
228                        self.new_message_menuitem_handler_id = None
229                #remove the existing submenus
230                if add_new_contact_menuitem.get_submenu():
231                        add_new_contact_menuitem.remove_submenu()
232                if service_disco_menuitem.get_submenu():
233                        service_disco_menuitem.remove_submenu()
234                if join_gc_menuitem.get_submenu():
235                        join_gc_menuitem.remove_submenu()
236                if new_message_menuitem.get_submenu():
237                        new_message_menuitem.remove_submenu()
238                if len(self.plugin.accounts.keys()) > 0:
239                        new_message_menuitem.set_sensitive(True)
240                        join_gc_menuitem.set_sensitive(True)
241                        add_new_contact_menuitem.set_sensitive(True)
242                        service_disco_menuitem.set_sensitive(True)
243                else:
244                        new_message_menuitem.set_sensitive(False)
245                        join_gc_menuitem.set_sensitive(False)
246                        add_new_contact_menuitem.set_sensitive(False)
247                        service_disco_menuitem.set_sensitive(False)
248                if len(self.plugin.accounts.keys()) >= 2: # 2 or more accounts? make submenus
249                        #add
250                        sub_menu = gtk.Menu()
251                        add_new_contact_menuitem.set_submenu(sub_menu)
252                        for account in self.plugin.accounts.keys():
253                                item = gtk.MenuItem(_('to ') + account + _(' account'))
254                                sub_menu.append(item)
255                                item.connect("activate", self.on_add_new_contact, account)
256                        sub_menu.show_all()
257                        #disco
258                        sub_menu = gtk.Menu()
259                        service_disco_menuitem.set_submenu(sub_menu)
260                        for account in self.plugin.accounts.keys():
261                                our_jid = self.plugin.accounts[account]['name'] + '@' +\
262                                        self.plugin.accounts[account]['hostname']
263                                item = gtk.MenuItem(_('using ') + account + _(' account'))
264                                sub_menu.append(item)
265                                item.connect('activate', self.on_service_disco_menuitem_activate, account)
266                        sub_menu.show_all()
267                        #join gc
268                        sub_menu = gtk.Menu()
269                        join_gc_menuitem.set_submenu(sub_menu)
270                        for account in self.plugin.accounts.keys():
271                                our_jid = self.plugin.accounts[account]['name'] + '@' +\
272                                        self.plugin.accounts[account]['hostname']
273                                item = gtk.MenuItem(_('as ') + our_jid)
274                                sub_menu.append(item)
275                                item.connect("activate", self.on_join_gc_activate, account)
276                        sub_menu.show_all()
277                        #new message
278                        sub_menu = gtk.Menu()
279                        new_message_menuitem.set_submenu(sub_menu)
280                        for account in self.plugin.accounts.keys():
281                                our_jid = self.plugin.accounts[account]['name'] + '@' +\
282                                        self.plugin.accounts[account]['hostname']
283                                item = gtk.MenuItem(_('as ') + our_jid)
284                                sub_menu.append(item)
285                                item.connect('activate', self.on_new_message_menuitem_activate, account)
286                        sub_menu.show_all()
287                elif len(self.plugin.accounts.keys()) == 1: # one account
288                        #add
289                        if not self.add_new_contact_handler_id:
290                                self.add_new_contact_handler_id = add_new_contact_menuitem.connect(\
291                                'activate', self.on_add_new_contact, self.plugin.accounts.keys()[0])
292                        #disco
293                        if not self.service_disco_handler_id:
294                                self.service_disco_handler_id = service_disco_menuitem.connect(\
295'activate', self.on_service_disco_menuitem_activate, self.plugin.accounts.keys()[0])
296                        #join_gc
297                        if not self.join_gc_handler_id:
298                                self.join_gc_handler_id = join_gc_menuitem.connect(\
299                                        'activate', self.on_join_gc_activate, self.plugin.accounts.keys()[0])
300                        if not self.new_message_menuitem_handler_id:
301                                self.new_message_menuitem_handler_id = new_message_menuitem.connect(\
302'activate', self.on_new_message_menuitem_activate, self.plugin.accounts.keys()[0])
303
304        def draw_roster(self):
305                """Clear and draw roster"""
306                self.make_menu()
307                self.tree.get_model().clear()
308                for acct in self.contacts.keys():
309                        self.add_account_to_roster(acct)
310                        for jid in self.contacts[acct].keys():
311                                self.add_user_to_roster(jid, acct)
312       
313        def mklists(self, array, account):
314                """fill self.contacts and self.groups"""
315                if not self.contacts.has_key(account):
316                        self.contacts[account] = {}
317                if not self.groups.has_key(account):
318                        self.groups[account] = {}
319                for jid in array.keys():
320                        jids = jid.split('/')
321                        #get jid
322                        ji = jids[0]
323                        #get resource
324                        resource = ''
325                        if len(jids) > 1:
326                                resource = jids[1:]
327                        #get name
328                        name = array[jid]['name']
329                        if not name:
330                                if ji.find("@") <= 0:
331                                        name = ji
332                                else:
333                                        name = jid.split('@')[0]
334                        #get show
335                        show = array[jid]['show']
336                        if not show:
337                                show = 'offline'
338
339                        user1 = User(ji, name, array[jid]['groups'], show, \
340                                array[jid]['status'], array[jid]['sub'], array[jid]['ask'], \
341                                resource, 0, '')
342                        #when we draw the roster, we can't have twice the same user with
343                        # 2 resources
344                        self.contacts[account][ji] = [user1]
345                        for g in array[jid]['groups'] :
346                                if not g in self.groups[account].keys():
347                                        if account+g in self.hidden_lines:
348                                                self.groups[account][g] = {'expand': False}
349                                        else:
350                                                self.groups[account][g] = {'expand': True}
351
352        def chg_user_status(self, user, show, status, account):
353                """When a user change his status"""
354                showOffline = self.plugin.config['showoffline']
355                model = self.tree.get_model()
356                luser = self.contacts[account][user.jid]
357                user.show = show
358                user.status = status
359                if (show == 'offline' or show == 'error') and \
360                        not self.plugin.queues[account].has_key(user.jid):
361                        if len(luser) > 1:
362                                luser.remove(user)
363                                self.redraw_jid(user.jid, account)
364                        elif not showOffline:
365                                self.remove_user(user, account)
366                        else:
367                                self.redraw_jid(user.jid, account)
368                else:
369                        if not self.get_user_iter(user.jid, account):
370                                self.add_user_to_roster(user.jid, account)
371                        self.redraw_jid(user.jid, account)
372                #Print status in chat window
373                if self.plugin.windows[account]['chats'].has_key(user.jid):
374                        self.plugin.windows[account]['chats'][user.jid].set_image(user.jid)
375                        name = user.name
376                        if user.resource != '':
377                                name += '/'+user.resource
378                        self.plugin.windows[account]['chats'][user.jid].print_conversation(\
379                                _("%s is now %s (%s)") % (name, show, status), user.jid, 'status')
380
381        def on_info(self, widget, user, account):
382                """Call vcard_information_window class to display user's information"""
383                if not self.plugin.windows[account]['infos'].has_key(user.jid):
384                        self.plugin.windows[account]['infos'][user.jid] = \
385                                vcard_information_window(user, self.plugin, account)
386
387        def on_agent_logging(self, widget, jid, state, account):
388                """When an agent is requested to log in or off"""
389                self.plugin.send('AGENT_LOGGING', account, (jid, state))
390
391        def on_remove_agent(self, widget, jid, account):
392                """When an agent is requested to log in or off"""
393                window = Confirmation_dialog(_('Are you sure you want to remove the agent %s from your roster?') % jid)
394                if window.get_response() == gtk.RESPONSE_YES:
395                        self.plugin.send('UNSUB_AGENT', account, jid)
396                        for u in self.contacts[account][jid]:
397                                self.remove_user(u, account)
398                        del self.contacts[account][u.jid]
399
400        def on_rename(self, widget, iter, path):
401                model = self.tree.get_model()
402                model.set_value(iter, 5, True)
403                self.tree.set_cursor(path, self.tree.get_column(0), True)
404               
405        def on_edit_groups(self, widget, user, account):
406                dlg = Edit_groups_dialog(user, account, self.plugin)
407                dlg.run()
408               
409        def on_history(self, widget, user):
410                """When history button is pressed : call log window"""
411                if not self.plugin.windows['logs'].has_key(user.jid):
412                        self.plugin.windows['logs'][user.jid] = history_window(self.plugin, \
413                                user.jid)
414       
415        def mk_menu_user(self, event, iter):
416                """Make user's popup menu"""
417                model = self.tree.get_model()
418                jid = model.get_value(iter, 3)
419                path = model.get_path(iter)
420                account = model.get_value(iter, 4)
421                user = self.contacts[account][jid][0]
422               
423                menu = gtk.Menu()
424                item = gtk.MenuItem(_('Start chat'))
425                menu.append(item)
426                item.connect('activate', self.on_roster_treeview_row_activated, path)
427                item = gtk.MenuItem(_('Rename'))
428                menu.append(item)
429                item.connect('activate', self.on_rename, iter, path)
430                if not 'not in the roster' in user.groups:
431                        item = gtk.MenuItem(_('Edit groups'))
432                        menu.append(item)
433                        item.connect('activate', self.on_edit_groups, user, account)
434                item = gtk.MenuItem()
435                menu.append(item)
436                item = gtk.MenuItem(_('Subscription'))
437                menu.append(item)
438               
439                sub_menu = gtk.Menu()
440                item.set_submenu(sub_menu)
441                item = gtk.MenuItem(_('Resend authorization to'))
442                sub_menu.append(item)
443                item.connect('activate', self.authorize, jid, account)
444                item = gtk.MenuItem(_('Rerequest authorization from'))
445                sub_menu.append(item)
446                item.connect('activate', self.req_sub, jid, \
447                        _('I would like to add you to my contact list.'), account)
448               
449                item = gtk.MenuItem(_('Remove'))
450                menu.append(item)
451                item.connect('activate', self.on_req_usub, user, account)
452
453                item = gtk.MenuItem()
454                menu.append(item)
455                item = gtk.MenuItem(_('Information'))
456                menu.append(item)
457                item.connect('activate', self.on_info, user, account)
458                item = gtk.MenuItem(_('History'))
459                menu.append(item)
460                item.connect('activate', self.on_history, user)
461
462                menu.popup(None, None, None, event.button, event.time)
463                menu.show_all()
464                menu.reposition()
465
466        def mk_menu_g(self, event, iter):
467                """Make group's popup menu"""
468                model = self.tree.get_model()
469                path = model.get_path(iter)
470
471                menu = gtk.Menu()
472                item = gtk.MenuItem(_('Rename'))
473                menu.append(item)
474                item.connect('activate', self.on_rename, iter, path)
475                menu.popup(None, None, None, event.button, event.time)
476                menu.show_all()
477                menu.reposition()
478       
479        def mk_menu_agent(self, event, iter):
480                """Make agent's popup menu"""
481                model = self.tree.get_model()
482                jid = model.get_value(iter, 3)
483                path = model.get_path(iter)
484                account = model.get_value(iter, 4)
485                menu = gtk.Menu()
486                item = gtk.MenuItem(_('Log on'))
487                if self.contacts[account][jid][0].show != 'offline':
488                        item.set_sensitive(False)
489                menu.append(item)
490                item.connect('activate', self.on_agent_logging, jid, 'available', account)
491
492                item = gtk.MenuItem(_('Log off'))
493                if self.contacts[account][jid][0].show == 'offline':
494                        item.set_sensitive(False)
495                menu.append(item)
496                item.connect('activate', self.on_agent_logging, jid, 'unavailable', \
497                        account)
498
499                item = gtk.MenuItem()
500                menu.append(item)
501
502                item = gtk.MenuItem(_('Remove'))
503                menu.append(item)
504                item.connect('activate', self.on_remove_agent, jid, account)
505
506                menu.popup(None, None, None, event.button, event.time)
507                menu.show_all()
508                menu.reposition()
509
510        def on_edit_account(self, widget, account):
511                if not self.plugin.windows.has_key('account_modification_window'):
512                        infos = self.plugin.accounts[account]
513                        infos['accname'] = account
514                        infos['jid'] = self.plugin.accounts[account]["name"] + \
515                                '@' +  self.plugin.accounts[account]["hostname"]
516                        self.plugin.windows['account_modification_window'] = \
517                                Account_modification_window(self.plugin, infos)
518
519        def mk_menu_account(self, event, iter):
520                """Make account's popup menu"""
521                model = self.tree.get_model()
522                account = model.get_value(iter, 3)
523               
524                menu = gtk.Menu()
525                item = gtk.MenuItem(_('Status'))
526                menu.append(item)
527               
528                sub_menu = gtk.Menu()
529                item.set_submenu(sub_menu)
530                item = gtk.MenuItem(_('Online'))
531                sub_menu.append(item)
532                item.connect('activate', self.change_status, account, 'online')
533                item = gtk.MenuItem(_('Away'))
534                sub_menu.append(item)
535                item.connect('activate', self.change_status, account, 'away')
536                item = gtk.MenuItem(_('NA'))
537                sub_menu.append(item)
538                item.connect('activate', self.change_status, account, 'xa')
539                item = gtk.MenuItem(_('DND'))
540                sub_menu.append(item)
541                item.connect('activate', self.change_status, account, 'dnd')
542                item = gtk.MenuItem(_('Invisible'))
543                sub_menu.append(item)
544                item.connect('activate', self.change_status, account, 'invisible')
545                item = gtk.MenuItem()
546                sub_menu.append(item)
547                item = gtk.Menu