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

Revision 3023, 42.0 kB (checked in by nk, 3 years ago)

now only accept invitation button does not work

Line 
1##      dialogs.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##      - Dimitur Kirov <dkirov@gmail.com>
8##
9##      Copyright (C) 2003-2005 Gajim Team
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
25
26import gtkgui_helpers
27
28from vcard import VcardWindow
29from filetransfers_window import FileTransfersWindow
30from gajim_themes_window import GajimThemesWindow
31from advanced import AdvancedConfigurationWindow
32from gajim import Contact
33from common import gajim
34from common import helpers
35from common import i18n
36
37_ = i18n._
38APP = i18n.APP
39gtk.glade.bindtextdomain (APP, i18n.DIR)
40gtk.glade.textdomain (APP)
41
42GTKGUI_GLADE = 'gtkgui.glade'
43
44class EditGroupsDialog:
45        '''Class for the edit group dialog window'''
46        def __init__(self, user, account, plugin):
47                self.xml = gtk.glade.XML(GTKGUI_GLADE, 'edit_groups_dialog', APP)
48                self.dialog = self.xml.get_widget('edit_groups_dialog')
49                self.plugin = plugin
50                self.account = account
51                self.user = user
52                self.changes_made = False
53                self.list = self.xml.get_widget('groups_treeview')
54                self.xml.get_widget('nickname_label').set_markup(
55                        _("Contact's name: <i>%s</i>") % user.name)
56                self.xml.get_widget('jid_label').set_markup(
57                        _('JID: <i>%s</i>') % user.jid)
58               
59                self.xml.signal_autoconnect(self)
60                self.init_list()
61
62        def run(self):
63                self.dialog.show_all()
64                if self.changes_made:
65                        gajim.connections[self.account].update_contact(self.user.jid,
66                                self.user.name, self.user.groups)
67
68        def on_edit_groups_dialog_response(self, widget, response_id):
69                if response_id == gtk.RESPONSE_CLOSE:
70                        self.dialog.destroy()
71
72        def update_contact(self):
73                self.plugin.roster.remove_contact(self.user, self.account)
74                self.plugin.roster.add_contact_to_roster(self.user.jid, self.account)
75                gajim.connections[self.account].update_contact(self.user.jid,
76                        self.user.name, self.user.groups)
77
78        def on_add_button_clicked(self, widget):
79                group = self.xml.get_widget('group_entry').get_text()
80                if not group:
81                        return
82                # check if it already exists
83                model = self.list.get_model()
84                iter = model.get_iter_root()
85                while iter:
86                        if model.get_value(iter, 0) == group:
87                                return
88                        iter = model.iter_next(iter)
89                self.changes_made = True
90                model.append((group, True))
91                self.user.groups.append(group)
92                self.update_contact()
93
94        def group_toggled_cb(self, cell, path):
95                self.changes_made = True
96                model = self.list.get_model()
97                if model[path][1] and len(self.user.groups) == 1: # we try to remove
98                                                                                                                                                  # the last group
99                        ErrorDialog(_('Cannot remove last group'),
100                                        _('At least one contact group must be present.')).get_response()
101                        return
102                model[path][1] = not model[path][1]
103                if model[path][1]:
104                        self.user.groups.append(model[path][0])
105                else:
106                        self.user.groups.remove(model[path][0])
107                self.update_contact()
108
109        def init_list(self):
110                store = gtk.ListStore(str, bool)
111                self.list.set_model(store)
112                for g in gajim.groups[self.account].keys():
113                        if g in [_('Transports'), _('not in the roster')]:
114                                continue
115                        iter = store.append()
116                        store.set(iter, 0, g)
117                        if g in self.user.groups:
118                                store.set(iter, 1, True)
119                        else:
120                                store.set(iter, 1, False)
121                column = gtk.TreeViewColumn(_('Group'))
122                self.list.append_column(column)
123                renderer = gtk.CellRendererText()
124                column.pack_start(renderer)
125                column.set_attributes(renderer, text = 0)
126               
127                column = gtk.TreeViewColumn(_('In the group'))
128                self.list.append_column(column)
129                renderer = gtk.CellRendererToggle()
130                column.pack_start(renderer)
131                renderer.set_property('activatable', True)
132                renderer.connect('toggled', self.group_toggled_cb)
133                column.set_attributes(renderer, active = 1)
134
135class PassphraseDialog:
136        '''Class for Passphrase dialog'''
137        def run(self):
138                '''Wait for OK button to be pressed and return passphrase/password'''
139                rep = self.window.run()
140                if rep == gtk.RESPONSE_OK:
141                        passphrase = self.passphrase_entry.get_text()
142                else:
143                        passphrase = -1
144                save_passphrase_checkbutton = self.xml.\
145                        get_widget('save_passphrase_checkbutton')
146                self.window.destroy()
147                return passphrase, save_passphrase_checkbutton.get_active()
148
149        def __init__(self, titletext, labeltext, checkbuttontext):
150                self.xml = gtk.glade.XML(GTKGUI_GLADE, 'passphrase_dialog', APP)
151                self.window = self.xml.get_widget('passphrase_dialog')
152                self.passphrase_entry = self.xml.get_widget('passphrase_entry')
153                self.passphrase = -1
154                self.window.set_title(titletext)
155                self.xml.get_widget('message_label').set_text(labeltext)
156                self.xml.get_widget('save_passphrase_checkbutton').set_label(
157                        checkbuttontext)
158                self.xml.signal_autoconnect(self)
159                self.window.show_all()
160
161class ChooseGPGKeyDialog:
162        '''Class for GPG key dialog'''
163        def __init__(self, title_text, prompt_text, secret_keys, selected = None):
164                #list : {keyID: userName, ...}
165                xml = gtk.glade.XML(GTKGUI_GLADE, 'choose_gpg_key_dialog', APP)
166                self.window = xml.get_widget('choose_gpg_key_dialog')
167                self.window.set_title(title_text)
168                self.keys_treeview = xml.get_widget('keys_treeview')
169                prompt_label = xml.get_widget('prompt_label')
170                prompt_label.set_text(prompt_text)
171                model = gtk.ListStore(str, str)
172                self.keys_treeview.set_model(model)
173                #columns
174                renderer = gtk.CellRendererText()
175                self.keys_treeview.insert_column_with_attributes(-1, _('KeyID'),
176                        renderer, text = 0)
177                renderer = gtk.CellRendererText()
178                self.keys_treeview.insert_column_with_attributes(-1, _('Contact name'),
179                        renderer, text = 1)
180                self.fill_tree(secret_keys, selected)
181                self.window.show_all()
182
183        def run(self):
184                rep = self.window.run()
185                if rep == gtk.RESPONSE_OK:
186                        selection = self.keys_treeview.get_selection()
187                        (model, iter) = selection.get_selected()
188                        keyID = [ model[iter][0], model[iter][1] ]
189                else:
190                        keyID = None
191                self.window.destroy()
192                return keyID
193
194        def fill_tree(self, list, selected):
195                model = self.keys_treeview.get_model()
196                for keyID in list.keys():
197                        iter = model.append((keyID, list[keyID]))
198                        if keyID == selected:
199                                path = model.get_path(iter)
200                                self.keys_treeview.set_cursor(path)
201
202
203class ChangeStatusMessageDialog:
204        def __init__(self, plugin, show):
205                self.show = show
206                self.xml = gtk.glade.XML(GTKGUI_GLADE, 'change_status_message_dialog', APP)
207                self.window = self.xml.get_widget('change_status_message_dialog')
208                uf_show = helpers.get_uf_show(show)
209                self.window.set_title(_('%s Status Message') % uf_show)
210               
211                message_textview = self.xml.get_widget('message_textview')
212                self.message_buffer = message_textview.get_buffer()
213                msg = gajim.config.get('last_status_msg_' + show)
214                if not msg:
215                        msg = ''
216                msg = helpers.from_one_line(msg)
217                self.message_buffer.set_text(msg)
218                self.values = {'':''} # have an empty string selectable, so user can clear msg
219                for msg in gajim.config.get_per('statusmsg'):
220                        self.values[msg] = gajim.config.get_per('statusmsg', msg, 'message')
221                sorted_keys_list = helpers.get_sorted_keys(self.values)
222                liststore = gtk.ListStore(str, str)
223                message_comboboxentry = self.xml.get_widget('message_comboboxentry')
224                message_comboboxentry.set_model(liststore)
225                message_comboboxentry.set_text_column(0)
226                message_comboboxentry.child.set_property('editable', False)
227                for val in sorted_keys_list:
228                        message_comboboxentry.append_text(val)
229                self.xml.signal_autoconnect(self)
230                self.window.show_all()
231
232        def run(self):
233                '''Wait for OK button to be pressed and return status messsage'''
234                rep = self.window.run()
235                if rep == gtk.RESPONSE_OK:
236                        beg, end = self.message_buffer.get_bounds()
237                        message = self.message_buffer.get_text(beg, end, 0).strip()
238                        msg = helpers.to_one_line(message)
239                        gajim.config.set('last_status_msg_' + self.show, msg)
240                else:
241                        message = -1
242                self.window.destroy()
243                return message
244
245        def on_message_comboboxentry_changed(self, widget, data = None):
246                model = widget.get_model()
247                active = widget.get_active()
248                if active < 0:
249                        return None
250                name = model[active][0]
251                self.message_buffer.set_text(self.values[name])
252       
253        def on_change_status_message_dialog_key_press_event(self, widget, event):
254                if event.keyval == gtk.keysyms.Return or \
255                event.keyval == gtk.keysyms.KP_Enter:  # catch CTRL+ENTER
256                        if (event.state & gtk.gdk.CONTROL_MASK):
257                                self.window.response(gtk.RESPONSE_OK)
258
259class AddNewContactWindow:
260        '''Class for AddNewContactWindow'''
261        def __init__(self, plugin, account, jid = None):
262                self.plugin = plugin
263                self.account = account
264                self.xml = gtk.glade.XML(GTKGUI_GLADE, 'add_new_contact_window', APP)
265                self.window = self.xml.get_widget('add_new_contact_window')
266                self.uid_entry = self.xml.get_widget('uid_entry')
267                self.protocol_combobox = self.xml.get_widget('protocol_combobox')
268                self.jid_entry = self.xml.get_widget('jid_entry')
269                self.nickname_entry = self.xml.get_widget('nickname_entry')
270                if len(gajim.connections) >= 2:
271                        prompt_text =\
272_('Please fill in the data of the contact you want to add in account %s') %account
273                else:
274                        prompt_text = _('Please fill in the data of the contact you want to add')
275                self.xml.get_widget('prompt_label').set_text(prompt_text)
276                self.old_uid_value = ''
277                liststore = gtk.ListStore(str, str)
278                liststore.append(['Jabber', ''])
279                self.agents = ['Jabber']
280                jid_agents = []
281                for j in gajim.contacts[account]:
282                        user = gajim.contacts[account][j][0]
283                        if _('Transports') in user.groups and user.show != 'offline' and \
284                                        user.show != 'error':
285                                jid_agents.append(j)
286                for a in jid_agents:
287                        if a.find('aim') > -1:
288                                name = 'AIM'
289                        elif a.find('icq') > -1:
290                                name = 'ICQ'
291                        elif a.find('msn') > -1:
292                                name = 'MSN'
293                        elif a.find('yahoo') > -1:
294                                name = 'Yahoo!'
295                        else:
296                                name = a
297                        iter = liststore.append([name, a])
298                        self.agents.append(name)
299               
300                self.protocol_combobox.set_model(liststore)
301                self.protocol_combobox.set_active(0)
302                self.fill_jid()
303                if jid:
304                        self.jid_entry.set_text(jid)
305                        jid_splited = jid.split('@')
306                        if jid_splited[1] in jid_agents:
307                                uid = jid_splited[0].replace('%', '@')
308                                self.uid_entry.set_text(uid)
309                                self.protocol_combobox.set_active(jid_agents.index(jid_splited[1]) + 1)
310                        else:
311                                self.uid_entry.set_text(jid)
312                                self.protocol_combobox.set_active(0)
313                        self.set_nickname()
314
315                self.group_comboboxentry = self.xml.get_widget('group_comboboxentry')
316                liststore = gtk.ListStore(str)
317                self.group_comboboxentry.set_model(liststore)
318                for g in gajim.groups[account].keys():
319                        if g != _('not in the roster') and g != _('Transports'):
320                                self.group_comboboxentry.append_text(g)
321
322                self.xml.signal_autoconnect(self)
323                self.window.show_all()
324
325        def on_add_new_contact_window_key_press_event(self, widget, event):
326                if event.keyval == gtk.keysyms.Escape: # ESCAPE
327                        self.window.destroy()
328
329        def on_cancel_button_clicked(self, widget):
330                '''When Cancel button is clicked'''
331                self.window.destroy()
332
333        def on_subscribe_button_clicked(self, widget):
334                '''When Subscribe button is clicked'''
335                jid = self.jid_entry.get_text()
336                nickname = self.nickname_entry.get_text()
337                if not jid:
338                        return
339                if jid.find('@') < 0:
340                        ErrorDialog(_("Invalid user name"),
341_('Contact names must be of the form "user@servername".')).get_response()
342                        return
343                message_buffer = self.xml.get_widget('message_textview').get_buffer()
344                start_iter = message_buffer.get_start_iter()
345                end_iter = message_buffer.get_end_iter()
346                message = message_buffer.get_text(start_iter, end_iter, 0)
347                group = self.group_comboboxentry.child.get_text()
348                self.plugin.roster.req_sub(self, jid, message, self.account,
349                        group = group, pseudo = nickname)
350                if self.xml.get_widget('auto_authorize_checkbutton').get_active():
351                        gajim.connections[self.account].send_authorization(jid)
352                self.window.destroy()
353               
354        def fill_jid(self):
355                model = self.protocol_combobox.get_model()
356                index = self.protocol_combobox.get_active()
357                jid = self.uid_entry.get_text().strip()
358                if index > 0: # it's not jabber but a transport
359                        jid = jid.replace('@', '%')
360                agent = model[index][1]
361                if agent:
362                        jid += '@' + agent
363                self.jid_entry.set_text(jid)
364
365        def on_protocol_combobox_changed(self, widget):
366                self.fill_jid()
367
368        def guess_agent(self):
369                uid = self.uid_entry.get_text()
370                model = self.protocol_combobox.get_model()
371               
372                #If login contains only numbers, it's probably an ICQ number
373                if uid.isdigit():
374                        if 'ICQ' in self.agents:
375                                self.protocol_combobox.set_active(self.agents.index('ICQ'))
376                                return
377
378        def set_nickname(self):
379                uid = self.uid_entry.get_text()
380                nickname = self.nickname_entry.get_text()
381                if nickname == self.old_uid_value:
382                        self.nickname_entry.set_text(uid.split('@')[0])
383                       
384        def on_uid_entry_changed(self, widget):
385                uid = self.uid_entry.get_text()
386                self.guess_agent()
387                self.set_nickname()
388                self.fill_jid()
389                self.old_uid_value = uid.split('@')[0]
390
391class AboutDialog:
392        '''Class for about dialog'''
393        def __init__(self):
394                if gtk.pygtk_version < (2, 6, 0) or gtk.gtk_version < (2, 6, 0):
395                        InformationDialog(_('Gajim - a GTK+ Jabber client'),
396                                _('Version %s') % gajim.version)
397                        return
398
399                dlg = gtk.AboutDialog()
400                dlg.set_name('Gajim')
401                dlg.set_version(gajim.version)
402                s = u'Copyright \xa9 2003-2005 Gajim Team'
403                dlg.set_copyright(s)
404                text = open('../COPYING').read()
405                dlg.set_license(text)
406
407                dlg.set_comments(_('A GTK jabber client'))
408                dlg.set_website('http://www.gajim.org')
409
410                authors = ['Yann Le Boulanger <asterix@lagaule.org>', 'Vincent Hanquez <tab@snarc.org>', 'Nikos Kouremenos <kourem@gmail.com>', 'Alex Podaras <bigpod@gmail.com>', 'Gajim patchers']
411                dlg.set_authors(authors)
412
413                pixbuf = gtk.gdk.pixbuf_new_from_file(os.path.join(gajim.DATA_DIR, 'pixmaps/gajim_about.png'))                 
414
415                dlg.set_logo(pixbuf)
416                dlg.set_translator_credits(_('translator-credits'))
417
418                rep = dlg.run()
419                dlg.destroy()
420
421class Dialog(gtk.Dialog):
422        def __init__(self, parent, title, buttons, default = None):
423                gtk.Dialog.__init__(self, title, parent, gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_MODAL | gtk.DIALOG_NO_SEPARATOR)
424
425                self.set_border_width(6)
426                self.vbox.set_spacing(12)
427                self.set_resizable(False)
428
429                for stock, response in buttons:
430                        self.add_button(stock, response)
431
432                if default is not None:
433                        self.set_default_response(default)
434                else:
435                        self.set_default_response(buttons[-1][1])
436
437        def get_button(self, index):
438                buttons = self.action_area.get_children()
439                return index < len(buttons) and buttons[index] or None
440
441
442class HigDialog(Dialog):
443        def __init__(self, parent, pritext, sectext, stockimage, buttons, default = None):
444                """GNOME higified version of the Dialog object. Inherit
445                from here if possible when you need a new dialog."""
446                Dialog.__init__(self, parent, "", buttons, default)
447
448                # hbox separating dialog image and contents
449                hbox = gtk.HBox()
450                hbox.set_spacing(12)
451                hbox.set_border_width(6)
452                self.vbox.pack_start(hbox)
453
454                # set up image
455                if stockimage is not None:
456                        image = gtk.Image()
457                        image.set_from_stock(stockimage, gtk.ICON_SIZE_DIALOG)
458                        image.set_alignment(0.5, 0)
459                        hbox.pack_start(image, False, False)
460
461                # set up main content area
462                self.contents = gtk.VBox()
463                self.contents.set_spacing(10)
464                hbox.pack_start(self.contents)
465
466                label = gtk.Label()
467                label.set_markup("<span size=\"larger\" weight=\"bold\">" + pritext + "</span>\n\n" + sectext)
468                label.set_line_wrap(True)
469                label.set_alignment(0, 0)
470                label.set_selectable(True)
471                self.contents.pack_start(label)
472
473        def get_response(self):
474                self.show_all()
475                response = gtk.Dialog.run(self)
476                self.destroy()
477                return response
478
479class ConfirmationDialog(HigDialog):
480        """HIG compliant confirmation dialog."""
481        def __init__(self, pritext, sectext=''):
482                HigDialog.__init__(self, None, pritext, sectext,
483                        gtk.STOCK_DIALOG_WARNING, [ [gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL],
484                        [ gtk.STOCK_OK, gtk.RESPONSE_OK ] ])
485                       
486class ConfirmationDialogCheck(ConfirmationDialog):
487        '''HIG compliant confirmation dialog with checkbutton.'''
488        def __init__(self, pritext, sectext='', checktext = ''):
489                HigDialog.__init__(self, None, pritext, sectext,
490                        gtk.STOCK_DIALOG_WARNING, [ [gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL] ])
491               
492                # add ok button manually, because we need to focus on it
493                ok_button = self.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
494                self.checkbutton = gtk.CheckButton(checktext)
495                self.vbox.pack_start(self.checkbutton, expand=False, fill=True)
496                ok_button.grab_focus()
497       
498        def is_checked(self):
499                ''' Get active state of the checkbutton '''
500                return self.checkbutton.get_active()
501               
502class WarningDialog(HigDialog):
503        def __init__(self, pritext, sectext=''):
504                """HIG compliant warning dialog."""
505                HigDialog.__init__(
506                        self, None, pritext, sectext, gtk.STOCK_DIALOG_WARNING,
507                        [ [ gtk.STOCK_OK, gtk.RESPONSE_OK ] ]
508                )
509
510class InformationDialog(HigDialog):
511        def __init__(self, pritext, sectext=''):
512                """HIG compliant info dialog."""
513                HigDialog.__init__(
514                        self, None, pritext, sectext, gtk.STOCK_DIALOG_INFO,
515                        [ [ gtk.STOCK_OK, gtk.RESPONSE_OK ] ]
516                )
517                hbox = self.action_area
518                ok_button = hbox.get_children()[0]
519                ok_button.connect('clicked', self.on_ok_button_clicked)
520                self.show_all()
521
522        def on_ok_button_clicked(self, widget):
523                self.destroy()
524
525class InputDialog:
526        '''Class for Input dialog'''
527        def __init__(self, title, label_str, input_str = None, is_modal = True, ok_handler = None):
528                xml = gtk.glade.XML(GTKGUI_GLADE, 'input_dialog', APP)
529                self.dialog = xml.get_widget('input_dialog')
530                label = xml.get_widget('label')
531                self.input_entry = xml.get_widget('input_entry')
532                self.dialog.set_title(title)
533                label.set_text(label_str)
534                if input_str:
535                        self.input_entry.set_text(input_str)
536                        self.input_entry.select_region(0, -1) # select all
537               
538                self.is_modal = is_modal
539                if not is_modal and ok_handler is not None:
540                        self.ok_handler = ok_handler
541                        okbutton = xml.get_widget('okbutton')
542                        okbutton.connect('clicked', self.on_okbutton_clicked)
543                        cancelbutton = xml.get_widget('cancelbutton')
544                        cancelbutton.connect('clicked', self.on_cancelbutton_clicked)
545                        self.dialog.show_all()
546
547        def on_okbutton_clicked(self,  widget):
548                response = self.input_entry.get_text()
549                self.dialog.destroy()
550                self.ok_handler(response)
551       
552        def on_cancelbutton_clicked(self,  widget):
553                self.dialog.destroy()
554
555        def get_response(self):
556                if self.is_modal:
557                        response = self.dialog.run()
558                        self.dialog.destroy()
559                return response
560       
561class ErrorDialog(HigDialog):
562        def __init__(self, pritext, sectext=''):
563                """HIG compliant error dialog."""
564                HigDialog.__init__(
565                        self, None, pritext, sectext, gtk.STOCK_DIALOG_ERROR,
566                        [ [ gtk.STOCK_OK, gtk.RESPONSE_OK ] ]
567                )
568
569
570class SubscriptionReq