1 # -*- coding: utf-8 -*-
4 ## Copyright (C) 2003-2005 Vincent Hanquez <tab AT snarc.org>
5 ## Copyright (C) 2003-2010 Yann Leboulanger <asterix AT lagaule.org>
6 ## Copyright (C) 2005 Alex Mauer <hawke AT hawkesnest.net>
7 ## Copyright (C) 2005-2006 Dimitur Kirov <dkirov AT gmail.com>
8 ## Travis Shirk <travis AT pobox.com>
9 ## Copyright (C) 2005-2008 Nikos Kouremenos <kourem AT gmail.com>
10 ## Copyright (C) 2006-2008 Jean-Marie Traissard <jim AT lapin.org>
11 ## Copyright (C) 2007 Lukas Petrovicky <lukas AT petrovicky.net>
12 ## Copyright (C) 2007-2008 Brendan Taylor <whateley AT gmail.com>
13 ## Julien Pivotto <roidelapluie AT gmail.com>
14 ## Stephan Erb <steve-e AT h3c.de>
15 ## Copyright (C) 2008 Jonathan Schleifer <js-gajim AT webkeks.org>
17 ## This file is part of Gajim.
19 ## Gajim is free software; you can redistribute it and/or modify
20 ## it under the terms of the GNU General Public License as published
21 ## by the Free Software Foundation; version 3 only.
23 ## Gajim is distributed in the hope that it will be useful,
24 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
25 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 ## GNU General Public License for more details.
28 ## You should have received a copy of the GNU General Public License
29 ## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
38 import conversation_textview
39 import message_control
40 import dataforms_widget
43 from random
import randrange
44 from common
import pep
45 from common
import ged
53 # those imports are not used in this file, but in files that 'import dialogs'
54 # so they can do dialog.GajimThemesWindow() for example
55 from filetransfers_window
import FileTransfersWindow
56 from gajim_themes_window
import GajimThemesWindow
57 from advanced_configuration_window
import AdvancedConfigurationWindow
59 from common
import gajim
60 from common
import helpers
61 from common
import dataforms
62 from common
.exceptions
import GajimGeneralException
64 class EditGroupsDialog
:
66 Class for the edit group dialog window
69 def __init__(self
, list_
):
71 list_ is a list of (contact, account) tuples
73 self
.xml
= gtkgui_helpers
.get_gtk_builder('edit_groups_dialog.ui')
74 self
.dialog
= self
.xml
.get_object('edit_groups_dialog')
75 self
.dialog
.set_transient_for(gajim
.interface
.roster
.window
)
77 self
.changes_made
= False
78 self
.treeview
= self
.xml
.get_object('groups_treeview')
81 self
.xml
.get_object('nickname_label').set_markup(
82 _('Contact name: <i>%s</i>') % contact
.get_shown_name())
83 self
.xml
.get_object('jid_label').set_markup(
84 _('Jabber ID: <i>%s</i>') % contact
.jid
)
86 self
.xml
.get_object('nickname_label').set_no_show_all(True)
87 self
.xml
.get_object('nickname_label').hide()
88 self
.xml
.get_object('jid_label').set_no_show_all(True)
89 self
.xml
.get_object('jid_label').hide()
91 self
.xml
.connect_signals(self
)
94 self
.dialog
.show_all()
96 for (contact
, account
) in self
.list_
:
97 gajim
.connections
[account
].update_contact(contact
.jid
,
98 contact
.name
, contact
.groups
)
100 def on_edit_groups_dialog_response(self
, widget
, response_id
):
101 if response_id
== gtk
.RESPONSE_CLOSE
:
102 self
.dialog
.destroy()
104 def remove_group(self
, group
):
106 Remove group group from all contacts and all their brothers
108 for (contact
, account
) in self
.list_
:
109 gajim
.interface
.roster
.remove_contact_from_groups(contact
.jid
,
112 # FIXME: Ugly workaround.
113 gajim
.interface
.roster
.draw_group(_('General'), account
)
115 def add_group(self
, group
):
117 Add group group to all contacts and all their brothers
119 for (contact
, account
) in self
.list_
:
120 gajim
.interface
.roster
.add_contact_to_groups(contact
.jid
, account
,
123 # FIXME: Ugly workaround.
124 # Maybe we haven't been in any group (defaults to General)
125 gajim
.interface
.roster
.draw_group(_('General'), account
)
127 def on_add_button_clicked(self
, widget
):
128 group
= self
.xml
.get_object('group_entry').get_text().decode('utf-8')
131 # Do not allow special groups
132 if group
in helpers
.special_groups
:
134 # check if it already exists
135 model
= self
.treeview
.get_model()
136 iter_
= model
.get_iter_root()
138 if model
.get_value(iter_
, 0).decode('utf-8') == group
:
140 iter_
= model
.iter_next(iter_
)
141 self
.changes_made
= True
142 model
.append((group
, True, False))
143 self
.add_group(group
)
144 self
.init_list() # Re-draw list to sort new item
146 def group_toggled_cb(self
, cell
, path
):
147 self
.changes_made
= True
148 model
= self
.treeview
.get_model()
150 model
[path
][2] = False
151 model
[path
][1] = True
153 model
[path
][1] = not model
[path
][1]
154 group
= model
[path
][0].decode('utf-8')
156 self
.add_group(group
)
158 self
.remove_group(group
)
161 store
= gtk
.ListStore(str, bool, bool)
162 self
.treeview
.set_model(store
)
163 for column
in self
.treeview
.get_columns():
164 # Clear treeview when re-drawing
165 self
.treeview
.remove_column(column
)
167 # Store groups in a list so we can sort them and the number of contacts in
170 for (contact
, account
) in self
.list_
:
171 if account
not in accounts
:
172 accounts
.append(account
)
173 for g
in gajim
.groups
[account
].keys():
177 c_groups
= contact
.groups
181 # Remove special groups if they are empty
183 if group
not in helpers
.special_groups
or groups
[group
] > 0:
184 group_list
.append(group
)
186 for group
in group_list
:
187 iter_
= store
.append()
188 store
.set(iter_
, 0, group
) # Group name
189 if groups
[group
] == 0:
190 store
.set(iter_
, 1, False)
192 store
.set(iter_
, 1, True)
193 if groups
[group
] == len(self
.list_
):
194 # all contacts are in this group
195 store
.set(iter_
, 2, False)
197 store
.set(iter_
, 2, True)
198 column
= gtk
.TreeViewColumn(_('Group'))
199 column
.set_expand(True)
200 self
.treeview
.append_column(column
)
201 renderer
= gtk
.CellRendererText()
202 column
.pack_start(renderer
)
203 column
.set_attributes(renderer
, text
=0)
205 column
= gtk
.TreeViewColumn(_('In the group'))
206 column
.set_expand(False)
207 self
.treeview
.append_column(column
)
208 renderer
= gtk
.CellRendererToggle()
209 column
.pack_start(renderer
)
210 renderer
.set_property('activatable', True)
211 renderer
.connect('toggled', self
.group_toggled_cb
)
212 column
.set_attributes(renderer
, active
=1, inconsistent
=2)
214 class PassphraseDialog
:
216 Class for Passphrase dialog
218 def __init__(self
, titletext
, labeltext
, checkbuttontext
=None,
219 ok_handler
=None, cancel_handler
=None):
220 self
.xml
= gtkgui_helpers
.get_gtk_builder('passphrase_dialog.ui')
221 self
.window
= self
.xml
.get_object('passphrase_dialog')
222 self
.passphrase_entry
= self
.xml
.get_object('passphrase_entry')
224 self
.window
.set_title(titletext
)
225 self
.xml
.get_object('message_label').set_text(labeltext
)
229 self
.cancel_handler
= cancel_handler
230 self
.ok_handler
= ok_handler
231 okbutton
= self
.xml
.get_object('ok_button')
232 okbutton
.connect('clicked', self
.on_okbutton_clicked
)
233 cancelbutton
= self
.xml
.get_object('cancel_button')
234 cancelbutton
.connect('clicked', self
.on_cancelbutton_clicked
)
236 self
.xml
.connect_signals(self
)
237 self
.window
.set_position(gtk
.WIN_POS_CENTER_ON_PARENT
)
238 self
.window
.show_all()
240 self
.check
= bool(checkbuttontext
)
241 checkbutton
= self
.xml
.get_object('save_passphrase_checkbutton')
243 checkbutton
.set_label(checkbuttontext
)
247 def on_okbutton_clicked(self
, widget
):
248 if not self
.ok_handler
:
251 passph
= self
.passphrase_entry
.get_text().decode('utf-8')
254 checked
= self
.xml
.get_object('save_passphrase_checkbutton').\
261 self
.window
.destroy()
263 if isinstance(self
.ok_handler
, tuple):
264 self
.ok_handler
[0](passph
, checked
, *self
.ok_handler
[1:])
266 self
.ok_handler(passph
, checked
)
268 def on_cancelbutton_clicked(self
, widget
):
269 self
.window
.destroy()
271 def on_passphrase_dialog_destroy(self
, widget
):
272 if self
.cancel_handler
and not self
.ok
:
273 self
.cancel_handler()
275 class ChooseGPGKeyDialog
:
277 Class for GPG key dialog
280 def __init__(self
, title_text
, prompt_text
, secret_keys
, on_response
,
282 '''secret_keys : {keyID: userName, ...}'''
283 self
.on_response
= on_response
284 xml
= gtkgui_helpers
.get_gtk_builder('choose_gpg_key_dialog.ui')
285 self
.window
= xml
.get_object('choose_gpg_key_dialog')
286 self
.window
.set_title(title_text
)
287 self
.keys_treeview
= xml
.get_object('keys_treeview')
288 prompt_label
= xml
.get_object('prompt_label')
289 prompt_label
.set_text(prompt_text
)
290 model
= gtk
.ListStore(str, str)
291 model
.set_sort_func(1, self
.sort_keys
)
292 model
.set_sort_column_id(1, gtk
.SORT_ASCENDING
)
293 self
.keys_treeview
.set_model(model
)
295 renderer
= gtk
.CellRendererText()
296 col
= self
.keys_treeview
.insert_column_with_attributes(-1, _('KeyID'),
298 col
.set_sort_column_id(0)
299 renderer
= gtk
.CellRendererText()
300 col
= self
.keys_treeview
.insert_column_with_attributes(-1,
301 _('Contact name'), renderer
, text
=1)
302 col
.set_sort_column_id(1)
303 self
.keys_treeview
.set_search_column(1)
304 self
.fill_tree(secret_keys
, selected
)
305 self
.window
.connect('response', self
.on_dialog_response
)
306 self
.window
.set_position(gtk
.WIN_POS_CENTER_ON_PARENT
)
307 self
.window
.show_all()
309 def sort_keys(self
, model
, iter1
, iter2
):
310 value1
= model
[iter1
][1]
311 value2
= model
[iter2
][1]
312 if value1
== _('None'):
314 elif value2
== _('None'):
316 elif value1
< value2
:
320 def on_dialog_response(self
, dialog
, response
):
321 selection
= self
.keys_treeview
.get_selection()
322 (model
, iter_
) = selection
.get_selected()
323 if iter_
and response
== gtk
.RESPONSE_OK
:
324 keyID
= [ model
[iter_
][0].decode('utf-8'),
325 model
[iter_
][1].decode('utf-8') ]
328 self
.on_response(keyID
)
329 self
.window
.destroy()
331 def fill_tree(self
, list_
, selected
):
332 model
= self
.keys_treeview
.get_model()
333 for keyID
in list_
.keys():
334 iter_
= model
.append((keyID
, list_
[keyID
]))
335 if keyID
== selected
:
336 path
= model
.get_path(iter_
)
337 self
.keys_treeview
.set_cursor(path
)
340 class ChangeActivityDialog
:
341 PAGELIST
= ['doing_chores', 'drinking', 'eating', 'exercising', 'grooming',
342 'having_appointment', 'inactive', 'relaxing', 'talking', 'traveling',
345 def __init__(self
, on_response
, activity
=None, subactivity
=None, text
=''):
346 self
.on_response
= on_response
347 self
.activity
= activity
348 self
.subactivity
= subactivity
350 self
.xml
= gtkgui_helpers
.get_gtk_builder('change_activity_dialog.ui')
351 self
.window
= self
.xml
.get_object('change_activity_dialog')
352 self
.window
.set_transient_for(gajim
.interface
.roster
.window
)
354 self
.checkbutton
= self
.xml
.get_object('enable_checkbutton')
355 self
.notebook
= self
.xml
.get_object('notebook')
356 self
.entry
= self
.xml
.get_object('description_entry')
361 for category
in pep
.ACTIVITIES
:
362 item
= self
.xml
.get_object(category
+ '_image')
363 item
.set_from_pixbuf(
364 gtkgui_helpers
.load_activity_icon(category
).get_pixbuf())
365 item
.set_tooltip_text(pep
.ACTIVITIES
[category
]['category'])
367 vbox
= self
.xml
.get_object(category
+ '_vbox')
368 vbox
.set_border_width(5)
371 act
= category
+ '_other'
374 rbtns
[act
] = gtk
.RadioButton(group
)
376 rbtns
[act
] = group
= gtk
.RadioButton()
378 hbox
= gtk
.HBox(False, 5)
379 hbox
.pack_start(gtkgui_helpers
.load_activity_icon(category
), False,
381 lbl
= gtk
.Label('<b>' + pep
.ACTIVITIES
[category
]['category'] + '</b>')
382 lbl
.set_use_markup(True)
383 hbox
.pack_start(lbl
, False, False, 0)
385 rbtns
[act
].connect('toggled', self
.on_rbtn_toggled
,
387 vbox
.pack_start(rbtns
[act
], False, False, 0)
390 for activity
in pep
.ACTIVITIES
[category
]:
391 activities
.append(activity
)
394 for activity
in activities
:
395 if activity
== 'category':
398 act
= category
+ '_' + activity
401 rbtns
[act
] = gtk
.RadioButton(group
)
403 rbtns
[act
] = group
= gtk
.RadioButton()
405 hbox
= gtk
.HBox(False, 5)
406 hbox
.pack_start(gtkgui_helpers
.load_activity_icon(category
,
407 activity
), False, False, 0)
408 hbox
.pack_start(gtk
.Label(pep
.ACTIVITIES
[category
][activity
]),
410 rbtns
[act
].connect('toggled', self
.on_rbtn_toggled
,
411 [category
, activity
])
413 vbox
.pack_start(rbtns
[act
], False, False, 0)
416 self
.default_radio
= rbtns
['doing_chores_other']
418 if self
.activity
in pep
.ACTIVITIES
:
419 if not self
.subactivity
in pep
.ACTIVITIES
[self
.activity
]:
420 self
.subactivity
= 'other'
422 rbtns
[self
.activity
+ '_' + self
.subactivity
].set_active(True)
424 self
.checkbutton
.set_active(True)
425 self
.notebook
.set_sensitive(True)
426 self
.entry
.set_sensitive(True)
428 self
.notebook
.set_current_page(
429 self
.PAGELIST
.index(self
.activity
))
431 self
.entry
.set_text(text
)
434 self
.checkbutton
.set_active(False)
436 self
.xml
.connect_signals(self
)
437 self
.window
.set_position(gtk
.WIN_POS_CENTER_ON_PARENT
)
438 self
.window
.show_all()
440 def on_enable_checkbutton_toggled(self
, widget
):
441 self
.notebook
.set_sensitive(widget
.get_active())
442 self
.entry
.set_sensitive(widget
.get_active())
443 if not self
.activity
:
444 self
.default_radio
.set_active(True)
446 def on_rbtn_toggled(self
, widget
, data
):
447 if widget
.get_active():
448 self
.activity
= data
[0]
449 self
.subactivity
= data
[1]
451 def on_ok_button_clicked(self
, widget
):
453 Return activity and messsage (None if no activity selected)
455 if self
.checkbutton
.get_active():
456 self
.on_response(self
.activity
, self
.subactivity
,
457 self
.entry
.get_text().decode('utf-8'))
459 self
.on_response(None, None, '')
460 self
.window
.destroy()
462 def on_cancel_button_clicked(self
, widget
):
463 self
.window
.destroy()
465 class ChangeMoodDialog
:
468 def __init__(self
, on_response
, mood
=None, text
=''):
469 self
.on_response
= on_response
472 self
.xml
= gtkgui_helpers
.get_gtk_builder('change_mood_dialog.ui')
474 self
.window
= self
.xml
.get_object('change_mood_dialog')
475 self
.window
.set_transient_for(gajim
.interface
.roster
.window
)
476 self
.window
.set_title(_('Set Mood'))
478 table
= self
.xml
.get_object('mood_icons_table')
479 self
.label
= self
.xml
.get_object('mood_label')
480 self
.entry
= self
.xml
.get_object('description_entry')
482 no_mood_button
= self
.xml
.get_object('no_mood_button')
483 no_mood_button
.set_mode(False)
484 no_mood_button
.connect('clicked',
485 self
.on_mood_button_clicked
, None)
489 self
.mood_buttons
= {}
493 for mood
in pep
.MOODS
:
494 self
.MOODS
.append(mood
)
497 for mood
in self
.MOODS
:
498 self
.mood_buttons
[mood
] = gtk
.RadioButton(no_mood_button
)
499 self
.mood_buttons
[mood
].set_mode(False)
500 self
.mood_buttons
[mood
].add(gtkgui_helpers
.load_mood_icon(mood
))
501 self
.mood_buttons
[mood
].set_relief(gtk
.RELIEF_NONE
)
502 self
.mood_buttons
[mood
].set_tooltip_text(pep
.MOODS
[mood
])
503 self
.mood_buttons
[mood
].connect('clicked',
504 self
.on_mood_button_clicked
, mood
)
505 table
.attach(self
.mood_buttons
[mood
], x
, x
+ 1, y
, y
+ 1)
507 # Calculate the next position
513 if self
.mood
in pep
.MOODS
:
514 self
.mood_buttons
[self
.mood
].set_active(True)
515 self
.label
.set_text(pep
.MOODS
[self
.mood
])
516 self
.entry
.set_sensitive(True)
518 self
.entry
.set_text(self
.text
)
520 self
.label
.set_text(_('None'))
521 self
.entry
.set_text('')
522 self
.entry
.set_sensitive(False)
524 self
.xml
.connect_signals(self
)
525 self
.window
.set_position(gtk
.WIN_POS_CENTER_ON_PARENT
)
526 self
.window
.show_all()
528 def on_mood_button_clicked(self
, widget
, data
):
530 self
.label
.set_text(pep
.MOODS
[data
])
531 self
.entry
.set_sensitive(True)
533 self
.label
.set_text(_('None'))
534 self
.entry
.set_text('')
535 self
.entry
.set_sensitive(False)
538 def on_ok_button_clicked(self
, widget
):
539 '''Return mood and messsage (None if no mood selected)'''
540 message
= self
.entry
.get_text().decode('utf-8')
541 self
.on_response(self
.mood
, message
)
542 self
.window
.destroy()
544 def on_cancel_button_clicked(self
, widget
):
545 self
.window
.destroy()
549 Class designed to be derivated to create timeout'd dialogs (dialogs that
550 closes automatically after a timeout)
552 def __init__(self
, timeout
, on_timeout
):
553 self
.countdown_left
= timeout
554 self
.countdown_enabled
= True
556 self
.on_timeout
= on_timeout
558 def run_timeout(self
):
559 if self
.countdown_left
> 0:
561 gobject
.timeout_add_seconds(1, self
.countdown
)
565 To be implemented in derivated classes
570 if self
.countdown_enabled
:
571 if self
.countdown_left
<= 0:
574 self
.dialog
.set_title('%s [%s]' % (self
.title_text
,
575 str(self
.countdown_left
)))
576 self
.countdown_left
-= 1
579 self
.dialog
.set_title(self
.title_text
)
582 class ChangeStatusMessageDialog(TimeoutDialog
):
583 def __init__(self
, on_response
, show
=None, show_pep
=True):
584 countdown_time
= gajim
.config
.get('change_status_window_timeout')
585 TimeoutDialog
.__init
__(self
, countdown_time
, self
.on_timeout
)
588 self
.show_pep
= show_pep
589 self
.on_response
= on_response
590 self
.xml
= gtkgui_helpers
.get_gtk_builder('change_status_message_dialog.ui')
591 self
.dialog
= self
.xml
.get_object('change_status_message_dialog')
592 self
.dialog
.set_transient_for(gajim
.interface
.roster
.window
)
595 uf_show
= helpers
.get_uf_show(show
)
596 self
.title_text
= _('%s Status Message') % uf_show
597 msg
= gajim
.config
.get_per('statusmsg', '_last_' + self
.show
,
599 self
.pep_dict
['activity'] = gajim
.config
.get_per('statusmsg',
600 '_last_' + self
.show
, 'activity')
601 self
.pep_dict
['subactivity'] = gajim
.config
.get_per('statusmsg',
602 '_last_' + self
.show
, 'subactivity')
603 self
.pep_dict
['activity_text'] = gajim
.config
.get_per('statusmsg',
604 '_last_' + self
.show
, 'activity_text')
605 self
.pep_dict
['mood'] = gajim
.config
.get_per('statusmsg',
606 '_last_' + self
.show
, 'mood')
607 self
.pep_dict
['mood_text'] = gajim
.config
.get_per('statusmsg',
608 '_last_' + self
.show
, 'mood_text')
610 self
.title_text
= _('Status Message')
611 self
.dialog
.set_title(self
.title_text
)
613 message_textview
= self
.xml
.get_object('message_textview')
614 self
.message_buffer
= message_textview
.get_buffer()
615 self
.message_buffer
.connect('changed', self
.on_message_buffer_changed
)
618 msg
= helpers
.from_one_line(msg
)
619 self
.message_buffer
.set_text(msg
)
621 # have an empty string selectable, so user can clear msg
622 self
.preset_messages_dict
= {'': ['', '', '', '', '', '']}
623 for msg_name
in gajim
.config
.get_per('statusmsg'):
624 if msg_name
.startswith('_last_'):
627 for opt
in ['message', 'activity', 'subactivity', 'activity_text',
628 'mood', 'mood_text']:
629 opts
.append(gajim
.config
.get_per('statusmsg', msg_name
, opt
))
630 opts
[0] = helpers
.from_one_line(opts
[0])
631 self
.preset_messages_dict
[msg_name
] = opts
632 sorted_keys_list
= helpers
.get_sorted_keys(self
.preset_messages_dict
)
634 self
.message_liststore
= gtk
.ListStore(str) # msg_name
635 self
.message_combobox
= self
.xml
.get_object('message_combobox')
636 self
.message_combobox
.set_model(self
.message_liststore
)
637 cellrenderertext
= gtk
.CellRendererText()
638 self
.message_combobox
.pack_start(cellrenderertext
, True)
639 self
.message_combobox
.add_attribute(cellrenderertext
, 'text', 0)
640 for msg_name
in sorted_keys_list
:
641 self
.message_liststore
.append((msg_name
,))
647 # remove acvtivity / mood lines
648 self
.xml
.get_object('activity_label').set_no_show_all(True)
649 self
.xml
.get_object('activity_button').set_no_show_all(True)
650 self
.xml
.get_object('mood_label').set_no_show_all(True)
651 self
.xml
.get_object('mood_button').set_no_show_all(True)
652 self
.xml
.get_object('activity_label').hide()
653 self
.xml
.get_object('activity_button').hide()
654 self
.xml
.get_object('mood_label').hide()
655 self
.xml
.get_object('mood_button').hide()
657 self
.xml
.connect_signals(self
)
659 self
.dialog
.connect('response', self
.on_dialog_response
)
660 self
.dialog
.set_position(gtk
.WIN_POS_CENTER_ON_PARENT
)
661 self
.dialog
.show_all()
663 def draw_activity(self
):
667 img
= self
.xml
.get_object('activity_image')
668 label
= self
.xml
.get_object('activity_button_label')
669 if 'activity' in self
.pep_dict
and self
.pep_dict
['activity'] in \
671 if 'subactivity' in self
.pep_dict
and self
.pep_dict
['subactivity'] \
672 in pep
.ACTIVITIES
[self
.pep_dict
['activity']]:
673 img
.set_from_pixbuf(gtkgui_helpers
.load_activity_icon(
674 self
.pep_dict
['activity'], self
.pep_dict
['subactivity']).\
677 img
.set_from_pixbuf(gtkgui_helpers
.load_activity_icon(
678 self
.pep_dict
['activity']).get_pixbuf())
679 if self
.pep_dict
['activity_text']:
680 label
.set_text(self
.pep_dict
['activity_text'])
684 img
.set_from_pixbuf(None)
691 img
= self
.xml
.get_object('mood_image')
692 label
= self
.xml
.get_object('mood_button_label')
693 if 'mood' in self
.pep_dict
and self
.pep_dict
['mood'] in pep
.MOODS
:
694 img
.set_from_pixbuf(gtkgui_helpers
.load_mood_icon(
695 self
.pep_dict
['mood']).get_pixbuf())
696 if self
.pep_dict
['mood_text']:
697 label
.set_text(self
.pep_dict
['mood_text'])
701 img
.set_from_pixbuf(None)
704 def on_timeout(self
):
705 # Prevent GUI freeze when the combobox menu is opened on close
706 self
.message_combobox
.popdown()
707 self
.dialog
.response(gtk
.RESPONSE_OK
)
709 def on_dialog_response(self
, dialog
, response
):
710 if response
== gtk
.RESPONSE_OK
:
711 beg
, end
= self
.message_buffer
.get_bounds()
712 message
= self
.message_buffer
.get_text(beg
, end
).decode('utf-8')\
714 message
= helpers
.remove_invalid_xml_chars(message
)
715 msg
= helpers
.to_one_line(message
)
717 gajim
.config
.set_per('statusmsg', '_last_' + self
.show
,
720 gajim
.config
.set_per('statusmsg', '_last_' + self
.show
,
721 'activity', self
.pep_dict
['activity'])
722 gajim
.config
.set_per('statusmsg', '_last_' + self
.show
,
723 'subactivity', self
.pep_dict
['subactivity'])
724 gajim
.config
.set_per('statusmsg', '_last_' + self
.show
,
725 'activity_text', self
.pep_dict
['activity_text'])
726 gajim
.config
.set_per('statusmsg', '_last_' + self
.show
,
727 'mood', self
.pep_dict
['mood'])
728 gajim
.config
.set_per('statusmsg', '_last_' + self
.show
,
729 'mood_text', self
.pep_dict
['mood_text'])
731 message
= None # user pressed Cancel button or X wm button
732 self
.dialog
.destroy()
733 self
.on_response(message
, self
.pep_dict
)
735 def on_message_combobox_changed(self
, widget
):
736 self
.countdown_enabled
= False
737 model
= widget
.get_model()
738 active
= widget
.get_active()
741 name
= model
[active
][0].decode('utf-8')
742 self
.message_buffer
.set_text(self
.preset_messages_dict
[name
][0])
743 self
.pep_dict
['activity'] = self
.preset_messages_dict
[name
][1]
744 self
.pep_dict
['subactivity'] = self
.preset_messages_dict
[name
][2]
745 self
.pep_dict
['activity_text'] = self
.preset_messages_dict
[name
][3]
746 self
.pep_dict
['mood'] = self
.preset_messages_dict
[name
][4]
747 self
.pep_dict
['mood_text'] = self
.preset_messages_dict
[name
][5]
751 def on_change_status_message_dialog_key_press_event(self
, widget
, event
):
752 self
.countdown_enabled
= False
753 if event
.keyval
== gtk
.keysyms
.Return
or \
754 event
.keyval
== gtk
.keysyms
.KP_Enter
: # catch CTRL+ENTER
755 if (event
.state
& gtk
.gdk
.CONTROL_MASK
):
756 self
.dialog
.response(gtk
.RESPONSE_OK
)
760 def on_message_buffer_changed(self
, widget
):
761 self
.countdown_enabled
= False
762 self
.toggle_sensitiviy_of_save_as_preset()
764 def toggle_sensitiviy_of_save_as_preset(self
):
765 btn
= self
.xml
.get_object('save_as_preset_button')
766 if self
.message_buffer
.get_char_count() == 0:
767 btn
.set_sensitive(False)
769 btn
.set_sensitive(True)
771 def on_save_as_preset_button_clicked(self
, widget
):
772 self
.countdown_enabled
= False
773 start_iter
, finish_iter
= self
.message_buffer
.get_bounds()
774 status_message_to_save_as_preset
= self
.message_buffer
.get_text(
775 start_iter
, finish_iter
)
777 msg_text
= status_message_to_save_as_preset
.decode('utf-8')
778 msg_text_1l
= helpers
.to_one_line(msg_text
)
779 if not msg_name
: # msg_name was ''
780 msg_name
= msg_text_1l
.decode('utf-8')
783 self
.preset_messages_dict
[msg_name
] = [
784 msg_text
, self
.pep_dict
.get('activity'),
785 self
.pep_dict
.get('subactivity'),
786 self
.pep_dict
.get('activity_text'),
787 self
.pep_dict
.get('mood'), self
.pep_dict
.get('mood_text')]
788 gajim
.config
.set_per('statusmsg', msg_name
, 'message',
790 gajim
.config
.set_per('statusmsg', msg_name
, 'activity',
791 self
.pep_dict
.get('activity'))
792 gajim
.config
.set_per('statusmsg', msg_name
, 'subactivity',
793 self
.pep_dict
.get('subactivity'))
794 gajim
.config
.set_per('statusmsg', msg_name
, 'activity_text',
795 self
.pep_dict
.get('activity_text'))
796 gajim
.config
.set_per('statusmsg', msg_name
, 'mood',
797 self
.pep_dict
.get('mood'))
798 gajim
.config
.set_per('statusmsg', msg_name
, 'mood_text',
799 self
.pep_dict
.get('mood_text'))
800 if msg_name
in self
.preset_messages_dict
:
801 ConfirmationDialog(_('Overwrite Status Message?'),
802 _('This name is already used. Do you want to overwrite this '
803 'status message?'), on_response_ok
=on_ok2
)
805 gajim
.config
.add_per('statusmsg', msg_name
)
807 iter_
= self
.message_liststore
.append((msg_name
,))
808 # select in combobox the one we just saved
809 self
.message_combobox
.set_active_iter(iter_
)
810 InputDialog(_('Save as Preset Status Message'),
811 _('Please type a name for this status message'), is_modal
=False,
814 def on_activity_button_clicked(self
, widget
):
815 self
.countdown_enabled
= False
816 def on_response(activity
, subactivity
, text
):
817 self
.pep_dict
['activity'] = activity
or ''
818 self
.pep_dict
['subactivity'] = subactivity
or ''
819 self
.pep_dict
['activity_text'] = text
821 ChangeActivityDialog(on_response
, self
.pep_dict
['activity'],
822 self
.pep_dict
['subactivity'], self
.pep_dict
['activity_text'])
824 def on_mood_button_clicked(self
, widget
):
825 self
.countdown_enabled
= False
826 def on_response(mood
, text
):
827 self
.pep_dict
['mood'] = mood
or ''
828 self
.pep_dict
['mood_text'] = text
830 ChangeMoodDialog(on_response
, self
.pep_dict
['mood'],
831 self
.pep_dict
['mood_text'])
833 class AddNewContactWindow
:
835 Class for AddNewContactWindow
838 uid_labels
= {'jabber': _('Jabber ID:'),
839 'aim': _('AIM Address:'),
840 'gadu-gadu': _('GG Number:'),
841 'icq': _('ICQ Number:'),
842 'msn': _('MSN Address:'),
843 'yahoo': _('Yahoo! Address:')}
845 def __init__(self
, account
=None, jid
=None, user_nick
=None, group
=None):
846 self
.account
= account
847 self
.adding_jid
= False
849 # fill accounts with active accounts
851 for account
in gajim
.connections
.keys():
852 if gajim
.connections
[account
].connected
> 1:
853 accounts
.append(account
)
856 if len(accounts
) == 1:
857 self
.account
= account
859 accounts
= [self
.account
]
861 location
= gajim
.interface
.instances
[self
.account
]
863 location
= gajim
.interface
.instances
864 if 'add_contact' in location
:
865 location
['add_contact'].window
.present()
866 # An instance is already opened
868 location
['add_contact'] = self
869 self
.xml
= gtkgui_helpers
.get_gtk_builder('add_new_contact_window.ui')
870 self
.xml
.connect_signals(self
)
871 self
.window
= self
.xml
.get_object('add_new_contact_window')
872 for w
in ('account_combobox', 'account_hbox', 'account_label',
873 'uid_label', 'uid_entry', 'protocol_combobox', 'protocol_jid_combobox',
874 'protocol_hbox', 'nickname_entry', 'message_scrolledwindow',
875 'save_message_checkbutton', 'register_hbox', 'subscription_table',
876 'add_button', 'message_textview', 'connected_label',
877 'group_comboboxentry', 'auto_authorize_checkbutton'):
878 self
.__dict
__[w
] = self
.xml
.get_object(w
)
879 if account
and len(gajim
.connections
) >= 2:
880 self
.default_desc
= _('Please fill in the data of the contact you '
881 'want to add in account %s') % account
883 self
.default_desc
= _('Please fill in the data of the contact you '
885 self
.xml
.get_object('prompt_label').set_text(self
.default_desc
)
886 self
.agents
= {'jabber': []}
887 self
.gateway_prompt
= {}
888 # types to which we are not subscribed but account has an agent for it
889 self
.available_types
= []
890 for acct
in accounts
:
891 for j
in gajim
.contacts
.get_jid_list(acct
):
892 if gajim
.jid_is_transport(j
):
893 type_
= gajim
.get_transport_name_from_jid(j
, False)
896 if type_
in self
.agents
:
897 self
.agents
[type_
].append(j
)
899 self
.agents
[type_
] = [j
]
900 self
.gateway_prompt
[j
] = {'desc': None, 'prompt': None}
901 # Now add the one to which we can register
902 for acct
in accounts
:
903 for type_
in gajim
.connections
[acct
].available_transports
:
904 if type_
in self
.agents
:
906 self
.agents
[type_
] = []
907 for jid_
in gajim
.connections
[acct
].available_transports
[type_
]:
908 if not jid_
in self
.agents
[type_
]:
909 self
.agents
[type_
].append(jid_
)
910 self
.gateway_prompt
[jid_
] = {'desc': None,
912 self
.available_types
.append(type_
)
913 # Combobox with transport/jabber icons
914 liststore
= gtk
.ListStore(str, gtk
.gdk
.Pixbuf
, str)
915 cell
= gtk
.CellRendererPixbuf()
916 self
.protocol_combobox
.pack_start(cell
, False)
917 self
.protocol_combobox
.add_attribute(cell
, 'pixbuf', 1)
918 cell
= gtk
.CellRendererText()
919 cell
.set_property('xpad', 5)
920 self
.protocol_combobox
.pack_start(cell
, True)
921 self
.protocol_combobox
.add_attribute(cell
, 'text', 0)
922 self
.protocol_combobox
.set_model(liststore
)
923 uf_type
= {'jabber': 'Jabber', 'aim': 'AIM', 'gadu-gadu': 'Gadu Gadu',
924 'icq': 'ICQ', 'msn': 'MSN', 'yahoo': 'Yahoo'}
926 img
= gajim
.interface
.jabber_state_images
['16']['online']
927 liststore
.append(['Jabber', img
.get_pixbuf(), 'jabber'])
928 for type_
in self
.agents
:
929 if type_
== 'jabber':
931 imgs
= gajim
.interface
.roster
.transports_state_images
933 if type_
in imgs
['16'] and 'online' in imgs
['16'][type_
]:
934 img
= imgs
['16'][type_
]['online']
936 liststore
.append([uf_type
[type_
], img
.get_pixbuf(), type_
])
938 liststore
.append([type_
, img
.get_pixbuf(), type_
])
940 liststore
.append([type_
, img
, type_
])
942 for service
in self
.agents
[type_
]:
943 gajim
.connections
[account
].request_gateway_prompt(service
)
944 self
.protocol_combobox
.set_active(0)
945 self
.auto_authorize_checkbutton
.show()
946 liststore
= gtk
.ListStore(str)
947 self
.protocol_jid_combobox
.set_model(liststore
)
949 type_
= gajim
.get_transport_name_from_jid(jid
)
952 if type_
== 'jabber':
953 self
.uid_entry
.set_text(jid
)
955 uid
, transport
= gajim
.get_name_and_server_from_jid(jid
)
956 self
.uid_entry
.set_text(uid
.replace('%', '@', 1))
957 # set protocol_combobox
958 model
= self
.protocol_combobox
.get_model()
959 iter_
= model
.get_iter_first()
962 if model
[iter_
][2] == type_
:
963 self
.protocol_combobox
.set_active(i
)
965 iter_
= model
.iter_next(iter_
)
968 # set protocol_jid_combobox
969 self
.protocol_jid_combobox
.set_active(0)
970 model
= self
.protocol_jid_combobox
.get_model()
971 iter_
= model
.get_iter_first()
974 if model
[iter_
][0] == transport
:
975 self
.protocol_jid_combobox
.set_active(i
)
977 iter_
= model
.iter_next(iter_
)
980 self
.nickname_entry
.set_text(user_nick
)
981 self
.nickname_entry
.grab_focus()
983 self
.uid_entry
.grab_focus()
985 for acct
in accounts
:
986 for g
in gajim
.groups
[acct
].keys():
987 if g
not in helpers
.special_groups
and g
not in group_names
:
988 group_names
.append(g
)
991 for g
in group_names
:
992 self
.group_comboboxentry
.append_text(g
)
994 self
.group_comboboxentry
.set_active(i
)
997 self
.window
.set_transient_for(gajim
.interface
.roster
.window
)
998 self
.window
.show_all()
1001 self
.account_label
.hide()
1002 self
.account_hbox
.hide()
1004 liststore
= gtk
.ListStore(str, str)
1005 for acct
in accounts
:
1006 liststore
.append([acct
, acct
])
1007 self
.account_combobox
.set_model(liststore
)
1008 self
.account_combobox
.set_active(0)
1011 message_buffer
= self
.message_textview
.get_buffer()
1012 message_buffer
.set_text(helpers
.get_subscription_request_msg(
1015 gajim
.ged
.register_event_handler('gateway-prompt-received', ged
.GUI1
,
1016 self
._nec
_gateway
_prompt
_received
)
1017 gajim
.ged
.register_event_handler('presence-received', ged
.GUI1
,
1018 self
._nec
_presence
_received
)
1020 def on_add_new_contact_window_destroy(self
, widget
):
1022 location
= gajim
.interface
.instances
[self
.account
]
1024 location
= gajim
.interface
.instances
1025 del location
['add_contact']
1026 gajim
.ged
.remove_event_handler('presence-received', ged
.GUI1
,
1027 self
._nec
_presence
_received
)
1028 gajim
.ged
.remove_event_handler('gateway-prompt-received', ged
.GUI1
,
1029 self
._nec
_gateway
_prompt
_received
)
1031 def on_register_button_clicked(self
, widget
):
1032 jid
= self
.protocol_jid_combobox
.get_active_text().decode('utf-8')
1033 gajim
.connections
[self
.account
].request_register_agent_info(jid
)
1035 def on_add_new_contact_window_key_press_event(self
, widget
, event
):
1036 if event
.keyval
== gtk
.keysyms
.Escape
: # ESCAPE
1037 self
.window
.destroy()
1039 def on_cancel_button_clicked(self
, widget
):
1041 When Cancel button is clicked
1043 self
.window
.destroy()
1045 def on_add_button_clicked(self
, widget
):
1047 When Subscribe button is clicked
1049 jid
= self
.uid_entry
.get_text().decode('utf-8').strip()
1053 model
= self
.protocol_combobox
.get_model()
1054 iter_
= self
.protocol_combobox
.get_active_iter()
1055 type_
= model
[iter_
][2]
1056 if type_
!= 'jabber':
1057 transport
= self
.protocol_jid_combobox
.get_active_text().decode(
1060 self
.adding_jid
= (jid
, transport
, type_
)
1061 gajim
.connections
[self
.account
].request_gateway_prompt(
1064 jid
= jid
.replace('@', '%') + '@' + transport
1065 self
._add
_jid
(jid
, type_
)
1067 self
._add
_jid
(jid
, type_
)
1069 def _add_jid(self
, jid
, type_
):
1070 # check if jid is conform to RFC and stringprep it
1072 jid
= helpers
.parse_jid(jid
)
1073 except helpers
.InvalidFormat
, s
:
1074 pritext
= _('Invalid User ID')
1075 ErrorDialog(pritext
, str(s
))
1078 # No resource in jid
1079 if jid
.find('/') >= 0:
1080 pritext
= _('Invalid User ID')
1081 ErrorDialog(pritext
, _('The user ID must not contain a resource.'))
1084 if jid
== gajim
.get_jid_from_account(self
.account
):
1085 pritext
= _('Invalid User ID')
1086 ErrorDialog(pritext
, _('You cannot add yourself to your roster.'))
1089 nickname
= self
.nickname_entry
.get_text().decode('utf-8') or ''
1090 # get value of account combobox, if account was not specified
1091 if not self
.account
:
1092 model
= self
.account_combobox
.get_model()
1093 index
= self
.account_combobox
.get_active()
1094 self
.account
= model
[index
][1]
1096 # Check if jid is already in roster
1097 if jid
in gajim
.contacts
.get_jid_list(self
.account
):
1098 c
= gajim
.contacts
.get_first_contact_from_jid(self
.account
, jid
)
1099 if _('Not in Roster') not in c
.groups
and c
.sub
in ('both', 'to'):
1100 ErrorDialog(_('Contact already in roster'),
1101 _('This contact is already listed in your roster.'))
1104 if type_
== 'jabber':
1105 message_buffer
= self
.message_textview
.get_buffer()
1106 start_iter
= message_buffer
.get_start_iter()
1107 end_iter
= message_buffer
.get_end_iter()
1108 message
= message_buffer
.get_text(start_iter
, end_iter
).decode('utf-8')
1109 if self
.save_message_checkbutton
.get_active():
1110 gajim
.config
.set_per('accounts', self
.account
,
1111 'subscription_request_msg', message
)
1114 group
= self
.group_comboboxentry
.child
.get_text().decode('utf-8')
1118 auto_auth
= self
.auto_authorize_checkbutton
.get_active()
1119 gajim
.interface
.roster
.req_sub(self
, jid
, message
, self
.account
,
1120 groups
=groups
, nickname
=nickname
, auto_auth
=auto_auth
)
1121 self
.window
.destroy()
1123 def on_account_combobox_changed(self
, widget
):
1124 model
= widget
.get_model()
1125 iter_
= widget
.get_active_iter()
1126 account
= model
[iter_
][0]
1127 message_buffer
= self
.message_textview
.get_buffer()
1128 message_buffer
.set_text(helpers
.get_subscription_request_msg(account
))
1130 def on_protocol_jid_combobox_changed(self
, widget
):
1131 model
= widget
.get_model()
1132 iter_
= widget
.get_active_iter()
1135 jid_
= model
[iter_
][0]
1136 model
= self
.protocol_combobox
.get_model()
1137 iter_
= self
.protocol_combobox
.get_active_iter()
1138 type_
= model
[iter_
][2]
1140 if self
.agents
[type_
] and jid_
in self
.gateway_prompt
:
1141 desc
= self
.gateway_prompt
[jid_
]['desc']
1143 desc
= self
.default_desc
1144 self
.xml
.get_object('prompt_label').set_text(desc
)
1147 if self
.agents
[type_
] and jid_
in self
.gateway_prompt
:
1148 prompt
= self
.gateway_prompt
[jid_
]['prompt']
1150 if type_
in self
.uid_labels
:
1151 prompt
= self
.uid_labels
[type_
]
1153 prompt
= _('User ID:')
1154 self
.uid_label
.set_text(prompt
)
1156 def on_protocol_combobox_changed(self
, widget
):
1157 model
= widget
.get_model()
1158 iter_
= widget
.get_active_iter()
1159 type_
= model
[iter_
][2]
1160 model
= self
.protocol_jid_combobox
.get_model()
1162 if len(self
.agents
[type_
]):
1163 for jid_
in self
.agents
[type_
]:
1164 model
.append([jid_
])
1165 self
.protocol_jid_combobox
.set_active(0)
1167 if self
.agents
[type_
]:
1168 jid_
= self
.agents
[type_
][0]
1169 if jid_
in self
.gateway_prompt
:
1170 desc
= self
.gateway_prompt
[jid_
]['desc']
1172 desc
= self
.default_desc
1173 self
.xml
.get_object('prompt_label').set_text(desc
)
1174 if len(self
.agents
[type_
]) > 1:
1175 self
.protocol_jid_combobox
.show()
1177 self
.protocol_jid_combobox
.hide()
1179 if self
.agents
[type_
]:
1180 jid_
= self
.agents
[type_
][0]
1181 if jid_
in self
.gateway_prompt
:
1182 prompt
= self
.gateway_prompt
[jid_
]['prompt']
1184 if type_
in self
.uid_labels
:
1185 prompt
= self
.uid_labels
[type_
]
1187 prompt
= _('User ID:')
1188 self
.uid_label
.set_text(prompt
)
1190 if type_
== 'jabber':
1191 self
.message_scrolledwindow
.show()
1192 self
.save_message_checkbutton
.show()
1194 self
.message_scrolledwindow
.hide()
1195 self
.save_message_checkbutton
.hide()
1196 if type_
in self
.available_types
:
1197 self
.register_hbox
.show()
1198 self
.auto_authorize_checkbutton
.hide()
1199 self
.connected_label
.hide()
1200 self
.subscription_table
.hide()
1201 self
.add_button
.set_sensitive(False)
1203 self
.register_hbox
.hide()
1204 if type_
!= 'jabber':
1205 jid
= self
.protocol_jid_combobox
.get_active_text()
1206 contact
= gajim
.contacts
.get_first_contact_from_jid(
1208 if contact
.show
in ('offline', 'error'):
1209 self
.subscription_table
.hide()
1210 self
.connected_label
.show()
1211 self
.add_button
.set_sensitive(False)
1212 self
.auto_authorize_checkbutton
.hide()
1214 self
.subscription_table
.show()
1215 self
.auto_authorize_checkbutton
.show()
1216 self
.connected_label
.hide()
1217 self
.add_button
.set_sensitive(True)
1219 def transport_signed_in(self
, jid
):
1220 if self
.protocol_jid_combobox
.get_active_text() == jid
:
1221 self
.register_hbox
.hide()
1222 self
.connected_label
.hide()
1223 self
.subscription_table
.show()
1224 self
.auto_authorize_checkbutton
.show()
1225 self
.add_button
.set_sensitive(True)
1227 def transport_signed_out(self
, jid
):
1228 if self
.protocol_jid_combobox
.get_active_text() == jid
:
1229 self
.subscription_table
.hide()
1230 self
.auto_authorize_checkbutton
.hide()
1231 self
.connected_label
.show()
1232 self
.add_button
.set_sensitive(False)
1234 def _nec_presence_received(self
, obj
):
1235 if gajim
.jid_is_transport(obj
.jid
):
1236 if obj
.old_show
== 0 and obj
.new_show
> 1:
1237 self
.transport_signed_in(obj
.jid
)
1238 elif obj
.old_show
> 1 and obj
.new_show
== 0:
1239 self
.transport_signed_out(obj
.jid
)
1241 def _nec_gateway_prompt_received(self
, obj
):
1243 jid
, transport
, type_
= self
.adding_jid
1245 self
._add
_jid
(obj
.prompt_jid
, type_
)
1247 jid
= jid
.replace('@', '%') + '@' + transport
1248 self
._add
_jid
(jid
, type_
)
1249 elif obj
.jid
in self
.gateway_prompt
:
1251 self
.gateway_prompt
[obj
.jid
]['desc'] = obj
.desc
1253 self
.gateway_prompt
[obj
.jid
]['prompt'] = obj
.prompt
1257 Class for about dialog
1261 dlg
= gtk
.AboutDialog()
1262 dlg
.set_transient_for(gajim
.interface
.roster
.window
)
1263 dlg
.set_name('Gajim')
1264 dlg
.set_version(gajim
.version
)
1265 s
= u
'Copyright © 2003-2010 Gajim Team'
1266 dlg
.set_copyright(s
)
1267 copying_file_path
= self
.get_path('COPYING')
1268 if copying_file_path
:
1269 text
= open(copying_file_path
).read()
1270 dlg
.set_license(text
)
1272 dlg
.set_comments('%s\n%s %s\n%s %s' % (_('A GTK+ jabber client'),
1273 _('GTK+ Version:'), self
.tuple2str(gtk
.gtk_version
), \
1274 _('PyGTK Version:'), self
.tuple2str(gtk
.pygtk_version
)))
1275 dlg
.set_website('http://www.gajim.org/')
1277 authors_file_path
= self
.get_path('AUTHORS')
1278 if authors_file_path
:
1280 authors_file
= open(authors_file_path
).read()
1281 authors_file
= authors_file
.split('\n')
1282 for author
in authors_file
:
1283 if author
== 'CURRENT DEVELOPERS:':
1284 authors
.append(_('Current Developers:'))
1285 elif author
== 'PAST DEVELOPERS:':
1286 authors
.append('\n' + _('Past Developers:'))
1287 elif author
!= '': # Real author line
1288 authors
.append(author
)
1290 thanks_file_path
= self
.get_path('THANKS')
1291 if thanks_file_path
:
1292 authors
.append('\n' + _('THANKS:'))
1294 text
= open(thanks_file_path
).read()
1295 text_splitted
= text
.split('\n')
1296 text
= '\n'.join(text_splitted
[:-2]) # remove one english sentence
1297 # and add it manually as translatable
1298 text
+= '\n%s\n' % _('Last but not least, we would like to thank all '
1299 'the package maintainers.')
1300 authors
.append(text
)
1302 dlg
.set_authors(authors
)
1304 dlg
.props
.wrap_license
= True
1306 pixbuf
= gtkgui_helpers
.get_icon_pixmap('gajim-about', 128)
1308 dlg
.set_logo(pixbuf
)
1309 #here you write your name in the form Name FamilyName <someone@somewhere>
1310 dlg
.set_translator_credits(_('translator-credits'))
1312 thanks_artists_file_path
= self
.get_path('THANKS.artists')
1313 if thanks_artists_file_path
:
1314 artists_text
= open(thanks_artists_file_path
).read()
1315 artists
= artists_text
.split('\n')
1316 dlg
.set_artists(artists
)
1317 # connect close button to destroy() function
1318 for button
in dlg
.action_area
.get_children():
1319 if button
.get_property('label') == gtk
.STOCK_CLOSE
:
1320 button
.connect('clicked', lambda x
:dlg
.destroy())
1323 def tuple2str(self
, tuple_
):
1326 str_
+= str(num
) + '.'
1327 return str_
[0:-1] # remove latest .
1329 def get_path(self
, filename
):
1331 Where can we find this Credits file?
1333 if os
.path
.isfile(os
.path
.join(gajim
.defs
.docdir
, filename
)):
1334 return os
.path
.join(gajim
.defs
.docdir
, filename
)
1335 elif os
.path
.isfile('../' + filename
):
1336 return ('../' + filename
)
1340 class Dialog(gtk
.Dialog
):
1341 def __init__(self
, parent
, title
, buttons
, default
=None,
1342 on_response_ok
=None, on_response_cancel
=None):
1343 gtk
.Dialog
.__init
__(self
, title
, parent
,
1344 gtk
.DIALOG_DESTROY_WITH_PARENT | gtk
.DIALOG_NO_SEPARATOR
)
1346 self
.user_response_ok
= on_response_ok
1347 self
.user_response_cancel
= on_response_cancel
1348 self
.set_border_width(6)
1349 self
.vbox
.set_spacing(12)
1350 self
.set_resizable(False)
1352 possible_responses
= {gtk
.STOCK_OK
: self
.on_response_ok
,
1353 gtk
.STOCK_CANCEL
: self
.on_response_cancel
}
1354 for stock
, response
in buttons
:
1355 b
= self
.add_button(stock
, response
)
1356 for response
in possible_responses
:
1357 if stock
== response
:
1358 b
.connect('clicked', possible_responses
[response
])
1361 if default
is not None:
1362 self
.set_default_response(default
)
1364 self
.set_default_response(buttons
[-1][1])
1366 def on_response_ok(self
, widget
):
1367 if self
.user_response_ok
:
1368 if isinstance(self
.user_response_ok
, tuple):
1369 self
.user_response_ok
[0](*self
.user_response_ok
[1:])
1371 self
.user_response_ok()
1374 def on_response_cancel(self
, widget
):
1375 if self
.user_response_cancel
:
1376 if isinstance(self
.user_response_cancel
, tuple):
1377 self
.user_response_cancel
[0](*self
.user_response_ok
[1:])
1379 self
.user_response_cancel()
1382 def just_destroy(self
, widget
):
1385 def get_button(self
, index
):
1386 buttons
= self
.action_area
.get_children()
1387 return index
< len(buttons
) and buttons
[index
] or None
1390 class HigDialog(gtk
.MessageDialog
):
1391 def __init__(self
, parent
, type_
, buttons
, pritext
, sectext
,
1392 on_response_ok
=None, on_response_cancel
=None, on_response_yes
=None,
1393 on_response_no
=None):
1394 self
.call_cancel_on_destroy
= True
1395 gtk
.MessageDialog
.__init
__(self
, parent
,
1396 gtk
.DIALOG_DESTROY_WITH_PARENT | gtk
.DIALOG_MODAL
,
1397 type_
, buttons
, message_format
= pritext
)
1399 self
.format_secondary_markup(sectext
)
1401 buttons
= self
.action_area
.get_children()
1402 self
.possible_responses
= {gtk
.STOCK_OK
: on_response_ok
,
1403 gtk
.STOCK_CANCEL
: on_response_cancel
, gtk
.STOCK_YES
: on_response_yes
,
1404 gtk
.STOCK_NO
: on_response_no
}
1406 for response
in self
.possible_responses
:
1407 if b
.get_label() == response
:
1408 if not self
.possible_responses
[response
]:
1409 b
.connect('clicked', self
.just_destroy
)
1410 elif isinstance(self
.possible_responses
[response
], tuple):
1411 if len(self
.possible_responses
[response
]) == 1:
1412 b
.connect('clicked', self
.possible_responses
[response
][0])
1414 b
.connect('clicked', *self
.possible_responses
[response
])
1416 b
.connect('clicked', self
.possible_responses
[response
])
1419 self
.connect('destroy', self
.on_dialog_destroy
)
1421 def on_dialog_destroy(self
, widget
):
1422 if not self
.call_cancel_on_destroy
:
1424 cancel_handler
= self
.possible_responses
[gtk
.STOCK_CANCEL
]
1425 if not cancel_handler
:
1427 if isinstance(cancel_handler
, tuple):
1428 cancel_handler
[0](None, *cancel_handler
[1:])
1430 cancel_handler(None)
1432 def just_destroy(self
, widget
):
1439 vb
= self
.get_children()[0].get_children()[0] # Give focus to top vbox
1440 vb
.set_flags(gtk
.CAN_FOCUS
)
1444 class FileChooserDialog(gtk
.FileChooserDialog
):
1446 Non-blocking FileChooser Dialog around gtk.FileChooserDialog
1448 def __init__(self
, title_text
, action
, buttons
, default_response
,
1449 select_multiple
=False, current_folder
=None, on_response_ok
=None,
1450 on_response_cancel
=None):
1452 gtk
.FileChooserDialog
.__init
__(self
, title
=title_text
, action
=action
,
1455 self
.set_default_response(default_response
)
1456 self
.set_select_multiple(select_multiple
)
1457 if current_folder
and os
.path
.isdir(current_folder
):
1458 self
.set_current_folder(current_folder
)
1460 self
.set_current_folder(helpers
.get_documents_path())
1461 self
.response_ok
, self
.response_cancel
= \
1462 on_response_ok
, on_response_cancel
1463 # in gtk+-2.10 clicked signal on some of the buttons in a dialog
1464 # is emitted twice, so we cannot rely on 'clicked' signal
1465 self
.connect('response', self
.on_dialog_response
)
1468 def on_dialog_response(self
, dialog
, response
):
1469 if response
in (gtk
.RESPONSE_CANCEL
, gtk
.RESPONSE_CLOSE
):
1470 if self
.response_cancel
:
1471 if isinstance(self
.response_cancel
, tuple):
1472 self
.response_cancel
[0](dialog
, *self
.response_cancel
[1:])
1474 self
.response_cancel(dialog
)
1476 self
.just_destroy(dialog
)
1477 elif response
== gtk
.RESPONSE_OK
:
1478 if self
.response_ok
:
1479 if isinstance(self
.response_ok
, tuple):
1480 self
.response_ok
[0](dialog
, *self
.response_ok
[1:])
1482 self
.response_ok(dialog
)
1484 self
.just_destroy(dialog
)
1486 def just_destroy(self
, widget
):
1489 class AspellDictError
:
1490 def __init__(self
, lang
):
1492 _('Dictionary for lang %s not available') % lang
,
1493 _('You have to install %s dictionary to use spellchecking, or '
1494 'choose another language by setting the speller_language option.'
1495 '\n\nHighlighting misspelled words feature will not be used') % lang
)
1496 gajim
.config
.set('use_speller', False)
1498 class ConfirmationDialog(HigDialog
):
1500 HIG compliant confirmation dialog
1503 def __init__(self
, pritext
, sectext
='', on_response_ok
=None,
1504 on_response_cancel
=None):
1505 self
.user_response_ok
= on_response_ok
1506 self
.user_response_cancel
= on_response_cancel
1507 HigDialog
.__init
__(self
, None,
1508 gtk
.MESSAGE_QUESTION
, gtk
.BUTTONS_OK_CANCEL
, pritext
, sectext
,
1509 self
.on_response_ok
, self
.on_response_cancel
)
1512 def on_response_ok(self
, widget
):
1513 if self
.user_response_ok
:
1514 if isinstance(self
.user_response_ok
, tuple):
1515 self
.user_response_ok
[0](*self
.user_response_ok
[1:])
1517 self
.user_response_ok()
1518 self
.call_cancel_on_destroy
= False
1521 def on_response_cancel(self
, widget
):
1522 if self
.user_response_cancel
:
1523 if isinstance(self
.user_response_cancel
, tuple):
1524 self
.user_response_cancel
[0](*self
.user_response_ok
[1:])
1526 self
.user_response_cancel()
1527 self
.call_cancel_on_destroy
= False
1530 class NonModalConfirmationDialog(HigDialog
):
1532 HIG compliant non modal confirmation dialog
1535 def __init__(self
, pritext
, sectext
='', on_response_ok
=None,
1536 on_response_cancel
=None):
1537 self
.user_response_ok
= on_response_ok
1538 self
.user_response_cancel
= on_response_cancel
1539 HigDialog
.__init
__(self
, None,
1540 gtk
.MESSAGE_QUESTION
, gtk
.BUTTONS_OK_CANCEL
, pritext
, sectext
,
1541 self
.on_response_ok
, self
.on_response_cancel
)
1542 self
.set_modal(False)
1544 def on_response_ok(self
, widget
):
1545 if self
.user_response_ok
:
1546 if isinstance(self
.user_response_ok
, tuple):
1547 self
.user_response_ok
[0](*self
.user_response_ok
[1:])
1549 self
.user_response_ok()
1550 self
.call_cancel_on_destroy
= False
1553 def on_response_cancel(self
, widget
):
1554 if self
.user_response_cancel
:
1555 if isinstance(self
.user_response_cancel
, tuple):
1556 self
.user_response_cancel
[0](*self
.user_response_cancel
[1:])
1558 self
.user_response_cancel()
1559 self
.call_cancel_on_destroy
= False
1562 class WarningDialog(HigDialog
):
1564 HIG compliant warning dialog
1567 def __init__(self
, pritext
, sectext
='', transient_for
=None):
1568 HigDialog
.__init
__(self
, None, gtk
.MESSAGE_WARNING
, gtk
.BUTTONS_OK
,
1570 self
.set_modal(False)
1571 if transient_for
is None and hasattr(gajim
.interface
, 'roster') and \
1572 gajim
.interface
.roster
:
1573 transient_for
= gajim
.interface
.roster
.window
1575 self
.set_transient_for(transient_for
)
1578 class InformationDialog(HigDialog
):
1580 HIG compliant info dialog
1583 def __init__(self
, pritext
, sectext
=''):
1584 HigDialog
.__init
__(self
, None, gtk
.MESSAGE_INFO
, gtk
.BUTTONS_OK
,
1586 self
.set_modal(False)
1587 self
.set_transient_for(gajim
.interface
.roster
.window
)
1590 class ErrorDialog(HigDialog
):
1592 HIG compliant error dialog
1595 def __init__(self
, pritext
, sectext
='', on_response_ok
=None,
1596 on_response_cancel
=None):
1597 HigDialog
.__init
__( self
, None, gtk
.MESSAGE_ERROR
, gtk
.BUTTONS_OK
,
1598 pritext
, sectext
, on_response_ok
=on_response_ok
,
1599 on_response_cancel
=on_response_cancel
)
1602 class YesNoDialog(HigDialog
):
1604 HIG compliant YesNo dialog
1607 def __init__(self
, pritext
, sectext
='', checktext
='', on_response_yes
=None,
1608 on_response_no
=None):
1609 self
.user_response_yes
= on_response_yes
1610 self
.user_response_no
= on_response_no
1611 HigDialog
.__init
__(self
, None, gtk
.MESSAGE_QUESTION
, gtk
.BUTTONS_YES_NO
,
1612 pritext
, sectext
, on_response_yes
=self
.on_response_yes
,
1613 on_response_no
=self
.on_response_no
)
1616 self
.checkbutton
= gtk
.CheckButton(checktext
)
1617 self
.vbox
.pack_start(self
.checkbutton
, expand
=False, fill
=True)
1619 self
.checkbutton
= None
1620 self
.set_modal(False)
1623 def on_response_yes(self
, widget
):
1624 if self
.user_response_yes
:
1625 if isinstance(self
.user_response_yes
, tuple):
1626 self
.user_response_yes
[0](self
.is_checked(),
1627 *self
.user_response_yes
[1:])
1629 self
.user_response_yes(self
.is_checked())
1630 self
.call_cancel_on_destroy
= False
1633 def on_response_no(self
, widget
):
1634 if self
.user_response_no
:
1635 if isinstance(self
.user_response_no
, tuple):
1636 self
.user_response_no
[0](*self
.user_response_no
[1:])
1638 self
.user_response_no()
1639 self
.call_cancel_on_destroy
= False
1642 def is_checked(self
):
1644 Get active state of the checkbutton
1646 if not self
.checkbutton
:
1648 return self
.checkbutton
.get_active()
1650 class ConfirmationDialogCheck(ConfirmationDialog
):
1652 HIG compliant confirmation dialog with checkbutton
1655 def __init__(self
, pritext
, sectext
='', checktext
='', on_response_ok
=None,
1656 on_response_cancel
=None, is_modal
=True):
1657 self
.user_response_ok
= on_response_ok
1658 self
.user_response_cancel
= on_response_cancel
1660 HigDialog
.__init
__(self
, None, gtk
.MESSAGE_QUESTION
,
1661 gtk
.BUTTONS_OK_CANCEL
, pritext
, sectext
, self
.on_response_ok
,
1662 self
.on_response_cancel
)
1664 self
.set_default_response(gtk
.RESPONSE_OK
)
1666 ok_button
= self
.action_area
.get_children()[0] # right to left
1667 ok_button
.grab_focus()
1669 self
.checkbutton
= gtk
.CheckButton(checktext
)
1670 self
.vbox
.pack_start(self
.checkbutton
, expand
=False, fill
=True)
1671 self
.set_modal(is_modal
)
1674 def on_response_ok(self
, widget
):
1675 if self
.user_response_ok
:
1676 if isinstance(self
.user_response_ok
, tuple):
1677 self
.user_response_ok
[0](self
.is_checked(),
1678 *self
.user_response_ok
[1:])
1680 self
.user_response_ok(self
.is_checked())
1681 self
.call_cancel_on_destroy
= False
1684 def on_response_cancel(self
, widget
):
1685 if self
.user_response_cancel
:
1686 if isinstance(self
.user_response_cancel
, tuple):
1687 self
.user_response_cancel
[0](self
.is_checked(),
1688 *self
.user_response_cancel
[1:])
1690 self
.user_response_cancel(self
.is_checked())
1691 self
.call_cancel_on_destroy
= False
1694 def is_checked(self
):
1696 Get active state of the checkbutton
1698 return self
.checkbutton
.get_active()
1700 class ConfirmationDialogDoubleCheck(ConfirmationDialog
):
1702 HIG compliant confirmation dialog with 2 checkbuttons
1705 def __init__(self
, pritext
, sectext
='', checktext1
='', checktext2
='',
1706 on_response_ok
=None, on_response_cancel
=None, is_modal
=True):
1707 self
.user_response_ok
= on_response_ok
1708 self
.user_response_cancel
= on_response_cancel
1710 HigDialog
.__init
__(self
, None, gtk
.MESSAGE_QUESTION
,
1711 gtk
.BUTTONS_OK_CANCEL
, pritext
, sectext
, self
.on_response_ok
,
1712 self
.on_response_cancel
)
1714 self
.set_default_response(gtk
.RESPONSE_OK
)
1716 ok_button
= self
.action_area
.get_children()[0] # right to left
1717 ok_button
.grab_focus()
1720 self
.checkbutton1
= gtk
.CheckButton(checktext1
)
1721 self
.vbox
.pack_start(self
.checkbutton1
, expand
=False, fill
=True)
1723 self
.checkbutton1
= None
1725 self
.checkbutton2
= gtk
.CheckButton(checktext2
)
1726 self
.vbox
.pack_start(self
.checkbutton2
, expand
=False, fill
=True)
1728 self
.checkbutton2
= None
1730 self
.set_modal(is_modal
)
1733 def on_response_ok(self
, widget
):
1734 if self
.user_response_ok
:
1735 if isinstance(self
.user_response_ok
, tuple):
1736 self
.user_response_ok
[0](self
.is_checked(),
1737 *self
.user_response_ok
[1:])
1739 self
.user_response_ok(self
.is_checked())
1740 self
.call_cancel_on_destroy
= False
1743 def on_response_cancel(self
, widget
):
1744 if self
.user_response_cancel
:
1745 if isinstance(self
.user_response_cancel
, tuple):
1746 self
.user_response_cancel
[0](*self
.user_response_cancel
[1:])
1748 self
.user_response_cancel()
1749 self
.call_cancel_on_destroy
= False
1752 def is_checked(self
):
1753 ''' Get active state of the checkbutton '''
1754 if self
.checkbutton1
:
1755 is_checked_1
= self
.checkbutton1
.get_active()
1757 is_checked_1
= False
1758 if self
.checkbutton2
:
1759 is_checked_2
= self
.checkbutton2
.get_active()
1761 is_checked_2
= False
1762 return [is_checked_1
, is_checked_2
]
1764 class ConfirmationDialogDoubleRadio(ConfirmationDialog
):
1766 HIG compliant confirmation dialog with 2 radios
1769 def __init__(self
, pritext
, sectext
='', radiotext1
='', radiotext2
='',
1770 on_response_ok
=None, on_response_cancel
=None, is_modal
=True):
1771 self
.user_response_ok
= on_response_ok
1772 self
.user_response_cancel
= on_response_cancel
1774 HigDialog
.__init
__(self
, None, gtk
.MESSAGE_QUESTION
,
1775 gtk
.BUTTONS_OK_CANCEL
, pritext
, sectext
, self
.on_response_ok
,
1776 self
.on_response_cancel
)
1778 self
.set_default_response(gtk
.RESPONSE_OK
)
1780 ok_button
= self
.action_area
.get_children()[0] # right to left
1781 ok_button
.grab_focus()
1783 self
.radiobutton1
= gtk
.RadioButton(label
=radiotext1
)
1784 self
.vbox
.pack_start(self
.radiobutton1
, expand
=False, fill
=True)
1786 self
.radiobutton2
= gtk
.RadioButton(group
=self
.radiobutton1
,
1788 self
.vbox
.pack_start(self
.radiobutton2
, expand
=False, fill
=True)
1790 self
.set_modal(is_modal
)
1793 def on_response_ok(self
, widget
):
1794 if self
.user_response_ok
:
1795 if isinstance(self
.user_response_ok
, tuple):
1796 self
.user_response_ok
[0](self
.is_checked(),
1797 *self
.user_response_ok
[1:])
1799 self
.user_response_ok(self
.is_checked())
1800 self
.call_cancel_on_destroy
= False
1803 def on_response_cancel(self
, widget
):
1804 if self
.user_response_cancel
:
1805 if isinstance(self
.user_response_cancel
, tuple):
1806 self
.user_response_cancel
[0](*self
.user_response_cancel
[1:])
1808 self
.user_response_cancel()
1809 self
.call_cancel_on_destroy
= False
1812 def is_checked(self
):
1813 ''' Get active state of the checkbutton '''
1814 if self
.radiobutton1
:
1815 is_checked_1
= self
.radiobutton1
.get_active()
1817 is_checked_1
= False
1818 if self
.radiobutton2
:
1819 is_checked_2
= self
.radiobutton2
.get_active()
1821 is_checked_2
= False
1822 return [is_checked_1
, is_checked_2
]
1824 class FTOverwriteConfirmationDialog(ConfirmationDialog
):
1826 HIG compliant confirmation dialog to overwrite or resume a file transfert
1829 def __init__(self
, pritext
, sectext
='', propose_resume
=True,
1831 HigDialog
.__init
__(self
, None, gtk
.MESSAGE_QUESTION
, gtk
.BUTTONS_CANCEL
,
1834 self
.on_response
= on_response
1837 b
= gtk
.Button('', gtk
.STOCK_REFRESH
)
1838 align
= b
.get_children()[0]
1839 hbox
= align
.get_children()[0]
1840 label
= hbox
.get_children()[1]
1841 label
.set_text(_('_Resume'))
1842 label
.set_use_underline(True)
1843 self
.add_action_widget(b
, 100)
1845 b
= gtk
.Button('', gtk
.STOCK_SAVE_AS
)
1846 align
= b
.get_children()[0]
1847 hbox
= align
.get_children()[0]
1848 label
= hbox
.get_children()[1]
1849 label
.set_text(_('Re_place'))
1850 label
.set_use_underline(True)
1851 self
.add_action_widget(b
, 200)
1853 self
.connect('response', self
.on_dialog_response
)
1856 def on_dialog_response(self
, dialog
, response
):
1857 if self
.on_response
:
1858 if isinstance(self
.on_response
, tuple):
1859 self
.on_response
[0](response
, *self
.on_response
[1:])
1861 self
.on_response(response
)
1862 self
.call_cancel_on_destroy
= False
1865 class CommonInputDialog
:
1867 Common Class for Input dialogs
1870 def __init__(self
, title
, label_str
, is_modal
, ok_handler
, cancel_handler
):
1871 self
.dialog
= self
.xml
.get_object('input_dialog')
1872 label
= self
.xml
.get_object('label')
1873 self
.dialog
.set_title(title
)
1874 label
.set_markup(label_str
)
1875 self
.cancel_handler
= cancel_handler
1876 self
.vbox
= self
.xml
.get_object('vbox')
1878 self
.ok_handler
= ok_handler
1879 okbutton
= self
.xml
.get_object('okbutton')
1880 okbutton
.connect('clicked', self
.on_okbutton_clicked
)
1881 cancelbutton
= self
.xml
.get_object('cancelbutton')
1882 cancelbutton
.connect('clicked', self
.on_cancelbutton_clicked
)
1883 self
.xml
.connect_signals(self
)
1884 self
.dialog
.show_all()
1886 def on_input_dialog_destroy(self
, widget
):
1887 if self
.cancel_handler
:
1888 self
.cancel_handler()
1890 def on_okbutton_clicked(self
, widget
):
1891 user_input
= self
.get_text()
1893 user_input
= user_input
.decode('utf-8')
1894 self
.cancel_handler
= None
1895 self
.dialog
.destroy()
1896 if isinstance(self
.ok_handler
, tuple):
1897 self
.ok_handler
[0](user_input
, *self
.ok_handler
[1:])
1899 self
.ok_handler(user_input
)
1901 def on_cancelbutton_clicked(self
, widget
):
1902 self
.dialog
.destroy()
1904 class InputDialog(CommonInputDialog
):
1906 Class for Input dialog
1909 def __init__(self
, title
, label_str
, input_str
=None, is_modal
=True,
1910 ok_handler
=None, cancel_handler
=None):
1911 self
.xml
= gtkgui_helpers
.get_gtk_builder('input_dialog.ui')
1912 CommonInputDialog
.__init
__(self
, title
, label_str
, is_modal
, ok_handler
,
1914 self
.input_entry
= self
.xml
.get_object('input_entry')
1916 self
.set_entry(input_str
)
1918 def on_input_dialog_delete_event(self
, widget
, event
):
1920 may be implemented by subclasses
1924 def set_entry(self
, value
):
1925 self
.input_entry
.set_text(value
)
1926 self
.input_entry
.select_region(0, -1) # select all
1929 return self
.input_entry
.get_text().decode('utf-8')
1931 class InputDialogCheck(InputDialog
):
1933 Class for Input dialog
1936 def __init__(self
, title
, label_str
, checktext
='', input_str
=None,
1937 is_modal
=True, ok_handler
=None, cancel_handler
=None):
1938 self
.xml
= gtkgui_helpers
.get_gtk_builder('input_dialog.ui')
1939 InputDialog
.__init
__(self
, title
, label_str
, input_str
=input_str
,
1940 is_modal
=is_modal
, ok_handler
=ok_handler
,
1941 cancel_handler
=cancel_handler
)
1942 self
.input_entry
= self
.xml
.get_object('input_entry')
1944 self
.input_entry
.set_text(input_str
)
1945 self
.input_entry
.select_region(0, -1) # select all
1948 self
.checkbutton
= gtk
.CheckButton(checktext
)
1949 self
.vbox
.pack_start(self
.checkbutton
, expand
=False, fill
=True)
1950 self
.checkbutton
.show()
1952 def on_okbutton_clicked(self
, widget
):
1953 user_input
= self
.get_text()
1955 user_input
= user_input
.decode('utf-8')
1956 self
.cancel_handler
= None
1957 self
.dialog
.destroy()
1958 if isinstance(self
.ok_handler
, tuple):
1959 self
.ok_handler
[0](user_input
, self
.is_checked(), *self
.ok_handler
[1:])
1961 self
.ok_handler(user_input
, self
.is_checked())
1964 return self
.input_entry
.get_text().decode('utf-8')
1966 def is_checked(self
):
1968 Get active state of the checkbutton
1971 return self
.checkbutton
.get_active()
1973 # There is no checkbutton
1976 class ChangeNickDialog(InputDialogCheck
):
1978 Class for changing room nickname in case of conflict
1981 def __init__(self
, account
, room_jid
, title
, prompt
, check_text
=None,
1984 change_nick must be set to True when we are already occupant of the room
1985 and we are changing our nick
1987 InputDialogCheck
.__init
__(self
, title
, '', checktext
=check_text
,
1988 input_str
='', is_modal
=True, ok_handler
=None, cancel_handler
=None)
1989 self
.room_queue
= [(account
, room_jid
, prompt
, change_nick
)]
1992 def on_input_dialog_delete_event(self
, widget
, event
):
1993 self
.on_cancelbutton_clicked(widget
)
1996 def setup_dialog(self
):
1997 self
.gc_control
= gajim
.interface
.msg_win_mgr
.get_gc_control(
1998 self
.room_jid
, self
.account
)
1999 if not self
.gc_control
and \
2000 self
.room_jid
in gajim
.interface
.minimized_controls
[self
.account
]:
2002 gajim
.interface
.minimized_controls
[self
.account
][self
.room_jid
]
2003 if not self
.gc_control
:
2006 label
= self
.xml
.get_object('label')
2007 label
.set_markup(self
.prompt
)
2008 self
.set_entry(self
.gc_control
.nick
+ \
2009 gajim
.config
.get('gc_proposed_nick_char'))
2011 def check_next(self
):
2012 if len(self
.room_queue
) == 0:
2013 self
.cancel_handler
= None
2014 self
.dialog
.destroy()
2015 if 'change_nick_dialog' in gajim
.interface
.instances
:
2016 del gajim
.interface
.instances
['change_nick_dialog']
2018 self
.account
, self
.room_jid
, self
.prompt
, self
.change_nick
= \
2019 self
.room_queue
.pop(0)
2022 if gajim
.new_room_nick
is not None and not gajim
.gc_connected
[
2023 self
.account
][self
.room_jid
] and self
.gc_control
.nick
!= \
2024 gajim
.new_room_nick
:
2026 self
.on_ok(gajim
.new_room_nick
, True)
2030 def on_okbutton_clicked(self
, widget
):
2031 nick
= self
.get_text()
2033 nick
= nick
.decode('utf-8')
2034 # send presence to room
2036 nick
= helpers
.parse_resource(nick
)
2039 ErrorDialog(_('Invalid nickname'),
2040 _('The nickname has not allowed characters.'))
2042 self
.on_ok(nick
, self
.is_checked())
2044 def on_ok(self
, nick
, is_checked
):
2046 gajim
.new_room_nick
= nick
2047 gajim
.connections
[self
.account
].join_gc(nick
, self
.room_jid
, None,
2048 change_nick
=self
.change_nick
)
2049 if gajim
.gc_connected
[self
.account
][self
.room_jid
]:
2050 # We are changing nick, we will change self.nick when we receive
2051 # presence that inform that it works
2052 self
.gc_control
.new_nick
= nick
2054 # We are connecting, we will not get a changed nick presence so
2055 # change it NOW. We don't already have a nick so it's harmless
2056 self
.gc_control
.nick
= nick
2059 def on_cancelbutton_clicked(self
, widget
):
2060 self
.gc_control
.new_nick
= ''
2063 def add_room(self
, account
, room_jid
, prompt
, change_nick
=False):
2064 if (account
, room_jid
, prompt
, change_nick
) not in self
.room_queue
:
2065 self
.room_queue
.append((account
, room_jid
, prompt
, change_nick
))
2067 class InputTextDialog(CommonInputDialog
):
2069 Class for multilines Input dialog (more place than InputDialog)
2072 def __init__(self
, title
, label_str
, input_str
=None, is_modal
=True,
2073 ok_handler
=None, cancel_handler
=None):
2074 self
.xml
= gtkgui_helpers
.get_gtk_builder('input_text_dialog.ui')
2075 CommonInputDialog
.__init
__(self
, title
, label_str
, is_modal
, ok_handler
,
2077 self
.input_buffer
= self
.xml
.get_object('input_textview').get_buffer()
2079 self
.input_buffer
.set_text(input_str
)
2080 start_iter
, end_iter
= self
.input_buffer
.get_bounds()
2081 self
.input_buffer
.select_range(start_iter
, end_iter
) # select all
2084 start_iter
, end_iter
= self
.input_buffer
.get_bounds()
2085 return self
.input_buffer
.get_text(start_iter
, end_iter
).decode('utf-8')
2087 class DoubleInputDialog
:
2089 Class for Double Input dialog
2092 def __init__(self
, title
, label_str1
, label_str2
, input_str1
=None,
2093 input_str2
=None, is_modal
=True, ok_handler
=None, cancel_handler
=None):
2094 self
.xml
= gtkgui_helpers
.get_gtk_builder('dubbleinput_dialog.ui')
2095 self
.dialog
= self
.xml
.get_object('dubbleinput_dialog')
2096 label1
= self
.xml
.get_object('label1')
2097 self
.input_entry1
= self
.xml
.get_object('input_entry1')
2098 label2
= self
.xml
.get_object('label2')
2099 self
.input_entry2
= self
.xml
.get_object('input_entry2')
2100 self
.dialog
.set_title(title
)
2101 label1
.set_markup(label_str1
)
2102 label2
.set_markup(label_str2
)
2103 self
.cancel_handler
= cancel_handler
2105 self
.input_entry1
.set_text(input_str1
)
2106 self
.input_entry1
.select_region(0, -1) # select all
2108 self
.input_entry2
.set_text(input_str2
)
2109 self
.input_entry2
.select_region(0, -1) # select all
2111 self
.dialog
.set_modal(is_modal
)
2113 self
.ok_handler
= ok_handler
2114 okbutton
= self
.xml
.get_object('okbutton')
2115 okbutton
.connect('clicked', self
.on_okbutton_clicked
)
2116 cancelbutton
= self
.xml
.get_object('cancelbutton')
2117 cancelbutton
.connect('clicked', self
.on_cancelbutton_clicked
)
2118 self
.xml
.connect_signals(self
)
2119 self
.dialog
.show_all()
2121 def on_dubbleinput_dialog_destroy(self
, widget
):
2122 if not self
.cancel_handler
:
2124 if isinstance(self
.cancel_handler
, tuple):
2125 self
.cancel_handler
[0](*self
.cancel_handler
[1:])
2127 self
.cancel_handler()
2129 def on_okbutton_clicked(self
, widget
):
2130 user_input1
= self
.input_entry1
.get_text().decode('utf-8')
2131 user_input2
= self
.input_entry2
.get_text().decode('utf-8')
2132 self
.dialog
.destroy()
2133 if not self
.ok_handler
:
2135 if isinstance(self
.ok_handler
, tuple):
2136 self
.ok_handler
[0](user_input1
, user_input2
, *self
.ok_handler
[1:])
2138 self
.ok_handler(user_input1
, user_input2
)
2140 def on_cancelbutton_clicked(self
, widget
):
2141 self
.dialog
.destroy()
2142 if not self
.cancel_handler
:
2144 if isinstance(self
.cancel_handler
, tuple):
2145 self
.cancel_handler
[0](*self
.cancel_handler
[1:])
2147 self
.cancel_handler()
2149 class SubscriptionRequestWindow
:
2150 def __init__(self
, jid
, text
, account
, user_nick
=None):
2151 xml
= gtkgui_helpers
.get_gtk_builder('subscription_request_window.ui')
2152 self
.window
= xml
.get_object('subscription_request_window')
2154 self
.account
= account
2155 self
.user_nick
= user_nick
2156 if len(gajim
.connections
) >= 2:
2158 _('Subscription request for account %(account)s from %(jid)s')\
2159 % {'account': account
, 'jid': self
.jid
}
2161 prompt_text
= _('Subscription request from %s') % self
.jid
2162 xml
.get_object('from_label').set_text(prompt_text
)
2163 xml
.get_object('message_textview').get_buffer().set_text(text
)
2164 xml
.connect_signals(self
)
2165 self
.window
.show_all()
2167 def prepare_popup_menu(self
):
2168 xml
= gtkgui_helpers
.get_gtk_builder('subscription_request_popup_menu.ui')
2169 menu
= xml
.get_object('subscription_request_popup_menu')
2170 xml
.connect_signals(self
)
2173 def on_close_button_clicked(self
, widget
):
2174 self
.window
.destroy()
2176 def on_authorize_button_clicked(self
, widget
):
2180 gajim
.connections
[self
.account
].send_authorization(self
.jid
)
2181 self
.window
.destroy()
2182 contact
= gajim
.contacts
.get_contact(self
.account
, self
.jid
)
2183 if not contact
or _('Not in Roster') in contact
.groups
:
2184 AddNewContactWindow(self
.account
, self
.jid
, self
.user_nick
)
2186 def on_contact_info_activate(self
, widget
):
2190 if self
.jid
in gajim
.interface
.instances
[self
.account
]['infos']:
2191 gajim
.interface
.instances
[self
.account
]['infos'][self
.jid
].window
.present()
2193 contact
= gajim
.contacts
.create_contact(jid
=self
.jid
, account
=self
.account
)
2194 gajim
.interface
.instances
[self
.account
]['infos'][self
.jid
] = \
2195 vcard
.VcardWindow(contact
, self
.account
)
2196 # Remove jabber page
2197 gajim
.interface
.instances
[self
.account
]['infos'][self
.jid
].xml
.\
2198 get_object('information_notebook').remove_page(0)
2200 def on_start_chat_activate(self
, widget
):
2204 gajim
.interface
.new_chat_from_jid(self
.account
, self
.jid
)
2206 def on_deny_button_clicked(self
, widget
):
2210 gajim
.connections
[self
.account
].refuse_authorization(self
.jid
)
2211 contact
= gajim
.contacts
.get_contact(self
.account
, self
.jid
)
2212 if contact
and _('Not in Roster') in contact
.get_shown_groups():
2213 gajim
.interface
.roster
.remove_contact(self
.jid
, self
.account
)
2214 self
.window
.destroy()
2216 def on_actions_button_clicked(self
, widget
):
2220 menu
= self
.prepare_popup_menu()
2222 gtkgui_helpers
.popup_emoticons_under_button(menu
, widget
,
2226 class JoinGroupchatWindow
:
2227 def __init__(self
, account
=None, room_jid
='', nick
='', password
='',
2230 Automatic is a dict like {'invities': []}. If automatic is not empty,
2231 this means room must be automaticaly configured and when done, invities
2232 must be automatically invited
2235 if room_jid
!= '' and room_jid
in gajim
.gc_connected
[account
] and\
2236 gajim
.gc_connected
[account
][room_jid
]:
2237 ErrorDialog(_('You are already in group chat %s') % room_jid
)
2238 raise GajimGeneralException
, 'You are already in this group chat'
2240 nick
= gajim
.nicks
[account
]
2241 if gajim
.connections
[account
].connected
< 2:
2242 ErrorDialog(_('You are not connected to the server'),
2243 _('You can not join a group chat unless you are connected.'))
2244 raise GajimGeneralException
, 'You must be connected to join a groupchat'
2246 self
.xml
= gtkgui_helpers
.get_gtk_builder('join_groupchat_window.ui')
2248 account_label
= self
.xml
.get_object('account_label')
2249 account_combobox
= self
.xml
.get_object('account_combobox')
2250 account_label
.set_no_show_all(False)
2251 account_combobox
.set_no_show_all(False)
2252 liststore
= gtk
.ListStore(str)
2253 account_combobox
.set_model(liststore
)
2254 cell
= gtk
.CellRendererText()
2255 account_combobox
.pack_start(cell
, True)
2256 account_combobox
.add_attribute(cell
, 'text', 0)
2257 account_combobox
.set_active(-1)
2259 # Add accounts, set current as active if it matches 'account'
2260 for acct
in [a
for a
in gajim
.connections
if \
2261 gajim
.account_is_connected(a
)]:
2262 account_combobox
.append_text(acct
)
2263 if account
and account
== acct
:
2264 account_combobox
.set_active(liststore
.iter_n_children(None)-1)
2266 self
.account
= account
2267 self
.automatic
= automatic
2268 self
._empty
_required
_widgets
= []
2270 self
.window
= self
.xml
.get_object('join_groupchat_window')
2271 self
.window
.set_transient_for(gajim
.interface
.roster
.window
)
2272 self
._room
_jid
_entry
= self
.xml
.get_object('room_jid_entry')
2273 self
._nickname
_entry
= self
.xml
.get_object('nickname_entry')
2274 self
._password
_entry
= self
.xml
.get_object('password_entry')
2276 self
._nickname
_entry
.set_text(nick
)
2278 self
._password
_entry
.set_text(password
)
2279 self
.xml
.connect_signals(self
)
2282 # now add us to open windows
2283 gajim
.interface
.instances
[account
]['join_gc'] = self
2284 if len(gajim
.connections
) > 1:
2285 title
= _('Join Group Chat with account %s') % account
2287 title
= _('Join Group Chat')
2288 self
.window
.set_title(title
)
2290 self
.server_comboboxentry
= self
.xml
.get_object('server_comboboxentry')
2291 self
.server_model
= self
.server_comboboxentry
.get_model()
2293 # get the muc server of our server
2294 if 'jabber' in gajim
.connections
[account
].muc_jid
:
2295 server_list
.append(gajim
.connections
[account
].muc_jid
['jabber'])
2297 self
.recently_combobox
= self
.xml
.get_object('recently_combobox')
2298 liststore
= gtk
.ListStore(str)
2299 self
.recently_combobox
.set_model(liststore
)
2300 cell
= gtk
.CellRendererText()
2301 self
.recently_combobox
.pack_start(cell
, True)
2302 self
.recently_combobox
.add_attribute(cell
, 'text', 0)
2303 self
.recently_groupchat
= gajim
.config
.get('recently_groupchat').split()
2304 for g
in self
.recently_groupchat
:
2305 self
.recently_combobox
.append_text(g
)
2306 server
= gajim
.get_server_from_jid(g
)
2307 if server
not in server_list
and not server
.startswith('irc'):
2308 server_list
.append(server
)
2310 for s
in server_list
:
2311 self
.server_model
.append([s
])
2312 self
.server_comboboxentry
.set_active(0)
2314 self
._set
_room
_jid
(room_jid
)
2316 if len(self
.recently_groupchat
) == 0:
2317 self
.recently_combobox
.set_sensitive(False)
2318 elif room_jid
== '':
2319 self
.recently_combobox
.set_active(0)
2320 self
._room
_jid
_entry
.select_region(0, -1)
2321 elif room_jid
!= '':
2322 self
.xml
.get_object('join_button').grab_focus()
2324 if not self
._room
_jid
_entry
.get_text():
2325 self
._empty
_required
_widgets
.append(self
._room
_jid
_entry
)
2326 if not self
._nickname
_entry
.get_text():
2327 self
._empty
_required
_widgets
.append(self
._nickname
_entry
)
2328 if len(self
._empty
_required
_widgets
):
2329 self
.xml
.get_object('join_button').set_sensitive(False)
2331 if account
and not gajim
.connections
[account
].private_storage_supported
:
2332 self
.xml
.get_object('bookmark_checkbutton').set_sensitive(False)
2334 self
.window
.show_all()
2336 def on_join_groupchat_window_destroy(self
, widget
):
2340 if self
.account
and 'join_gc' in gajim
.interface
.instances
[self
.account
]:
2341 # remove us from open windows
2342 del gajim
.interface
.instances
[self
.account
]['join_gc']
2344 def on_join_groupchat_window_key_press_event(self
, widget
, event
):
2345 if event
.keyval
== gtk
.keysyms
.Escape
: # ESCAPE
2348 def on_required_entry_changed(self
, widget
):
2349 if not widget
.get_text():
2350 self
._empty
_required
_widgets
.append(widget
)
2351 self
.xml
.get_object('join_button').set_sensitive(False)
2353 if widget
in self
._empty
_required
_widgets
:
2354 self
._empty
_required
_widgets
.remove(widget
)
2355 if not self
._empty
_required
_widgets
and self
.account
:
2356 self
.xml
.get_object('join_button').set_sensitive(True)
2357 text
= self
._room
_jid
_entry
.get_text()
2358 if widget
== self
._room
_jid
_entry
and '@' in text
:
2359 # Don't allow @ char in room entry
2360 room_jid
, server
= text
.split('@', 1)
2361 self
._room
_jid
_entry
.set_text(room_jid
)
2363 self
.server_comboboxentry
.child
.set_text(server
)
2364 self
.server_comboboxentry
.grab_focus()
2366 def on_account_combobox_changed(self
, widget
):
2367 model
= widget
.get_model()
2368 iter_
= widget
.get_active_iter()
2369 self
.account
= model
[iter_
][0].decode('utf-8')
2370 self
.on_required_entry_changed(self
._nickname
_entry
)
2372 def _set_room_jid(self
, room_jid
):
2373 room
, server
= gajim
.get_name_and_server_from_jid(room_jid
)
2374 self
._room
_jid
_entry
.set_text(room
)
2375 self
.server_comboboxentry
.child
.set_text(server
)
2377 def on_recently_combobox_changed(self
, widget
):
2378 model
= widget
.get_model()
2379 iter_
= widget
.get_active_iter()
2380 room_jid
= model
[iter_
][0].decode('utf-8')
2381 self
._set
_room
_jid
(room_jid
)
2383 def on_browse_rooms_button_clicked(self
, widget
):
2384 server
= self
.server_comboboxentry
.child
.get_text().decode('utf-8')
2385 if server
in gajim
.interface
.instances
[self
.account
]['disco']:
2386 gajim
.interface
.instances
[self
.account
]['disco'][server
].window
.\
2390 # Object will add itself to the window dict
2391 disco
.ServiceDiscoveryWindow(self
.account
, server
,
2392 initial_identities
=[{'category': 'conference',
2394 except GajimGeneralException
:
2397 def on_cancel_button_clicked(self
, widget
):
2399 When Cancel button is clicked
2401 self
.window
.destroy()
2403 def on_bookmark_checkbutton_toggled(self
, widget
):
2404 auto_join_checkbutton
= self
.xml
.get_object('auto_join_checkbutton')
2405 if widget
.get_active():
2406 auto_join_checkbutton
.set_sensitive(True)
2408 auto_join_checkbutton
.set_sensitive(False)
2410 def on_join_button_clicked(self
, widget
):
2412 When Join button is clicked
2414 if not self
.account
:
2415 ErrorDialog(_('Invalid Account'),
2416 _('You have to choose an account from which you want to join the '
2419 nickname
= self
._nickname
_entry
.get_text().decode('utf-8')
2420 server
= self
.server_comboboxentry
.child
.get_text().decode('utf-8')
2421 room
= self
._room
_jid
_entry
.get_text().decode('utf-8')
2422 room_jid
= room
+ '@' + server
2423 password
= self
._password
_entry
.get_text().decode('utf-8')
2425 nickname
= helpers
.parse_resource(nickname
)
2427 ErrorDialog(_('Invalid Nickname'),
2428 _('The nickname has not allowed characters.'))
2430 user
, server
, resource
= helpers
.decompose_jid(room_jid
)
2431 if not user
or not server
or resource
:
2432 ErrorDialog(_('Invalid group chat Jabber ID'),
2433 _('Please enter the group chat Jabber ID as room@server.'))
2436 room_jid
= helpers
.parse_jid(room_jid
)
2438 ErrorDialog(_('Invalid group chat Jabber ID'),
2439 _('The group chat Jabber ID has not allowed characters.'))
2442 if gajim
.interface
.msg_win_mgr
.has_window(room_jid
, self
.account
):
2443 ctrl
= gajim
.interface
.msg_win_mgr
.get_gc_control(room_jid
,
2445 if ctrl
.type_id
!= message_control
.TYPE_GC
:
2446 ErrorDialog(_('This is not a group chat'),
2447 _('%s is not the name of a group chat.') % room_jid
)
2449 if room_jid
in self
.recently_groupchat
:
2450 self
.recently_groupchat
.remove(room_jid
)
2451 self
.recently_groupchat
.insert(0, room_jid
)
2452 if len(self
.recently_groupchat
) > 10:
2453 self
.recently_groupchat
= self
.recently_groupchat
[0:10]
2454 gajim
.config
.set('recently_groupchat',
2455 ' '.join(self
.recently_groupchat
))
2457 if self
.xml
.get_object('bookmark_checkbutton').get_active():
2458 if self
.xml
.get_object('auto_join_checkbutton').get_active():
2462 # Add as bookmark, with autojoin and not minimized
2463 name
= gajim
.get_nick_from_jid(room_jid
)
2464 gajim
.interface
.add_gc_bookmark(self
.account
, name
, room_jid
, autojoin
,
2465 '0', password
, nickname
)
2468 gajim
.automatic_rooms
[self
.account
][room_jid
] = self
.automatic
2469 gajim
.interface
.join_gc_room(self
.account
, room_jid
, nickname
, password
)
2471 self
.window
.destroy()
2473 class SynchroniseSelectAccountDialog
:
2474 def __init__(self
, account
):
2475 # 'account' can be None if we are about to create our first one
2476 if not account
or gajim
.connections
[account
].connected
< 2:
2477 ErrorDialog(_('You are not connected to the server'),
2478 _('Without a connection, you can not synchronise your contacts.'))
2479 raise GajimGeneralException
, 'You are not connected to the server'
2480 self
.account
= account
2481 self
.xml
= gtkgui_helpers
.get_gtk_builder('synchronise_select_account_dialog.ui')
2482 self
.dialog
= self
.xml
.get_object('synchronise_select_account_dialog')
2483 self
.accounts_treeview
= self
.xml
.get_object('accounts_treeview')
2484 model
= gtk
.ListStore(str, str, bool)
2485 self
.accounts_treeview
.set_model(model
)
2487 renderer
= gtk
.CellRendererText()
2488 self
.accounts_treeview
.insert_column_with_attributes(-1, _('Name'),
2490 renderer
= gtk
.CellRendererText()
2491 self
.accounts_treeview
.insert_column_with_attributes(-1, _('Server'),
2494 self
.xml
.connect_signals(self
)
2495 self
.init_accounts()
2496 self
.dialog
.show_all()
2498 def on_accounts_window_key_press_event(self
, widget
, event
):
2499 if event
.keyval
== gtk
.keysyms
.Escape
:
2500 self
.window
.destroy()
2502 def init_accounts(self
):
2504 Initialize listStore with existing accounts
2506 model
= self
.accounts_treeview
.get_model()
2508 for remote_account
in gajim
.connections
:
2509 if remote_account
== self
.account
:
2510 # Do not show the account we're sync'ing
2512 iter_
= model
.append()
2513 model
.set(iter_
, 0, remote_account
, 1,
2514 gajim
.get_hostname_from_account(remote_account
))
2516 def on_cancel_button_clicked(self
, widget
):
2517 self
.dialog
.destroy()
2519 def on_ok_button_clicked(self
, widget
):
2520 sel
= self
.accounts_treeview
.get_selection()
2521 (model
, iter_
) = sel
.get_selected()
2524 remote_account
= model
.get_value(iter_
, 0).decode('utf-8')
2526 if gajim
.connections
[remote_account
].connected
< 2:
2527 ErrorDialog(_('This account is not connected to the server'),
2528 _('You cannot synchronize with an account unless it is connected.'))
2532 SynchroniseSelectContactsDialog(self
.account
, remote_account
)
2533 except GajimGeneralException
:
2534 # if we showed ErrorDialog, there will not be dialog instance
2536 self
.dialog
.destroy()
2538 class SynchroniseSelectContactsDialog
:
2539 def __init__(self
, account
, remote_account
):
2540 self
.local_account
= account
2541 self
.remote_account
= remote_account
2542 self
.xml
= gtkgui_helpers
.get_gtk_builder(
2543 'synchronise_select_contacts_dialog.ui')
2544 self
.dialog
= self
.xml
.get_object('synchronise_select_contacts_dialog')
2545 self
.contacts_treeview
= self
.xml
.get_object('contacts_treeview')
2546 model
= gtk
.ListStore(bool, str)
2547 self
.contacts_treeview
.set_model(model
)
2549 renderer1
= gtk
.CellRendererToggle()
2550 renderer1
.set_property('activatable', True)
2551 renderer1
.connect('toggled', self
.toggled_callback
)
2552 self
.contacts_treeview
.insert_column_with_attributes(-1,
2553 _('Synchronise'), renderer1
, active
=0)
2554 renderer2
= gtk
.CellRendererText()
2555 self
.contacts_treeview
.insert_column_with_attributes(-1, _('Name'),
2558 self
.xml
.connect_signals(self
)
2559 self
.init_contacts()
2560 self
.dialog
.show_all()
2562 def toggled_callback(self
, cell
, path
):
2563 model
= self
.contacts_treeview
.get_model()
2564 iter_
= model
.get_iter(path
)
2565 model
[iter_
][0] = not cell
.get_active()
2567 def on_contacts_window_key_press_event(self
, widget
, event
):
2568 if event
.keyval
== gtk
.keysyms
.Escape
:
2569 self
.window
.destroy()
2571 def init_contacts(self
):
2573 Initialize listStore with existing accounts
2575 model
= self
.contacts_treeview
.get_model()
2578 # recover local contacts
2579 local_jid_list
= gajim
.contacts
.get_contacts_jid_list(self
.local_account
)
2581 remote_jid_list
= gajim
.contacts
.get_contacts_jid_list(
2582 self
.remote_account
)
2583 for remote_jid
in remote_jid_list
:
2584 if remote_jid
not in local_jid_list
:
2585 iter_
= model
.append()
2586 model
.set(iter_
, 0, True, 1, remote_jid
)
2588 def on_cancel_button_clicked(self
, widget
):
2589 self
.dialog
.destroy()
2591 def on_ok_button_clicked(self
, widget
):
2592 model
= self
.contacts_treeview
.get_model()
2593 iter_
= model
.get_iter_root()
2597 remote_jid
= model
[iter_
][1].decode('utf-8')
2598 message
= 'I\'m synchronizing my contacts from my %s account, could you please add this address to your contact list?' % \
2599 gajim
.get_hostname_from_account(self
.remote_account
)
2600 remote_contact
= gajim
.contacts
.get_first_contact_from_jid(
2601 self
.remote_account
, remote_jid
)
2602 # keep same groups and same nickname
2603 gajim
.interface
.roster
.req_sub(self
, remote_jid
, message
,
2604 self
.local_account
, groups
= remote_contact
.groups
,
2605 nickname
= remote_contact
.name
, auto_auth
= True)
2606 iter_
= model
.iter_next(iter_
)
2607 self
.dialog
.destroy()
2609 class NewChatDialog(InputDialog
):
2610 def __init__(self
, account
):
2611 self
.account
= account
2613 if len(gajim
.connections
) > 1:
2614 title
= _('Start Chat with account %s') % account
2616 title
= _('Start Chat')
2617 prompt_text
= _('Fill in the nickname or the Jabber ID of the contact you would like\nto send a chat message to:')
2618 InputDialog
.__init
__(self
, title
, prompt_text
, is_modal
=False)
2620 self
.completion_dict
= {}
2621 liststore
= gtkgui_helpers
.get_completion_liststore(self
.input_entry
)
2622 self
.completion_dict
= helpers
.get_contact_dict_for_account(account
)
2623 # add all contacts to the model
2624 keys
= sorted(self
.completion_dict
.keys())
2626 contact
= self
.completion_dict
[jid
]
2627 img
= gajim
.interface
.jabber_state_images
['16'][contact
.show
]
2628 liststore
.append((img
.get_pixbuf(), jid
))
2630 self
.ok_handler
= self
.new_chat_response
2631 okbutton
= self
.xml
.get_object('okbutton')
2632 okbutton
.connect('clicked', self
.on_okbutton_clicked
)
2633 cancelbutton
= self
.xml
.get_object('cancelbutton')
2634 cancelbutton
.connect('clicked', self
.on_cancelbutton_clicked
)
2635 self
.dialog
.set_transient_for(gajim
.interface
.roster
.window
)
2636 self
.dialog
.show_all()
2638 def new_chat_response(self
, jid
):
2640 Called when ok button is clicked
2642 if gajim
.connections
[self
.account
].connected
<= 1:
2643 #if offline or connecting
2644 ErrorDialog(_('Connection not available'),
2645 _('Please make sure you are connected with "%s".') % self
.account
)
2648 if jid
in self
.completion_dict
:
2649 jid
= self
.completion_dict
[jid
].jid
2652 jid
= helpers
.parse_jid(jid
)
2653 except helpers
.InvalidFormat
, e
:
2654 ErrorDialog(_('Invalid JID'), e
[0])
2657 ErrorDialog(_('Invalid JID'), _('Unable to parse "%s".') % jid
)
2659 gajim
.interface
.new_chat_from_jid(self
.account
, jid
)
2661 class ChangePasswordDialog
:
2662 def __init__(self
, account
, on_response
):
2663 # 'account' can be None if we are about to create our first one
2664 if not account
or gajim
.connections
[account
].connected
< 2:
2665 ErrorDialog(_('You are not connected to the server'),
2666 _('Without a connection, you can not change your password.'))
2667 raise GajimGeneralException
, 'You are not connected to the server'
2668 self
.account
= account
2669 self
.on_response
= on_response
2670 self
.xml
= gtkgui_helpers
.get_gtk_builder('change_password_dialog.ui')
2671 self
.dialog
= self
.xml
.get_object('change_password_dialog')
2672 self
.password1_entry
= self
.xml
.get_object('password1_entry')
2673 self
.password2_entry
= self
.xml
.get_object('password2_entry')
2674 self
.dialog
.connect('response', self
.on_dialog_response
)
2676 self
.dialog
.show_all()
2678 def on_dialog_response(self
, dialog
, response
):
2679 if response
!= gtk
.RESPONSE_OK
:
2681 self
.on_response(None)
2683 password1
= self
.password1_entry
.get_text().decode('utf-8')
2685 ErrorDialog(_('Invalid password'), _('You must enter a password.'))
2687 password2
= self
.password2_entry
.get_text().decode('utf-8')
2688 if password1
!= password2
:
2689 ErrorDialog(_('Passwords do not match'),
2690 _('The passwords typed in both fields must be identical.'))
2693 self
.on_response(password1
)
2695 class PopupNotificationWindow
:
2696 def __init__(self
, event_type
, jid
, account
, msg_type
='',
2697 path_to_image
=None, title
=None, text
=None):
2698 self
.account
= account
2700 self
.msg_type
= msg_type
2702 xml
= gtkgui_helpers
.get_gtk_builder('popup_notification_window.ui')
2703 self
.window
= xml
.get_object('popup_notification_window')
2704 self
.window
.set_type_hint(gtk
.gdk
.WINDOW_TYPE_HINT_TOOLTIP
)
2705 close_button
= xml
.get_object('close_button')
2706 event_type_label
= xml
.get_object('event_type_label')
2707 event_description_label
= xml
.get_object('event_description_label')
2708 eventbox
= xml
.get_object('eventbox')
2709 image
= xml
.get_object('notification_image')
2712 text
= gajim
.get_name_from_jid(account
, jid
) # default value of text
2716 event_type_label
.set_markup(
2717 '<span foreground="black" weight="bold">%s</span>' %
2718 gobject
.markup_escape_text(title
))
2720 # set colors [ http://www.pitt.edu/~nisg/cis/web/cgi/rgb.html ]
2721 self
.window
.modify_bg(gtk
.STATE_NORMAL
, gtk
.gdk
.color_parse('black'))
2724 if not path_to_image
:
2725 path_to_image
= gtkgui_helpers
.get_icon_path('gajim-chat_msg_recv', 48)
2727 if event_type
== _('Contact Signed In'):
2728 bg_color
= 'limegreen'
2729 elif event_type
== _('Contact Signed Out'):
2731 elif event_type
in (_('New Message'), _('New Single Message'),
2732 _('New Private Message'), _('New E-mail')):
2733 bg_color
= 'dodgerblue'
2734 elif event_type
== _('File Transfer Request'):
2736 elif event_type
== _('File Transfer Error'):
2737 bg_color
= 'firebrick'
2738 elif event_type
in (_('File Transfer Completed'),
2739 _('File Transfer Stopped')):
2740 bg_color
= 'yellowgreen'
2741 elif event_type
== _('Groupchat Invitation'):
2743 elif event_type
== _('Contact Changed Status'):
2744 bg_color
= 'thistle2'
2745 else: # Unknown event! Shouldn't happen but deal with it
2747 popup_bg_color
= gtk
.gdk
.color_parse(bg_color
)
2748 close_button
.modify_bg(gtk
.STATE_NORMAL
, popup_bg_color
)
2749 eventbox
.modify_bg(gtk
.STATE_NORMAL
, popup_bg_color
)
2750 event_description_label
.set_markup('<span foreground="black">%s</span>' %
2751 gobject
.markup_escape_text(text
))
2754 image
.set_from_file(path_to_image
)
2756 # position the window to bottom-right of screen
2757 window_width
, self
.window_height
= self
.window
.get_size()
2758 gajim
.interface
.roster
.popups_notification_height
+= self
.window_height
2759 pos_x
= gajim
.config
.get('notification_position_x')
2761 pos_x
= gtk
.gdk
.screen_width() - window_width
+ pos_x
+ 1
2762 pos_y
= gajim
.config
.get('notification_position_y')
2764 pos_y
= gtk
.gdk
.screen_height() - \
2765 gajim
.interface
.roster
.popups_notification_height
+ pos_y
+ 1
2766 self
.window
.move(pos_x
, pos_y
)
2768 xml
.connect_signals(self
)
2769 self
.window
.show_all()
2770 timeout
= gajim
.config
.get('notification_timeout')
2771 gobject
.timeout_add_seconds(timeout
, self
.on_timeout
)
2773 def on_close_button_clicked(self
, widget
):
2774 self
.adjust_height_and_move_popup_notification_windows()
2776 def on_timeout(self
):
2777 self
.adjust_height_and_move_popup_notification_windows()
2779 def adjust_height_and_move_popup_notification_windows(self
):
2781 gajim
.interface
.roster
.popups_notification_height
-= self
.window_height
2782 self
.window
.destroy()
2784 if len(gajim
.interface
.roster
.popup_notification_windows
) > 0:
2785 # we want to remove the first window added in the list
2786 gajim
.interface
.roster
.popup_notification_windows
.pop(0)
2788 # move the rest of popup windows
2789 gajim
.interface
.roster
.popups_notification_height
= 0
2790 for window_instance
in gajim
.interface
.roster
.popup_notification_windows
:
2791 window_width
, window_height
= window_instance
.window
.get_size()
2792 gajim
.interface
.roster
.popups_notification_height
+= window_height
2793 window_instance
.window
.move(gtk
.gdk
.screen_width() - window_width
,
2794 gtk
.gdk
.screen_height() - \
2795 gajim
.interface
.roster
.popups_notification_height
)
2797 def on_popup_notification_window_button_press_event(self
, widget
, event
):
2798 if event
.button
!= 1:
2799 self
.window
.destroy()
2801 gajim
.interface
.handle_event(self
.account
, self
.jid
, self
.msg_type
)
2802 self
.adjust_height_and_move_popup_notification_windows()
2804 class SingleMessageWindow
:
2806 SingleMessageWindow can send or show a received singled message depending on
2807 action argument which can be 'send' or 'receive'
2809 # Keep a reference on windows so garbage collector don't restroy them
2811 def __init__(self
, account
, to
='', action
='', from_whom
='', subject
='',
2812 message
='', resource
='', session
=None, form_node
=None):
2813 self
.instances
.append(self
)
2814 self
.account
= account
2815 self
.action
= action
2817 self
.subject
= subject
2818 self
.message
= message
2820 self
.from_whom
= from_whom
2821 self
.resource
= resource
2822 self
.session
= session
2824 self
.xml
= gtkgui_helpers
.get_gtk_builder('single_message_window.ui')
2825 self
.window
= self
.xml
.get_object('single_message_window')
2826 self
.count_chars_label
= self
.xml
.get_object('count_chars_label')
2827 self
.from_label
= self
.xml
.get_object('from_label')
2828 self
.from_entry
= self
.xml
.get_object('from_entry')
2829 self
.to_label
= self
.xml
.get_object('to_label')
2830 self
.to_entry
= self
.xml
.get_object('to_entry')
2831 self
.subject_entry
= self
.xml
.get_object('subject_entry')
2832 self
.message_scrolledwindow
= self
.xml
.get_object(
2833 'message_scrolledwindow')
2834 self
.message_textview
= self
.xml
.get_object('message_textview')
2835 self
.message_tv_buffer
= self
.message_textview
.get_buffer()
2836 self
.conversation_scrolledwindow
= self
.xml
.get_object(
2837 'conversation_scrolledwindow')
2838 self
.conversation_textview
= conversation_textview
.ConversationTextview(
2840 self
.conversation_textview
.tv
.show()
2841 self
.conversation_tv_buffer
= self
.conversation_textview
.tv
.get_buffer()
2842 self
.xml
.get_object('conversation_scrolledwindow').add(
2843 self
.conversation_textview
.tv
)
2845 self
.form_widget
= None
2846 parent_box
= self
.xml
.get_object('conversation_scrolledwindow').\
2849 dataform
= dataforms
.ExtendForm(node
=form_node
)
2850 self
.form_widget
= dataforms_widget
.DataFormWidget(dataform
)
2851 self
.form_widget
.show_all()
2852 parent_box
.add(self
.form_widget
)
2853 parent_box
.child_set_property(self
.form_widget
, 'position',
2854 parent_box
.child_get_property(self
.xml
.get_object(
2855 'conversation_scrolledwindow'), 'position'))
2856 self
.action
= 'form'
2858 self
.send_button
= self
.xml
.get_object('send_button')
2859 self
.reply_button
= self
.xml
.get_object('reply_button')
2860 self
.send_and_close_button
= self
.xml
.get_object('send_and_close_button')
2861 self
.cancel_button
= self
.xml
.get_object('cancel_button')
2862 self
.close_button
= self
.xml
.get_object('close_button')
2863 self
.message_tv_buffer
.connect('changed', self
.update_char_counter
)
2864 if isinstance(to
, list):
2865 jid
= ', '.join( [i
[0].get_full_jid() for i
in to
])
2866 self
.to_entry
.set_text(jid
)
2867 self
.to_entry
.set_sensitive(False)
2869 self
.to_entry
.set_text(to
)
2871 if gajim
.config
.get('use_speller') and HAS_GTK_SPELL
and action
== 'send':
2873 lang
= gajim
.config
.get('speller_language')
2876 gtkspell
.Spell(self
.conversation_textview
.tv
, lang
)
2877 gtkspell
.Spell(self
.message_textview
, lang
)
2878 except (gobject
.GError
, TypeError, RuntimeError, OSError):
2879 AspellDictError(lang
)
2881 self
.prepare_widgets_for(self
.action
)
2883 # set_text(None) raises TypeError exception
2884 if self
.subject
is None:
2886 self
.subject_entry
.set_text(self
.subject
)
2890 liststore
= gtkgui_helpers
.get_completion_liststore(self
.to_entry
)
2891 self
.completion_dict
= helpers
.get_contact_dict_for_account(account
)
2892 keys
= sorted(self
.completion_dict
.keys())
2894 contact
= self
.completion_dict
[jid
]
2895 img
= gajim
.interface
.jabber_state_images
['16'][contact
.show
]
2896 liststore
.append((img
.get_pixbuf(), jid
))
2898 self
.completion_dict
= {}
2899 self
.xml
.connect_signals(self
)
2901 # get window position and size from config
2902 gtkgui_helpers
.resize_window(self
.window
,
2903 gajim
.config
.get('single-msg-width'),
2904 gajim
.config
.get('single-msg-height'))
2905 gtkgui_helpers
.move_window(self
.window
,
2906 gajim
.config
.get('single-msg-x-position'),
2907 gajim
.config
.get('single-msg-y-position'))
2909 self
.window
.show_all()
2911 def on_single_message_window_destroy(self
, widget
):
2912 self
.instances
.remove(self
)
2913 c
= gajim
.contacts
.get_contact_with_highest_priority(self
.account
,
2916 # Groupchat is maybe already destroyed
2918 if c
.is_groupchat() and not self
.from_whom
in \
2919 gajim
.interface
.minimized_controls
[self
.account
] and self
.action
== \
2920 'receive' and gajim
.events
.get_nb_roster_events(self
.account
,
2921 self
.from_whom
, types
=['chat', 'normal']) == 0:
2922 gajim
.interface
.roster
.remove_groupchat(self
.from_whom
, self
.account
)
2924 def set_cursor_to_end(self
):
2925 end_iter
= self
.message_tv_buffer
.get_end_iter()
2926 self
.message_tv_buffer
.place_cursor(end_iter
)
2929 # save the window size and position
2930 x
, y
= self
.window
.get_position()
2931 gajim
.config
.set('single-msg-x-position', x
)
2932 gajim
.config
.set('single-msg-y-position', y
)
2933 width
, height
= self
.window
.get_size()
2934 gajim
.config
.set('single-msg-width', width
)
2935 gajim
.config
.set('single-msg-height', height
)
2936 gajim
.interface
.save_config()
2938 def on_single_message_window_delete_event(self
, window
, ev
):
2941 def prepare_widgets_for(self
, action
):
2942 if len(gajim
.connections
) > 1:
2943 if action
== 'send':
2944 title
= _('Single Message using account %s') % self
.account
2946 title
= _('Single Message in account %s') % self
.account
2948 title
= _('Single Message')
2950 if action
== 'send': # prepare UI for Sending
2951 title
= _('Send %s') % title
2952 self
.send_button
.show()
2953 self
.send_and_close_button
.show()
2954 self
.to_label
.show()
2955 self
.to_entry
.show()
2956 self
.reply_button
.hide()
2957 self
.from_label
.hide()
2958 self
.from_entry
.hide()
2959 self
.conversation_scrolledwindow
.hide()
2960 self
.message_scrolledwindow
.show()
2962 if self
.message
: # we come from a reply?
2963 self
.message_textview
.grab_focus()
2964 self
.cancel_button
.hide()
2965 self
.close_button
.show()
2966 self
.message_tv_buffer
.set_text(self
.message
)
2967 gobject
.idle_add(self
.set_cursor_to_end
)
2968 else: # we write a new message (not from reply)
2969 self
.close_button
.hide()
2970 if self
.to
: # do we already have jid?
2971 self
.subject_entry
.grab_focus()
2973 elif action
== 'receive': # prepare UI for Receiving
2974 title
= _('Received %s') % title
2975 self
.reply_button
.show()
2976 self
.from_label
.show()
2977 self
.from_entry
.show()
2978 self
.send_button
.hide()
2979 self
.send_and_close_button
.hide()
2980 self
.to_label
.hide()
2981 self
.to_entry
.hide()
2982 self
.conversation_scrolledwindow
.show()
2983 self
.message_scrolledwindow
.hide()
2986 self
.conversation_textview
.print_real_text(self
.message
)
2987 fjid
= self
.from_whom
2989 fjid
+= '/' + self
.resource
# Full jid of sender (with resource)
2990 self
.from_entry
.set_text(fjid
)
2991 self
.from_entry
.set_property('editable', False)
2992 self
.subject_entry
.set_property('editable', False)
2993 self
.reply_button
.grab_focus()
2994 self
.cancel_button
.hide()
2995 self
.close_button
.show()
2996 elif action
== 'form': # prepare UI for Receiving
2997 title
= _('Form %s') % title
2998 self
.send_button
.show()
2999 self
.send_and_close_button
.show()
3000 self
.to_label
.show()
3001 self
.to_entry
.show()
3002 self
.reply_button
.hide()
3003 self
.from_label
.hide()
3004 self
.from_entry
.hide()
3005 self
.conversation_scrolledwindow
.hide()
3006 self
.message_scrolledwindow
.hide()
3008 self
.window
.set_title(title
)
3010 def on_cancel_button_clicked(self
, widget
):
3012 self
.window
.destroy()
3014 def on_close_button_clicked(self
, widget
):
3016 self
.window
.destroy()
3018 def update_char_counter(self
, widget
):
3019 characters_no
= self
.message_tv_buffer
.get_char_count()
3020 self
.count_chars_label
.set_text(unicode(characters_no
))
3022 def send_single_message(self
):
3023 if gajim
.connections
[self
.account
].connected
<= 1:
3024 # if offline or connecting
3025 ErrorDialog(_('Connection not available'),
3026 _('Please make sure you are connected with "%s".') % self
.account
)
3028 if isinstance(self
.to
, list):
3029 sender_list
= [i
[0].jid
+ '/' + i
[0].resource
for i
in self
.to
]
3031 sender_list
= [self
.to_entry
.get_text().decode('utf-8')]
3033 for to_whom_jid
in sender_list
:
3034 if to_whom_jid
in self
.completion_dict
:
3035 to_whom_jid
= self
.completion_dict
[to_whom_jid
].jid
3037 to_whom_jid
= helpers
.parse_jid(to_whom_jid
)
3038 except helpers
.InvalidFormat
:
3039 ErrorDialog(_('Invalid Jabber ID'),
3040 _('It is not possible to send a message to %s, this JID is not '
3041 'valid.') % to_whom_jid
)
3044 subject
= self
.subject_entry
.get_text().decode('utf-8')
3045 begin
, end
= self
.message_tv_buffer
.get_bounds()
3046 message
= self
.message_tv_buffer
.get_text(begin
, end
).decode('utf-8')
3048 if '/announce/' in to_whom_jid
:
3049 gajim
.connections
[self
.account
].send_motd(to_whom_jid
, subject
,
3054 session
= self
.session
3056 session
= gajim
.connections
[self
.account
].make_new_session(
3059 if self
.form_widget
:
3060 form_node
= self
.form_widget
.data_form
3063 # FIXME: allow GPG message some day
3064 gajim
.connections
[self
.account
].send_message(to_whom_jid
, message
,
3065 keyID
=None, type_
='normal', subject
=subject
, session
=session
,
3066 form_node
=form_node
)
3068 self
.subject_entry
.set_text('') # we sent ok, clear the subject
3069 self
.message_tv_buffer
.set_text('') # we sent ok, clear the textview
3071 def on_send_button_clicked(self
, widget
):
3072 self
.send_single_message()
3074 def on_reply_button_clicked(self
, widget
):
3075 # we create a new blank window to send and we preset RE: and to jid
3076 self
.subject
= _('RE: %s') % self
.subject
3077 self
.message
= _('%s wrote:\n') % self
.from_whom
+ self
.message
3078 # add > at the begining of each line
3079 self
.message
= self
.message
.replace('\n', '\n> ') + '\n\n'
3080 self
.window
.destroy()
3081 SingleMessageWindow(self
.account
, to
=self
.from_whom
, action
='send',
3082 from_whom
=self
.from_whom
, subject
=self
.subject
, message
=self
.message
,
3083 session
=self
.session
)
3085 def on_send_and_close_button_clicked(self
, widget
):
3086 self
.send_single_message()
3088 self
.window
.destroy()
3090 def on_single_message_window_key_press_event(self
, widget
, event
):
3091 if event
.keyval
== gtk
.keysyms
.Escape
: # ESCAPE
3093 self
.window
.destroy()
3095 class XMLConsoleWindow
:
3096 def __init__(self
, account
):
3097 self
.account
= account
3099 self
.xml
= gtkgui_helpers
.get_gtk_builder('xml_console_window.ui')
3100 self
.window
= self
.xml
.get_object('xml_console_window')
3101 self
.input_textview
= self
.xml
.get_object('input_textview')
3102 self
.stanzas_log_textview
= self
.xml
.get_object('stanzas_log_textview')
3103 self
.input_tv_buffer
= self
.input_textview
.get_buffer()
3104 buffer_
= self
.stanzas_log_textview
.get_buffer()
3105 end_iter
= buffer_
.get_end_iter()
3106 buffer_
.create_mark('end', end_iter
, False)
3108 self
.tagIn
= buffer_
.create_tag('incoming')
3109 color
= gajim
.config
.get('inmsgcolor')
3110 self
.tagIn
.set_property('foreground', color
)
3111 self
.tagInPresence
= buffer_
.create_tag('incoming_presence')
3112 self
.tagInPresence
.set_property('foreground', color
)
3113 self
.tagInMessage
= buffer_
.create_tag('incoming_message')
3114 self
.tagInMessage
.set_property('foreground', color
)
3115 self
.tagInIq
= buffer_
.create_tag('incoming_iq')
3116 self
.tagInIq
.set_property('foreground', color
)
3118 self
.tagOut
= buffer_
.create_tag('outgoing')
3119 color
= gajim
.config
.get('outmsgcolor')
3120 self
.tagOut
.set_property('foreground', color
)
3121 self
.tagOutPresence
= buffer_
.create_tag('outgoing_presence')
3122 self
.tagOutPresence
.set_property('foreground', color
)
3123 self
.tagOutMessage
= buffer_
.create_tag('outgoing_message')
3124 self
.tagOutMessage
.set_property('foreground', color
)
3125 self
.tagOutIq
= buffer_
.create_tag('outgoing_iq')
3126 self
.tagOutIq
.set_property('foreground', color
)
3127 buffer_
.create_tag('') # Default tag
3130 self
.xml
.get_object('enable_checkbutton').set_active(True)
3132 self
.input_textview
.modify_text(
3133 gtk
.STATE_NORMAL
, gtk
.gdk
.color_parse(color
))
3135 if len(gajim
.connections
) > 1:
3136 title
= _('XML Console for %s') % self
.account
3138 title
= _('XML Console')
3140 self
.window
.set_title(title
)
3141 self
.window
.show_all()
3142 gajim
.ged
.register_event_handler('stanza-received', ged
.GUI1
,
3143 self
._nec
_stanza
_received
)
3144 gajim
.ged
.register_event_handler('stanza-sent', ged
.GUI1
,
3145 self
._nec
_stanza
_sent
)
3147 self
.xml
.connect_signals(self
)
3149 def on_xml_console_window_destroy(self
, widget
):
3150 del gajim
.interface
.instances
[self
.account
]['xml_console']
3151 gajim
.ged
.remove_event_handler('stanza-received', ged
.GUI1
,
3152 self
._nec
_stanza
_received
)
3153 gajim
.ged
.remove_event_handler('stanza-sent', ged
.GUI1
,
3154 self
._nec
_stanza
_sent
)
3156 def on_clear_button_clicked(self
, widget
):
3157 buffer_
= self
.stanzas_log_textview
.get_buffer()
3158 buffer_
.set_text('')
3160 def on_enable_checkbutton_toggled(self
, widget
):
3161 self
.enabled
= widget
.get_active()
3163 def on_in_stanza_checkbutton_toggled(self
, widget
):
3164 active
= widget
.get_active()
3165 self
.tagIn
.set_property('invisible', active
)
3166 self
.tagInPresence
.set_property('invisible', active
)
3167 self
.tagInMessage
.set_property('invisible', active
)
3168 self
.tagInIq
.set_property('invisible', active
)
3170 def on_presence_stanza_checkbutton_toggled(self
, widget
):
3171 active
= widget
.get_active()
3172 self
.tagInPresence
.set_property('invisible', active
)
3173 self
.tagOutPresence
.set_property('invisible', active
)
3175 def on_out_stanza_checkbutton_toggled(self
, widget
):
3176 active
= widget
.get_active()
3177 self
.tagOut
.set_property('invisible', active
)
3178 self
.tagOutPresence
.set_property('invisible', active
)
3179 self
.tagOutMessage
.set_property('invisible', active
)
3180 self
.tagOutIq
.set_property('invisible', active
)
3182 def on_message_stanza_checkbutton_toggled(self
, widget
):
3183 active
= widget
.get_active()
3184 self
.tagInMessage
.set_property('invisible', active
)
3185 self
.tagOutMessage
.set_property('invisible', active
)
3187 def on_iq_stanza_checkbutton_toggled(self
, widget
):
3188 active
= widget
.get_active()
3189 self
.tagInIq
.set_property('invisible', active
)
3190 self
.tagOutIq
.set_property('invisible', active
)
3192 def scroll_to_end(self
, ):
3193 parent
= self
.stanzas_log_textview
.get_parent()
3194 buffer_
= self
.stanzas_log_textview
.get_buffer()
3195 end_mark
= buffer_
.get_mark('end')
3198 self
.stanzas_log_textview
.scroll_to_mark(end_mark
, 0, True, 0, 1)
3199 adjustment
= parent
.get_hadjustment()
3200 adjustment
.set_value(0)
3203 def print_stanza(self
, stanza
, kind
):
3204 # kind must be 'incoming' or 'outgoing'
3205 if not self
.enabled
:
3210 buffer = self
.stanzas_log_textview
.get_buffer()
3212 end_iter
= buffer.get_end_iter()
3213 end_rect
= self
.stanzas_log_textview
.get_iter_location(end_iter
)
3214 visible_rect
= self
.stanzas_log_textview
.get_visible_rect()
3215 if end_rect
.y
<= (visible_rect
.y
+ visible_rect
.height
):
3217 end_iter
= buffer.get_end_iter()
3220 if stanza
[1:9] == 'presence':
3222 elif stanza
[1:8] == 'message':
3224 elif stanza
[1:3] == 'iq':
3228 type_
= kind
+ '_' + type_
3230 type_
= kind
# 'incoming' or 'outgoing'
3232 if kind
== 'incoming':
3233 buffer.insert_with_tags_by_name(end_iter
, '<!-- In -->\n', type_
)
3234 elif kind
== 'outgoing':
3235 buffer.insert_with_tags_by_name(end_iter
, '<!-- Out -->\n', type_
)
3236 end_iter
= buffer.get_end_iter()
3237 buffer.insert_with_tags_by_name(end_iter
, stanza
.replace('><', '>\n<') \
3240 gobject
.idle_add(self
.scroll_to_end
)
3242 def _nec_stanza_received(self
, obj
):
3243 if obj
.conn
.name
!= self
.account
:
3245 self
.print_stanza(obj
.stanza_str
, 'incoming')
3247 def _nec_stanza_sent(self
, obj
):
3248 if obj
.conn
.name
!= self
.account
:
3250 self
.print_stanza(obj
.stanza_str
, 'outgoing')
3252 def on_send_button_clicked(self
, widget
):
3253 if gajim
.connections
[self
.account
].connected
<= 1:
3254 # if offline or connecting
3255 ErrorDialog(_('Connection not available'),
3256 _('Please make sure you are connected with "%s".') % \
3259 begin_iter
, end_iter
= self
.input_tv_buffer
.get_bounds()
3260 stanza
= self
.input_tv_buffer
.get_text(begin_iter
, end_iter
).decode(
3263 gajim
.connections
[self
.account
].send_stanza(stanza
)
3264 self
.input_tv_buffer
.set_text('') # we sent ok, clear the textview
3266 def on_presence_button_clicked(self
, widget
):
3267 self
.input_tv_buffer
.set_text(
3268 '<presence><show></show><status></status><priority></priority>'
3271 def on_iq_button_clicked(self
, widget
):
3272 self
.input_tv_buffer
.set_text(
3273 '<iq to="" type=""><query xmlns=""></query></iq>')
3275 def on_message_button_clicked(self
, widget
):
3276 self
.input_tv_buffer
.set_text(
3277 '<message to="" type=""><body></body></message>')
3279 def on_expander_activate(self
, widget
):
3280 if not widget
.get_expanded(): # it's the opposite!
3282 self
.input_textview
.grab_focus()
3284 #Action that can be done with an incoming list of contacts
3285 TRANSLATED_ACTION
= {'add': _('add'), 'modify': _('modify'),
3286 'remove': _('remove')}
3287 class RosterItemExchangeWindow
:
3289 Windows used when someone send you a exchange contact suggestion
3292 def __init__(self
, account
, action
, exchange_list
, jid_from
,
3294 self
.account
= account
3295 self
.action
= action
3296 self
.exchange_list
= exchange_list
3297 self
.message_body
= message_body
3298 self
.jid_from
= jid_from
3302 # Connect to gtk builder
3303 self
.xml
= gtkgui_helpers
.get_gtk_builder(
3304 'roster_item_exchange_window.ui')
3305 self
.window
= self
.xml
.get_object('roster_item_exchange_window')
3308 for widget_to_add
in ['accept_button_label', 'type_label',
3309 'body_scrolledwindow', 'body_textview', 'items_list_treeview']:
3310 self
.__dict
__[widget_to_add
] = self
.xml
.get_object(widget_to_add
)
3313 # self.action can be 'add', 'modify' or 'remove'
3314 self
.type_label
.set_label(
3315 _('<b>%(jid)s</b> would like you to <b>%(action)s</b> some contacts '
3316 'in your roster.') % {'jid': jid_from
,
3317 'action': TRANSLATED_ACTION
[self
.action
]})
3319 buffer_
= self
.body_textview
.get_buffer()
3320 buffer_
.set_text(self
.message_body
)
3322 self
.body_scrolledwindow
.hide()
3324 model
= gtk
.ListStore(bool, str, str, str, str)
3325 self
.items_list_treeview
.set_model(model
)
3327 renderer1
= gtk
.CellRendererToggle()
3328 renderer1
.set_property('activatable', True)
3329 renderer1
.connect('toggled', self
.toggled_callback
)
3330 if self
.action
== 'add':
3332 elif self
.action
== 'modify':
3334 elif self
.action
== 'delete':
3336 self
.items_list_treeview
.insert_column_with_attributes(-1, title
,
3337 renderer1
, active
=0)
3338 renderer2
= gtk
.CellRendererText()
3339 self
.items_list_treeview
.insert_column_with_attributes(-1, _('Jabber ID'),
3341 renderer3
= gtk
.CellRendererText()
3342 self
.items_list_treeview
.insert_column_with_attributes(-1, _('Name'),
3344 renderer4
= gtk
.CellRendererText()
3345 self
.items_list_treeview
.insert_column_with_attributes(-1, _('Groups'),
3349 model
= self
.items_list_treeview
.get_model()
3353 for jid
in self
.exchange_list
:
3356 contact
= gajim
.contacts
.get_contact_with_highest_priority(
3359 is_in_roster
= False
3360 name
= self
.exchange_list
[jid
][0]
3361 num_list
= len(self
.exchange_list
[jid
][1])
3363 for group
in self
.exchange_list
[jid
][1]:
3365 if contact
and not group
in contact
.groups
:
3366 is_in_roster
= False
3367 if current
== num_list
:
3368 groups
= groups
+ group
3370 groups
= groups
+ group
+ ', '
3371 if not is_in_roster
:
3373 iter_
= model
.append()
3374 model
.set(iter_
, 0, True, 1, jid
, 2, name
, 3, groups
)
3376 # Change label for accept_button to action name instead of 'OK'.
3377 self
.accept_button_label
.set_label(_('Add'))
3378 elif action
== 'modify':
3379 for jid
in self
.exchange_list
:
3383 contact
= gajim
.contacts
.get_contact_with_highest_priority(
3385 name
= self
.exchange_list
[jid
][0]
3387 is_in_roster
= False
3390 if name
!= contact
.name
:
3392 num_list
= len(self
.exchange_list
[jid
][1])
3394 for group
in self
.exchange_list
[jid
][1]:
3396 if contact
and not group
in contact
.groups
:
3398 if current
== num_list
:
3399 groups
= groups
+ group
3401 groups
= groups
+ group
+ ', '
3402 if not is_right
and is_in_roster
:
3404 iter_
= model
.append()
3405 model
.set(iter_
, 0, True, 1, jid
, 2, name
, 3, groups
)
3407 # Change label for accept_button to action name instead of 'OK'.
3408 self
.accept_button_label
.set_label(_('Modify'))
3409 elif action
== 'delete':
3410 for jid
in self
.exchange_list
:
3413 contact
= gajim
.contacts
.get_contact_with_highest_priority(
3415 name
= self
.exchange_list
[jid
][0]
3417 is_in_roster
= False
3418 num_list
= len(self
.exchange_list
[jid
][1])
3420 for group
in self
.exchange_list
[jid
][1]:
3422 if current
== num_list
:
3423 groups
= groups
+ group
3425 groups
= groups
+ group
+ ', '
3428 iter_
= model
.append()
3429 model
.set(iter_
, 0, True, 1, jid
, 2, name
, 3, groups
)
3431 # Change label for accept_button to action name instead of 'OK'.
3432 self
.accept_button_label
.set_label(_('Delete'))
3435 self
.window
.show_all()
3436 self
.xml
.connect_signals(self
)
3438 def toggled_callback(self
, cell
, path
):
3439 model
= self
.items_list_treeview
.get_model()
3440 iter_
= model
.get_iter(path
)
3441 model
[iter_
][0] = not cell
.get_active()
3443 def on_accept_button_clicked(self
, widget
):
3444 model
= self
.items_list_treeview
.get_model()
3445 iter_
= model
.get_iter_root()
3446 if self
.action
== 'add':
3452 #remote_jid = model[iter_][1].decode('utf-8')
3453 message
= _('%s suggested me to add you in my roster.'
3455 # keep same groups and same nickname
3456 groups
= model
[iter_
][3].split(', ')
3459 jid
= model
[iter_
][1].decode('utf-8')
3460 if gajim
.jid_is_transport(self
.jid_from
):
3461 gajim
.connections
[self
.account
].automatically_added
.append(
3463 gajim
.interface
.roster
.req_sub(self
, jid
, message
,
3464 self
.account
, groups
=groups
, nickname
=model
[iter_
][2],
3466 iter_
= model
.iter_next(iter_
)
3467 InformationDialog(_('Added %s contacts') % str(a
))
3468 elif self
.action
== 'modify':
3474 jid
= model
[iter_
][1].decode('utf-8')
3475 # keep same groups and same nickname
3476 groups
= model
[iter_
][3].split(', ')
3479 for u
in gajim
.contacts
.get_contact(self
.account
, jid
):
3480 u
.name
= model
[iter_
][2]
3481 gajim
.connections
[self
.account
].update_contact(jid
,
3482 model
[iter_
][2], groups
)
3483 self
.draw_contact(jid
, self
.account
)
3484 # Update opened chat
3485 ctrl
= gajim
.interface
.msg_win_mgr
.get_control(jid
, self
.account
)
3488 win
= gajim
.interface
.msg_win_mgr
.get_window(jid
,
3490 win
.redraw_tab(ctrl
)
3492 iter_
= model
.iter_next(iter_
)
3493 elif self
.action
== 'delete':
3499 jid
= model
[iter_
][1].decode('utf-8')
3500 gajim
.connections
[self
.account
].unsubscribe(jid
)
3501 gajim
.interface
.roster
.remove_contact(jid
, self
.account
)
3502 gajim
.contacts
.remove_jid(self
.account
, jid
)
3503 iter_
= model
.iter_next(iter_
)
3504 InformationDialog(_('Removed %s contacts') % str(a
))
3505 self
.window
.destroy()
3507 def on_cancel_button_clicked(self
, widget
):
3508 self
.window
.destroy()
3511 class ItemArchivingPreferencesWindow
:
3512 otr_name
= ('approve', 'concede', 'forbid', 'oppose', 'prefer', 'require')
3513 otr_index
= dict([(j
, i
) for i
, j
in enumerate(otr_name
)])
3514 save_name
= ('body', 'false', 'message', 'stream')
3515 save_index
= dict([(j
, i
) for i
, j
in enumerate(save_name
)])
3517 def __init__(self
, account
, item
):
3518 self
.account
= account
3520 if self
.item
and self
.item
!= 'Default':
3521 self
.item_config
= gajim
.connections
[self
.account
].items
[self
.item
]
3523 self
.item_config
= gajim
.connections
[self
.account
].default
3526 # Connect to gtk builder
3527 self
.xml
= gtkgui_helpers
.get_gtk_builder(
3528 'item_archiving_preferences_window.ui')
3529 self
.window
= self
.xml
.get_object('item_archiving_preferences_window')
3532 for widget_to_add
in ('jid_entry', 'expire_entry', 'otr_combobox',
3533 'save_combobox', 'cancel_button', 'ok_button', 'progressbar'):
3534 self
.__dict
__[widget_to_add
] = self
.xml
.get_object(widget_to_add
)
3537 self
.jid_entry
.set_text(self
.item
)
3538 expire_value
= self
.item_config
['expire'] or ''
3539 self
.otr_combobox
.set_active(self
.otr_index
[self
.item_config
['otr']])
3540 self
.save_combobox
.set_active(
3541 self
.save_index
[self
.item_config
['save']])
3542 self
.expire_entry
.set_text(expire_value
)
3544 self
.window
.set_title(_('Archiving Preferences for %s') % self
.account
)
3546 self
.window
.show_all()
3547 self
.progressbar
.hide()
3548 self
.xml
.connect_signals(self
)
3550 def update_progressbar(self
):
3552 self
.progressbar
.pulse()
3556 def on_otr_combobox_changed(self
, widget
):
3557 otr
= self
.otr_name
[self
.otr_combobox
.get_active()]
3558 if otr
== 'require':
3559 self
.save_combobox
.set_active(self
.save_index
['false'])
3561 def on_ok_button_clicked(self
, widget
):
3562 # Return directly if operation in progress
3566 item
= self
.jid_entry
.get_text()
3567 otr
= self
.otr_name
[self
.otr_combobox
.get_active()]
3568 save
= self
.save_name
[self
.save_combobox
.get_active()]
3569 expire
= self
.expire_entry
.get_text()
3571 if self
.item
!= 'Default':
3573 item
= helpers
.parse_jid(item
)
3574 except helpers
.InvalidFormat
, s
:
3575 pritext
= _('Invalid User ID')
3576 ErrorDialog(pritext
, str(s
))
3581 if int(expire
) < 0 or str(int(expire
)) != expire
:
3584 pritext
= _('Invalid expire value')
3585 sectext
= _('Expire must be a valid positive integer.')
3586 ErrorDialog(pritext
, sectext
)
3589 if not (item
== self
.item
and expire
== self
.item_config
['expire'] and
3590 otr
== self
.item_config
['otr'] and save
== self
.item_config
['save']):
3591 if not self
.item
or self
.item
== item
:
3592 if self
.item
== 'Default':
3593 self
.waiting
= 'default'
3594 gajim
.connections
[self
.account
].set_default(
3597 self
.waiting
= 'item'
3598 gajim
.connections
[self
.account
].append_or_update_item(
3599 item
, otr
, save
, expire
)
3601 self
.waiting
= 'item'
3602 gajim
.connections
[self
.account
].append_or_update_item(
3603 item
, otr
, save
, expire
)
3604 gajim
.connections
[self
.account
].remove_item(self
.item
)
3605 self
.launch_progressbar()
3606 #self.window.destroy()
3608 def on_cancel_button_clicked(self
, widget
):
3609 self
.window
.destroy()
3611 def on_item_archiving_preferences_window_destroy(self
, widget
):
3613 key_name
= 'edit_item_archiving_preferences_%s' % self
.item
3615 key_name
= 'new_item_archiving_preferences'
3616 if key_name
in gajim
.interface
.instances
[self
.account
]:
3617 del gajim
.interface
.instances
[self
.account
][key_name
]
3619 def launch_progressbar(self
):
3620 self
.progressbar
.show()
3621 self
.update_progressbar_timeout_id
= gobject
.timeout_add(
3622 100, self
.update_progressbar
)
3624 def response_arrived(self
, data
):
3626 self
.window
.destroy()
3628 def error_arrived(self
, error
):
3631 self
.progressbar
.hide()
3632 pritext
= _('There is an error with the form')
3634 ErrorDialog(pritext
, sectext
)
3637 class ArchivingPreferencesWindow
:
3638 auto_name
= ('false', 'true')
3639 auto_index
= dict([(j
, i
) for i
, j
in enumerate(auto_name
)])
3640 method_foo_name
= ('prefer', 'concede', 'forbid')
3641 method_foo_index
= dict([(j
, i
) for i
, j
in enumerate(method_foo_name
)])
3643 def __init__(self
, account
):
3644 self
.account
= account
3648 self
.xml
= gtkgui_helpers
.get_gtk_builder(
3649 'archiving_preferences_window.ui')
3650 self
.window
= self
.xml
.get_object('archiving_preferences_window')
3653 for widget_to_add
in ('auto_combobox', 'method_auto_combobox',
3654 'method_local_combobox', 'method_manual_combobox', 'close_button',
3655 'item_treeview', 'item_notebook', 'otr_combobox', 'save_combobox',
3656 'expire_entry', 'remove_button', 'edit_button'):
3657 self
.__dict
__[widget_to_add
] = self
.xml
.get_object(widget_to_add
)
3659 self
.auto_combobox
.set_active(
3660 self
.auto_index
[gajim
.connections
[self
.account
].auto
])
3661 self
.method_auto_combobox
.set_active(
3662 self
.method_foo_index
[gajim
.connections
[self
.account
].method_auto
])
3663 self
.method_local_combobox
.set_active(
3664 self
.method_foo_index
[gajim
.connections
[self
.account
].method_local
])
3665 self
.method_manual_combobox
.set_active(
3666 self
.method_foo_index
[gajim
.connections
[self
.account
].\
3669 model
= gtk
.ListStore(str, str, str, str)
3670 self
.item_treeview
.set_model(model
)
3671 col
= gtk
.TreeViewColumn('jid')
3672 self
.item_treeview
.append_column(col
)
3673 renderer
= gtk
.CellRendererText()
3674 col
.pack_start(renderer
, True)
3675 col
.set_attributes(renderer
, text
=0)
3677 col
= gtk
.TreeViewColumn('expire')
3678 col
.pack_start(renderer
, True)
3679 col
.set_attributes(renderer
, text
=1)
3680 self
.item_treeview
.append_column(col
)
3682 col
= gtk
.TreeViewColumn('otr')
3683 col
.pack_start(renderer
, True)
3684 col
.set_attributes(renderer
, text
=2)
3685 self
.item_treeview
.append_column(col
)
3687 col
= gtk
.TreeViewColumn('save')
3688 col
.pack_start(renderer
, True)
3689 col
.set_attributes(renderer
, text
=3)
3690 self
.item_treeview
.append_column(col
)
3694 self
.current_item
= None
3696 def sort_items(model
, iter1
, iter2
):
3697 item1
= model
.get_value(iter1
, 0)
3698 item2
= model
.get_value(iter2
, 0)
3699 if item1
== 'Default':
3701 if item2
== 'Default':
3704 if '@' not in item2
:
3712 # item1 == item2 ? WTF?
3715 model
.set_sort_column_id(0, gtk
.SORT_ASCENDING
)
3716 model
.set_sort_func(0, sort_items
)
3718 self
.remove_button
.set_sensitive(False)
3719 self
.edit_button
.set_sensitive(False)
3721 self
.window
.set_title(_('Archiving Preferences for %s') % self
.account
)
3723 gajim
.ged
.register_event_handler(
3724 'archiving-preferences-changed-received', ged
.GUI1
,
3725 self
._nec
_archiving
_changed
_received
)
3726 gajim
.ged
.register_event_handler('archiving-error-received', ged
.GUI1
,
3727 self
._nec
_archiving
_error
)
3729 self
.window
.show_all()
3731 self
.xml
.connect_signals(self
)
3733 def on_add_item_button_clicked(self
, widget
):
3734 key_name
= 'new_item_archiving_preferences'
3735 if key_name
in gajim
.interface
.instances
[self
.account
]:
3736 gajim
.interface
.instances
[self
.account
][key_name
].window
.present()
3738 gajim
.interface
.instances
[self
.account
][key_name
] = \
3739 ItemArchivingPreferencesWindow(self
.account
, '')
3741 def on_remove_item_button_clicked(self
, widget
):
3742 if not self
.current_item
:
3745 self
.waiting
.append('itemremove')
3746 sel
= self
.item_treeview
.get_selection()
3747 (model
, iter_
) = sel
.get_selected()
3748 gajim
.connections
[self
.account
].remove_item(model
[iter_
][0])
3750 self
.remove_button
.set_sensitive(False)
3751 self
.edit_button
.set_sensitive(False)
3753 def on_edit_item_button_clicked(self
, widget
):
3754 if not self
.current_item
:
3757 key_name
= 'edit_item_archiving_preferences_%s' % self
.current_item
3758 if key_name
in gajim
.interface
.instances
[self
.account
]:
3759 gajim
.interface
.instances
[self
.account
][key_name
].window
.present()
3761 gajim
.interface
.instances
[self
.account
][key_name
] = \
3762 ItemArchivingPreferencesWindow(self
.account
, self
.current_item
)
3764 def on_item_treeview_cursor_changed(self
, widget
):
3765 sel
= self
.item_treeview
.get_selection()
3766 (model
, iter_
) = sel
.get_selected()
3769 item
= model
[iter_
][0]
3770 if self
.current_item
and self
.current_item
== item
:
3773 self
.current_item
= item
3774 if self
.current_item
== 'Default':
3775 self
.remove_button
.set_sensitive(False)
3776 self
.edit_button
.set_sensitive(True)
3777 elif self
.current_item
:
3778 self
.remove_button
.set_sensitive(True)
3779 self
.edit_button
.set_sensitive(True)
3781 self
.remove_button
.set_sensitive(False)
3782 self
.edit_button
.set_sensitive(False)
3784 def on_auto_combobox_changed(self
, widget
):
3785 save
= self
.auto_name
[widget
.get_active()]
3786 gajim
.connections
[self
.account
].set_auto(save
)
3788 def on_method_foo_combobox_changed(self
, widget
):
3789 # We retrieve method type from widget name
3790 # ('foo' in 'method_foo_combobox')
3791 method_type
= widget
.name
.split('_')[1]
3792 use
= self
.method_foo_name
[widget
.get_active()]
3793 self
.waiting
.append('method_%s' % method_type
)
3794 gajim
.connections
[self
.account
].set_method(method_type
, use
)
3796 def get_child_window(self
):
3797 edit_key_name
= 'edit_item_archiving_preferences_%s' % self
.current_item
3798 new_key_name
= 'new_item_archiving_preferences'
3800 if edit_key_name
in gajim
.interface
.instances
[self
.account
]:
3801 return gajim
.interface
.instances
[self
.account
][edit_key_name
]
3803 if new_key_name
in gajim
.interface
.instances
[self
.account
]:
3804 return gajim
.interface
.instances
[self
.account
][new_key_name
]
3806 def _nec_archiving_changed_received(self
, obj
):
3807 if obj
.conn
.name
!= self
.account
:
3809 for key
in ('auto', 'method_auto', 'method_local', 'method_manual'):
3810 if key
in obj
.conf
and key
in self
.waiting
:
3811 self
.waiting
.remove(key
)
3812 if 'default' in obj
.conf
:
3813 key_name
= 'edit_item_archiving_preferences_%s' % \
3815 if key_name
in gajim
.interface
.instances
[self
.account
]:
3816 gajim
.interface
.instances
[self
.account
][key_name
].\
3817 response_arrived(obj
.conf
['default'])
3818 self
.fill_items(True)
3819 for jid
, pref
in obj
.new_items
.items():
3820 child
= self
.get_child_window()
3822 is_new
= not child
.item
3823 child
.response_arrived(pref
)
3825 model
= self
.item_treeview
.get_model()
3826 model
.append((jid
, pref
['expire'], pref
['otr'],
3829 self
.fill_items(True)
3830 if 'itemremove' in self
.waiting
and obj
.removed_items
:
3831 self
.waiting
.remove('itemremove')
3832 self
.fill_items(True)
3834 def fill_items(self
, clear
=False):
3835 model
= self
.item_treeview
.get_model()
3838 default_config
= gajim
.connections
[self
.account
].default
3839 expire_value
= default_config
['expire'] or ''
3840 model
.append(('Default', expire_value
,
3841 default_config
['otr'], default_config
['save']))
3842 for item
, item_config
in \
3843 gajim
.connections
[self
.account
].items
.items():
3844 expire_value
= item_config
['expire'] or ''
3845 model
.append((item
, expire_value
, item_config
['otr'],
3846 item_config
['save']))
3848 def _nec_archiving_error(self
, obj
):
3849 if obj
.conn
.name
!= self
.account
:
3852 pritext
= _('There is an error')
3853 sectext
= obj
.error_msg
3854 ErrorDialog(pritext
, sectext
)
3857 child
= self
.get_child_window()
3859 child
.error_arrived(obj
.error_msg
)
3861 def on_close_button_clicked(self
, widget
):
3862 self
.window
.destroy()
3864 def on_archiving_preferences_window_destroy(self
, widget
):
3865 gajim
.ged
.remove_event_handler(
3866 'archiving-preferences-changed-received', ged
.GUI1
,
3867 self
._nec
_archiving
_changed
_received
)
3868 gajim
.ged
.remove_event_handler('archiving-error-received', ged
.GUI1
,
3869 self
._nec
_archiving
_error
)
3870 if 'archiving_preferences' in gajim
.interface
.instances
[self
.account
]:
3871 del gajim
.interface
.instances
[self
.account
]['archiving_preferences']
3874 class PrivacyListWindow
:
3876 Window that is used for creating NEW or EDITING already there privacy lists
3879 def __init__(self
, account
, privacy_list_name
, action
):
3880 '''action is 'EDIT' or 'NEW' depending on if we create a new priv list
3881 or edit an already existing one'''
3882 self
.account
= account
3883 self
.privacy_list_name
= privacy_list_name
3885 # Dicts and Default Values
3886 self
.active_rule
= ''
3887 self
.global_rules
= {}
3888 self
.list_of_groups
= {}
3892 # Default Edit Values
3893 self
.edit_rule_type
= 'jid'
3894 self
.allow_deny
= 'allow'
3896 # Connect to gtk builder
3897 self
.xml
= gtkgui_helpers
.get_gtk_builder('privacy_list_window.ui')
3898 self
.window
= self
.xml
.get_object('privacy_list_edit_window')
3902 for widget_to_add
in ('title_hbox', 'privacy_lists_title_label',
3903 'list_of_rules_label', 'add_edit_rule_label', 'delete_open_buttons_hbox',
3904 'privacy_list_active_checkbutton', 'privacy_list_default_checkbutton',
3905 'list_of_rules_combobox', 'delete_open_buttons_hbox',
3906 'delete_rule_button', 'open_rule_button', 'edit_allow_radiobutton',
3907 'edit_deny_radiobutton', 'edit_type_jabberid_radiobutton',
3908 'edit_type_jabberid_entry', 'edit_type_group_radiobutton',
3909 'edit_type_group_combobox', 'edit_type_subscription_radiobutton',
3910 'edit_type_subscription_combobox', 'edit_type_select_all_radiobutton',
3911 'edit_queries_send_checkbutton', 'edit_send_messages_checkbutton',
3912 'edit_view_status_checkbutton', 'edit_all_checkbutton',
3913 'edit_order_spinbutton', 'new_rule_button', 'save_rule_button',
3914 'privacy_list_refresh_button', 'privacy_list_close_button',
3915 'edit_send_status_checkbutton', 'add_edit_vbox',
3916 'privacy_list_active_checkbutton', 'privacy_list_default_checkbutton'):
3917 self
.__dict
__[widget_to_add
] = self
.xml
.get_object(widget_to_add
)
3919 self
.privacy_lists_title_label
.set_label(
3920 _('Privacy List <b><i>%s</i></b>') % \
3921 gobject
.markup_escape_text(self
.privacy_list_name
))
3923 if len(gajim
.connections
) > 1:
3924 title
= _('Privacy List for %s') % self
.account
3926 title
= _('Privacy List')
3928 self
.delete_rule_button
.set_sensitive(False)
3929 self
.open_rule_button
.set_sensitive(False)
3930 self
.privacy_list_active_checkbutton
.set_sensitive(False)
3931 self
.privacy_list_default_checkbutton
.set_sensitive(False)
3932 self
.list_of_rules_combobox
.set_sensitive(False)
3934 # set jabber id completion
3935 jids_list_store
= gtk
.ListStore(gobject
.TYPE_STRING
)
3936 for jid
in gajim
.contacts
.get_jid_list(self
.account
):
3937 jids_list_store
.append([jid
])
3938 jid_entry_completion
= gtk
.EntryCompletion()
3939 jid_entry_completion
.set_text_column(0)
3940 jid_entry_completion
.set_model(jids_list_store
)
3941 jid_entry_completion
.set_popup_completion(True)
3942 self
.edit_type_jabberid_entry
.set_completion(jid_entry_completion
)
3943 if action
== 'EDIT':
3944 self
.refresh_rules()
3947 for group
in gajim
.groups
[self
.account
]:
3948 self
.list_of_groups
[group
] = count
3950 self
.edit_type_group_combobox
.append_text(group
)
3951 self
.edit_type_group_combobox
.set_active(0)
3953 self
.window
.set_title(title
)
3955 gajim
.ged
.register_event_handler('privacy-list-received', ged
.GUI1
,
3956 self
._nec
_privacy
_list
_received
)
3957 gajim
.ged
.register_event_handler('privacy-list-active-default',
3958 ged
.GUI1
, self
._nec
_privacy
_list
_active
_default
)
3960 self
.window
.show_all()
3961 self
.add_edit_vbox
.hide()
3963 self
.xml
.connect_signals(self
)
3965 def on_privacy_list_edit_window_destroy(self
, widget
):
3966 key_name
= 'privacy_list_%s' % self
.privacy_list_name
3967 if key_name
in gajim
.interface
.instances
[self
.account
]:
3968 del gajim
.interface
.instances
[self
.account
][key_name
]
3969 gajim
.ged
.remove_event_handler('privacy-list-received', ged
.GUI1
,
3970 self
._nec
_privacy
_list
_received
)
3971 gajim
.ged
.remove_event_handler('privacy-list-active-default',
3972 ged
.GUI1
, self
._nec
_privacy
_list
_active
_default
)
3974 def _nec_privacy_list_active_default(self
, obj
):
3975 if obj
.conn
.name
!= self
.account
:
3977 if obj
.active_list
== self
.privacy_list_name
:
3978 self
.privacy_list_active_checkbutton
.set_active(True)
3980 self
.privacy_list_active_checkbutton
.set_active(False)
3981 if obj
.default_list
== self
.privacy_list_name
:
3982 self
.privacy_list_default_checkbutton
.set_active(True)
3984 self
.privacy_list_default_checkbutton
.set_active(False)
3986 def privacy_list_received(self
, rules
):
3987 self
.list_of_rules_combobox
.get_model().clear()
3988 self
.global_rules
= {}
3991 text_item
= _('Order: %(order)s, action: %(action)s, type: %(type)s'
3992 ', value: %(value)s') % {'order': rule
['order'],
3993 'action': rule
['action'], 'type': rule
['type'],
3994 'value': rule
['value']}
3996 text_item
= _('Order: %(order)s, action: %(action)s') % \
3997 {'order': rule
['order'], 'action': rule
['action']}
3998 if int(rule
['order']) > self
.max_order
:
3999 self
.max_order
= int(rule
['order'])
4000 self
.global_rules
[text_item
] = rule
4001 self
.list_of_rules_combobox
.append_text(text_item
)
4003 self
.title_hbox
.set_sensitive(False)
4004 self
.list_of_rules_combobox
.set_sensitive(False)
4005 self
.delete_rule_button
.set_sensitive(False)
4006 self
.open_rule_button
.set_sensitive(False)
4007 self
.privacy_list_active_checkbutton
.set_sensitive(False)
4008 self
.privacy_list_default_checkbutton
.set_sensitive(False)
4010 self
.list_of_rules_combobox
.set_active(0)
4011 self
.title_hbox
.set_sensitive(True)
4012 self
.list_of_rules_combobox
.set_sensitive(True)
4013 self
.delete_rule_button
.set_sensitive(True)
4014 self
.open_rule_button
.set_sensitive(True)
4015 self
.privacy_list_active_checkbutton
.set_sensitive(True)
4016 self
.privacy_list_default_checkbutton
.set_sensitive(True)
4018 gajim
.connections
[self
.account
].get_active_default_lists()
4020 def _nec_privacy_list_received(self
, obj
):
4021 if obj
.conn
.name
!= self
.account
:
4023 if obj
.list_name
!= self
.privacy_list_name
:
4025 self
.privacy_list_received(obj
.rules
)
4027 def refresh_rules(self
):
4028 gajim
.connections
[self
.account
].get_privacy_list(self
.privacy_list_name
)
4030 def on_delete_rule_button_clicked(self
, widget
):
4032 for rule
in self
.global_rules
:
4033 if rule
!= self
.list_of_rules_combobox
.get_active_text():
4034 tags
.append(self
.global_rules
[rule
])
4035 gajim
.connections
[self
.account
].set_privacy_list(
4036 self
.privacy_list_name
, tags
)
4037 self
.privacy_list_received(tags
)
4038 self
.add_edit_vbox
.hide()
4039 if not tags
: # we removed latest rule
4040 if 'privacy_lists' in gajim
.interface
.instances
[self
.account
]:
4041 win
= gajim
.interface
.instances
[self
.account
]['privacy_lists']
4042 win
.remove_privacy_list_from_combobox(self
.privacy_list_name
)
4045 def on_open_rule_button_clicked(self
, widget
):
4046 self
.add_edit_rule_label
.set_label(
4047 _('<b>Edit a rule</b>'))
4048 active_num
= self
.list_of_rules_combobox
.get_active()
4049 if active_num
== -1:
4050 self
.active_rule
= ''
4052 self
.active_rule
= \
4053 self
.list_of_rules_combobox
.get_active_text().decode('utf-8')
4054 if self
.active_rule
!= '':
4055 rule_info
= self
.global_rules
[self
.active_rule
]
4056 self
.edit_order_spinbutton
.set_value(int(rule_info
['order']))
4057 if 'type' in rule_info
:
4058 if rule_info
['type'] == 'jid':
4059 self
.edit_type_jabberid_radiobutton
.set_active(True)
4060 self
.edit_type_jabberid_entry
.set_text(rule_info
['value'])
4061 elif rule_info
['type'] == 'group':
4062 self
.edit_type_group_radiobutton
.set_active(True)
4063 if rule_info
['value'] in self
.list_of_groups
:
4064 self
.edit_type_group_combobox
.set_active(
4065 self
.list_of_groups
[rule_info
['value']])
4067 self
.edit_type_group_combobox
.set_active(0)
4068 elif rule_info
['type'] == 'subscription':
4069 self
.edit_type_subscription_radiobutton
.set_active(True)
4070 sub_value
= rule_info
['value']
4071 if sub_value
== 'none':
4072 self
.edit_type_subscription_combobox
.set_active(0)
4073 elif sub_value
== 'both':
4074 self
.edit_type_subscription_combobox
.set_active(1)
4075 elif sub_value
== 'from':
4076 self
.edit_type_subscription_combobox
.set_active(2)
4077 elif sub_value
== 'to':
4078 self
.edit_type_subscription_combobox
.set_active(3)
4080 self
.edit_type_select_all_radiobutton
.set_active(True)
4082 self
.edit_type_select_all_radiobutton
.set_active(True)
4083 self
.edit_send_messages_checkbutton
.set_active(False)
4084 self
.edit_queries_send_checkbutton
.set_active(False)
4085 self
.edit_view_status_checkbutton
.set_active(False)
4086 self
.edit_send_status_checkbutton
.set_active(False)
4087 self
.edit_all_checkbutton
.set_active(False)
4088 if not rule_info
['child']:
4089 self
.edit_all_checkbutton
.set_active(True)
4091 if 'presence-out' in rule_info
['child']:
4092 self
.edit_send_status_checkbutton
.set_active(True)
4093 if 'presence-in' in rule_info
['child']:
4094 self
.edit_view_status_checkbutton
.set_active(True)
4095 if 'iq' in rule_info
['child']:
4096 self
.edit_queries_send_checkbutton
.set_active(True)
4097 if 'message' in rule_info
['child']:
4098 self
.edit_send_messages_checkbutton
.set_active(True)
4100 if rule_info
['action'] == 'allow':
4101 self
.edit_allow_radiobutton
.set_active(True)
4103 self
.edit_deny_radiobutton
.set_active(True)
4104 self
.add_edit_vbox
.show()
4106 def on_edit_all_checkbutton_toggled(self
, widget
):
4107 if widget
.get_active():
4108 self
.edit_send_messages_checkbutton
.set_active(True)
4109 self
.edit_queries_send_checkbutton
.set_active(True)
4110 self
.edit_view_status_checkbutton
.set_active(True)
4111 self
.edit_send_status_checkbutton
.set_active(True)
4112 self
.edit_send_messages_checkbutton
.set_sensitive(False)
4113 self
.edit_queries_send_checkbutton
.set_sensitive(False)
4114 self
.edit_view_status_checkbutton
.set_sensitive(False)
4115 self
.edit_send_status_checkbutton
.set_sensitive(False)
4117 self
.edit_send_messages_checkbutton
.set_active(False)
4118 self
.edit_queries_send_checkbutton
.set_active(False)
4119 self
.edit_view_status_checkbutton
.set_active(False)
4120 self
.edit_send_status_checkbutton
.set_active(False)
4121 self
.edit_send_messages_checkbutton
.set_sensitive(True)
4122 self
.edit_queries_send_checkbutton
.set_sensitive(True)
4123 self
.edit_view_status_checkbutton
.set_sensitive(True)
4124 self
.edit_send_status_checkbutton
.set_sensitive(True)
4126 def on_privacy_list_active_checkbutton_toggled(self
, widget
):
4127 if widget
.get_active():
4128 gajim
.connections
[self
.account
].set_active_list(
4129 self
.privacy_list_name
)
4131 gajim
.connections
[self
.account
].set_active_list(None)
4133 def on_privacy_list_default_checkbutton_toggled(self
, widget
):
4134 if widget
.get_active():
4135 gajim
.connections
[self
.account
].set_default_list(
4136 self
.privacy_list_name
)
4138 gajim
.connections
[self
.account
].set_default_list(None)
4140 def on_new_rule_button_clicked(self
, widget
):
4142 self
.add_edit_vbox
.show()
4144 def reset_fields(self
):
4145 self
.edit_type_jabberid_entry
.set_text('')
4146 self
.edit_allow_radiobutton
.set_active(True)
4147 self
.edit_type_jabberid_radiobutton
.set_active(True)
4148 self
.active_rule
= ''
4149 self
.edit_send_messages_checkbutton
.set_active(False)
4150 self
.edit_queries_send_checkbutton
.set_active(False)
4151 self
.edit_view_status_checkbutton
.set_active(False)
4152 self
.edit_send_status_checkbutton
.set_active(False)
4153 self
.edit_all_checkbutton
.set_active(False)
4154 self
.edit_order_spinbutton
.set_value(self
.max_order
+ 1)
4155 self
.edit_type_group_combobox
.set_active(0)
4156 self
.edit_type_subscription_combobox
.set_active(0)
4157 self
.add_edit_rule_label
.set_label(
4158 _('<b>Add a rule</b>'))
4160 def get_current_tags(self
):
4161 if self
.edit_type_jabberid_radiobutton
.get_active():
4163 edit_value
= self
.edit_type_jabberid_entry
.get_text()
4164 elif self
.edit_type_group_radiobutton
.get_active():
4166 edit_value
= self
.edit_type_group_combobox
.get_active_text()
4167 elif self
.edit_type_subscription_radiobutton
.get_active():
4168 edit_type
= 'subscription'
4169 subs
= ['none', 'both', 'from', 'to']
4170 edit_value
= subs
[self
.edit_type_subscription_combobox
.get_active()]
4171 elif self
.edit_type_select_all_radiobutton
.get_active():
4174 edit_order
= str(self
.edit_order_spinbutton
.get_value_as_int())
4175 if self
.edit_allow_radiobutton
.get_active():
4180 if not self
.edit_all_checkbutton
.get_active():
4181 if self
.edit_send_messages_checkbutton
.get_active():
4182 child
.append('message')
4183 if self
.edit_queries_send_checkbutton
.get_active():
4185 if self
.edit_send_status_checkbutton
.get_active():
4186 child
.append('presence-out')
4187 if self
.edit_view_status_checkbutton
.get_active():
4188 child
.append('presence-in')
4190 return {'order': edit_order
, 'action': edit_deny
,
4191 'type': edit_type
, 'value': edit_value
, 'child': child
}
4192 return {'order': edit_order
, 'action': edit_deny
, 'child': child
}
4194 def on_save_rule_button_clicked(self
, widget
):
4196 current_tags
= self
.get_current_tags()
4197 if int(current_tags
['order']) > self
.max_order
:
4198 self
.max_order
= int(current_tags
['order'])
4199 if self
.active_rule
== '':
4200 tags
.append(current_tags
)
4202 for rule
in self
.global_rules
:
4203 if rule
!= self
.active_rule
:
4204 tags
.append(self
.global_rules
[rule
])
4206 tags
.append(current_tags
)
4208 gajim
.connections
[self
.account
].set_privacy_list(
4209 self
.privacy_list_name
, tags
)
4210 self
.refresh_rules()
4211 self
.add_edit_vbox
.hide()
4212 if 'privacy_lists' in gajim
.interface
.instances
[self
.account
]:
4213 win
= gajim
.interface
.instances
[self
.account
]['privacy_lists']
4214 win
.add_privacy_list_to_combobox(self
.privacy_list_name
)
4217 def on_list_of_rules_combobox_changed(self
, widget
):
4218 self
.add_edit_vbox
.hide()
4220 def on_edit_type_radiobutton_changed(self
, widget
, radiobutton
):
4221 active_bool
= widget
.get_active()
4223 self
.edit_rule_type
= radiobutton
4225 def on_edit_allow_radiobutton_changed(self
, widget
, radiobutton
):
4226 active_bool
= widget
.get_active()
4228 self
.allow_deny
= radiobutton
4230 def on_close_button_clicked(self
, widget
):
4231 self
.window
.destroy()
4233 class PrivacyListsWindow
:
4235 Window that is the main window for Privacy Lists; we can list there the
4236 privacy lists and ask to create a new one or edit an already there one
4238 def __init__(self
, account
):
4239 self
.account
= account
4240 self
.privacy_lists_save
= []
4242 self
.xml
= gtkgui_helpers
.get_gtk_builder('privacy_lists_window.ui')
4244 self
.window
= self
.xml
.get_object('privacy_lists_first_window')
4245 for widget_to_add
in ('list_of_privacy_lists_combobox',
4246 'delete_privacy_list_button', 'open_privacy_list_button',
4247 'new_privacy_list_button', 'new_privacy_list_entry',
4248 'privacy_lists_refresh_button', 'close_privacy_lists_window_button'):
4249 self
.__dict
__[widget_to_add
] = self
.xml
.get_object(widget_to_add
)
4251 self
.draw_privacy_lists_in_combobox([])
4252 self
.privacy_lists_refresh()
4256 if len(gajim
.connections
) > 1:
4257 title
= _('Privacy Lists for %s') % self
.account
4259 title
= _('Privacy Lists')
4261 self
.window
.set_title(title
)
4263 gajim
.ged
.register_event_handler('privacy-lists-received', ged
.GUI1
,
4264 self
._nec
_privacy
_lists
_received
)
4265 gajim
.ged
.register_event_handler('privacy-lists-removed', ged
.GUI1
,
4266 self
._nec
_privacy
_lists
_removed
)
4268 self
.window
.show_all()
4270 self
.xml
.connect_signals(self
)
4272 def on_privacy_lists_first_window_destroy(self
, widget
):
4273 if 'privacy_lists' in gajim
.interface
.instances
[self
.account
]:
4274 del gajim
.interface
.instances
[self
.account
]['privacy_lists']
4275 gajim
.ged
.remove_event_handler('privacy-lists-received', ged
.GUI1
,
4276 self
._nec
_privacy
_lists
_received
)
4277 gajim
.ged
.remove_event_handler('privacy-lists-removed', ged
.GUI1
,
4278 self
._nec
_privacy
_lists
_removed
)
4280 def remove_privacy_list_from_combobox(self
, privacy_list
):
4281 if privacy_list
not in self
.privacy_lists_save
:
4283 privacy_list_index
= self
.privacy_lists_save
.index(privacy_list
)
4284 self
.list_of_privacy_lists_combobox
.remove_text(privacy_list_index
)
4285 self
.privacy_lists_save
.remove(privacy_list
)
4287 def add_privacy_list_to_combobox(self
, privacy_list
):
4288 if privacy_list
in self
.privacy_lists_save
:
4290 self
.list_of_privacy_lists_combobox
.append_text(privacy_list
)
4291 self
.privacy_lists_save
.append(privacy_list
)
4293 def draw_privacy_lists_in_combobox(self
, privacy_lists
):
4294 self
.list_of_privacy_lists_combobox
.set_active(-1)
4295 self
.list_of_privacy_lists_combobox
.get_model().clear()
4296 self
.privacy_lists_save
= []
4297 for add_item
in privacy_lists
:
4298 self
.add_privacy_list_to_combobox(add_item
)
4301 def draw_widgets(self
):
4302 if len(self
.privacy_lists_save
) == 0:
4303 self
.list_of_privacy_lists_combobox
.set_sensitive(False)
4304 self
.open_privacy_list_button
.set_sensitive(False)
4305 self
.delete_privacy_list_button
.set_sensitive(False)
4307 self
.list_of_privacy_lists_combobox
.set_sensitive(True)
4308 self
.list_of_privacy_lists_combobox
.set_active(0)
4309 self
.open_privacy_list_button
.set_sensitive(True)
4310 self
.delete_privacy_list_button
.set_sensitive(True)
4312 def on_close_button_clicked(self
, widget
):
4313 self
.window
.destroy()
4315 def on_delete_privacy_list_button_clicked(self
, widget
):
4316 active_list
= self
.privacy_lists_save
[
4317 self
.list_of_privacy_lists_combobox
.get_active()]
4318 gajim
.connections
[self
.account
].del_privacy_list(active_list
)
4320 def privacy_list_removed(self
, active_list
):
4321 self
.privacy_lists_save
.remove(active_list
)
4322 self
.privacy_lists_received({'lists': self
.privacy_lists_save
})
4324 def _nec_privacy_lists_removed(self
, obj
):
4325 if obj
.conn
.name
!= self
.account
:
4327 self
.privacy_list_removed(obj
.lists_list
)
4329 def privacy_lists_received(self
, lists
):
4333 for privacy_list
in lists
['lists']:
4334 privacy_lists
.append(privacy_list
)
4335 self
.draw_privacy_lists_in_combobox(privacy_lists
)
4337 def _nec_privacy_lists_received(self
, obj
):
4338 if obj
.conn
.name
!= self
.account
:
4340 self
.privacy_lists_received(obj
.lists_list
)
4342 def privacy_lists_refresh(self
):
4343 gajim
.connections
[self
.account
].get_privacy_lists()
4345 def on_new_privacy_list_button_clicked(self
, widget
):
4346 name
= self
.new_privacy_list_entry
.get_text()
4348 ErrorDialog(_('Invalid List Name'),
4349 _('You must enter a name to create a privacy list.'))
4351 key_name
= 'privacy_list_%s' % name
4352 if key_name
in gajim
.interface
.instances
[self
.account
]:
4353 gajim
.interface
.instances
[self
.account
][key_name
].window
.present()
4355 gajim
.interface
.instances
[self
.account
][key_name
] = \
4356 PrivacyListWindow(self
.account
, name
, 'NEW')
4357 self
.new_privacy_list_entry
.set_text('')
4359 def on_privacy_lists_refresh_button_clicked(self
, widget
):
4360 self
.privacy_lists_refresh()
4362 def on_open_privacy_list_button_clicked(self
, widget
):
4363 name
= self
.privacy_lists_save
[
4364 self
.list_of_privacy_lists_combobox
.get_active()]
4365 key_name
= 'privacy_list_%s' % name
4366 if key_name
in gajim
.interface
.instances
[self
.account
]:
4367 gajim
.interface
.instances
[self
.account
][key_name
].window
.present()
4369 gajim
.interface
.instances
[self
.account
][key_name
] = \
4370 PrivacyListWindow(self
.account
, name
, 'EDIT')
4372 class InvitationReceivedDialog
:
4373 def __init__(self
, account
, room_jid
, contact_jid
, password
=None,
4374 comment
=None, is_continued
=False):
4376 self
.room_jid
= room_jid
4377 self
.account
= account
4378 self
.password
= password
4379 self
.is_continued
= is_continued
4381 pritext
= _('''You are invited to a groupchat''')
4382 #Don't translate $Contact
4384 sectext
= _('$Contact has invited you to join a discussion')
4386 sectext
= _('$Contact has invited you to group chat %(room_jid)s')\
4387 % {'room_jid': room_jid
}
4388 contact
= gajim
.contacts
.get_first_contact_from_jid(account
, contact_jid
)
4389 contact_text
= contact
and contact
.name
or contact_jid
4390 sectext
= sectext
.replace('$Contact', contact_text
)
4392 if comment
: # only if not None and not ''
4393 comment
= gobject
.markup_escape_text(comment
)
4394 comment
= _('Comment: %s') % comment
4395 sectext
+= '\n\n%s' % comment
4396 sectext
+= '\n\n' + _('Do you want to accept the invitation?')
4398 def on_yes(checked
):
4400 if self
.is_continued
:
4401 gajim
.interface
.join_gc_room(self
.account
, self
.room_jid
,
4402 gajim
.nicks
[self
.account
], None, is_continued
=True)
4404 JoinGroupchatWindow(self
.account
, self
.room_jid
)
4405 except GajimGeneralException
:
4408 YesNoDialog(pritext
, sectext
, on_response_yes
=on_yes
)
4410 class ProgressDialog
:
4411 def __init__(self
, title_text
, during_text
, messages_queue
):
4413 During text is what to show during the procedure, messages_queue has the
4414 message to show in the textview
4416 self
.xml
= gtkgui_helpers
.get_gtk_builder('progress_dialog.ui')
4417 self
.dialog
= self
.xml
.get_object('progress_dialog')
4418 self
.label
= self
.xml
.get_object('label')
4419 self
.label
.set_markup('<big>' + during_text
+ '</big>')
4420 self
.progressbar
= self
.xml
.get_object('progressbar')
4421 self
.dialog
.set_title(title_text
)
4422 self
.dialog
.set_default_size(450, 250)
4423 self
.window
.set_position(gtk
.WIN_POS_CENTER_ON_PARENT
)
4424 self
.dialog
.show_all()
4425 self
.xml
.connect_signals(self
)
4427 self
.update_progressbar_timeout_id
= gobject
.timeout_add(100,
4428 self
.update_progressbar
)
4430 def update_progressbar(self
):
4432 self
.progressbar
.pulse()
4433 return True # loop forever
4436 def on_progress_dialog_delete_event(self
, widget
, event
):
4437 return True # WM's X button or Escape key should not destroy the window
4440 class ClientCertChooserDialog(FileChooserDialog
):
4441 def __init__(self
, path_to_clientcert_file
='', on_response_ok
=None,
4442 on_response_cancel
=None):
4444 optionally accepts path_to_clientcert_file so it has that as selected
4446 def on_ok(widget
, callback
):
4448 check if file exists and call callback
4450 path_to_clientcert_file
= self
.get_filename()
4451 path_to_clientcert_file
= \
4452 gtkgui_helpers
.decode_filechooser_file_paths(
4453 (path_to_clientcert_file
,))[0]
4454 if os
.path
.exists(path_to_clientcert_file
):
4455 callback(widget
, path_to_clientcert_file
)
4457 FileChooserDialog
.__init
__(self
,
4458 title_text
=_('Choose Client Cert #PCKS12'),
4459 action
=gtk
.FILE_CHOOSER_ACTION_OPEN
,
4460 buttons
=(gtk
.STOCK_CANCEL
, gtk
.RESPONSE_CANCEL
,
4461 gtk
.STOCK_OPEN
, gtk
.RESPONSE_OK
),
4463 default_response
=gtk
.RESPONSE_OK
,
4464 on_response_ok
=(on_ok
, on_response_ok
),
4465 on_response_cancel
=on_response_cancel
)
4467 filter_
= gtk
.FileFilter()
4468 filter_
.set_name(_('All files'))
4469 filter_
.add_pattern('*')
4470 self
.add_filter(filter_
)
4472 filter_
= gtk
.FileFilter()
4473 filter_
.set_name(_('PKCS12 Files'))
4474 filter_
.add_pattern('*.p12')
4475 self
.add_filter(filter_
)
4476 self
.set_filter(filter_
)
4478 if path_to_clientcert_file
:
4479 # set_filename accept only absolute path
4480 path_to_clientcert_file
= os
.path
.abspath(path_to_clientcert_file
)
4481 self
.set_filename(path_to_clientcert_file
)
4484 class SoundChooserDialog(FileChooserDialog
):
4485 def __init__(self
, path_to_snd_file
='', on_response_ok
=None,
4486 on_response_cancel
=None):
4488 Optionally accepts path_to_snd_file so it has that as selected
4490 def on_ok(widget
, callback
):
4492 Check if file exists and call callback
4494 path_to_snd_file
= self
.get_filename()
4495 path_to_snd_file
= gtkgui_helpers
.decode_filechooser_file_paths(
4496 (path_to_snd_file
,))[0]
4497 if os
.path
.exists(path_to_snd_file
):
4498 callback(widget
, path_to_snd_file
)
4500 FileChooserDialog
.__init
__(self
, title_text
= _('Choose Sound'),
4501 action
= gtk
.FILE_CHOOSER_ACTION_OPEN
,
4502 buttons
= (gtk
.STOCK_CANCEL
, gtk
.RESPONSE_CANCEL
,
4503 gtk
.STOCK_OPEN
, gtk
.RESPONSE_OK
),
4504 default_response
= gtk
.RESPONSE_OK
,
4505 current_folder
= gajim
.config
.get('last_sounds_dir'),
4506 on_response_ok
= (on_ok
, on_response_ok
),
4507 on_response_cancel
= on_response_cancel
)
4509 filter_
= gtk
.FileFilter()
4510 filter_
.set_name(_('All files'))
4511 filter_
.add_pattern('*')
4512 self
.add_filter(filter_
)
4514 filter_
= gtk
.FileFilter()
4515 filter_
.set_name(_('Wav Sounds'))
4516 filter_
.add_pattern('*.wav')
4517 self
.add_filter(filter_
)
4518 self
.set_filter(filter_
)
4520 path_to_snd_file
= helpers
.check_soundfile_path(path_to_snd_file
)
4521 if path_to_snd_file
:
4522 # set_filename accept only absolute path
4523 path_to_snd_file
= os
.path
.abspath(path_to_snd_file
)
4524 self
.set_filename(path_to_snd_file
)
4526 class ImageChooserDialog(FileChooserDialog
):
4527 def __init__(self
, path_to_file
='', on_response_ok
=None,
4528 on_response_cancel
=None):
4530 Optionally accepts path_to_snd_file so it has that as selected
4532 def on_ok(widget
, callback
):
4533 '''check if file exists and call callback'''
4534 path_to_file
= self
.get_filename()
4535 if not path_to_file
:
4537 path_to_file
= gtkgui_helpers
.decode_filechooser_file_paths(
4539 if os
.path
.exists(path_to_file
):
4540 if isinstance(callback
, tuple):
4541 callback
[0](widget
, path_to_file
, *callback
[1:])
4543 callback(widget
, path_to_file
)
4547 path
= helpers
.get_my_pictures_path()
4549 path
= os
.environ
['HOME']
4552 FileChooserDialog
.__init
__(self
,
4553 title_text
= _('Choose Image'),
4554 action
= gtk
.FILE_CHOOSER_ACTION_OPEN
,
4555 buttons
= (gtk
.STOCK_CANCEL
, gtk
.RESPONSE_CANCEL
,
4556 gtk
.STOCK_OPEN
, gtk
.RESPONSE_OK
),
4557 default_response
= gtk
.RESPONSE_OK
,
4558 current_folder
= path
,
4559 on_response_ok
= (on_ok
, on_response_ok
),
4560 on_response_cancel
= on_response_cancel
)
4562 if on_response_cancel
:
4563 self
.connect('destroy', on_response_cancel
)
4565 filter_
= gtk
.FileFilter()
4566 filter_
.set_name(_('All files'))
4567 filter_
.add_pattern('*')
4568 self
.add_filter(filter_
)
4570 filter_
= gtk
.FileFilter()
4571 filter_
.set_name(_('Images'))
4572 filter_
.add_mime_type('image/png')
4573 filter_
.add_mime_type('image/jpeg')
4574 filter_
.add_mime_type('image/gif')
4575 filter_
.add_mime_type('image/tiff')
4576 filter_
.add_mime_type('image/svg+xml')
4577 filter_
.add_mime_type('image/x-xpixmap') # xpm
4578 self
.add_filter(filter_
)
4579 self
.set_filter(filter_
)
4582 self
.set_filename(path_to_file
)
4584 self
.set_use_preview_label(False)
4585 self
.set_preview_widget(gtk
.Image())
4586 self
.connect('selection-changed', self
.update_preview
)
4588 def update_preview(self
, widget
):
4589 path_to_file
= widget
.get_preview_filename()
4590 if path_to_file
is None or os
.path
.isdir(path_to_file
):
4591 # nothing to preview or directory
4592 # make sure you clean image do show nothing
4593 widget
.get_preview_widget().set_from_file(None)
4596 pixbuf
= gtk
.gdk
.pixbuf_new_from_file_at_size(path_to_file
, 100, 100)
4597 except gobject
.GError
:
4599 widget
.get_preview_widget().set_from_pixbuf(pixbuf
)
4601 class AvatarChooserDialog(ImageChooserDialog
):
4602 def __init__(self
, path_to_file
='', on_response_ok
=None,
4603 on_response_cancel
=None, on_response_clear
=None):
4604 ImageChooserDialog
.__init
__(self
, path_to_file
, on_response_ok
,
4606 button
= gtk
.Button(None, gtk
.STOCK_CLEAR
)
4607 self
.response_clear
= on_response_clear
4608 if on_response_clear
:
4609 button
.connect('clicked', self
.on_clear
)
4611 self
.action_area
.pack_start(button
)
4612 self
.action_area
.reorder_child(button
, 0)
4614 def on_clear(self
, widget
):
4615 if isinstance(self
.response_clear
, tuple):
4616 self
.response_clear
[0](widget
, *self
.response_clear
[1:])
4618 self
.response_clear(widget
)
4621 class ArchiveChooserDialog(FileChooserDialog
):
4622 def __init__(self
, on_response_ok
=None, on_response_cancel
=None):
4624 def on_ok(widget
, callback
):
4625 '''check if file exists and call callback'''
4626 path_to_file
= self
.get_filename()
4627 if not path_to_file
:
4629 path_to_file
= gtkgui_helpers
.decode_filechooser_file_paths(
4631 if os
.path
.exists(path_to_file
):
4632 if isinstance(callback
, tuple):
4633 callback
[0](path_to_file
, *callback
[1:])
4635 callback(path_to_file
)
4638 path
= helpers
.get_documents_path()
4640 FileChooserDialog
.__init
__(self
,
4641 title_text
=_('Choose Archive'),
4642 action
=gtk
.FILE_CHOOSER_ACTION_OPEN
,
4643 buttons
=(gtk
.STOCK_CANCEL
, gtk
.RESPONSE_CANCEL
,
4644 gtk
.STOCK_OPEN
, gtk
.RESPONSE_OK
),
4645 default_response
=gtk
.RESPONSE_OK
,
4646 current_folder
=path
,
4647 on_response_ok
=(on_ok
, on_response_ok
),
4648 on_response_cancel
=on_response_cancel
)
4650 if on_response_cancel
:
4651 self
.connect('destroy', on_response_cancel
)
4653 filter_
= gtk
.FileFilter()
4654 filter_
.set_name(_('All files'))
4655 filter_
.add_pattern('*')
4656 self
.add_filter(filter_
)
4658 filter_
= gtk
.FileFilter()
4659 filter_
.set_name(_('Zip files'))
4660 filter_
.add_pattern('*.zip')
4662 self
.add_filter(filter_
)
4663 self
.set_filter(filter_
)
4666 class AddSpecialNotificationDialog
:
4667 def __init__(self
, jid
):
4669 jid is the jid for which we want to add special notification (sound and
4670 notification popups)
4672 self
.xml
= gtkgui_helpers
.get_gtk_builder(
4673 'add_special_notification_window.ui')
4674 self
.window
= self
.xml
.get_object('add_special_notification_window')
4675 self
.condition_combobox
= self
.xml
.get_object('condition_combobox')
4676 self
.condition_combobox
.set_active(0)
4677 self
.notification_popup_yes_no_combobox
= self
.xml
.get_object(
4678 'notification_popup_yes_no_combobox')
4679 self
.notification_popup_yes_no_combobox
.set_active(0)
4680 self
.listen_sound_combobox
= self
.xml
.get_object('listen_sound_combobox')
4681 self
.listen_sound_combobox
.set_active(0)
4684 self
.xml
.get_object('when_foo_becomes_label').set_text(
4685 _('When %s becomes:') % self
.jid
)
4687 self
.window
.set_title(_('Adding Special Notification for %s') % jid
)
4688 self
.window
.show_all()
4689 self
.xml
.connect_signals(self
)
4691 def on_cancel_button_clicked(self
, widget
):
4692 self
.window
.destroy()
4694 def on_add_special_notification_window_delete_event(self
, widget
, event
):
4695 self
.window
.destroy()
4697 def on_listen_sound_combobox_changed(self
, widget
):
4698 active
= widget
.get_active()
4699 if active
== 1: # user selected 'choose sound'
4700 def on_ok(widget
, path_to_snd_file
):
4702 #print path_to_snd_file
4704 def on_cancel(widget
):
4705 widget
.set_active(0) # go back to No Sound
4707 self
.dialog
= SoundChooserDialog(on_response_ok
=on_ok
,
4708 on_response_cancel
=on_cancel
)
4710 def on_ok_button_clicked(self
, widget
):
4711 conditions
= ('online', 'chat', 'online_and_chat',
4712 'away', 'xa', 'away_and_xa', 'dnd', 'xa_and_dnd', 'offline')
4713 active
= self
.condition_combobox
.get_active()
4715 active_iter
= self
.listen_sound_combobox
.get_active_iter()
4716 listen_sound_model
= self
.listen_sound_combobox
.get_model()
4718 class AdvancedNotificationsWindow
:
4719 events_list
= ['message_received', 'contact_connected',
4720 'contact_disconnected', 'contact_change_status', 'gc_msg_highlight',
4721 'gc_msg', 'ft_request', 'ft_started', 'ft_finished']
4722 recipient_types_list
= ['contact', 'group', 'all']
4723 config_options
= ['event', 'recipient_type', 'recipients', 'status',
4724 'tab_opened', 'sound', 'sound_file', 'popup', 'auto_open',
4725 'run_command', 'command', 'systray', 'roster', 'urgency_hint']
4727 self
.xml
= gtkgui_helpers
.get_gtk_builder(
4728 'advanced_notifications_window.ui')
4729 self
.window
= self
.xml
.get_object('advanced_notifications_window')
4730 for w
in ('conditions_treeview', 'config_vbox', 'event_combobox',
4731 'recipient_type_combobox', 'recipient_list_entry', 'delete_button',
4732 'status_hbox', 'use_sound_cb', 'disable_sound_cb', 'use_popup_cb',
4733 'disable_popup_cb', 'use_auto_open_cb', 'disable_auto_open_cb',
4734 'use_systray_cb', 'disable_systray_cb', 'use_roster_cb',
4735 'disable_roster_cb', 'tab_opened_cb', 'not_tab_opened_cb',
4736 'sound_entry', 'sound_file_hbox', 'up_button', 'down_button',
4737 'run_command_cb', 'command_entry', 'urgency_hint_cb'):
4738 self
.__dict
__[w
] = self
.xml
.get_object(w
)
4740 # Contains status checkboxes
4741 childs
= self
.status_hbox
.get_children()
4743 self
.all_status_rb
= childs
[0]
4744 self
.special_status_rb
= childs
[1]
4745 self
.online_cb
= childs
[2]
4746 self
.away_cb
= childs
[3]
4747 self
.xa_cb
= childs
[4]
4748 self
.dnd_cb
= childs
[5]
4749 self
.invisible_cb
= childs
[6]
4751 model
= gtk
.ListStore(int, str)
4752 model
.set_sort_column_id(0, gtk
.SORT_ASCENDING
)
4754 self
.conditions_treeview
.set_model(model
)
4757 col
= gtk
.TreeViewColumn(_('#'))
4758 self
.conditions_treeview
.append_column(col
)
4759 renderer
= gtk
.CellRendererText()
4760 col
.pack_start(renderer
, expand
=False)
4761 col
.set_attributes(renderer
, text
=0)
4763 col
= gtk
.TreeViewColumn(_('Condition'))
4764 self
.conditions_treeview
.append_column(col
)
4765 renderer
= gtk
.CellRendererText()
4766 col
.pack_start(renderer
, expand
=True)
4767 col
.set_attributes(renderer
, text
=1)
4769 self
.xml
.connect_signals(self
)
4771 # Fill conditions_treeview
4773 while gajim
.config
.get_per('notifications', str(num
)):
4774 iter_
= model
.append((num
, ''))
4775 path
= model
.get_path(iter_
)
4776 self
.conditions_treeview
.set_cursor(path
)
4777 self
.active_num
= num
4778 self
.initiate_rule_state()
4779 self
.set_treeview_string()
4782 # No rule selected at init time
4783 self
.conditions_treeview
.get_selection().unselect_all()
4784 self
.active_num
= -1
4785 self
.config_vbox
.set_sensitive(False)
4786 self
.delete_button
.set_sensitive(False)
4787 self
.down_button
.set_sensitive(False)
4788 self
.up_button
.set_sensitive(False)
4790 self
.window
.show_all()
4792 def initiate_rule_state(self
):
4794 Set values for all widgets
4796 if self
.active_num
< 0:
4799 value
= gajim
.config
.get_per('notifications', str(self
.active_num
),
4802 self
.event_combobox
.set_active(self
.events_list
.index(value
))
4804 self
.event_combobox
.set_active(-1)
4806 value
= gajim
.config
.get_per('notifications', str(self
.active_num
),
4809 self
.recipient_type_combobox
.set_active(
4810 self
.recipient_types_list
.index(value
))
4812 self
.recipient_type_combobox
.set_active(-1)
4814 value
= gajim
.config
.get_per('notifications', str(self
.active_num
),
4818 self
.recipient_list_entry
.set_text(value
)
4820 value
= gajim
.config
.get_per('notifications', str(self
.active_num
),
4823 self
.all_status_rb
.set_active(True)
4825 self
.special_status_rb
.set_active(True)
4826 values
= value
.split()
4827 for v
in ('online', 'away', 'xa', 'dnd', 'invisible'):
4829 self
.__dict
__[v
+ '_cb'].set_active(True)
4831 self
.__dict
__[v
+ '_cb'].set_active(False)
4832 self
.on_status_radiobutton_toggled(self
.all_status_rb
)
4834 value
= gajim
.config
.get_per('notifications', str(self
.active_num
),
4836 self
.tab_opened_cb
.set_active(True)
4837 self
.not_tab_opened_cb
.set_active(True)
4839 self
.tab_opened_cb
.set_active(False)
4840 elif value
== 'yes':
4841 self
.not_tab_opened_cb
.set_active(False)
4843 value
= gajim
.config
.get_per('notifications', str(self
.active_num
),
4845 self
.sound_entry
.set_text(value
)
4846 # sound, popup, auto_open, systray, roster
4847 for option
in ('sound', 'popup', 'auto_open', 'systray', 'roster'):
4848 value
= gajim
.config
.get_per('notifications', str(self
.active_num
),
4851 self
.__dict
__['use_' + option
+ '_cb'].set_active(True)
4853 self
.__dict
__['use_' + option
+ '_cb'].set_active(False)
4855 self
.__dict
__['disable_' + option
+ '_cb'].set_active(True)
4857 self
.__dict
__['disable_' + option
+ '_cb'].set_active(False)
4859 value
= gajim
.config
.get_per('notifications', str(self
.active_num
),
4861 self
.run_command_cb
.set_active(value
)
4863 value
= gajim
.config
.get_per('notifications', str(self
.active_num
),
4865 self
.command_entry
.set_text(value
)
4867 value
= gajim
.config
.get_per('notifications', str(self
.active_num
),
4869 self
.urgency_hint_cb
.set_active(value
)
4871 def set_treeview_string(self
):
4872 (model
, iter_
) = self
.conditions_treeview
.get_selection().get_selected()
4875 event
= self
.event_combobox
.get_active_text()
4876 recipient_type
= self
.recipient_type_combobox
.get_active_text()
4878 if recipient_type
!= 'everybody':
4879 recipient
= self
.recipient_list_entry
.get_text()
4880 if self
.all_status_rb
.get_active():
4883 status
= _('when I am ')
4884 for st
in ('online', 'away', 'xa', 'dnd', 'invisible'):
4885 if self
.__dict
__[st
+ '_cb'].get_active():
4886 status
+= helpers
.get_uf_show(st
) + ' '
4887 model
[iter_
][1] = "When %s for %s %s %s" % (event
, recipient_type
,
4890 def on_conditions_treeview_cursor_changed(self
, widget
):
4891 (model
, iter_
) = widget
.get_selection().get_selected()
4893 self
.active_num
= -1
4895 self
.active_num
= model
[iter_
][0]
4896 if self
.active_num
== 0:
4897 self
.up_button
.set_sensitive(False)
4899 self
.up_button
.set_sensitive(True)
4900 max = self
.conditions_treeview
.get_model().iter_n_children(None)
4901 if self
.active_num
== max - 1:
4902 self
.down_button
.set_sensitive(False)
4904 self
.down_button
.set_sensitive(True)
4905 self
.initiate_rule_state()
4906 self
.config_vbox
.set_sensitive(True)
4907 self
.delete_button
.set_sensitive(True)
4909 def on_new_button_clicked(self
, widget
):
4910 model
= self
.conditions_treeview
.get_model()
4911 num
= self
.conditions_treeview
.get_model().iter_n_children(None)
4912 gajim
.config
.add_per('notifications', str(num
))
4913 iter_
= model
.append((num
, ''))
4914 path
= model
.get_path(iter_
)
4915 self
.conditions_treeview
.set_cursor(path
)
4916 self
.active_num
= num
4917 self
.set_treeview_string()
4918 self
.config_vbox
.set_sensitive(True)
4920 def on_delete_button_clicked(self
, widget
):
4921 (model
, iter_
) = self
.conditions_treeview
.get_selection().get_selected()
4925 iter2
= model
.iter_next(iter_
)
4926 num
= self
.active_num
4928 num
= model
[iter2
][0]
4929 model
[iter2
][0] = num
- 1
4930 for opt
in self
.config_options
:
4931 val
= gajim
.config
.get_per('notifications', str(num
), opt
)
4932 gajim
.config
.set_per('notifications', str(num
- 1), opt
, val
)
4933 iter2
= model
.iter_next(iter2
)
4935 gajim
.config
.del_per('notifications', str(num
)) # delete latest
4936 self
.active_num
= -1
4937 self
.config_vbox
.set_sensitive(False)
4938 self
.delete_button
.set_sensitive(False)
4939 self
.up_button
.set_sensitive(False)
4940 self
.down_button
.set_sensitive(False)
4942 def on_up_button_clicked(self
, widget
):
4943 (model
, iter_
) = self
.conditions_treeview
.get_selection().\
4947 for opt
in self
.config_options
:
4948 val
= gajim
.config
.get_per('notifications', str(self
.active_num
),
4950 val2
= gajim
.config
.get_per('notifications',
4951 str(self
.active_num
- 1), opt
)
4952 gajim
.config
.set_per('notifications', str(self
.active_num
), opt
,
4954 gajim
.config
.set_per('notifications', str(self
.active_num
- 1), opt
,
4957 model
[iter_
][0] = self
.active_num
- 1
4959 path
= model
.get_path(iter_
)
4960 iter_
= model
.get_iter((path
[0] - 1,))
4961 model
[iter_
][0] = self
.active_num
4962 self
.on_conditions_treeview_cursor_changed(self
.conditions_treeview
)
4964 def on_down_button_clicked(self
, widget
):
4965 (model
, iter_
) = self
.conditions_treeview
.get_selection().get_selected()
4968 for opt
in self
.config_options
:
4969 val
= gajim
.config
.get_per('notifications', str(self
.active_num
),
4971 val2
= gajim
.config
.get_per('notifications',
4972 str(self
.active_num
+ 1), opt
)
4973 gajim
.config
.set_per('notifications', str(self
.active_num
), opt
,
4975 gajim
.config
.set_per('notifications', str(self
.active_num
+ 1), opt
,
4978 model
[iter_
][0] = self
.active_num
+ 1
4979 iter_
= model
.iter_next(iter_
)
4980 model
[iter_
][0] = self
.active_num
4981 self
.on_conditions_treeview_cursor_changed(self
.conditions_treeview
)
4983 def on_event_combobox_changed(self
, widget
):
4984 if self
.active_num
< 0:
4986 active
= self
.event_combobox
.get_active()
4990 event
= self
.events_list
[active
]
4991 gajim
.config
.set_per('notifications', str(self
.active_num
), 'event',
4993 self
.set_treeview_string()
4995 def on_recipient_type_combobox_changed(self
, widget
):
4996 if self
.active_num
< 0:
4998 recipient_type
= self
.recipient_types_list
[self
.recipient_type_combobox
.\
5000 gajim
.config
.set_per('notifications', str(self
.active_num
),
5001 'recipient_type', recipient_type
)
5002 if recipient_type
== 'all':
5003 self
.recipient_list_entry
.hide()
5005 self
.recipient_list_entry
.show()
5006 self
.set_treeview_string()
5008 def on_recipient_list_entry_changed(self
, widget
):
5009 if self
.active_num
< 0:
5011 recipients
= widget
.get_text().decode('utf-8')
5012 #TODO: do some check
5013 gajim
.config
.set_per('notifications', str(self
.active_num
),
5014 'recipients', recipients
)
5015 self
.set_treeview_string()
5017 def set_status_config(self
):
5018 if self
.active_num
< 0:
5021 for st
in ('online', 'away', 'xa', 'dnd', 'invisible'):
5022 if self
.__dict
__[st
+ '_cb'].get_active():
5025 status
= status
[:-1]
5026 gajim
.config
.set_per('notifications', str(self
.active_num
), 'status',
5028 self
.set_treeview_string()
5030 def on_status_radiobutton_toggled(self
, widget
):
5031 if self
.active_num
< 0:
5033 if self
.all_status_rb
.get_active():
5034 gajim
.config
.set_per('notifications', str(self
.active_num
), 'status',
5036 # 'All status' clicked
5037 for st
in ('online', 'away', 'xa', 'dnd', 'invisible'):
5038 self
.__dict
__[st
+ '_cb'].hide()
5040 self
.special_status_rb
.show()
5042 self
.set_status_config()
5043 # 'special status' clicked
5044 for st
in ('online', 'away', 'xa', 'dnd', 'invisible'):
5045 self
.__dict
__[st
+ '_cb'].show()
5047 self
.special_status_rb
.hide()
5048 self
.set_treeview_string()
5050 def on_status_cb_toggled(self
, widget
):
5051 if self
.active_num
< 0:
5053 self
.set_status_config()
5055 # tab_opened OR (not xor) not_tab_opened must be active
5056 def on_tab_opened_cb_toggled(self
, widget
):
5057 if self
.active_num
< 0:
5059 if self
.tab_opened_cb
.get_active():
5060 if self
.not_tab_opened_cb
.get_active():
5061 gajim
.config
.set_per('notifications', str(self
.active_num
),
5062 'tab_opened', 'both')
5064 gajim
.config
.set_per('notifications', str(self
.active_num
),
5065 'tab_opened', 'yes')
5066 elif not self
.not_tab_opened_cb
.get_active():
5067 self
.not_tab_opened_cb
.set_active(True)
5068 gajim
.config
.set_per('notifications', str(self
.active_num
),
5071 def on_not_tab_opened_cb_toggled(self
, widget
):
5072 if self
.active_num
< 0:
5074 if self
.not_tab_opened_cb
.get_active():
5075 if self
.tab_opened_cb
.get_active():
5076 gajim
.config
.set_per('notifications', str(self
.active_num
),
5077 'tab_opened', 'both')
5079 gajim
.config
.set_per('notifications', str(self
.active_num
),
5081 elif not self
.tab_opened_cb
.get_active():
5082 self
.tab_opened_cb
.set_active(True)
5083 gajim
.config
.set_per('notifications', str(self
.active_num
),
5084 'tab_opened', 'yes')
5086 def on_use_it_toggled(self
, widget
, oposite_widget
, option
):
5087 if widget
.get_active():
5088 if oposite_widget
.get_active():
5089 oposite_widget
.set_active(False)
5090 gajim
.config
.set_per('notifications', str(self
.active_num
), option
,
5092 elif oposite_widget
.get_active():
5093 gajim
.config
.set_per('notifications', str(self
.active_num
), option
,
5096 gajim
.config
.set_per('notifications', str(self
.active_num
),
5099 def on_disable_it_toggled(self
, widget
, oposite_widget
, option
):
5100 if widget
.get_active():
5101 if oposite_widget
.get_active():
5102 oposite_widget
.set_active(False)
5103 gajim
.config
.set_per('notifications', str(self
.active_num
), option
,
5105 elif oposite_widget
.get_active():
5106 gajim
.config
.set_per('notifications', str(self
.active_num
), option
,
5109 gajim
.config
.set_per('notifications', str(self
.active_num
), option
,
5112 def on_use_sound_cb_toggled(self
, widget
):
5113 self
.on_use_it_toggled(widget
, self
.disable_sound_cb
, 'sound')
5114 if widget
.get_active():
5115 self
.sound_file_hbox
.set_sensitive(True)
5117 self
.sound_file_hbox
.set_sensitive(False)
5119 def on_browse_for_sounds_button_clicked(self
, widget
, data
=None):
5120 if self
.active_num
< 0:
5123 def on_ok(widget
, path_to_snd_file
):
5125 if not path_to_snd_file
:
5126 path_to_snd_file
= ''
5127 gajim
.config
.set_per('notifications', str(self
.active_num
),
5128 'sound_file', path_to_snd_file
)
5129 self
.sound_entry
.set_text(path_to_snd_file
)
5131 path_to_snd_file
= self
.sound_entry
.get_text().decode('utf-8')
5132 path_to_snd_file
= os
.path
.join(os
.getcwd(), path_to_snd_file
)
5133 dialog
= SoundChooserDialog(path_to_snd_file
, on_ok
)
5135 def on_play_button_clicked(self
, widget
):
5136 helpers
.play_sound_file(self
.sound_entry
.get_text().decode('utf-8'))
5138 def on_disable_sound_cb_toggled(self
, widget
):
5139 self
.on_disable_it_toggled(widget
, self
.use_sound_cb
, 'sound')
5141 def on_sound_entry_changed(self
, widget
):
5142 gajim
.config
.set_per('notifications', str(self
.active_num
),
5143 'sound_file', widget
.get_text().decode('utf-8'))
5145 def on_use_popup_cb_toggled(self
, widget
):
5146 self
.on_use_it_toggled(widget
, self
.disable_popup_cb
, 'popup')
5148 def on_disable_popup_cb_toggled(self
, widget
):
5149 self
.on_disable_it_toggled(widget
, self
.use_popup_cb
, 'popup')
5151 def on_use_auto_open_cb_toggled(self
, widget
):
5152 self
.on_use_it_toggled(widget
, self
.disable_auto_open_cb
, 'auto_open')
5154 def on_disable_auto_open_cb_toggled(self
, widget
):
5155 self
.on_disable_it_toggled(widget
, self
.use_auto_open_cb
, 'auto_open')
5157 def on_run_command_cb_toggled(self
, widget
):
5158 gajim
.config
.set_per('notifications', str(self
.active_num
),
5159 'run_command', widget
.get_active())
5160 if widget
.get_active():
5161 self
.command_entry
.set_sensitive(True)
5163 self
.command_entry
.set_sensitive(False)
5165 def on_command_entry_changed(self
, widget
):
5166 gajim
.config
.set_per('notifications', str(self
.active_num
), 'command',
5167 widget
.get_text().decode('utf-8'))
5169 def on_use_systray_cb_toggled(self
, widget
):
5170 self
.on_use_it_toggled(widget
, self
.disable_systray_cb
, 'systray')
5172 def on_disable_systray_cb_toggled(self
, widget
):
5173 self
.on_disable_it_toggled(widget
, self
.use_systray_cb
, 'systray')
5175 def on_use_roster_cb_toggled(self
, widget
):
5176 self
.on_use_it_toggled(widget
, self
.disable_roster_cb
, 'roster')
5178 def on_disable_roster_cb_toggled(self
, widget
):
5179 self
.on_disable_it_toggled(widget
, self
.use_roster_cb
, 'roster')
5181 def on_urgency_hint_cb_toggled(self
, widget
):
5182 gajim
.config
.set_per('notifications', str(self
.active_num
),
5183 'uregency_hint', widget
.get_active())
5185 def on_close_window(self
, widget
):
5186 self
.window
.destroy()
5188 class TransformChatToMUC
:
5189 # Keep a reference on windows so garbage collector don't restroy them
5191 def __init__(self
, account
, jids
, preselected
=None):
5193 This window is used to trasform a one-to-one chat to a MUC. We do 2
5194 things: first select the server and then make a guests list
5197 self
.instances
.append(self
)
5198 self
.account
= account
5199 self
.auto_jids
= jids
5200 self
.preselected_jids
= preselected
5202 self
.xml
= gtkgui_helpers
.get_gtk_builder('chat_to_muc_window.ui')
5203 self
.window
= self
.xml
.get_object('chat_to_muc_window')
5205 for widget_to_add
in ('invite_button', 'cancel_button',
5206 'server_list_comboboxentry', 'guests_treeview',
5207 'server_and_guests_hseparator', 'server_select_label'):
5208 self
.__dict
__[widget_to_add
] = self
.xml
.get_object(widget_to_add
)
5211 self
.servers
= gtk
.ListStore(str)
5212 self
.server_list_comboboxentry
.set_model(self
.servers
)
5214 self
.server_list_comboboxentry
.set_text_column(0)
5216 # get the muc server of our server
5217 if 'jabber' in gajim
.connections
[account
].muc_jid
:
5218 server_list
.append(gajim
.connections
[account
].muc_jid
['jabber'])
5219 # add servers or recently joined groupchats
5220 recently_groupchat
= gajim
.config
.get('recently_groupchat').split()
5221 for g
in recently_groupchat
:
5222 server
= gajim
.get_server_from_jid(g
)
5223 if server
not in server_list
and not server
.startswith('irc'):
5224 server_list
.append(server
)
5225 # add a default server
5227 server_list
.append('conference.jabber.org')
5229 for s
in server_list
:
5230 self
.servers
.append([s
])
5232 self
.server_list_comboboxentry
.set_active(0)
5236 self
.store
= gtk
.ListStore(gtk
.gdk
.Pixbuf
, str, str)
5237 self
.store
.set_sort_column_id(1, gtk
.SORT_ASCENDING
)
5238 self
.guests_treeview
.set_model(self
.store
)
5240 renderer1
= gtk
.CellRendererText()
5241 renderer2
= gtk
.CellRendererPixbuf()
5242 column
= gtk
.TreeViewColumn('Status', renderer2
, pixbuf
=0)
5243 self
.guests_treeview
.append_column(column
)
5244 column
= gtk
.TreeViewColumn('Name', renderer1
, text
=1)
5245 self
.guests_treeview
.append_column(column
)
5247 self
.guests_treeview
.get_selection().set_mode(gtk
.SELECTION_MULTIPLE
)
5249 # All contacts beside the following can be invited:
5250 # transports, zeroconf contacts, minimized groupchats
5251 def invitable(contact
, contact_transport
=None):
5252 return (contact
.jid
not in self
.auto_jids
and
5253 contact
.jid
!= gajim
.get_jid_from_account(self
.account
) and
5254 contact
.jid
not in gajim
.interface
.minimized_controls
[account
] and
5255 not contact
.is_transport() and
5256 not contact_transport
)
5258 # set jabber id and pseudos
5259 for account
in gajim
.contacts
.get_accounts():
5260 if gajim
.connections
[account
].is_zeroconf
:
5262 for jid
in gajim
.contacts
.get_jid_list(account
):
5263 contact
= gajim
.contacts
.get_contact_with_highest_priority(
5265 contact_transport
= gajim
.get_transport_name_from_jid(jid
)
5266 # Add contact if it can be invited
5267 if invitable(contact
, contact_transport
) and \
5268 contact
.show
not in ('offline', 'error'):
5269 img
= gajim
.interface
.jabber_state_images
['16'][contact
.show
]
5272 name
= jid
.split('@')[0]
5273 iter_
= self
.store
.append([img
.get_pixbuf(), name
, jid
])
5274 # preselect treeview rows
5275 if self
.preselected_jids
and jid
in self
.preselected_jids
:
5276 path
= self
.store
.get_path(iter_
)
5277 self
.guests_treeview
.get_selection().select_path(path
)
5279 gajim
.ged
.register_event_handler('unique-room-id-supported', ged
.GUI1
,
5280 self
._nec
_unique
_room
_id
_supported
)
5281 gajim
.ged
.register_event_handler('unique-room-id-not-supported',
5282 ged
.GUI1
, self
._nec
_unique
_room
_id
_not
_supported
)
5285 self
.window
.show_all()
5287 self
.xml
.connect_signals(self
)
5289 def on_chat_to_muc_window_destroy(self
, widget
):
5290 gajim
.ged
.remove_event_handler('unique-room-id-supported', ged
.GUI1
,
5291 self
._nec
_unique
_room
_id
_supported
)
5292 gajim
.ged
.remove_event_handler('unique-room-id-not-supported', ged
.GUI1
,
5293 self
._nec
_unique
_room
_id
_not
_supported
)
5294 self
.instances
.remove(self
)
5296 def on_chat_to_muc_window_key_press_event(self
, widget
, event
):
5297 if event
.keyval
== gtk
.keysyms
.Escape
: # ESCAPE
5298 self
.window
.destroy()
5300 def on_invite_button_clicked(self
, widget
):
5301 server
= self
.server_list_comboboxentry
.get_active_text()
5304 gajim
.connections
[self
.account
].check_unique_room_id_support(server
, self
)
5306 def _nec_unique_room_id_supported(self
, obj
):
5307 if obj
.instance
!= self
:
5310 guests
= self
.guests_treeview
.get_selection().get_selected_rows()
5311 for guest
in guests
[1]:
5312 iter_
= self
.store
.get_iter(guest
)
5313 guest_list
.append(self
.store
[iter_
][2].decode('utf-8'))
5314 for guest
in self
.auto_jids
:
5315 guest_list
.append(guest
)
5316 room_jid
= obj
.room_id
+ '@' + obj
.server
5317 gajim
.automatic_rooms
[self
.account
][room_jid
] = {}
5318 gajim
.automatic_rooms
[self
.account
][room_jid
]['invities'] = guest_list
5319 gajim
.automatic_rooms
[self
.account
][room_jid
]['continue_tag'] = True
5320 gajim
.interface
.join_gc_room(self
.account
, room_jid
,
5321 gajim
.nicks
[self
.account
], None, is_continued
=True)
5322 self
.window
.destroy()
5324 def on_cancel_button_clicked(self
, widget
):
5325 self
.window
.destroy()
5327 def _nec_unique_room_id_not_supported(self
, obj
):
5328 if obj
.instance
!= self
:
5330 obj
.room_id
= gajim
.nicks
[self
.account
].lower().replace(' ', '') + \
5331 str(randrange(9999999))
5332 self
._nec
_unique
_room
_id
_supported
(obj
)
5334 class DataFormWindow(Dialog
):
5335 def __init__(self
, form
, on_response_ok
):
5336 self
.df_response_ok
= on_response_ok
5337 Dialog
.__init
__(self
, None, 'test', [(gtk
.STOCK_CANCEL
,
5338 gtk
.RESPONSE_REJECT
), (gtk
.STOCK_OK
, gtk
.RESPONSE_ACCEPT
)],
5339 on_response_ok
=self
.on_ok
)
5340 self
.set_resizable(True)
5341 gtkgui_helpers
.resize_window(self
, 600, 400)
5342 self
.dataform_widget
= dataforms_widget
.DataFormWidget()
5343 self
.dataform
= dataforms
.ExtendForm(node
=form
)
5344 self
.dataform_widget
.set_sensitive(True)
5345 self
.dataform_widget
.data_form
= self
.dataform
5346 self
.dataform_widget
.show_all()
5347 self
.vbox
.pack_start(self
.dataform_widget
)
5350 form
= self
.dataform_widget
.data_form
5351 if isinstance(self
.df_response_ok
, tuple):
5352 self
.df_response_ok
[0](form
, *self
.df_response_ok
[1:])
5354 self
.df_response_ok(form
)
5357 class ESessionInfoWindow
:
5359 Class for displaying information about a XEP-0116 encrypted session
5361 def __init__(self
, session
):
5362 self
.session
= session
5364 self
.xml
= gtkgui_helpers
.get_gtk_builder('esession_info_window.ui')
5365 self
.xml
.connect_signals(self
)
5367 self
.security_image
= self
.xml
.get_object('security_image')
5368 self
.verify_now_button
= self
.xml
.get_object('verify_now_button')
5369 self
.button_label
= self
.xml
.get_object('button_label')
5370 self
.window
= self
.xml
.get_object('esession_info_window')
5374 self
.window
.show_all()
5376 def update_info(self
):
5377 labeltext
= _('''Your chat session with <b>%(jid)s</b> is encrypted.\n\nThis session's Short Authentication String is <b>%(sas)s</b>.''') % {'jid': self
.session
.jid
, 'sas': self
.session
.sas
}
5379 if self
.session
.verified_identity
:
5380 labeltext
+= '\n\n' + _('''You have already verified this contact's identity.''')
5381 security_image
= 'gajim-security_high'
5382 if self
.session
.control
:
5383 self
.session
.control
._show
_lock
_image
(True, 'E2E', True,
5384 self
.session
.is_loggable(), True)
5386 verification_status
= _('''Contact's identity verified''')
5387 self
.window
.set_title(verification_status
)
5388 self
.xml
.get_object('verification_status_label').set_markup(
5389 '<b><span size="x-large">%s</span></b>' % verification_status
)
5391 self
.xml
.get_object('dialog-action_area1').set_no_show_all(True)
5392 self
.button_label
.set_text(_('Verify again...'))
5394 if self
.session
.control
:
5395 self
.session
.control
._show
_lock
_image
(True, 'E2E', True,
5396 self
.session
.is_loggable(), False)
5397 labeltext
+= '\n\n' + _('''To be certain that <b>only</b> the expected person can read your messages or send you messages, you need to verify their identity by clicking the button below.''')
5398 security_image
= 'gajim-security_low'
5400 verification_status
= _('''Contact's identity NOT verified''')
5401 self
.window
.set_title(verification_status
)
5402 self
.xml
.get_object('verification_status_label').set_markup(
5403 '<b><span size="x-large">%s</span></b>' % verification_status
)
5405 self
.button_label
.set_text(_('Verify...'))
5407 path
= gtkgui_helpers
.get_icon_path(security_image
, 32)
5408 self
.security_image
.set_from_file(path
)
5410 self
.xml
.get_object('info_display').set_markup(labeltext
)
5412 def on_close_button_clicked(self
, widget
):
5413 self
.window
.destroy()
5415 def on_verify_now_button_clicked(self
, widget
):
5416 pritext
= _('''Have you verified the contact's identity?''')
5417 sectext
= _('''To prevent talking to an unknown person, you should speak to <b>%(jid)s</b> directly (in person or on the phone) and verify that they see the same Short Authentication String (SAS) as you.\n\nThis session's Short Authentication String is <b>%(sas)s</b>.''') % {'jid': self
.session
.jid
, 'sas': self
.session
.sas
}
5418 sectext
+= '\n\n' + _('Did you talk to the remote contact and verify the SAS?')
5420 def on_yes(checked
):
5421 self
.session
._verified
_srs
_cb
()
5422 self
.session
.verified_identity
= True
5426 self
.session
._unverified
_srs
_cb
()
5427 self
.session
.verified_identity
= False
5430 YesNoDialog(pritext
, sectext
, on_response_yes
=on_yes
, on_response_no
=on_no
)
5432 class GPGInfoWindow
:
5434 Class for displaying information about a XEP-0116 encrypted session
5436 def __init__(self
, control
):
5437 xml
= gtkgui_helpers
.get_gtk_builder('esession_info_window.ui')
5438 security_image
= xml
.get_object('security_image')
5439 status_label
= xml
.get_object('verification_status_label')
5440 info_label
= xml
.get_object('info_display')
5441 verify_now_button
= xml
.get_object('verify_now_button')
5442 self
.window
= xml
.get_object('esession_info_window')
5443 account
= control
.account
5444 keyID
= control
.contact
.keyID
5447 verify_now_button
.set_no_show_all(True)
5448 verify_now_button
.hide()
5450 if keyID
.endswith('MISMATCH'):
5451 verification_status
= _('''Contact's identity NOT verified''')
5452 info
= _('The contact\'s key (%s) <b>does not match</b> the key '
5453 'assigned in Gajim.') % keyID
[:8]
5454 image
= 'gajim-security_low'
5456 # No key assigned nor a key is used by remote contact
5457 verification_status
= _('No GPG key assigned')
5458 info
= _('No GPG key is assigned to this contact. So you cannot '
5459 'encrypt messages.')
5460 image
= 'gajim-security_low'
5462 error
= gajim
.connections
[account
].gpg
.encrypt('test', [keyID
])[1]
5464 verification_status
= _('''Contact's identity NOT verified''')
5465 info
= _('GPG key is assigned to this contact, but <b>you do not '
5466 'trust his key</b>, so message <b>cannot</b> be encrypted. Use '
5467 'your GPG client to trust this key.')
5468 image
= 'gajim-security_low'
5470 verification_status
= _('''Contact's identity verified''')
5471 info
= _('GPG Key is assigned to this contact, and you trust his '
5472 'key, so messages will be encrypted.')
5473 image
= 'gajim-security_high'
5475 status_label
.set_markup('<b><span size="x-large">%s</span></b>' % \
5476 verification_status
)
5477 info_label
.set_markup(info
)
5479 path
= gtkgui_helpers
.get_icon_path(image
, 32)
5480 security_image
.set_from_file(path
)
5482 xml
.connect_signals(self
)
5483 self
.window
.show_all()
5485 def on_close_button_clicked(self
, widget
):
5486 self
.window
.destroy()
5490 class ResourceConflictDialog(TimeoutDialog
, InputDialog
):
5491 def __init__(self
, title
, text
, resource
, ok_handler
):
5492 TimeoutDialog
.__init
__(self
, 15, self
.on_timeout
)
5493 InputDialog
.__init
__(self
, title
, text
, input_str
=resource
,
5494 is_modal
=False, ok_handler
=ok_handler
)
5495 self
.title_text
= title
5498 def on_timeout(self
):
5499 self
.on_okbutton_clicked(None)
5503 class VoIPCallReceivedDialog(object):
5505 def __init__(self
, account
, contact_jid
, sid
, content_types
):
5506 self
.instances
[(contact_jid
, sid
)] = self
5507 self
.account
= account
5508 self
.fjid
= contact_jid
5510 self
.content_types
= content_types
5512 xml
= gtkgui_helpers
.get_gtk_builder('voip_call_received_dialog.ui')
5513 xml
.connect_signals(self
)
5515 jid
= gajim
.get_jid_without_resource(self
.fjid
)
5516 contact
= gajim
.contacts
.get_first_contact_from_jid(account
, jid
)
5517 if contact
and contact
.name
:
5518 self
.contact_text
= '%s (%s)' % (contact
.name
, jid
)
5520 self
.contact_text
= contact_jid
5522 self
.dialog
= xml
.get_object('voip_call_received_messagedialog')
5523 self
.set_secondary_text()
5525 self
.dialog
.show_all()
5528 def get_dialog(cls
, jid
, sid
):
5529 if (jid
, sid
) in cls
.instances
:
5530 return cls
.instances
[(jid
, sid
)]
5534 def set_secondary_text(self
):
5535 if 'audio' in self
.content_types
and 'video' in self
.content_types
:
5536 types_text
= _('an audio and video')
5537 elif 'audio' in self
.content_types
:
5538 types_text
= _('an audio')
5539 elif 'video' in self
.content_types
:
5540 types_text
= _('a video')
5542 # do the substitution
5543 self
.dialog
.set_property('secondary-text',
5544 _('%(contact)s wants to start %(type)s session with you. Do you want '
5545 'to answer the call?') % {'contact': self
.contact_text
,
5546 'type': types_text
})
5548 def add_contents(self
, content_types
):
5549 for type_
in content_types
:
5550 if type_
not in self
.content_types
:
5551 self
.content_types
.add(type_
)
5552 self
.set_secondary_text()
5554 def remove_contents(self
, content_types
):
5555 for type_
in content_types
:
5556 if type_
in self
.content_types
:
5557 self
.content_types
.remove(type_
)
5558 if not self
.content_types
:
5559 self
.dialog
.destroy()
5561 self
.set_secondary_text()
5563 def on_voip_call_received_messagedialog_destroy(self
, dialog
):
5564 if (self
.fjid
, self
.sid
) in self
.instances
:
5565 del self
.instances
[(self
.fjid
, self
.sid
)]
5567 def on_voip_call_received_messagedialog_close(self
, dialog
):
5568 return self
.on_voip_call_received_messagedialog_response(dialog
,
5571 def on_voip_call_received_messagedialog_response(self
, dialog
, response
):
5572 # we've got response from user, either stop connecting or accept the call
5573 session
= gajim
.connections
[self
.account
].get_jingle_session(self
.fjid
,
5577 if response
== gtk
.RESPONSE_YES
:
5578 #TODO: Ensure that ctrl.contact.resource == resource
5579 jid
= gajim
.get_jid_without_resource(self
.fjid
)
5580 resource
= gajim
.get_resource_from_jid(self
.fjid
)
5581 ctrl
= (gajim
.interface
.msg_win_mgr
.get_control(self
.fjid
, self
.account
)
5582 or gajim
.interface
.msg_win_mgr
.get_control(jid
, self
.account
)
5583 or gajim
.interface
.new_chat_from_jid(self
.account
, jid
))
5585 # Chat control opened, update content's status
5586 audio
= session
.get_content('audio')
5587 video
= session
.get_content('video')
5588 if audio
and not audio
.negotiated
:
5589 ctrl
.set_audio_state('connecting', self
.sid
)
5590 if video
and not video
.negotiated
:
5591 ctrl
.set_video_state('connecting', self
.sid
)
5592 # Now, accept the content/sessions.
5593 # This should be done after the chat control is running
5594 if not session
.accepted
:
5595 session
.approve_session()
5596 for content
in self
.content_types
:
5597 session
.approve_content(content
)
5598 else: # response==gtk.RESPONSE_NO
5599 if not session
.accepted
:
5600 session
.decline_session()
5602 for content
in self
.content_types
:
5603 session
.reject_content(content
)