root/tags/gajim-0.11.4/src/dialogs.py

Revision 9073, 102.7 kB (checked in by asterix, 12 months ago)

[Dicson] fix save preset status message behaviour. Fixes #3584

  • 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 <kourem@gmail.com>
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 gobject
23import os
24
25import gtkgui_helpers
26import vcard
27import conversation_textview
28import message_control
29
30try:
31        import gtkspell
32        HAS_GTK_SPELL = True
33except:
34        HAS_GTK_SPELL = False
35
36# those imports are not used in this file, but in files that 'import dialogs'
37# so they can do dialog.GajimThemesWindow() for example
38from filetransfers_window import FileTransfersWindow
39from gajim_themes_window import GajimThemesWindow
40from advanced import AdvancedConfigurationWindow
41
42from common import gajim
43from common import helpers
44from common.exceptions import GajimGeneralException
45
46class EditGroupsDialog:
47        '''Class for the edit group dialog window'''
48        def __init__(self, list_):
49                '''list_ is a list of (contact, account) tuples'''
50                self.xml = gtkgui_helpers.get_glade('edit_groups_dialog.glade')
51                self.dialog = self.xml.get_widget('edit_groups_dialog')
52                self.dialog.set_transient_for(gajim.interface.roster.window)
53                self.list_ = list_
54                self.changes_made = False
55                self.list = self.xml.get_widget('groups_treeview')
56                if len(list_) == 1:
57                        contact = list_[0][0]
58                        self.xml.get_widget('nickname_label').set_markup(
59                                _("Contact name: <i>%s</i>") % contact.get_shown_name())
60                        self.xml.get_widget('jid_label').set_markup(
61                                _('Jabber ID: <i>%s</i>') % contact.jid)
62                else:
63                        self.xml.get_widget('nickname_label').set_no_show_all(True)
64                        self.xml.get_widget('nickname_label').hide()
65                        self.xml.get_widget('jid_label').set_no_show_all(True)
66                        self.xml.get_widget('jid_label').hide()
67
68                self.xml.signal_autoconnect(self)
69                self.init_list()
70
71        def run(self):
72                self.dialog.show_all()
73                if self.changes_made:
74                        for (contact, account) in self.list_:
75                                gajim.connections[account].update_contact(contact.jid, contact.name,
76                                        contact.groups)
77
78        def on_edit_groups_dialog_response(self, widget, response_id):
79                if response_id == gtk.RESPONSE_CLOSE:
80                        self.dialog.destroy()
81
82        def update_contact(self):
83                for (contact, account) in self.list_:
84                        tag = gajim.contacts.get_metacontacts_tag(account, contact.jid)
85                        if not tag:
86                                gajim.interface.roster.remove_contact(contact, account)
87                                gajim.interface.roster.add_contact_to_roster(contact.jid, account)
88                                gajim.connections[account].update_contact(contact.jid, contact.name,
89                                        contact.groups)
90                                continue
91                        all_jid = gajim.contacts.get_metacontacts_jids(tag)
92                        for _account in all_jid:
93                                if not gajim.interface.roster.regroup and _account != account:
94                                        continue
95                                for _jid in all_jid[_account]:
96                                        c = gajim.contacts.get_first_contact_from_jid(_account, _jid)
97                                        if not c:
98                                                continue
99                                        gajim.interface.roster.remove_contact(c, _account)
100                                        gajim.interface.roster.add_contact_to_roster(_jid, _account)
101                                        gajim.connections[_account].update_contact(_jid, c.name,
102                                                c.groups)
103
104        def remove_group(self, group):
105                '''remove group group from all contacts and all their brothers'''
106                for (contact, account) in self.list_:
107                        tag = gajim.contacts.get_metacontacts_tag(account, contact.jid)
108                        if not tag:
109                                if group in contact.groups:
110                                        contact.groups.remove(group)
111                                continue
112                        all_jid = gajim.contacts.get_metacontacts_jids(tag)
113                        for _account in all_jid:
114                                if not gajim.interface.roster.regroup and _account != account:
115                                        continue
116                                for _jid in all_jid[_account]:
117                                        contacts = gajim.contacts.get_contact(_account, _jid)
118                                        for c in contacts:
119                                                if group in c.groups:
120                                                        c.groups.remove(group)
121
122        def add_group(self, group):
123                '''add group group to all contacts and all their brothers'''
124                for (contact, account) in self.list_:
125                        tag = gajim.contacts.get_metacontacts_tag(account, contact.jid)
126                        if not tag:
127                                if group not in contact.groups:
128                                        contact.groups.append(group)
129                                continue
130                        all_jid = gajim.contacts.get_metacontacts_jids(tag)
131                        for _account in all_jid:
132                                if not gajim.interface.roster.regroup and _account != account:
133                                        continue
134                                for _jid in all_jid[_account]:
135                                        contacts = gajim.contacts.get_contact(_account, _jid)
136                                        for c in contacts:
137                                                if not group in c.groups:
138                                                        c.groups.append(group)
139
140        def on_add_button_clicked(self, widget):
141                group = self.xml.get_widget('group_entry').get_text().decode('utf-8')
142                if not group:
143                        return
144                # Do not allow special groups
145                if group in helpers.special_groups:
146                        return
147                # check if it already exists
148                model = self.list.get_model()
149                iter = model.get_iter_root()
150                while iter:
151                        if model.get_value(iter, 0).decode('utf-8') == group:
152                                return
153                        iter = model.iter_next(iter)
154                self.changes_made = True
155                model.append((group, True, False))
156                self.add_group(group)
157                self.update_contact()
158                self.init_list() # Re-draw list to sort new item
159
160        def group_toggled_cb(self, cell, path):
161                self.changes_made = True
162                model = self.list.get_model()
163                if model[path][2]:
164                        model[path][2] = False
165                        model[path][1] = True
166                else:
167                        model[path][1] = not model[path][1]
168                group = model[path][0].decode('utf-8')
169                if model[path][1]:
170                        self.add_group(group)
171                else:
172                        self.remove_group(group)
173                self.update_contact()
174
175        def init_list(self):
176                store = gtk.ListStore(str, bool, bool)
177                self.list.set_model(store)
178                for column in self.list.get_columns(): # Clear treeview when re-drawing
179                        self.list.remove_column(column)
180                accounts = []
181                # Store groups in a list so we can sort them and the number of contacts in
182                # it
183                groups = {}
184                for (contact, account) in self.list_:
185                        if account not in accounts:
186                                accounts.append(account)
187                                for g in gajim.groups[account].keys():
188                                        if g in groups:
189                                                continue
190                                        groups[g] = 0
191                        for g in contact.groups:
192                                groups[g] += 1
193                group_list = []
194                # Remove special groups if they are empty
195                for group in groups:
196                        if group not in helpers.special_groups or groups[group] > 0:
197                                group_list.append(group)
198                group_list.sort()                       
199                for group in group_list:
200                        iter = store.append()
201                        store.set(iter, 0, group) # Group name
202                        if groups[group] == 0:
203                                store.set(iter, 1, False)
204                        else:
205                                store.set(iter, 1, True)
206                                if groups[group] == len(self.list_):
207                                        # all contacts are in this group
208                                        store.set(iter, 2, False)
209                                else:
210                                        store.set(iter, 2, True)
211                column = gtk.TreeViewColumn(_('Group'))
212                column.set_expand(True)
213                self.list.append_column(column)
214                renderer = gtk.CellRendererText()
215                column.pack_start(renderer)
216                column.set_attributes(renderer, text = 0)
217
218                column = gtk.TreeViewColumn(_('In the group'))
219                column.set_expand(False)
220                self.list.append_column(column)
221                renderer = gtk.CellRendererToggle()
222                column.pack_start(renderer)
223                renderer.set_property('activatable', True)
224                renderer.connect('toggled', self.group_toggled_cb)
225                column.set_attributes(renderer, active = 1, inconsistent = 2)
226
227class PassphraseDialog:
228        '''Class for Passphrase dialog'''
229        def run(self):
230                '''Wait for OK button to be pressed and return passphrase/password'''
231                rep = self.window.run()
232                if rep == gtk.RESPONSE_OK:
233                        passphrase = self.passphrase_entry.get_text().decode('utf-8')
234                else:
235                        passphrase = -1
236                save_passphrase_checkbutton = self.xml.\
237                        get_widget('save_passphrase_checkbutton')
238                self.window.destroy()
239                return passphrase, save_passphrase_checkbutton.get_active()
240
241        def __init__(self, titletext, labeltext, checkbuttontext):
242                self.xml = gtkgui_helpers.get_glade('passphrase_dialog.glade')
243                self.window = self.xml.get_widget('passphrase_dialog')
244                self.passphrase_entry = self.xml.get_widget('passphrase_entry')
245                self.passphrase = -1
246                self.window.set_title(titletext)
247                self.xml.get_widget('message_label').set_text(labeltext)
248                self.xml.get_widget('save_passphrase_checkbutton').set_label(
249                        checkbuttontext)
250                self.xml.signal_autoconnect(self)
251                self.window.show_all()
252
253class ChooseGPGKeyDialog:
254        '''Class for GPG key dialog'''
255        def __init__(self, title_text, prompt_text, secret_keys, selected = None):
256                #list : {keyID: userName, ...}
257                xml = gtkgui_helpers.get_glade('choose_gpg_key_dialog.glade')
258                self.window = xml.get_widget('choose_gpg_key_dialog')
259                self.window.set_title(title_text)
260                self.keys_treeview = xml.get_widget('keys_treeview')
261                prompt_label = xml.get_widget('prompt_label')
262                prompt_label.set_text(prompt_text)
263                model = gtk.ListStore(str, str)
264                model.set_sort_func(1, self.sort_keys)
265                model.set_sort_column_id(1, gtk.SORT_ASCENDING)
266                self.keys_treeview.set_model(model)
267                #columns
268                renderer = gtk.CellRendererText()
269                self.keys_treeview.insert_column_with_attributes(-1, _('KeyID'),
270                        renderer, text = 0)
271                renderer = gtk.CellRendererText()
272                self.keys_treeview.insert_column_with_attributes(-1, _('Contact name'),
273                        renderer, text = 1)
274                self.keys_treeview.set_search_column(1)
275                self.fill_tree(secret_keys, selected)
276                self.window.show_all()
277
278        def sort_keys(self, model, iter1, iter2):
279                value1 = model[iter1][1]
280                value2 = model[iter2][1]
281                if value1 == _('None'):
282                        return -1
283                elif value2 == _('None'):
284                        return 1
285                elif value1 < value2:
286                        return -1
287                return 1
288
289        def run(self):
290                rep = self.window.run()
291                if rep == gtk.RESPONSE_OK:
292                        selection = self.keys_treeview.get_selection()
293                        (model, iter) = selection.get_selected()
294                        keyID = [ model[iter][0].decode('utf-8'),
295                                model[iter][1].decode('utf-8') ]
296                else:
297                        keyID = None
298                self.window.destroy()
299                return keyID
300
301        def fill_tree(self, list, selected):
302                model = self.keys_treeview.get_model()
303                for keyID in list.keys():
304                        iter = model.append((keyID, list[keyID]))
305                        if keyID == selected:
306                                path = model.get_path(iter)
307                                self.keys_treeview.set_cursor(path)
308
309
310class ChangeStatusMessageDialog:
311        def __init__(self, show = None):
312                self.show = show
313                self.xml = gtkgui_helpers.get_glade('change_status_message_dialog.glade')
314                self.window = self.xml.get_widget('change_status_message_dialog')
315                self.window.set_transient_for(gajim.interface.roster.window)
316                if show:
317                        uf_show = helpers.get_uf_show(show)
318                        title_text = _('%s Status Message') % uf_show
319                else:
320                        title_text = _('Status Message')
321                self.window.set_title(title_text)
322
323                message_textview = self.xml.get_widget('message_textview')
324                self.message_buffer = message_textview.get_buffer()
325                self.message_buffer.connect('changed',
326                        self.toggle_sensitiviy_of_save_as_preset)
327                msg = None
328                if show:
329                        msg = gajim.config.get('last_status_msg_' + show)
330                if not msg:
331                        msg = ''
332                msg = helpers.from_one_line(msg)
333                self.message_buffer.set_text(msg)
334
335                # have an empty string selectable, so user can clear msg
336                self.preset_messages_dict = {'': ''}
337                for msg_name in gajim.config.get_per('statusmsg'):
338                        msg_text = gajim.config.get_per('statusmsg', msg_name, 'message')
339                        msg_text = helpers.from_one_line(msg_text)
340                        self.preset_messages_dict[msg_name] = msg_text
341                sorted_keys_list = helpers.get_sorted_keys(self.preset_messages_dict)
342
343                self.message_liststore = gtk.ListStore(str) # msg_name
344                self.message_combobox = self.xml.get_widget('message_combobox')
345                self.message_combobox.set_model(self.message_liststore)
346                cellrenderertext = gtk.CellRendererText()
347                self.message_combobox.pack_start(cellrenderertext, True)
348                self.message_combobox.add_attribute(cellrenderertext, 'text', 0)
349                for msg_name in sorted_keys_list:
350                        self.message_liststore.append((msg_name,))
351                self.xml.signal_autoconnect(self)
352                self.window.show_all()
353
354        def run(self):
355                '''Wait for OK or Cancel button to be pressed and return status messsage
356                (None if users pressed Cancel or x button of WM'''
357                rep = self.window.run()
358                if rep == gtk.RESPONSE_OK:
359                        beg, end = self.message_buffer.get_bounds()
360                        message = self.message_buffer.get_text(beg, end).decode('utf-8')\
361                                .strip()
362                        msg = helpers.to_one_line(message)
363                        if self.show:
364                                gajim.config.set('last_status_msg_' + self.show, msg)
365                else:
366                        message = None # user pressed Cancel button or X wm button
367                self.window.destroy()
368                return message
369
370        def on_message_combobox_changed(self, widget):
371                model = widget.get_model()
372                active = widget.get_active()
373                if active < 0:
374                        return None
375                name = model[active][0].decode('utf-8')
376                self.message_buffer.set_text(self.preset_messages_dict[name])
377
378        def on_change_status_message_dialog_key_press_event(self, widget, event):
379                if event.keyval == gtk.keysyms.Return or \
380                event.keyval == gtk.keysyms.KP_Enter:  # catch CTRL+ENTER
381                        if (event.state & gtk.gdk.CONTROL_MASK):
382                                self.window.response(gtk.RESPONSE_OK)
383                                # Stop the event
384                                return True
385
386        def toggle_sensitiviy_of_save_as_preset(self, widget):
387                btn = self.xml.get_widget('save_as_preset_button')
388                if self.message_buffer.get_char_count() == 0:
389                        btn.set_sensitive(False)
390                else:
391                        btn.set_sensitive(True)
392
393        def on_save_as_preset_button_clicked(self, widget):
394                start_iter, finish_iter = self.message_buffer.get_bounds()
395                status_message_to_save_as_preset = self.message_buffer.get_text(
396                        start_iter, finish_iter)
397                dlg = InputDialog(_('Save as Preset Status Message'),
398                        _('Please type a name for this status message'), is_modal = True)
399                response = dlg.get_response()
400                if response == gtk.RESPONSE_OK:
401                        msg_name = dlg.input_entry.get_text()
402                        msg_text = status_message_to_save_as_preset.decode('utf-8')
403                        msg_text_1l = helpers.to_one_line(msg_text)
404                        if not msg_name: # msg_name was ''
405                                msg_name = msg_text_1l
406                        msg_name = msg_name.decode('utf-8')
407
408                        if msg_name in self.preset_messages_dict:
409                                dlg2 = ConfirmationDialog(_('Overwrite Status Message?'),
410                                        _('This name is already used. Do you want to overwrite this status message?'))
411                                resp = dlg2.run()
412                                if resp != gtk.RESPONSE_OK:
413                                        return
414                                self.preset_messages_dict[msg_name] = msg_text
415                        else:
416                                self.preset_messages_dict[msg_name] = msg_text
417                                iter_ = self.message_liststore.append((msg_name,))
418                                gajim.config.add_per('statusmsg', msg_name)
419                                # select in combobox the one we just saved
420                                self.message_combobox.set_active_iter(iter_)
421                        gajim.config.set_per('statusmsg', msg_name, 'message', msg_text_1l)
422
423
424class AddNewContactWindow:
425        '''Class for AddNewContactWindow'''
426        uid_labels = {'jabber': _('Jabber ID:'),
427                'aim': _('AIM Address:'),
428                'gadu-gadu': _('GG Number:'),
429                'icq': _('ICQ Number:'),
430                'msn': _('MSN Address:'),
431                'yahoo': _('Yahoo! Address:')}
432        def __init__(self, account = None, jid = None, user_nick = None,
433        group = None):
434                self.account = account
435                if account == None:
436                        # fill accounts with active accounts
437                        accounts = []
438                        for account in gajim.connections.keys():
439                                if gajim.connections[account].connected > 1:
440                                        accounts.append(account)
441                        if not accounts:
442                                return
443                        if len(accounts) == 1:
444                                self.account = account
445                else:
446                        accounts = [self.account]
447                if self.account:
448                        location = gajim.interface.instances[self.account]
449                else:
450                        location = gajim.interface.instances
451                if location.has_key('add_contact'):
452                        location['add_contact'].window.present()
453                        # An instance is already opened
454                        return
455                location['add_contact'] = self
456                self.xml = gtkgui_helpers.get_glade('add_new_contact_window.glade')
457                self.window = self.xml.get_widget('add_new_contact_window')
458                for w in ('account_combobox', 'account_hbox', 'account_label',
459                'uid_label', 'uid_entry', 'protocol_combobox', 'protocol_jid_combobox',
460                'protocol_hbox', 'nickname_entry', 'message_scrolledwindow',
461                'register_hbox', 'subscription_table', 'add_button',
462                'message_textview', 'connected_label', 'group_comboboxentry',
463                'auto_authorize_checkbutton'):
464                        self.__dict__[w] = self.xml.get_widget(w)
465                if account and len(gajim.connections) >= 2:
466                        prompt_text =\
467_('Please fill in the data of the contact you want to add in account %s') %account
468                else:
469                        prompt_text = _('Please fill in the data of the contact you want to add')
470                self.xml.get_widget('prompt_label').set_text(prompt_text)
471                self.agents = {'jabber': []}
472                # types to which we are not subscribed but account has an agent for it
473                self.available_types = []
474                for acct in accounts:
475                        for j in gajim.contacts.get_jid_list(acct):
476                                if gajim.jid_is_transport(j):
477                                        type_ = gajim.get_transport_name_from_jid(j, False)
478                                        if self.agents.has_key(type_):
479                                                self.agents[type_].append(j)
480                                        else:
481                                                self.agents[type_] = [j]
482                # Now add the one to which we can register
483                for acct in accounts:
484                        for type_ in gajim.connections[acct].available_transports:
485                                if type_ in self.agents:
486                                        continue
487                                self.agents[type_] = []
488                                for jid_ in gajim.connections[acct].available_transports[type_]:
489                                        if not jid_ in self.agents[type_]:
490                                                self.agents[type_].append(jid_)
491                                self.available_types.append(type_)
492                liststore = gtk.ListStore(str)
493                self.group_comboboxentry.set_model(liststore)
494                liststore = gtk.ListStore(str, str)
495                uf_type = {'jabber': 'Jabber', 'aim': 'AIM', 'gadu-gadu': 'Gadu Gadu',
496                        'icq': 'ICQ', 'msn': 'MSN', 'yahoo': 'Yahoo'}
497                # Jabber as first
498                liststore.append(['Jabber', 'jabber'])
499                for type_ in self.agents:
500                        if type_ == 'jabber':
501                                continue
502                        if type_ in uf_type:
503                                liststore.append([uf_type[type_], type_])
504                        else:
505                                liststore.append([type_, type_])
506                self.protocol_combobox.set_model(liststore)
507                self.protocol_combobox.set_active(0)
508                self.protocol_jid_combobox.set_no_show_all(True)
509                self.protocol_jid_combobox.hide()
510                self.subscription_table.set_no_show_all(True)
511                self.auto_authorize_checkbutton.show()
512                self.message_scrolledwindow.set_no_show_all(True)
513                self.register_hbox.set_no_show_all(True)
514                self.register_hbox.hide()
515                self.connected_label.set_no_show_all(True)
516                self.connected_label.hide()
517                liststore = gtk.ListStore(str)
518                self.protocol_jid_combobox.set_model(liststore)
519                self.xml.signal_autoconnect(self)
520                if jid:
521                        type_ = gajim.get_transport_name_from_jid(jid)
522                        if not type_:
523                                type_ = 'jabber'
524                        if type_ == 'jabber':
525                                self.uid_entry.set_text(jid)
526                        else:
527                                uid, transport = gajim.get_name_and_server_from_jid(jid)
528                                self.uid_entry.set_text(uid.replace('%', '@', 1))
529                        #set protocol_combobox
530                        model = self.protocol_combobox.get_model()
531                        iter = model.get_iter_first()
532                        i = 0
533                        while iter:
534                                if model[iter][1] == type_:
535                                        self.protocol_combobox.set_active(i)
536                                        break
537                                iter = model.iter_next(iter)
538                                i += 1
539
540                        # set protocol_jid_combobox
541                        self.protocol_jid_combobox.set_active(0)
542                        model = self.protocol_jid_combobox.get_model()
543                        iter = model.get_iter_first()
544                        i = 0
545                        while iter:
546                                if model[iter][0] == transport:
547                                        self.protocol_jid_combobox.set_active(i)
548                                        break
549                                iter = model.iter_next(iter)
550                                i += 1
551                        if user_nick:
552                                self.nickname_entry.set_text(user_nick)
553                        self.nickname_entry.grab_focus()
554                else:
555                        self.uid_entry.grab_focus()
556                group_names = []
557                for acct in accounts