root/branches/gajim_0.10.1/src/dialogs.py

Revision 6407, 58.5 kB (checked in by dkirov, 2 years ago)

r6265, r6266, r6267, r6269, r6350, r6366

  • Property svn:eol-style set to LF
Line 
1# -*- coding: utf-8 -*-
2##      dialogs.py
3##
4## Copyright (C) 2003-2006 Yann Le Boulanger <asterix@lagaule.org>
5## Copyright (C) 2003-2004 Vincent Hanquez <tab@snarc.org>
6## Copyright (C) 2005-2006 Nikos Kouremenos <nkour@jabber.org>
7## Copyright (C) 2005 Dimitur Kirov <dkirov@gmail.com>
8## Copyright (C) 2005-2006 Travis Shirk <travis@pobox.com>
9## Copyright (C) 2005 Norman Rasmussen <norman@rasmussen.co.za>
10##
11## This program is free software; you can redistribute it and/or modify
12## it under the terms of the GNU General Public License as published
13## by the Free Software Foundation; version 2 only.
14##
15## This program is distributed in the hope that it will be useful,
16## but WITHOUT ANY WARRANTY; without even the implied warranty of
17## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18## GNU General Public License for more details.
19##
20
21import gtk
22import gtk.glade
23import gobject
24import os
25import sys
26
27import gtkgui_helpers
28import vcard
29import conversation_textview
30
31try:
32        import gtkspell
33        HAS_GTK_SPELL = True
34except:
35        HAS_GTK_SPELL = False
36
37# those imports are not used in this file, but in files that 'import dialogs'
38# so they can do dialog.GajimThemesWindow() for example
39from filetransfers_window import FileTransfersWindow
40from gajim_themes_window import GajimThemesWindow
41from advanced import AdvancedConfigurationWindow
42
43from common import gajim
44from common import helpers
45from common import i18n
46
47_ = i18n._
48APP = i18n.APP
49gtk.glade.bindtextdomain (APP, i18n.DIR)
50gtk.glade.textdomain (APP)
51
52class EditGroupsDialog:
53        '''Class for the edit group dialog window'''
54        def __init__(self, user, account):
55                self.xml = gtkgui_helpers.get_glade('edit_groups_dialog.glade')
56                self.dialog = self.xml.get_widget('edit_groups_dialog')
57                self.account = account
58                self.user = user
59                self.changes_made = False
60                self.list = self.xml.get_widget('groups_treeview')
61                self.xml.get_widget('nickname_label').set_markup(
62                        _("Contact's name: <i>%s</i>") % user.get_shown_name())
63                self.xml.get_widget('jid_label').set_markup(
64                        _('JID: <i>%s</i>') % user.jid)
65               
66                self.xml.signal_autoconnect(self)
67                self.init_list()
68
69        def run(self):
70                self.dialog.show_all()
71                if self.changes_made:
72                        gajim.connections[self.account].update_contact(self.user.jid,
73                                self.user.name, self.user.groups)
74
75        def on_edit_groups_dialog_response(self, widget, response_id):
76                if response_id == gtk.RESPONSE_CLOSE:
77                        self.dialog.destroy()
78
79        def update_contact(self):
80                tag = gajim.contacts.get_metacontacts_tag(self.account, self.user.jid)
81                if not tag:
82                        gajim.interface.roster.remove_contact(self.user, self.account)
83                        gajim.interface.roster.add_contact_to_roster(self.user.jid,
84                                self.account)
85                        gajim.connections[self.account].update_contact(self.user.jid,
86                                self.user.name, self.user.groups)
87                        return
88                all_jid = gajim.contacts.get_metacontacts_jids(tag)
89                for _account in all_jid:
90                        for _jid in all_jid[_account]:
91                                c = gajim.contacts.get_first_contact_from_jid(_account, _jid)
92                                if not c:
93                                        continue
94                                gajim.interface.roster.remove_contact(c, _account)
95                                gajim.interface.roster.add_contact_to_roster(_jid, _account)
96                                gajim.connections[_account].update_contact(_jid, c.name, c.groups)
97
98        def remove_group(self, group):
99                '''add group group to self.user and all his brothers'''
100                tag = gajim.contacts.get_metacontacts_tag(self.account, self.user.jid)
101                if not tag:
102                        if group in self.user.groups:
103                                self.user.groups.remove(group)
104                        return
105                all_jid = gajim.contacts.get_metacontacts_jids(tag)
106                for _account in all_jid:
107                        for _jid in all_jid[_account]:
108                                contacts = gajim.contacts.get_contact(_account, _jid)
109                                for contact in contacts:
110                                        if group in contact.groups:
111                                                contact.groups.remove(group)
112
113        def add_group(self, group):
114                '''add group group to self.user and all his brothers'''
115                tag = gajim.contacts.get_metacontacts_tag(self.account, self.user.jid)
116                if not tag:
117                        if group not in self.user.groups:
118                                self.user.groups.append(group)
119                        return
120                all_jid = gajim.contacts.get_metacontacts_jids(tag)
121                for _account in all_jid:
122                        for _jid in all_jid[_account]:
123                                contacts = gajim.contacts.get_contact(_account, _jid)
124                                for contact in contacts:
125                                        if not group in contact.groups:
126                                                contact.groups.append(group)
127
128        def on_add_button_clicked(self, widget):
129                group = self.xml.get_widget('group_entry').get_text().decode('utf-8')
130                if not group:
131                        return
132                # check if it already exists
133                model = self.list.get_model()
134                iter = model.get_iter_root()
135                while iter:
136                        if model.get_value(iter, 0).decode('utf-8') == group:
137                                return
138                        iter = model.iter_next(iter)
139                self.changes_made = True
140                model.append((group, True))
141                self.add_group(group)
142                self.update_contact()
143
144        def group_toggled_cb(self, cell, path):
145                self.changes_made = True
146                model = self.list.get_model()
147                model[path][1] = not model[path][1]
148                group = model[path][0].decode('utf-8')
149                if model[path][1]:
150                        self.add_group(group)
151                else:
152                        self.remove_group(group)
153                self.update_contact()
154
155        def init_list(self):
156                store = gtk.ListStore(str, bool)
157                self.list.set_model(store)
158                for g in gajim.groups[self.account].keys():
159                        if g in helpers.special_groups:
160                                continue
161                        iter = store.append()
162                        store.set(iter, 0, g)
163                        if g in self.user.groups:
164                                store.set(iter, 1, True)
165                        else:
166                                store.set(iter, 1, False)
167                column = gtk.TreeViewColumn(_('Group'))
168                column.set_expand(True)
169                self.list.append_column(column)
170                renderer = gtk.CellRendererText()
171                column.pack_start(renderer)
172                column.set_attributes(renderer, text = 0)
173               
174                column = gtk.TreeViewColumn(_('In the group'))
175                column.set_expand(False)
176                self.list.append_column(column)
177                renderer = gtk.CellRendererToggle()
178                column.pack_start(renderer)
179                renderer.set_property('activatable', True)
180                renderer.connect('toggled', self.group_toggled_cb)
181                column.set_attributes(renderer, active = 1)
182
183class PassphraseDialog:
184        '''Class for Passphrase dialog'''
185        def run(self):
186                '''Wait for OK button to be pressed and return passphrase/password'''
187                rep = self.window.run()
188                if rep == gtk.RESPONSE_OK:
189                        passphrase = self.passphrase_entry.get_text().decode('utf-8')
190                else:
191                        passphrase = -1
192                save_passphrase_checkbutton = self.xml.\
193                        get_widget('save_passphrase_checkbutton')
194                self.window.destroy()
195                return passphrase, save_passphrase_checkbutton.get_active()
196
197        def __init__(self, titletext, labeltext, checkbuttontext):
198                self.xml = gtkgui_helpers.get_glade('passphrase_dialog.glade')
199                self.window = self.xml.get_widget('passphrase_dialog')
200                self.passphrase_entry = self.xml.get_widget('passphrase_entry')
201                self.passphrase = -1
202                self.window.set_title(titletext)
203                self.xml.get_widget('message_label').set_text(labeltext)
204                self.xml.get_widget('save_passphrase_checkbutton').set_label(
205                        checkbuttontext)
206                self.xml.signal_autoconnect(self)
207                self.window.show_all()
208
209class ChooseGPGKeyDialog:
210        '''Class for GPG key dialog'''
211        def __init__(self, title_text, prompt_text, secret_keys, selected = None):
212                #list : {keyID: userName, ...}
213                xml = gtkgui_helpers.get_glade('choose_gpg_key_dialog.glade')
214                self.window = xml.get_widget('choose_gpg_key_dialog')
215                self.window.set_title(title_text)
216                self.keys_treeview = xml.get_widget('keys_treeview')
217                prompt_label = xml.get_widget('prompt_label')
218                prompt_label.set_text(prompt_text)
219                model = gtk.ListStore(str, str)
220                model.set_sort_column_id(1, gtk.SORT_ASCENDING)
221                self.keys_treeview.set_model(model)
222                #columns
223                renderer = gtk.CellRendererText()
224                self.keys_treeview.insert_column_with_attributes(-1, _('KeyID'),
225                        renderer, text = 0)
226                renderer = gtk.CellRendererText()
227                self.keys_treeview.insert_column_with_attributes(-1, _('Contact name'),
228                        renderer, text = 1)
229                self.fill_tree(secret_keys, selected)
230                self.window.show_all()
231
232        def run(self):
233                rep = self.window.run()
234                if rep == gtk.RESPONSE_OK:
235                        selection = self.keys_treeview.get_selection()
236                        (model, iter) = selection.get_selected()
237                        keyID = [ model[iter][0].decode('utf-8'),
238                                model[iter][1].decode('utf-8') ]
239                else:
240                        keyID = None
241                self.window.destroy()
242                return keyID
243
244        def fill_tree(self, list, selected):
245                model = self.keys_treeview.get_model()
246                for keyID in list.keys():
247                        iter = model.append((keyID, list[keyID]))
248                        if keyID == selected:
249                                path = model.get_path(iter)
250                                self.keys_treeview.set_cursor(path)
251
252
253class ChangeStatusMessageDialog:
254        def __init__(self, show = None):
255                self.show = show
256                self.xml = gtkgui_helpers.get_glade('change_status_message_dialog.glade')
257                self.window = self.xml.get_widget('change_status_message_dialog')
258                if show:
259                        uf_show = helpers.get_uf_show(show)
260                        title_text = _('%s Status Message') % uf_show
261                else:
262                        title_text = _('Status Message')
263                self.window.set_title(title_text)
264               
265                message_textview = self.xml.get_widget('message_textview')
266                self.message_buffer = message_textview.get_buffer()
267                self.message_buffer.connect('changed',
268                        self.toggle_sensitiviy_of_save_as_preset)
269                msg = None
270                if show:
271                        msg = gajim.config.get('last_status_msg_' + show)
272                if not msg:
273                        msg = ''
274                msg = helpers.from_one_line(msg)
275                self.message_buffer.set_text(msg)
276               
277                # have an empty string selectable, so user can clear msg
278                self.preset_messages_dict = {'': ''}
279                for msg_name in gajim.config.get_per('statusmsg'):
280                        msg_text = gajim.config.get_per('statusmsg', msg_name, 'message')
281                        msg_text = helpers.from_one_line(msg_text)
282                        self.preset_messages_dict[msg_name] = msg_text
283                sorted_keys_list = helpers.get_sorted_keys(self.preset_messages_dict)
284               
285                self.message_liststore = gtk.ListStore(str) # msg_name
286                self.message_combobox = self.xml.get_widget('message_combobox')
287                self.message_combobox.set_model(self.message_liststore)
288                cellrenderertext = gtk.CellRendererText()
289                self.message_combobox.pack_start(cellrenderertext, True)
290                self.message_combobox.add_attribute(cellrenderertext, 'text', 0)
291                for msg_name in sorted_keys_list:
292                        self.message_liststore.append((msg_name,))
293                self.xml.signal_autoconnect(self)
294                self.window.show_all()
295
296        def run(self):
297                '''Wait for OK or Cancel button to be pressed and return status messsage
298                (None if users pressed Cancel or x button of WM'''
299                rep = self.window.run()
300                if rep == gtk.RESPONSE_OK:
301                        beg, end = self.message_buffer.get_bounds()
302                        message = self.message_buffer.get_text(beg, end).decode('utf-8')\
303                                .strip()
304                        msg = helpers.to_one_line(message)
305                        if self.show:
306                                gajim.config.set('last_status_msg_' + self.show, msg)
307                else:
308                        message = None # user pressed Cancel button or X wm button
309                self.window.destroy()
310                return message
311
312        def on_message_combobox_changed(self, widget):
313                model = widget.get_model()
314                active = widget.get_active()
315                if active < 0:
316                        return None
317                name = model[active][0].decode('utf-8')
318                self.message_buffer.set_text(self.preset_messages_dict[name])
319       
320        def on_change_status_message_dialog_key_press_event(self, widget, event):
321                if event.keyval == gtk.keysyms.Return or \
322                event.keyval == gtk.keysyms.KP_Enter:  # catch CTRL+ENTER
323                        if (event.state & gtk.gdk.CONTROL_MASK):
324                                self.window.response(gtk.RESPONSE_OK)
325
326        def toggle_sensitiviy_of_save_as_preset(self, widget):
327                btn = self.xml.get_widget('save_as_preset_button')
328                if self.message_buffer.get_char_count() == 0:
329                        btn.set_sensitive(False)
330                else:
331                        btn.set_sensitive(True)
332       
333        def on_save_as_preset_button_clicked(self, widget):
334                start_iter, finish_iter = self.message_buffer.get_bounds()
335                status_message_to_save_as_preset = self.message_buffer.get_text(
336                        start_iter, finish_iter)
337                dlg = InputDialog(_('Save as Preset Status Message'),
338                        _('Please type a name for this status message'), is_modal = True)
339                response = dlg.get_response()
340                if response == gtk.RESPONSE_OK:
341                        msg_name = dlg.input_entry.get_text()
342                        msg_text = helpers.to_one_line(status_message_to_save_as_preset)
343                        if not msg_name: # msg_name was ''
344                                msg_name = msg_text
345                        msg_name = msg_name.decode('utf-8')
346                        msg_text = msg_text.decode('utf-8')
347                        iter_ = self.message_liststore.append((msg_name,))
348                       
349                        gajim.config.add_per('statusmsg', msg_name)
350                        gajim.config.set_per('statusmsg', msg_name, 'message', msg_text)
351                        self.preset_messages_dict[msg_name] = msg_text
352                        # select in combobox the one we just saved
353                        self.message_combobox.set_active_iter(iter_)
354
355
356class AddNewContactWindow:
357        '''Class for AddNewContactWindow'''
358        def __init__(self, account, jid = None):
359                self.account = account
360                self.xml = gtkgui_helpers.get_glade('add_new_contact_window.glade')
361                self.window = self.xml.get_widget('add_new_contact_window')
362                self.uid_entry = self.xml.get_widget('uid_entry')
363                self.protocol_combobox = self.xml.get_widget('protocol_combobox')
364                self.jid_entry = self.xml.get_widget('jid_entry')
365                self.nickname_entry = self.xml.get_widget('nickname_entry')
366                if len(gajim.connections) >= 2:
367                        prompt_text =\
368_('Please fill in the data of the contact you want to add in account %s') %account
369                else:
370                        prompt_text = _('Please fill in the data of the contact you want to add')
371                self.xml.get_widget('prompt_label').set_text(prompt_text)
372                self.old_uid_value = ''
373                liststore = gtk.ListStore(str, str)
374                liststore.append(['Jabber', ''])
375                self.agents = ['Jabber']
376                jid_agents = []
377                for j in gajim.contacts.get_jid_list(account):
378                        contact = gajim.contacts.get_first_contact_from_jid(account, j)
379                        if _('Transports') in contact.groups and contact.show != 'offline' and\
380                                        contact.show != 'error':
381                                jid_agents.append(j)
382                for a in jid_agents:
383                        if a.find('aim') > -1:
384                                name = 'AIM'
385                        elif a.find('icq') > -1:
386                                name = 'ICQ'
387                        elif a.find('msn') > -1:
388                                name = 'MSN'
389                        elif a.find('yahoo') > -1:
390                                name = 'Yahoo!'
391                        else:
392                                name = a
393                        iter = liststore.append([name, a])
394                        self.agents.append(name)
395               
396                self.protocol_combobox.set_model(liststore)
397                self.protocol_combobox.set_active(0)
398                self.fill_jid()
399                if jid:
400                        self.jid_entry.set_text(jid)
401                        self.uid_entry.set_sensitive(False)
402                        jid_splited = jid.split('@')
403                        if jid_splited[1] in jid_agents:
404                                uid = jid_splited[0].replace('%', '@')
405                                self.uid_entry.set_text(uid)
406                                self.protocol_combobox.set_active(jid_agents.index(jid_splited[1])\
407                                        + 1)
408                        else:
409                                self.uid_entry.set_text(jid)
410                                self.protocol_combobox.set_active(0)
411                        self.set_nickname()
412                        self.nickname_entry.grab_focus()
413
414                self.group_comboboxentry = self.xml.get_widget('group_comboboxentry')
415                liststore = gtk.ListStore(str)
416                self.group_comboboxentry.set_model(liststore)
417                for g in gajim.groups[account].keys():
418                        if g not in helpers.special_groups:
419                                self.group_comboboxentry.append_text(g)
420
421                if not jid_agents:
422                        # There are no transports, so hide the protocol combobox and label
423                        self.protocol_combobox.hide()
424                        self.protocol_combobox.set_no_show_all(True)
425                        protocol_label = self.xml.get_widget('protocol_label')
426                        protocol_label.hide()
427                        protocol_label.set_no_show_all(True)
428
429                self.xml.signal_autoconnect(self)
430                self.window.show_all()
431
432        def on_add_new_contact_window_key_press_event(self, widget, event):
433                if event.keyval == gtk.keysyms.Escape: # ESCAPE
434                        self.window.destroy()
435
436        def on_cancel_button_clicked(self, widget):
437                '''When Cancel button is clicked'''
438                self.window.destroy()
439
440        def on_subscribe_button_clicked(self, widget):
441                '''When Subscribe button is clicked'''
442                jid = self.jid_entry.get_text().decode('utf-8')
443                nickname = self.nickname_entry.get_text().decode('utf-8')
444                if not jid:
445                        return
446       
447                # check if jid is conform to RFC and stringprep it
448                try:
449                        jid = helpers.parse_jid(jid)
450                except helpers.InvalidFormat, s:
451                        pritext = _('Invalid User ID')
452                        ErrorDialog(pritext, str(s))
453                        return
454
455                # No resource in jid
456                if jid.find('/') >= 0:
457                        pritext = _('Invalid User ID')
458                        ErrorDialog(pritext, _('The user ID must not contain a resource.'))
459                        return
460
461                # Check if jid is already in roster
462                if jid in gajim.contacts.get_jid_list(self.account):
463                        c = gajim.contacts.get_first_contact_from_jid(self.account, jid)
464                        if _('Not in Roster') not in c.groups and c.sub in ('both', 'to'):
465                                ErrorDialog(_('Contact already in roster'),
466                                _('This contact is already listed in your roster.'))
467                                return
468
469                message_buffer = self.xml.get_widget('message_textview').get_buffer()
470                start_iter = message_buffer.get_start_iter()
471                end_iter = message_buffer.get_end_iter()
472                message = message_buffer.get_text(start_iter, end_iter).decode('utf-8')
473                group = self.group_comboboxentry.child.get_text().decode('utf-8')
474                auto_auth = self.xml.get_widget('auto_authorize_checkbutton').get_active()
475                gajim.interface.roster.req_sub(self, jid, message, self.account,
476                        group = group, pseudo = nickname, auto_auth = auto_auth)
477                self.window.destroy()
478               
479        def fill_jid(self):
480                model = self.protocol_combobox.get_model()
481                index = self.protocol_combobox.get_active()
482                jid = self.uid_entry.get_text().decode('utf-8').strip()
483                if index > 0: # it's not jabber but a transport
484                        jid = jid.replace('@', '%')
485                agent = model[index][1].decode('utf-8')
486                if agent:
487                        jid += '@' + agent
488                self.jid_entry.set_text(jid)
489
490        def on_protocol_combobox_changed(self, widget):
491                self.fill_jid()
492
493        def guess_agent(self):
494                uid = self.uid_entry.get_text().decode('utf-8')
495                model = self.protocol_combobox.get_model()
496               
497                #If login contains only numbers, it's probably an ICQ number
498                if uid.isdigit():
499                        if 'ICQ' in self.agents:
500                                self.protocol_combobox.set_active(self.agents.index('ICQ'))
501                                return
502
503        def set_nickname(self):
504                uid = self.uid_entry.get_text().decode('utf-8')
505                nickname = self.nickname_entry.get_text().decode('utf-8')
506                if nickname == self.old_uid_value:
507                        self.nickname_entry.set_text(uid.split('@')[0])
508                       
509        def on_uid_entry_changed(self, widget):
510                uid = self.uid_entry.get_text().decode('utf-8')
511                self.guess_agent()
512                self.set_nickname()
513                self.fill_jid()
514                self.old_uid_value = uid.split('@')[0]
515
516class AboutDialog:
517        '''Class for about dialog'''
518        def __init__(self):
519                dlg = gtk.AboutDialog()
520                dlg.set_name('Gajim')
521                dlg.set_version(gajim.version)
522                s = u'Copyright © 2003-2006 Gajim Team'
523                dlg.set_copyright(s)
524                text = open('../COPYING').read()
525                dlg.set_license(text)
526               
527                #FIXME: do versions strings translatable after .10
528                #FIXME: use %s then
529                dlg.set_comments(_('A GTK+ jabber client') + '\nGTK+ Version: ' + \
530                        self.tuple2str(gtk.gtk_version) + '\nPyGTK Version: ' + \
531                        self.tuple2str(gtk.pygtk_version))
532                dlg.set_website('http://www.gajim.org')
533
534                #FIXME: do current devs a translatable string
535                authors = [
536                        'Current Developers:',
537                        'Yann Le Boulanger <asterix@lagaule.org>',
538                        'Dimitur Kirov <dkirov@gmail.com>',
539                        'Travis Shirk <travis@pobox.com>',
540                        '',
541                        _('Past Developers:'),
542                        'Nikos Kouremenos <kourem@gmail.com>',
543                        'Vincent Hanquez <tab@snarc.org>',
544                        '',
545                        _('THANKS:'),
546                ]
547
548                text = open('../THANKS').read()
549                text_splitted = text.split('\n')
550                text = '\n'.join(text_splitted[:-2]) # remove one english setence
551                # and add it manually as translatable
552                text += '\n%s\n' % _('Last but not least, we would like to thank all '
553                        'the package maintainers.')
554                authors.append(text)
555               
556                dlg.set_authors(authors)
557               
558                if gtk.pygtk_version >= (2, 8, 0) and gtk.gtk_version >= (2, 8, 0):
559                        dlg.props.wrap_license = True
560
561                pixbuf = gtk.gdk.pixbuf_new_from_file(os.path.join(
562                        gajim.DATA_DIR, 'pixmaps', 'gajim_about.png'))                 
563
564                dlg.set_logo(pixbuf)
565                #here you write your name in the form Name FamilyName <someone@somewhere>
566                dlg.set_translator_credits(_('translator-credits'))
567