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
42 from random
import randrange
43 from common
import pep
44 from common
import ged
52 # those imports are not used in this file, but in files that 'import dialogs'
53 # so they can do dialog.GajimThemesWindow() for example
54 from filetransfers_window
import FileTransfersWindow
55 from gajim_themes_window
import GajimThemesWindow
56 from advanced_configuration_window
import AdvancedConfigurationWindow
58 from common
import gajim
59 from common
import helpers
60 from common
import dataforms
61 from common
.exceptions
import GajimGeneralException
63 class EditGroupsDialog
:
65 Class for the edit group dialog window
68 def __init__(self
, list_
):
70 list_ is a list of (contact, account) tuples
72 self
.xml
= gtkgui_helpers
.get_gtk_builder('edit_groups_dialog.ui')
73 self
.dialog
= self
.xml
.get_object('edit_groups_dialog')
74 self
.dialog
.set_transient_for(gajim
.interface
.roster
.window
)
76 self
.changes_made
= False
77 self
.treeview
= self
.xml
.get_object('groups_treeview')
80 self
.xml
.get_object('nickname_label').set_markup(
81 _('Contact name: <i>%s</i>') % contact
.get_shown_name())
82 self
.xml
.get_object('jid_label').set_markup(
83 _('Jabber ID: <i>%s</i>') % contact
.jid
)
85 self
.xml
.get_object('nickname_label').set_no_show_all(True)
86 self
.xml
.get_object('nickname_label').hide()
87 self
.xml
.get_object('jid_label').set_no_show_all(True)
88 self
.xml
.get_object('jid_label').hide()
90 self
.xml
.connect_signals(self
)
93 self
.dialog
.show_all()
95 for (contact
, account
) in self
.list_
:
96 gajim
.connections
[account
].update_contact(contact
.jid
,
97 contact
.name
, contact
.groups
)
99 def on_edit_groups_dialog_response(self
, widget
, response_id
):
100 if response_id
== gtk
.RESPONSE_CLOSE
:
101 self
.dialog
.destroy()
103 def remove_group(self
, group
):
105 Remove group group from all contacts and all their brothers
107 for (contact
, account
) in self
.list_
:
108 gajim
.interface
.roster
.remove_contact_from_groups(contact
.jid
,
111 # FIXME: Ugly workaround.
112 gajim
.interface
.roster
.draw_group(_('General'), account
)
114 def add_group(self
, group
):
116 Add group group to all contacts and all their brothers
118 for (contact
, account
) in self
.list_
:
119 gajim
.interface
.roster
.add_contact_to_groups(contact
.jid
, account
,
122 # FIXME: Ugly workaround.
123 # Maybe we haven't been in any group (defaults to General)
124 gajim
.interface
.roster
.draw_group(_('General'), account
)
126 def on_add_button_clicked(self
, widget
):
127 group
= self
.xml
.get_object('group_entry').get_text().decode('utf-8')
130 # Do not allow special groups
131 if group
in helpers
.special_groups
:
133 # check if it already exists
134 model
= self
.treeview
.get_model()
135 iter_
= model
.get_iter_root()
137 if model
.get_value(iter_
, 0).decode('utf-8') == group
:
139 iter_
= model
.iter_next(iter_
)
140 self
.changes_made
= True
141 model
.append((group
, True, False))
142 self
.add_group(group
)
143 self
.init_list() # Re-draw list to sort new item
145 def group_toggled_cb(self
, cell
, path
):
146 self
.changes_made
= True
147 model
= self
.treeview
.get_model()
149 model
[path
][2] = False
150 model
[path
][1] = True
152 model
[path
][1] = not model
[path
][1]
153 group
= model
[path
][0].decode('utf-8')
155 self
.add_group(group
)
157 self
.remove_group(group
)
160 store
= gtk
.ListStore(str, bool, bool)
161 self
.treeview
.set_model(store
)
162 for column
in self
.treeview
.get_columns():
163 # Clear treeview when re-drawing
164 self
.treeview
.remove_column(column
)
166 # Store groups in a list so we can sort them and the number of contacts in
169 for (contact
, account
) in self
.list_
:
170 if account
not in accounts
:
171 accounts
.append(account
)
172 for g
in gajim
.groups
[account
].keys():
176 c_groups
= contact
.groups
180 # Remove special groups if they are empty
182 if group
not in helpers
.special_groups
or groups
[group
] > 0:
183 group_list
.append(group
)
185 for group
in group_list
:
186 iter_
= store
.append()
187 store
.set(iter_
, 0, group
) # Group name
188 if groups
[group
] == 0:
189 store
.set(iter_
, 1, False)
191 store
.set(iter_
, 1, True)
192 if groups
[group
] == len(self
.list_
):
193 # all contacts are in this group
194 store
.set(iter_
, 2, False)
196 store
.set(iter_
, 2, True)
197 column
= gtk
.TreeViewColumn(_('Group'))
198 column
.set_expand(True)
199 self
.treeview
.append_column(column
)
200 renderer
= gtk
.CellRendererText()
201 column
.pack_start(renderer
)
202 column
.set_attributes(renderer
, text
=0)
204 column
= gtk
.TreeViewColumn(_('In the group'))
205 column
.set_expand(False)
206 self
.treeview
.append_column(column
)
207 renderer
= gtk
.CellRendererToggle()
208 column
.pack_start(renderer
)
209 renderer
.set_property('activatable', True)
210 renderer
.connect('toggled', self
.group_toggled_cb
)
211 column
.set_attributes(renderer
, active
=1, inconsistent
=2)
213 class PassphraseDialog
:
215 Class for Passphrase dialog
217 def __init__(self
, titletext
, labeltext
, checkbuttontext
=None,
218 ok_handler
=None, cancel_handler
=None):
219 self
.xml
= gtkgui_helpers
.get_gtk_builder('passphrase_dialog.ui')
220 self
.window
= self
.xml
.get_object('passphrase_dialog')
221 self
.passphrase_entry
= self
.xml
.get_object('passphrase_entry')
223 self
.window
.set_title(titletext
)
224 self
.xml
.get_object('message_label').set_text(labeltext
)
228 self
.cancel_handler
= cancel_handler
229 self
.ok_handler
= ok_handler
230 okbutton
= self
.xml
.get_object('ok_button')
231 okbutton
.connect('clicked', self
.on_okbutton_clicked
)
232 cancelbutton
= self
.xml
.get_object('cancel_button')
233 cancelbutton
.connect('clicked', self
.on_cancelbutton_clicked
)
235 self
.xml
.connect_signals(self
)
236 self
.window
.set_position(gtk
.WIN_POS_CENTER_ON_PARENT
)
237 self
.window
.show_all()
239 self
.check
= bool(checkbuttontext
)
240 checkbutton
= self
.xml
.get_object('save_passphrase_checkbutton')
242 checkbutton
.set_label(checkbuttontext
)
246 def on_okbutton_clicked(self
, widget
):
247 if not self
.ok_handler
:
250 passph
= self
.passphrase_entry
.get_text().decode('utf-8')
253 checked
= self
.xml
.get_object('save_passphrase_checkbutton').\
260 self
.window
.destroy()
262 if isinstance(self
.ok_handler
, tuple):
263 self
.ok_handler
[0](passph
, checked
, *self
.ok_handler
[1:])
265 self
.ok_handler(passph
, checked
)
267 def on_cancelbutton_clicked(self
, widget
):
268 self
.window
.destroy()
270 def on_passphrase_dialog_destroy(self
, widget
):
271 if self
.cancel_handler
and not self
.ok
:
272 self
.cancel_handler()
274 class ChooseGPGKeyDialog
:
276 Class for GPG key dialog
279 def __init__(self
, title_text
, prompt_text
, secret_keys
, on_response
,
281 '''secret_keys : {keyID: userName, ...}'''
282 self
.on_response
= on_response
283 xml
= gtkgui_helpers
.get_gtk_builder('choose_gpg_key_dialog.ui')
284 self
.window
= xml
.get_object('choose_gpg_key_dialog')
285 self
.window
.set_title(title_text
)
286 self
.keys_treeview
= xml
.get_object('keys_treeview')
287 prompt_label
= xml
.get_object('prompt_label')
288 prompt_label
.set_text(prompt_text
)
289 model
= gtk
.ListStore(str, str)
290 model
.set_sort_func(1, self
.sort_keys
)
291 model
.set_sort_column_id(1, gtk
.SORT_ASCENDING
)
292 self
.keys_treeview
.set_model(model
)
294 renderer
= gtk
.CellRendererText()
295 col
= self
.keys_treeview
.insert_column_with_attributes(-1, _('KeyID'),
297 col
.set_sort_column_id(0)
298 renderer
= gtk
.CellRendererText()
299 col
= self
.keys_treeview
.insert_column_with_attributes(-1,
300 _('Contact name'), renderer
, text
=1)
301 col
.set_sort_column_id(1)
302 self
.keys_treeview
.set_search_column(1)
303 self
.fill_tree(secret_keys
, selected
)
304 self
.window
.connect('response', self
.on_dialog_response
)
305 self
.window
.set_position(gtk
.WIN_POS_CENTER_ON_PARENT
)
306 self
.window
.show_all()
308 def sort_keys(self
, model
, iter1
, iter2
):
309 value1
= model
[iter1
][1]
310 value2
= model
[iter2
][1]
311 if value1
== _('None'):
313 elif value2
== _('None'):
315 elif value1
< value2
:
319 def on_dialog_response(self
, dialog
, response
):
320 selection
= self
.keys_treeview
.get_selection()
321 (model
, iter_
) = selection
.get_selected()
322 if iter_
and response
== gtk
.RESPONSE_OK
:
323 keyID
= [ model
[iter_
][0].decode('utf-8'),
324 model
[iter_
][1].decode('utf-8') ]
327 self
.on_response(keyID
)
328 self
.window
.destroy()
330 def fill_tree(self
, list_
, selected
):
331 model
= self
.keys_treeview
.get_model()
332 for keyID
in list_
.keys():
333 iter_
= model
.append((keyID
, list_
[keyID
]))
334 if keyID
== selected
:
335 path
= model
.get_path(iter_
)
336 self
.keys_treeview
.set_cursor(path
)
339 class ChangeActivityDialog
:
340 PAGELIST
= ['doing_chores', 'drinking', 'eating', 'exercising', 'grooming',
341 'having_appointment', 'inactive', 'relaxing', 'talking', 'traveling',
344 def __init__(self
, on_response
, activity
=None, subactivity
=None, text
=''):
345 self
.on_response
= on_response
346 self
.activity
= activity
347 self
.subactivity
= subactivity
349 self
.xml
= gtkgui_helpers
.get_gtk_builder('change_activity_dialog.ui')
350 self
.window
= self
.xml
.get_object('change_activity_dialog')
351 self
.window
.set_transient_for(gajim
.interface
.roster
.window
)
353 self
.checkbutton
= self
.xml
.get_object('enable_checkbutton')
354 self
.notebook
= self
.xml
.get_object('notebook')
355 self
.entry
= self
.xml
.get_object('description_entry')
360 for category
in pep
.ACTIVITIES
:
361 item
= self
.xml
.get_object(category
+ '_image')
362 item
.set_from_pixbuf(
363 gtkgui_helpers
.load_activity_icon(category
).get_pixbuf())
364 item
.set_tooltip_text(pep
.ACTIVITIES
[category
]['category'])
366 vbox
= self
.xml
.get_object(category
+ '_vbox')
367 vbox
.set_border_width(5)
370 act
= category
+ '_other'
373 rbtns
[act
] = gtk
.RadioButton(group
)
375 rbtns
[act
] = group
= gtk
.RadioButton()
377 hbox
= gtk
.HBox(False, 5)
378 hbox
.pack_start(gtkgui_helpers
.load_activity_icon(category
), False,
380 lbl
= gtk
.Label('<b>' + pep
.ACTIVITIES
[category
]['category'] + '</b>')
381 lbl
.set_use_markup(True)
382 hbox
.pack_start(lbl
, False, False, 0)
384 rbtns
[act
].connect('toggled', self
.on_rbtn_toggled
,
386 vbox
.pack_start(rbtns
[act
], False, False, 0)
389 for activity
in pep
.ACTIVITIES
[category
]:
390 activities
.append(activity
)
393 for activity
in activities
:
394 if activity
== 'category':
397 act
= category
+ '_' + activity
400 rbtns
[act
] = gtk
.RadioButton(group
)
402 rbtns
[act
] = group
= gtk
.RadioButton()
404 hbox
= gtk
.HBox(False, 5)
405 hbox
.pack_start(gtkgui_helpers
.load_activity_icon(category
,
406 activity
), False, False, 0)
407 hbox
.pack_start(gtk
.Label(pep
.ACTIVITIES
[category
][activity
]),
409 rbtns
[act
].connect('toggled', self
.on_rbtn_toggled
,
410 [category
, activity
])
412 vbox
.pack_start(rbtns
[act
], False, False, 0)
415 self
.default_radio
= rbtns
['doing_chores_other']
417 if self
.activity
in pep
.ACTIVITIES
:
418 if not self
.subactivity
in pep
.ACTIVITIES
[self
.activity
]:
419 self
.subactivity
= 'other'
421 rbtns
[self
.activity
+ '_' + self
.subactivity
].set_active(True)
423 self
.checkbutton
.set_active(True)
424 self
.notebook
.set_sensitive(True)
425 self
.entry
.set_sensitive(True)
427 self
.notebook
.set_current_page(
428 self
.PAGELIST
.index(self
.activity
))
430 self
.entry
.set_text(text
)
433 self
.checkbutton
.set_active(False)
435 self
.xml
.connect_signals(self
)
436 self
.window
.set_position(gtk
.WIN_POS_CENTER_ON_PARENT
)
437 self
.window
.show_all()
439 def on_enable_checkbutton_toggled(self
, widget
):
440 self
.notebook
.set_sensitive(widget
.get_active())
441 self
.entry
.set_sensitive(widget
.get_active())
442 if not self
.activity
:
443 self
.default_radio
.set_active(True)
445 def on_rbtn_toggled(self
, widget
, data
):
446 if widget
.get_active():
447 self
.activity
= data
[0]
448 self
.subactivity
= data
[1]
450 def on_ok_button_clicked(self
, widget
):
452 Return activity and messsage (None if no activity selected)
454 if self
.checkbutton
.get_active():
455 self
.on_response(self
.activity
, self
.subactivity
,
456 self
.entry
.get_text().decode('utf-8'))
458 self
.on_response(None, None, '')
459 self
.window
.destroy()
461 def on_cancel_button_clicked(self
, widget
):
462 self
.window
.destroy()
464 class ChangeMoodDialog
:
467 def __init__(self
, on_response
, mood
=None, text
=''):
468 self
.on_response
= on_response
471 self
.xml
= gtkgui_helpers
.get_gtk_builder('change_mood_dialog.ui')
473 self
.window
= self
.xml
.get_object('change_mood_dialog')
474 self
.window
.set_transient_for(gajim
.interface
.roster
.window
)
475 self
.window
.set_title(_('Set Mood'))
477 table
= self
.xml
.get_object('mood_icons_table')
478 self
.label
= self
.xml
.get_object('mood_label')
479 self
.entry
= self
.xml
.get_object('description_entry')
481 no_mood_button
= self
.xml
.get_object('no_mood_button')
482 no_mood_button
.set_mode(False)
483 no_mood_button
.connect('clicked',
484 self
.on_mood_button_clicked
, None)
488 self
.mood_buttons
= {}
492 for mood
in pep
.MOODS
:
493 self
.MOODS
.append(mood
)
496 for mood
in self
.MOODS
:
497 self
.mood_buttons
[mood
] = gtk
.RadioButton(no_mood_button
)
498 self
.mood_buttons
[mood
].set_mode(False)
499 self
.mood_buttons
[mood
].add(gtkgui_helpers
.load_mood_icon(mood
))
500 self
.mood_buttons
[mood
].set_relief(gtk
.RELIEF_NONE
)
501 self
.mood_buttons
[mood
].set_tooltip_text(pep
.MOODS
[mood
])
502 self
.mood_buttons
[mood
].connect('clicked',
503 self
.on_mood_button_clicked
, mood
)
504 table
.attach(self
.mood_buttons
[mood
], x
, x
+ 1, y
, y
+ 1)
506 # Calculate the next position
512 if self
.mood
in pep
.MOODS
:
513 self
.mood_buttons
[self
.mood
].set_active(True)
514 self
.label
.set_text(pep
.MOODS
[self
.mood
])
515 self
.entry
.set_sensitive(True)
517 self
.entry
.set_text(self
.text
)
519 self
.label
.set_text(_('None'))
520 self
.entry
.set_text('')
521 self
.entry
.set_sensitive(False)
523 self
.xml
.connect_signals(self
)
524 self
.window
.set_position(gtk
.WIN_POS_CENTER_ON_PARENT
)
525 self
.window
.show_all()
527 def on_mood_button_clicked(self
, widget
, data
):
529 self
.label
.set_text(pep
.MOODS
[data
])
530 self
.entry
.set_sensitive(True)
532 self
.label
.set_text(_('None'))
533 self
.entry
.set_text('')
534 self
.entry
.set_sensitive(False)
537 def on_ok_button_clicked(self
, widget
):
538 '''Return mood and messsage (None if no mood selected)'''
539 message
= self
.entry
.get_text().decode('utf-8')
540 self
.on_response(self
.mood
, message
)
541 self
.window
.destroy()
543 def on_cancel_button_clicked(self
, widget
):
544 self
.window
.destroy()
548 Class designed to be derivated to create timeout'd dialogs (dialogs that
549 closes automatically after a timeout)
551 def __init__(self
, timeout
, on_timeout
):
552 self
.countdown_left
= timeout
553 self
.countdown_enabled
= True
555 self
.on_timeout
= on_timeout
557 def run_timeout(self
):
558 if self
.countdown_left
> 0:
560 gobject
.timeout_add_seconds(1, self
.countdown
)
564 To be implemented in derivated classes
569 if self
.countdown_enabled
:
570 if self
.countdown_left
<= 0:
573 self
.dialog
.set_title('%s [%s]' % (self
.title_text
,
574 str(self
.countdown_left
)))
575 self
.countdown_left
-= 1
578 self
.dialog
.set_title(self
.title_text
)
581 class ChangeStatusMessageDialog(TimeoutDialog
):
582 def __init__(self
, on_response
, show
=None, show_pep
=True):
583 countdown_time
= gajim
.config
.get('change_status_window_timeout')
584 TimeoutDialog
.__init
__(self
, countdown_time
, self
.on_timeout
)
587 self
.show_pep
= show_pep
588 self
.on_response
= on_response
589 self
.xml
= gtkgui_helpers
.get_gtk_builder('change_status_message_dialog.ui')
590 self
.dialog
= self
.xml
.get_object('change_status_message_dialog')
591 self
.dialog
.set_transient_for(gajim
.interface
.roster
.window
)
594 uf_show
= helpers
.get_uf_show(show
)
595 self
.title_text
= _('%s Status Message') % uf_show
596 msg
= gajim
.config
.get_per('statusmsg', '_last_' + self
.show
,
598 self
.pep_dict
['activity'] = gajim
.config
.get_per('statusmsg',
599 '_last_' + self
.show
, 'activity')
600 self
.pep_dict
['subactivity'] = gajim
.config
.get_per('statusmsg',
601 '_last_' + self
.show
, 'subactivity')
602 self
.pep_dict
['activity_text'] = gajim
.config
.get_per('statusmsg',
603 '_last_' + self
.show
, 'activity_text')
604 self
.pep_dict
['mood'] = gajim
.config
.get_per('statusmsg',
605 '_last_' + self
.show
, 'mood')
606 self
.pep_dict
['mood_text'] = gajim
.config
.get_per('statusmsg',
607 '_last_' + self
.show
, 'mood_text')
609 self
.title_text
= _('Status Message')
610 self
.dialog
.set_title(self
.title_text
)
612 message_textview
= self
.xml
.get_object('message_textview')
613 self
.message_buffer
= message_textview
.get_buffer()
614 self
.message_buffer
.connect('changed', self
.on_message_buffer_changed
)
617 msg
= helpers
.from_one_line(msg
)
618 self
.message_buffer
.set_text(msg
)
620 # have an empty string selectable, so user can clear msg
621 self
.preset_messages_dict
= {'': ['', '', '', '', '', '']}
622 for msg_name
in gajim
.config
.get_per('statusmsg'):
623 if msg_name
.startswith('_last_'):
626 for opt
in ['message', 'activity', 'subactivity', 'activity_text',
627 'mood', 'mood_text']:
628 opts
.append(gajim
.config
.get_per('statusmsg', msg_name
, opt
))
629 opts
[0] = helpers
.from_one_line(opts
[0])
630 self
.preset_messages_dict
[msg_name
] = opts
631 sorted_keys_list
= helpers
.get_sorted_keys(self
.preset_messages_dict
)
633 self
.message_liststore
= gtk
.ListStore(str) # msg_name
634 self
.message_combobox
= self
.xml
.get_object('message_combobox')
635 self
.message_combobox
.set_model(self
.message_liststore
)
636 cellrenderertext
= gtk
.CellRendererText()
637 self
.message_combobox
.pack_start(cellrenderertext
, True)
638 self
.message_combobox
.add_attribute(cellrenderertext
, 'text', 0)
639 for msg_name
in sorted_keys_list
:
640 self
.message_liststore
.append((msg_name
,))
646 # remove acvtivity / mood lines
647 self
.xml
.get_object('activity_label').set_no_show_all(True)
648 self
.xml
.get_object('activity_button').set_no_show_all(True)
649 self
.xml
.get_object('mood_label').set_no_show_all(True)
650 self
.xml
.get_object('mood_button').set_no_show_all(True)
651 self
.xml
.get_object('activity_label').hide()
652 self
.xml
.get_object('activity_button').hide()
653 self
.xml
.get_object('mood_label').hide()
654 self
.xml
.get_object('mood_button').hide()
656 self
.xml
.connect_signals(self
)
658 self
.dialog
.connect('response', self
.on_dialog_response
)
659 self
.dialog
.set_position(gtk
.WIN_POS_CENTER_ON_PARENT
)
660 self
.dialog
.show_all()
662 def draw_activity(self
):
666 img
= self
.xml
.get_object('activity_image')
667 label
= self
.xml
.get_object('activity_button_label')
668 if 'activity' in self
.pep_dict
and self
.pep_dict
['activity'] in \
670 if 'subactivity' in self
.pep_dict
and self
.pep_dict
['subactivity'] \
671 in pep
.ACTIVITIES
[self
.pep_dict
['activity']]:
672 img
.set_from_pixbuf(gtkgui_helpers
.load_activity_icon(
673 self
.pep_dict
['activity'], self
.pep_dict
['subactivity']).\
676 img
.set_from_pixbuf(gtkgui_helpers
.load_activity_icon(
677 self
.pep_dict
['activity']).get_pixbuf())
678 if self
.pep_dict
['activity_text']:
679 label
.set_text(self
.pep_dict
['activity_text'])
683 img
.set_from_pixbuf(None)
690 img
= self
.xml
.get_object('mood_image')
691 label
= self
.xml
.get_object('mood_button_label')
692 if 'mood' in self
.pep_dict
and self
.pep_dict
['mood'] in pep
.MOODS
:
693 img
.set_from_pixbuf(gtkgui_helpers
.load_mood_icon(
694 self
.pep_dict
['mood']).get_pixbuf())
695 if self
.pep_dict
['mood_text']:
696 label
.set_text(self
.pep_dict
['mood_text'])
700 img
.set_from_pixbuf(None)
703 def on_timeout(self
):
704 # Prevent GUI freeze when the combobox menu is opened on close
705 self
.message_combobox
.popdown()
706 self
.dialog
.response(gtk
.RESPONSE_OK
)
708 def on_dialog_response(self
, dialog
, response
):
709 if response
== gtk
.RESPONSE_OK
:
710 beg
, end
= self
.message_buffer
.get_bounds()
711 message
= self
.message_buffer
.get_text(beg
, end
).decode('utf-8')\
713 message
= helpers
.remove_invalid_xml_chars(message
)
714 msg
= helpers
.to_one_line(message
)
716 gajim
.config
.set_per('statusmsg', '_last_' + self
.show
,
719 gajim
.config
.set_per('statusmsg', '_last_' + self
.show
,
720 'activity', self
.pep_dict
['activity'])
721 gajim
.config
.set_per('statusmsg', '_last_' + self
.show
,
722 'subactivity', self
.pep_dict
['subactivity'])
723 gajim
.config
.set_per('statusmsg', '_last_' + self
.show
,
724 'activity_text', self
.pep_dict
['activity_text'])
725 gajim
.config
.set_per('statusmsg', '_last_' + self
.show
,
726 'mood', self
.pep_dict
['mood'])
727 gajim
.config
.set_per('statusmsg', '_last_' + self
.show
,
728 'mood_text', self
.pep_dict
['mood_text'])
730 message
= None # user pressed Cancel button or X wm button
731 self
.dialog
.destroy()
732 self
.on_response(message
, self
.pep_dict
)
734 def on_message_combobox_changed(self
, widget
):
735 self
.countdown_enabled
= False
736 model
= widget
.get_model()
737 active
= widget
.get_active()
740 name
= model
[active
][0].decode('utf-8')
741 self
.message_buffer
.set_text(self
.preset_messages_dict
[name
][0])
742 self
.pep_dict
['activity'] = self
.preset_messages_dict
[name
][1]
743 self
.pep_dict
['subactivity'] = self
.preset_messages_dict
[name
][2]
744 self
.pep_dict
['activity_text'] = self
.preset_messages_dict
[name
][3]
745 self
.pep_dict
['mood'] = self
.preset_messages_dict
[name
][4]
746 self
.pep_dict
['mood_text'] = self
.preset_messages_dict
[name
][5]
750 def on_change_status_message_dialog_key_press_event(self
, widget
, event
):
751 self
.countdown_enabled
= False
752 if event
.keyval
== gtk
.keysyms
.Return
or \
753 event
.keyval
== gtk
.keysyms
.KP_Enter
: # catch CTRL+ENTER
754 if (event
.state
& gtk
.gdk
.CONTROL_MASK
):
755 self
.dialog
.response(gtk
.RESPONSE_OK
)
759 def on_message_buffer_changed(self
, widget
):
760 self
.countdown_enabled
= False
761 self
.toggle_sensitiviy_of_save_as_preset()
763 def toggle_sensitiviy_of_save_as_preset(self
):
764 btn
= self
.xml
.get_object('save_as_preset_button')
765 if self
.message_buffer
.get_char_count() == 0:
766 btn
.set_sensitive(False)
768 btn
.set_sensitive(True)
770 def on_save_as_preset_button_clicked(self
, widget
):
771 self
.countdown_enabled
= False
772 start_iter
, finish_iter
= self
.message_buffer
.get_bounds()
773 status_message_to_save_as_preset
= self
.message_buffer
.get_text(
774 start_iter
, finish_iter
)
776 msg_text
= status_message_to_save_as_preset
.decode('utf-8')
777 msg_text_1l
= helpers
.to_one_line(msg_text
)
778 if not msg_name
: # msg_name was ''
779 msg_name
= msg_text_1l
.decode('utf-8')
782 self
.preset_messages_dict
[msg_name
] = [
783 msg_text
, self
.pep_dict
.get('activity'),
784 self
.pep_dict
.get('subactivity'),
785 self
.pep_dict
.get('activity_text'),
786 self
.pep_dict
.get('mood'), self
.pep_dict
.get('mood_text')]
787 gajim
.config
.set_per('statusmsg', msg_name
, 'message',
789 gajim
.config
.set_per('statusmsg', msg_name
, 'activity',
790 self
.pep_dict
.get('activity'))
791 gajim
.config
.set_per('statusmsg', msg_name
, 'subactivity',
792 self
.pep_dict
.get('subactivity'))
793 gajim
.config
.set_per('statusmsg', msg_name
, 'activity_text',
794 self
.pep_dict
.get('activity_text'))
795 gajim
.config
.set_per('statusmsg', msg_name
, 'mood',
796 self
.pep_dict
.get('mood'))
797 gajim
.config
.set_per('statusmsg', msg_name
, 'mood_text',
798 self
.pep_dict
.get('mood_text'))
799 if msg_name
in self
.preset_messages_dict
:
800 ConfirmationDialog(_('Overwrite Status Message?'),
801 _('This name is already used. Do you want to overwrite this '
802 'status message?'), on_response_ok
=on_ok2
)
804 gajim
.config
.add_per('statusmsg', msg_name
)
806 iter_
= self
.message_liststore
.append((msg_name
,))
807 # select in combobox the one we just saved
808 self
.message_combobox
.set_active_iter(iter_
)
809 InputDialog(_('Save as Preset Status Message'),
810 _('Please type a name for this status message'), is_modal
=False,
813 def on_activity_button_clicked(self
, widget
):
814 self
.countdown_enabled
= False
815 def on_response(activity
, subactivity
, text
):
816 self
.pep_dict
['activity'] = activity
or ''
817 self
.pep_dict
['subactivity'] = subactivity
or ''
818 self
.pep_dict
['activity_text'] = text
820 ChangeActivityDialog(on_response
, self
.pep_dict
['activity'],
821 self
.pep_dict
['subactivity'], self
.pep_dict
['activity_text'])
823 def on_mood_button_clicked(self
, widget
):
824 self
.countdown_enabled
= False
825 def on_response(mood
, text
):
826 self
.pep_dict
['mood'] = mood
or ''
827 self
.pep_dict
['mood_text'] = text
829 ChangeMoodDialog(on_response
, self
.pep_dict
['mood'],
830 self
.pep_dict
['mood_text'])
832 class AddNewContactWindow
:
834 Class for AddNewContactWindow
837 uid_labels
= {'jabber': _('Jabber ID:'),
838 'aim': _('AIM Address:'),
839 'gadu-gadu': _('GG Number:'),
840 'icq': _('ICQ Number:'),
841 'msn': _('MSN Address:'),
842 'yahoo': _('Yahoo! Address:')}
844 def __init__(self
, account
=None, jid
=None, user_nick
=None, group
=None):
845 self
.account
= account
846 self
.adding_jid
= False
848 # fill accounts with active accounts
850 for account
in gajim
.connections
.keys():
851 if gajim
.connections
[account
].connected
> 1:
852 accounts
.append(account
)
855 if len(accounts
) == 1:
856 self
.account
= account
858 accounts
= [self
.account
]
860 location
= gajim
.interface
.instances
[self
.account
]
862 location
= gajim
.interface
.instances
863 if 'add_contact' in location
:
864 location
['add_contact'].window
.present()
865 # An instance is already opened
867 location
['add_contact'] = self
868 self
.xml
= gtkgui_helpers
.get_gtk_builder('add_new_contact_window.ui')
869 self
.xml
.connect_signals(self
)
870 self
.window
= self
.xml
.get_object('add_new_contact_window')
871 for w
in ('account_combobox', 'account_hbox', 'account_label',
872 'uid_label', 'uid_entry', 'protocol_combobox', 'protocol_jid_combobox',
873 'protocol_hbox', 'nickname_entry', 'message_scrolledwindow',
874 'save_message_checkbutton', 'register_hbox', 'subscription_table',
875 'add_button', 'message_textview', 'connected_label',
876 'group_comboboxentry', 'auto_authorize_checkbutton'):
877 self
.__dict
__[w
] = self
.xml
.get_object(w
)
878 if account
and len(gajim
.connections
) >= 2:
879 self
.default_desc
= _('Please fill in the data of the contact you '
880 'want to add in account %s') % account
882 self
.default_desc
= _('Please fill in the data of the contact you '
884 self
.xml
.get_object('prompt_label').set_text(self
.default_desc
)
885 self
.agents
= {'jabber': []}
886 self
.gateway_prompt
= {}
887 # types to which we are not subscribed but account has an agent for it
888 self
.available_types
= []
889 for acct
in accounts
:
890 for j
in gajim
.contacts
.get_jid_list(acct
):
891 if gajim
.jid_is_transport(j
):
892 type_
= gajim
.get_transport_name_from_jid(j
, False)
895 if type_
in self
.agents
:
896 self
.agents
[type_
].append(j
)
898 self
.agents
[type_
] = [j
]
899 self
.gateway_prompt
[j
] = {'desc': None, 'prompt': None}
900 # Now add the one to which we can register
901 for acct
in accounts
:
902 for type_
in gajim
.connections
[acct
].available_transports
:
903 if type_
in self
.agents
:
905 self
.agents
[type_
] = []
906 for jid_
in gajim
.connections
[acct
].available_transports
[type_
]:
907 if not jid_
in self
.agents
[type_
]:
908 self
.agents
[type_
].append(jid_
)
909 self
.gateway_prompt
[jid_
] = {'desc': None,
911 self
.available_types
.append(type_
)
912 # Combobox with transport/jabber icons
913 liststore
= gtk
.ListStore(str, gtk
.gdk
.Pixbuf
, str)
914 cell
= gtk
.CellRendererPixbuf()
915 self
.protocol_combobox
.pack_start(cell
, False)
916 self
.protocol_combobox
.add_attribute(cell
, 'pixbuf', 1)
917 cell
= gtk
.CellRendererText()
918 cell
.set_property('xpad', 5)
919 self
.protocol_combobox
.pack_start(cell
, True)
920 self
.protocol_combobox
.add_attribute(cell
, 'text', 0)
921 self
.protocol_combobox
.set_model(liststore
)
922 uf_type
= {'jabber': 'Jabber', 'aim': 'AIM', 'gadu-gadu': 'Gadu Gadu',
923 'icq': 'ICQ', 'msn': 'MSN', 'yahoo': 'Yahoo'}
925 img
= gajim
.interface
.jabber_state_images
['16']['online']
926 liststore
.append(['Jabber', img
.get_pixbuf(), 'jabber'])
927 for type_
in self
.agents
:
928 if type_
== 'jabber':
930 imgs
= gajim
.interface
.roster
.transports_state_images
932 if type_
in imgs
['16'] and 'online' in imgs
['16'][type_
]:
933 img
= imgs
['16'][type_
]['online']
935 liststore
.append([uf_type
[type_
], img
.get_pixbuf(), type_
])
937 liststore
.append([type_
, img
.get_pixbuf(), type_
])
939 liststore
.append([type_
, img
, type_
])
941 for service
in self
.agents
[type_
]:
942 gajim
.connections
[account
].request_gateway_prompt(service
)
943 self
.protocol_combobox
.set_active(0)
944 self
.auto_authorize_checkbutton
.show()
945 liststore
= gtk
.ListStore(str)
946 self
.protocol_jid_combobox
.set_model(liststore
)
948 type_
= gajim
.get_transport_name_from_jid(jid
)
951 if type_
== 'jabber':
952 self
.uid_entry
.set_text(jid
)
954 uid
, transport
= gajim
.get_name_and_server_from_jid(jid
)
955 self
.uid_entry
.set_text(uid
.replace('%', '@', 1))
956 # set protocol_combobox
957 model
= self
.protocol_combobox
.get_model()
958 iter_
= model
.get_iter_first()
961 if model
[iter_
][2] == type_
:
962 self
.protocol_combobox
.set_active(i
)
964 iter_
= model
.iter_next(iter_
)
967 # set protocol_jid_combobox
968 self
.protocol_jid_combobox
.set_active(0)
969 model
= self
.protocol_jid_combobox
.get_model()
970 iter_
= model
.get_iter_first()
973 if model
[iter_
][0] == transport
:
974 self
.protocol_jid_combobox
.set_active(i
)
976 iter_
= model
.iter_next(iter_
)
979 self
.nickname_entry
.set_text(user_nick
)
980 self
.nickname_entry
.grab_focus()
982 self
.uid_entry
.grab_focus()
984 for acct
in accounts
:
985 for g
in gajim
.groups
[acct
].keys():
986 if g
not in helpers
.special_groups
and g
not in group_names
:
987 group_names
.append(g
)
990 for g
in group_names
:
991 self
.group_comboboxentry
.append_text(g
)
993 self
.group_comboboxentry
.set_active(i
)
996 self
.window
.set_transient_for(gajim
.interface
.roster
.window
)
997 self
.window
.show_all()
1000 self
.account_label
.hide()
1001 self
.account_hbox
.hide()
1003 liststore
= gtk
.ListStore(str, str)
1004 for acct
in accounts
:
1005 liststore
.append([acct
, acct
])
1006 self
.account_combobox
.set_model(liststore
)
1007 self
.account_combobox
.set_active(0)
1010 message_buffer
= self
.message_textview
.get_buffer()
1011 message_buffer
.set_text(helpers
.get_subscription_request_msg(
1014 gajim
.ged
.register_event_handler('gateway-prompt-received', ged
.GUI1
,
1015 self
._nec
_gateway
_prompt
_received
)
1016 gajim
.ged
.register_event_handler('presence-received', ged
.GUI1
,
1017 self
._nec
_presence
_received
)
1019 def on_add_new_contact_window_destroy(self
, widget
):
1021 location
= gajim
.interface
.instances
[self
.account
]
1023 location
= gajim
.interface
.instances
1024 del location
['add_contact']
1025 gajim
.ged
.remove_event_handler('presence-received', ged
.GUI1
,
1026 self
._nec
_presence
_received
)
1027 gajim
.ged
.remove_event_handler('gateway-prompt-received', ged
.GUI1
,
1028 self
._nec
_gateway
_prompt
_received
)
1030 def on_register_button_clicked(self
, widget
):
1031 jid
= self
.protocol_jid_combobox
.get_active_text().decode('utf-8')
1032 gajim
.connections
[self
.account
].request_register_agent_info(jid
)
1034 def on_add_new_contact_window_key_press_event(self
, widget
, event
):
1035 if event
.keyval
== gtk
.keysyms
.Escape
: # ESCAPE
1036 self
.window
.destroy()
1038 def on_cancel_button_clicked(self
, widget
):
1040 When Cancel button is clicked
1042 self
.window
.destroy()
1044 def on_add_button_clicked(self
, widget
):
1046 When Subscribe button is clicked
1048 jid
= self
.uid_entry
.get_text().decode('utf-8').strip()
1052 model
= self
.protocol_combobox
.get_model()
1053 iter_
= self
.protocol_combobox
.get_active_iter()
1054 type_
= model
[iter_
][2]
1055 if type_
!= 'jabber':
1056 transport
= self
.protocol_jid_combobox
.get_active_text().decode(
1059 self
.adding_jid
= (jid
, transport
, type_
)
1060 gajim
.connections
[self
.account
].request_gateway_prompt(
1063 jid
= jid
.replace('@', '%') + '@' + transport
1064 self
._add
_jid
(jid
, type_
)
1066 self
._add
_jid
(jid
, type_
)
1068 def _add_jid(self
, jid
, type_
):
1069 # check if jid is conform to RFC and stringprep it
1071 jid
= helpers
.parse_jid(jid
)
1072 except helpers
.InvalidFormat
, s
:
1073 pritext
= _('Invalid User ID')
1074 ErrorDialog(pritext
, str(s
))
1077 # No resource in jid
1078 if jid
.find('/') >= 0:
1079 pritext
= _('Invalid User ID')
1080 ErrorDialog(pritext
, _('The user ID must not contain a resource.'))
1083 if jid
== gajim
.get_jid_from_account(self
.account
):
1084 pritext
= _('Invalid User ID')
1085 ErrorDialog(pritext
, _('You cannot add yourself to your roster.'))
1088 nickname
= self
.nickname_entry
.get_text().decode('utf-8') or ''
1089 # get value of account combobox, if account was not specified
1090 if not self
.account
:
1091 model
= self
.account_combobox
.get_model()
1092 index
= self
.account_combobox
.get_active()
1093 self
.account
= model
[index
][1]
1095 # Check if jid is already in roster
1096 if jid
in gajim
.contacts
.get_jid_list(self
.account
):
1097 c
= gajim
.contacts
.get_first_contact_from_jid(self
.account
, jid
)
1098 if _('Not in Roster') not in c
.groups
and c
.sub
in ('both', 'to'):
1099 ErrorDialog(_('Contact already in roster'),
1100 _('This contact is already listed in your roster.'))
1103 if type_
== 'jabber':
1104 message_buffer
= self
.message_textview
.get_buffer()
1105 start_iter
= message_buffer
.get_start_iter()
1106 end_iter
= message_buffer
.get_end_iter()
1107 message
= message_buffer
.get_text(start_iter
, end_iter
).decode('utf-8')
1108 if self
.save_message_checkbutton
.get_active():
1109 gajim
.config
.set_per('accounts', self
.account
,
1110 'subscription_request_msg', message
)
1113 group
= self
.group_comboboxentry
.child
.get_text().decode('utf-8')
1117 auto_auth
= self
.auto_authorize_checkbutton
.get_active()
1118 gajim
.interface
.roster
.req_sub(self
, jid
, message
, self
.account
,
1119 groups
=groups
, nickname
=nickname
, auto_auth
=auto_auth
)
1120 self
.window
.destroy()
1122 def on_account_combobox_changed(self
, widget
):
1123 model
= widget
.get_model()
1124 iter_
= widget
.get_active_iter()
1125 account
= model
[iter_
][0]
1126 message_buffer
= self
.message_textview
.get_buffer()
1127 message_buffer
.set_text(helpers
.get_subscription_request_msg(account
))
1129 def on_protocol_jid_combobox_changed(self
, widget
):
1130 model
= widget
.get_model()
1131 iter_
= widget
.get_active_iter()
1134 jid_
= model
[iter_
][0]
1135 model
= self
.protocol_combobox
.get_model()
1136 iter_
= self
.protocol_combobox
.get_active_iter()
1137 type_
= model
[iter_
][2]
1139 if self
.agents
[type_
] and jid_
in self
.gateway_prompt
:
1140 desc
= self
.gateway_prompt
[jid_
]['desc']
1142 desc
= self
.default_desc
1143 self
.xml
.get_object('prompt_label').set_text(desc
)
1146 if self
.agents
[type_
] and jid_
in self
.gateway_prompt
:
1147 prompt
= self
.gateway_prompt
[jid_
]['prompt']
1149 if type_
in self
.uid_labels
:
1150 prompt
= self
.uid_labels
[type_
]
1152 prompt
= _('User ID:')
1153 self
.uid_label
.set_text(prompt
)
1155 def on_protocol_combobox_changed(self
, widget
):
1156 model
= widget
.get_model()
1157 iter_
= widget
.get_active_iter()
1158 type_
= model
[iter_
][2]
1159 model
= self
.protocol_jid_combobox
.get_model()
1161 if len(self
.agents
[type_
]):
1162 for jid_
in self
.agents
[type_
]:
1163 model
.append([jid_
])
1164 self
.protocol_jid_combobox
.set_active(0)
1166 if self
.agents
[type_
]:
1167 jid_
= self
.agents
[type_
][0]
1168 if jid_
in self
.gateway_prompt
:
1169 desc
= self
.gateway_prompt
[jid_
]['desc']
1171 desc
= self
.default_desc
1172 self
.xml
.get_object('prompt_label').set_text(desc
)
1173 if len(self
.agents
[type_
]) > 1:
1174 self
.protocol_jid_combobox
.show()
1176 self
.protocol_jid_combobox
.hide()
1178 if self
.agents
[type_
]:
1179 jid_
= self
.agents
[type_
][0]
1180 if jid_
in self
.gateway_prompt
:
1181 prompt
= self
.gateway_prompt
[jid_
]['prompt']
1183 if type_
in self
.uid_labels
:
1184 prompt
= self
.uid_labels
[type_
]
1186 prompt
= _('User ID:')
1187 self
.uid_label
.set_text(prompt
)
1189 if type_
== 'jabber':
1190 self
.message_scrolledwindow
.show()
1191 self
.save_message_checkbutton
.show()
1193 self
.message_scrolledwindow
.hide()
1194 self
.save_message_checkbutton
.hide()
1195 if type_
in self
.available_types
:
1196 self
.register_hbox
.show()
1197 self
.auto_authorize_checkbutton
.hide()
1198 self
.connected_label
.hide()
1199 self
.subscription_table
.hide()
1200 self
.add_button
.set_sensitive(False)
1202 self
.register_hbox
.hide()
1203 if type_
!= 'jabber':
1204 jid
= self
.protocol_jid_combobox
.get_active_text()
1205 contact
= gajim
.contacts
.get_first_contact_from_jid(
1207 if contact
.show
in ('offline', 'error'):
1208 self
.subscription_table
.hide()
1209 self
.connected_label
.show()
1210 self
.add_button
.set_sensitive(False)
1211 self
.auto_authorize_checkbutton
.hide()
1213 self
.subscription_table
.show()
1214 self
.auto_authorize_checkbutton
.show()
1215 self
.connected_label
.hide()
1216 self
.add_button
.set_sensitive(True)
1218 def transport_signed_in(self
, jid
):
1219 if self
.protocol_jid_combobox
.get_active_text() == jid
:
1220 self
.register_hbox
.hide()
1221 self
.connected_label
.hide()
1222 self
.subscription_table
.show()
1223 self
.auto_authorize_checkbutton
.show()
1224 self
.add_button
.set_sensitive(True)
1226 def transport_signed_out(self
, jid
):
1227 if self
.protocol_jid_combobox
.get_active_text() == jid
:
1228 self
.subscription_table
.hide()
1229 self
.auto_authorize_checkbutton
.hide()
1230 self
.connected_label
.show()
1231 self
.add_button
.set_sensitive(False)
1233 def _nec_presence_received(self
, obj
):
1234 if gajim
.jid_is_transport(obj
.jid
):
1235 if obj
.old_show
== 0 and obj
.new_show
> 1:
1236 self
.transport_signed_in(obj
.jid
)
1237 elif obj
.old_show
> 1 and obj
.new_show
== 0:
1238 self
.transport_signed_out(obj
.jid
)
1240 def _nec_gateway_prompt_received(self
, obj
):
1242 jid
, transport
, type_
= self
.adding_jid
1244 self
._add
_jid
(obj
.prompt_jid
, type_
)
1246 jid
= jid
.replace('@', '%') + '@' + transport
1247 self
._add
_jid
(jid
, type_
)
1248 elif obj
.jid
in self
.gateway_prompt
:
1250 self
.gateway_prompt
[obj
.jid
]['desc'] = obj
.desc
1252 self
.gateway_prompt
[obj
.jid
]['prompt'] = obj
.prompt
1256 Class for about dialog
1260 dlg
= gtk
.AboutDialog()
1261 dlg
.set_transient_for(gajim
.interface
.roster
.window
)
1262 dlg
.set_name('Gajim')
1263 dlg
.set_version(gajim
.version
)
1264 s
= u
'Copyright © 2003-2010 Gajim Team'
1265 dlg
.set_copyright(s
)
1266 copying_file_path
= self
.get_path('COPYING')
1267 if copying_file_path
:
1268 text
= open(copying_file_path
).read()
1269 dlg
.set_license(text
)
1271 dlg
.set_comments('%s\n%s %s\n%s %s' % (_('A GTK+ jabber client'),
1272 _('GTK+ Version:'), self
.tuple2str(gtk
.gtk_version
), \
1273 _('PyGTK Version:'), self
.tuple2str(gtk
.pygtk_version
)))
1274 dlg
.set_website('http://www.gajim.org/')
1276 authors_file_path
= self
.get_path('AUTHORS')
1277 if authors_file_path
:
1279 authors_file
= open(authors_file_path
).read()
1280 authors_file
= authors_file
.split('\n')
1281 for author
in authors_file
:
1282 if author
== 'CURRENT DEVELOPERS:':
1283 authors
.append(_('Current Developers:'))
1284 elif author
== 'PAST DEVELOPERS:':
1285 authors
.append('\n' + _('Past Developers:'))
1286 elif author
!= '': # Real author line
1287 authors
.append(author
)
1289 thanks_file_path
= self
.get_path('THANKS')
1290 if thanks_file_path
:
1291 authors
.append('\n' + _('THANKS:'))
1293 text
= open(thanks_file_path
).read()
1294 text_splitted
= text
.split('\n')
1295 text
= '\n'.join(text_splitted
[:-2]) # remove one english sentence
1296 # and add it manually as translatable
1297 text
+= '\n%s\n' % _('Last but not least, we would like to thank all '
1298 'the package maintainers.')
1299 authors
.append(text
)
1301 dlg
.set_authors(authors
)
1303 dlg
.props
.wrap_license
= True
1305 pixbuf
= gtkgui_helpers
.get_icon_pixmap('gajim-about', 128)
1307 dlg
.set_logo(pixbuf
)
1308 #here you write your name in the form Name FamilyName <someone@somewhere>
1309 dlg
.set_translator_credits(_('translator-credits'))
1311 thanks_artists_file_path
= self
.get_path('THANKS.artists')
1312 if thanks_artists_file_path
:
1313 artists_text
= open(thanks_artists_file_path
).read()
1314 artists
= artists_text
.split('\n')
1315 dlg
.set_artists(artists
)
1316 # connect close button to destroy() function
1317 for button
in dlg
.action_area
.get_children():
1318 if button
.get_property('label') == gtk
.STOCK_CLOSE
:
1319 button
.connect('clicked', lambda x
:dlg
.destroy())
1322 def tuple2str(self
, tuple_
):
1325 str_
+= str(num
) + '.'
1326 return str_
[0:-1] # remove latest .
1328 def get_path(self
, filename
):
1330 Where can we find this Credits file?
1332 if os
.path
.isfile(os
.path
.join(gajim
.defs
.docdir
, filename
)):
1333 return os
.path
.join(gajim
.defs
.docdir
, filename
)
1334 elif os
.path
.isfile('../' + filename
):
1335 return ('../' + filename
)
1339 class Dialog(gtk
.Dialog
):
1340 def __init__(self
, parent
, title
, buttons
, default
=None,
1341 on_response_ok
=None, on_response_cancel
=None):
1342 gtk
.Dialog
.__init
__(self
, title
, parent
,
1343 gtk
.DIALOG_DESTROY_WITH_PARENT | gtk
.DIALOG_NO_SEPARATOR
)
1345 self
.user_response_ok
= on_response_ok
1346 self
.user_response_cancel
= on_response_cancel
1347 self
.set_border_width(6)
1348 self
.vbox
.set_spacing(12)
1349 self
.set_resizable(False)
1351 possible_responses
= {gtk
.STOCK_OK
: self
.on_response_ok
,
1352 gtk
.STOCK_CANCEL
: self
.on_response_cancel
}
1353 for stock
, response
in buttons
:
1354 b
= self
.add_button(stock
, response
)
1355 for response
in possible_responses
:
1356 if stock
== response
:
1357 b
.connect('clicked', possible_responses
[response
])
1360 if default
is not None:
1361 self
.set_default_response(default
)
1363 self
.set_default_response(buttons
[-1][1])
1365 def on_response_ok(self
, widget
):
1366 if self
.user_response_ok
:
1367 if isinstance(self
.user_response_ok
, tuple):
1368 self
.user_response_ok
[0](*self
.user_response_ok
[1:])
1370 self
.user_response_ok()
1373 def on_response_cancel(self
, widget
):
1374 if self
.user_response_cancel
:
1375 if isinstance(self
.user_response_cancel
, tuple):
1376 self
.user_response_cancel
[0](*self
.user_response_ok
[1:])
1378 self
.user_response_cancel()
1381 def just_destroy(self
, widget
):
1384 def get_button(self
, index
):
1385 buttons
= self
.action_area
.get_children()
1386 return index
< len(buttons
) and buttons
[index
] or None
1389 class HigDialog(gtk
.MessageDialog
):
1390 def __init__(self
, parent
, type_
, buttons
, pritext
, sectext
,
1391 on_response_ok
=None, on_response_cancel
=None, on_response_yes
=None,
1392 on_response_no
=None):
1393 self
.call_cancel_on_destroy
= True
1394 gtk
.MessageDialog
.__init
__(self
, parent
,
1395 gtk
.DIALOG_DESTROY_WITH_PARENT | gtk
.DIALOG_MODAL
,
1396 type_
, buttons
, message_format
= pritext
)
1398 self
.format_secondary_markup(sectext
)
1400 buttons
= self
.action_area
.get_children()
1401 self
.possible_responses
= {gtk
.STOCK_OK
: on_response_ok
,
1402 gtk
.STOCK_CANCEL
: on_response_cancel
, gtk
.STOCK_YES
: on_response_yes
,
1403 gtk
.STOCK_NO
: on_response_no
}
1405 for response
in self
.possible_responses
:
1406 if b
.get_label() == response
:
1407 if not self
.possible_responses
[response
]:
1408 b
.connect('clicked', self
.just_destroy
)
1409 elif isinstance(self
.possible_responses
[response
], tuple):
1410 if len(self
.possible_responses
[response
]) == 1:
1411 b
.connect('clicked', self
.possible_responses
[response
][0])
1413 b
.connect('clicked', *self
.possible_responses
[response
])
1415 b
.connect('clicked', self
.possible_responses
[response
])
1418 self
.connect('destroy', self
.on_dialog_destroy
)
1420 def on_dialog_destroy(self
, widget
):
1421 if not self
.call_cancel_on_destroy
:
1423 cancel_handler
= self
.possible_responses
[gtk
.STOCK_CANCEL
]
1424 if not cancel_handler
:
1426 if isinstance(cancel_handler
, tuple):
1427 cancel_handler
[0](None, *cancel_handler
[1:])
1429 cancel_handler(None)
1431 def just_destroy(self
, widget
):
1438 vb
= self
.get_children()[0].get_children()[0] # Give focus to top vbox
1439 vb
.set_flags(gtk
.CAN_FOCUS
)
1443 class FileChooserDialog(gtk
.FileChooserDialog
):
1445 Non-blocking FileChooser Dialog around gtk.FileChooserDialog
1447 def __init__(self
, title_text
, action
, buttons
, default_response
,
1448 select_multiple
=False, current_folder
=None, on_response_ok
=None,
1449 on_response_cancel
=None):
1451 gtk
.FileChooserDialog
.__init
__(self
, title
=title_text
, action
=action
,
1454 self
.set_default_response(default_response
)
1455 self
.set_select_multiple(select_multiple
)
1456 if current_folder
and os
.path
.isdir(current_folder
):
1457 self
.set_current_folder(current_folder
)
1459 self
.set_current_folder(helpers
.get_documents_path())
1460 self
.response_ok
, self
.response_cancel
= \
1461 on_response_ok
, on_response_cancel
1462 # in gtk+-2.10 clicked signal on some of the buttons in a dialog
1463 # is emitted twice, so we cannot rely on 'clicked' signal
1464 self
.connect('response', self
.on_dialog_response
)
1467 def on_dialog_response(self
, dialog
, response
):
1468 if response
in (gtk
.RESPONSE_CANCEL
, gtk
.RESPONSE_CLOSE
):
1469 if self
.response_cancel
:
1470 if isinstance(self
.response_cancel
, tuple):
1471 self
.response_cancel
[0](dialog
, *self
.response_cancel
[1:])
1473 self
.response_cancel(dialog
)
1475 self
.just_destroy(dialog
)
1476 elif response
== gtk
.RESPONSE_OK
:
1477 if self
.response_ok
:
1478 if isinstance(self
.response_ok
, tuple):
1479 self
.response_ok
[0](dialog
, *self
.response_ok
[1:])
1481 self
.response_ok(dialog
)
1483 self
.just_destroy(dialog
)
1485 def just_destroy(self
, widget
):
1488 class AspellDictError
:
1489 def __init__(self
, lang
):
1491 _('Dictionary for lang %s not available') % lang
,
1492 _('You have to install %s dictionary to use spellchecking, or '
1493 'choose another language by setting the speller_language option.'
1494 '\n\nHighlighting misspelled words feature will not be used') % lang
)
1495 gajim
.config
.set('use_speller', False)
1497 class ConfirmationDialog(HigDialog
):
1499 HIG compliant confirmation dialog
1502 def __init__(self
, pritext
, sectext
='', on_response_ok
=None,
1503 on_response_cancel
=None):
1504 self
.user_response_ok
= on_response_ok
1505 self
.user_response_cancel
= on_response_cancel
1506 HigDialog
.__init
__(self
, None,
1507 gtk
.MESSAGE_QUESTION
, gtk
.BUTTONS_OK_CANCEL
, pritext
, sectext
,
1508 self
.on_response_ok
, self
.on_response_cancel
)
1511 def on_response_ok(self
, widget
):
1512 if self
.user_response_ok
:
1513 if isinstance(self
.user_response_ok
, tuple):
1514 self
.user_response_ok
[0](*self
.user_response_ok
[1:])
1516 self
.user_response_ok()
1517 self
.call_cancel_on_destroy
= False
1520 def on_response_cancel(self
, widget
):
1521 if self
.user_response_cancel
:
1522 if isinstance(self
.user_response_cancel
, tuple):
1523 self
.user_response_cancel
[0](*self
.user_response_ok
[1:])
1525 self
.user_response_cancel()
1526 self
.call_cancel_on_destroy
= False
1529 class NonModalConfirmationDialog(HigDialog
):
1531 HIG compliant non modal confirmation dialog
1534 def __init__(self
, pritext
, sectext
='', on_response_ok
=None,
1535 on_response_cancel
=None):
1536 self
.user_response_ok
= on_response_ok
1537 self
.user_response_cancel
= on_response_cancel
1538 HigDialog
.__init
__(self
, None,
1539 gtk
.MESSAGE_QUESTION
, gtk
.BUTTONS_OK_CANCEL
, pritext
, sectext
,
1540 self
.on_response_ok
, self
.on_response_cancel
)
1541 self
.set_modal(False)
1543 def on_response_ok(self
, widget
):
1544 if self
.user_response_ok
:
1545 if isinstance(self
.user_response_ok
, tuple):
1546 self
.user_response_ok
[0](*self
.user_response_ok
[1:])
1548 self
.user_response_ok()
1549 self
.call_cancel_on_destroy
= False
1552 def on_response_cancel(self
, widget
):
1553 if self
.user_response_cancel
:
1554 if isinstance(self
.user_response_cancel
, tuple):
1555 self
.user_response_cancel
[0](*self
.user_response_cancel
[1:])
1557 self
.user_response_cancel()
1558 self
.call_cancel_on_destroy
= False
1561 class WarningDialog(HigDialog
):
1563 HIG compliant warning dialog
1566 def __init__(self
, pritext
, sectext
='', transient_for
=None):
1567 HigDialog
.__init
__(self
, None, gtk
.MESSAGE_WARNING
, gtk
.BUTTONS_OK
,
1569 self
.set_modal(False)
1570 if transient_for
is None and hasattr(gajim
.interface
, 'roster') and \
1571 gajim
.interface
.roster
:
1572 transient_for
= gajim
.interface
.roster
.window
1574 self
.set_transient_for(transient_for
)
1577 class InformationDialog(HigDialog
):
1579 HIG compliant info dialog
1582 def __init__(self
, pritext
, sectext
=''):
1583 HigDialog
.__init
__(self
, None, gtk
.MESSAGE_INFO
, gtk
.BUTTONS_OK
,
1585 self
.set_modal(False)
1586 self
.set_transient_for(gajim
.interface
.roster
.window
)
1589 class ErrorDialog(HigDialog
):
1591 HIG compliant error dialog
1594 def __init__(self
, pritext
, sectext
='', on_response_ok
=None,
1595 on_response_cancel
=None):
1596 HigDialog
.__init
__( self
, None, gtk
.MESSAGE_ERROR
, gtk
.BUTTONS_OK
,
1597 pritext
, sectext
, on_response_ok
=on_response_ok
,
1598 on_response_cancel
=on_response_cancel
)
1601 class YesNoDialog(HigDialog
):
1603 HIG compliant YesNo dialog
1606 def __init__(self
, pritext
, sectext
='', checktext
='', on_response_yes
=None,
1607 on_response_no
=None):
1608 self
.user_response_yes
= on_response_yes
1609 self
.user_response_no
= on_response_no
1610 HigDialog
.__init
__(self
, None, gtk
.MESSAGE_QUESTION
, gtk
.BUTTONS_YES_NO
,
1611 pritext
, sectext
, on_response_yes
=self
.on_response_yes
,
1612 on_response_no
=self
.on_response_no
)
1615 self
.checkbutton
= gtk
.CheckButton(checktext
)
1616 self
.vbox
.pack_start(self
.checkbutton
, expand
=False, fill
=True)
1618 self
.checkbutton
= None
1619 self
.set_modal(False)
1622 def on_response_yes(self
, widget
):
1623 if self
.user_response_yes
:
1624 if isinstance(self
.user_response_yes
, tuple):
1625 self
.user_response_yes
[0](self
.is_checked(),
1626 *self
.user_response_yes
[1:])
1628 self
.user_response_yes(self
.is_checked())
1629 self
.call_cancel_on_destroy
= False
1632 def on_response_no(self
, widget
):
1633 if self
.user_response_no
:
1634 if isinstance(self
.user_response_no
, tuple):
1635 self
.user_response_no
[0](*self
.user_response_no
[1:])
1637 self
.user_response_no()
1638 self
.call_cancel_on_destroy
= False
1641 def is_checked(self
):
1643 Get active state of the checkbutton
1645 if not self
.checkbutton
:
1647 return self
.checkbutton
.get_active()
1649 class ConfirmationDialogCheck(ConfirmationDialog
):
1651 HIG compliant confirmation dialog with checkbutton
1654 def __init__(self
, pritext
, sectext
='', checktext
='', on_response_ok
=None,
1655 on_response_cancel
=None, is_modal
=True):
1656 self
.user_response_ok
= on_response_ok
1657 self
.user_response_cancel
= on_response_cancel
1659 HigDialog
.__init
__(self
, None, gtk
.MESSAGE_QUESTION
,
1660 gtk
.BUTTONS_OK_CANCEL
, pritext
, sectext
, self
.on_response_ok
,
1661 self
.on_response_cancel
)
1663 self
.set_default_response(gtk
.RESPONSE_OK
)
1665 ok_button
= self
.action_area
.get_children()[0] # right to left
1666 ok_button
.grab_focus()
1668 self
.checkbutton
= gtk
.CheckButton(checktext
)
1669 self
.vbox
.pack_start(self
.checkbutton
, expand
=False, fill
=True)
1670 self
.set_modal(is_modal
)
1673 def on_response_ok(self
, widget
):
1674 if self
.user_response_ok
:
1675 if isinstance(self
.user_response_ok
, tuple):
1676 self
.user_response_ok
[0](self
.is_checked(),
1677 *self
.user_response_ok
[1:])
1679 self
.user_response_ok(self
.is_checked())
1680 self
.call_cancel_on_destroy
= False
1683 def on_response_cancel(self
, widget
):
1684 if self
.user_response_cancel
:
1685 if isinstance(self
.user_response_cancel
, tuple):
1686 self
.user_response_cancel
[0](self
.is_checked(),
1687 *self
.user_response_cancel
[1:])
1689 self
.user_response_cancel(self
.is_checked())
1690 self
.call_cancel_on_destroy
= False
1693 def is_checked(self
):
1695 Get active state of the checkbutton
1697 return self
.checkbutton
.get_active()
1699 class ConfirmationDialogDoubleCheck(ConfirmationDialog
):
1701 HIG compliant confirmation dialog with 2 checkbuttons
1704 def __init__(self
, pritext
, sectext
='', checktext1
='', checktext2
='',
1705 on_response_ok
=None, on_response_cancel
=None, is_modal
=True):
1706 self
.user_response_ok
= on_response_ok
1707 self
.user_response_cancel
= on_response_cancel
1709 HigDialog
.__init
__(self
, None, gtk
.MESSAGE_QUESTION
,
1710 gtk
.BUTTONS_OK_CANCEL
, pritext
, sectext
, self
.on_response_ok
,
1711 self
.on_response_cancel
)
1713 self
.set_default_response(gtk
.RESPONSE_OK
)
1715 ok_button
= self
.action_area
.get_children()[0] # right to left
1716 ok_button
.grab_focus()
1719 self
.checkbutton1
= gtk
.CheckButton(checktext1
)
1720 self
.vbox
.pack_start(self
.checkbutton1
, expand
=False, fill
=True)
1722 self
.checkbutton1
= None
1724 self
.checkbutton2
= gtk
.CheckButton(checktext2
)
1725 self
.vbox
.pack_start(self
.checkbutton2
, expand
=False, fill
=True)
1727 self
.checkbutton2
= None
1729 self
.set_modal(is_modal
)
1732 def on_response_ok(self
, widget
):
1733 if self
.user_response_ok
:
1734 if isinstance(self
.user_response_ok
, tuple):
1735 self
.user_response_ok
[0](self
.is_checked(),
1736 *self
.user_response_ok
[1:])
1738 self
.user_response_ok(self
.is_checked())
1739 self
.call_cancel_on_destroy
= False
1742 def on_response_cancel(self
, widget
):
1743 if self
.user_response_cancel
:
1744 if isinstance(self
.user_response_cancel
, tuple):
1745 self
.user_response_cancel
[0](*self
.user_response_cancel
[1:])
1747 self
.user_response_cancel()
1748 self
.call_cancel_on_destroy
= False
1751 def is_checked(self
):
1752 ''' Get active state of the checkbutton '''
1753 if self
.checkbutton1
:
1754 is_checked_1
= self
.checkbutton1
.get_active()
1756 is_checked_1
= False
1757 if self
.checkbutton2
:
1758 is_checked_2
= self
.checkbutton2
.get_active()
1760 is_checked_2
= False
1761 return [is_checked_1
, is_checked_2
]
1763 class ConfirmationDialogDoubleRadio(ConfirmationDialog
):
1765 HIG compliant confirmation dialog with 2 radios
1768 def __init__(self
, pritext
, sectext
='', radiotext1
='', radiotext2
='',
1769 on_response_ok
=None, on_response_cancel
=None, is_modal
=True):
1770 self
.user_response_ok
= on_response_ok
1771 self
.user_response_cancel
= on_response_cancel
1773 HigDialog
.__init
__(self
, None, gtk
.MESSAGE_QUESTION
,
1774 gtk
.BUTTONS_OK_CANCEL
, pritext
, sectext
, self
.on_response_ok
,
1775 self
.on_response_cancel
)
1777 self
.set_default_response(gtk
.RESPONSE_OK
)
1779 ok_button
= self
.action_area
.get_children()[0] # right to left
1780 ok_button
.grab_focus()
1782 self
.radiobutton1
= gtk
.RadioButton(label
=radiotext1
)
1783 self
.vbox
.pack_start(self
.radiobutton1
, expand
=False, fill
=True)
1785 self
.radiobutton2
= gtk
.RadioButton(group
=self
.radiobutton1
,
1787 self
.vbox
.pack_start(self
.radiobutton2
, expand
=False, fill
=True)
1789 self
.set_modal(is_modal
)
1792 def on_response_ok(self
, widget
):
1793 if self
.user_response_ok
:
1794 if isinstance(self
.user_response_ok
, tuple):
1795 self
.user_response_ok
[0](self
.is_checked(),
1796 *self
.user_response_ok
[1:])
1798 self
.user_response_ok(self
.is_checked())
1799 self
.call_cancel_on_destroy
= False
1802 def on_response_cancel(self
, widget
):
1803 if self
.user_response_cancel
:
1804 if isinstance(self
.user_response_cancel
, tuple):
1805 self
.user_response_cancel
[0](*self
.user_response_cancel
[1:])
1807 self
.user_response_cancel()
1808 self
.call_cancel_on_destroy
= False
1811 def is_checked(self
):
1812 ''' Get active state of the checkbutton '''
1813 if self
.radiobutton1
:
1814 is_checked_1
= self
.radiobutton1
.get_active()
1816 is_checked_1
= False
1817 if self
.radiobutton2
:
1818 is_checked_2
= self
.radiobutton2
.get_active()
1820 is_checked_2
= False
1821 return [is_checked_1
, is_checked_2
]
1823 class FTOverwriteConfirmationDialog(ConfirmationDialog
):
1825 HIG compliant confirmation dialog to overwrite or resume a file transfert
1828 def __init__(self
, pritext
, sectext
='', propose_resume
=True,
1830 HigDialog
.__init
__(self
, None, gtk
.MESSAGE_QUESTION
, gtk
.BUTTONS_CANCEL
,
1833 self
.on_response
= on_response
1836 b
= gtk
.Button('', gtk
.STOCK_REFRESH
)
1837 align
= b
.get_children()[0]
1838 hbox
= align
.get_children()[0]
1839 label
= hbox
.get_children()[1]
1840 label
.set_text(_('_Resume'))
1841 label
.set_use_underline(True)
1842 self
.add_action_widget(b
, 100)
1844 b
= gtk
.Button('', gtk
.STOCK_SAVE_AS
)
1845 align
= b
.get_children()[0]
1846 hbox
= align
.get_children()[0]
1847 label
= hbox
.get_children()[1]
1848 label
.set_text(_('Re_place'))
1849 label
.set_use_underline(True)
1850 self
.add_action_widget(b
, 200)
1852 self
.connect('response', self
.on_dialog_response
)
1855 def on_dialog_response(self
, dialog
, response
):
1856 if self
.on_response
:
1857 if isinstance(self
.on_response
, tuple):
1858 self
.on_response
[0](response
, *self
.on_response
[1:])
1860 self
.on_response(response
)
1861 self
.call_cancel_on_destroy
= False
1864 class CommonInputDialog
:
1866 Common Class for Input dialogs
1869 def __init__(self
, title
, label_str
, is_modal
, ok_handler
, cancel_handler
):
1870 self
.dialog
= self
.xml
.get_object('input_dialog')
1871 label
= self
.xml
.get_object('label')
1872 self
.dialog
.set_title(title
)
1873 label
.set_markup(label_str
)
1874 self
.cancel_handler
= cancel_handler
1875 self
.vbox
= self
.xml
.get_object('vbox')
1877 self
.ok_handler
= ok_handler
1878 okbutton
= self
.xml
.get_object('okbutton')
1879 okbutton
.connect('clicked', self
.on_okbutton_clicked
)
1880 cancelbutton
= self
.xml
.get_object('cancelbutton')
1881 cancelbutton
.connect('clicked', self
.on_cancelbutton_clicked
)
1882 self
.xml
.connect_signals(self
)
1883 self
.dialog
.show_all()
1885 def on_input_dialog_destroy(self
, widget
):
1886 if self
.cancel_handler
:
1887 self
.cancel_handler()
1889 def on_okbutton_clicked(self
, widget
):
1890 user_input
= self
.get_text()
1892 user_input
= user_input
.decode('utf-8')
1893 self
.cancel_handler
= None
1894 self
.dialog
.destroy()
1895 if isinstance(self
.ok_handler
, tuple):
1896 self
.ok_handler
[0](user_input
, *self
.ok_handler
[1:])
1898 self
.ok_handler(user_input
)
1900 def on_cancelbutton_clicked(self
, widget
):
1901 self
.dialog
.destroy()
1903 class InputDialog(CommonInputDialog
):
1905 Class for Input dialog
1908 def __init__(self
, title
, label_str
, input_str
=None, is_modal
=True,
1909 ok_handler
=None, cancel_handler
=None):
1910 self
.xml
= gtkgui_helpers
.get_gtk_builder('input_dialog.ui')
1911 CommonInputDialog
.__init
__(self
, title
, label_str
, is_modal
, ok_handler
,
1913 self
.input_entry
= self
.xml
.get_object('input_entry')
1915 self
.set_entry(input_str
)
1917 def on_input_dialog_delete_event(self
, widget
, event
):
1919 may be implemented by subclasses
1923 def set_entry(self
, value
):
1924 self
.input_entry
.set_text(value
)
1925 self
.input_entry
.select_region(0, -1) # select all
1928 return self
.input_entry
.get_text().decode('utf-8')
1930 class InputDialogCheck(InputDialog
):
1932 Class for Input dialog
1935 def __init__(self
, title
, label_str
, checktext
='', input_str
=None,
1936 is_modal
=True, ok_handler
=None, cancel_handler
=None):
1937 self
.xml
= gtkgui_helpers
.get_gtk_builder('input_dialog.ui')
1938 InputDialog
.__init
__(self
, title
, label_str
, input_str
=input_str
,
1939 is_modal
=is_modal
, ok_handler
=ok_handler
,
1940 cancel_handler
=cancel_handler
)
1941 self
.input_entry
= self
.xml
.get_object('input_entry')
1943 self
.input_entry
.set_text(input_str
)
1944 self
.input_entry
.select_region(0, -1) # select all
1947 self
.checkbutton
= gtk
.CheckButton(checktext
)
1948 self
.vbox
.pack_start(self
.checkbutton
, expand
=False, fill
=True)
1949 self
.checkbutton
.show()
1951 def on_okbutton_clicked(self
, widget
):
1952 user_input
= self
.get_text()
1954 user_input
= user_input
.decode('utf-8')
1955 self
.cancel_handler
= None
1956 self
.dialog
.destroy()
1957 if isinstance(self
.ok_handler
, tuple):
1958 self
.ok_handler
[0](user_input
, self
.is_checked(), *self
.ok_handler
[1:])
1960 self
.ok_handler(user_input
, self
.is_checked())
1963 return self
.input_entry
.get_text().decode('utf-8')
1965 def is_checked(self
):
1967 Get active state of the checkbutton
1970 return self
.checkbutton
.get_active()
1972 # There is no checkbutton
1975 class ChangeNickDialog(InputDialogCheck
):
1977 Class for changing room nickname in case of conflict
1980 def __init__(self
, account
, room_jid
, title
, prompt
, check_text
=None,
1983 change_nick must be set to True when we are already occupant of the room
1984 and we are changing our nick
1986 InputDialogCheck
.__init
__(self
, title
, '', checktext
=check_text
,
1987 input_str
='', is_modal
=True, ok_handler
=None, cancel_handler
=None)
1988 self
.room_queue
= [(account
, room_jid
, prompt
, change_nick
)]
1991 def on_input_dialog_delete_event(self
, widget
, event
):
1992 self
.on_cancelbutton_clicked(widget
)
1995 def setup_dialog(self
):
1996 self
.gc_control
= gajim
.interface
.msg_win_mgr
.get_gc_control(
1997 self
.room_jid
, self
.account
)
1998 if not self
.gc_control
and \
1999 self
.room_jid
in gajim
.interface
.minimized_controls
[self
.account
]:
2001 gajim
.interface
.minimized_controls
[self
.account
][self
.room_jid
]
2002 if not self
.gc_control
:
2005 label
= self
.xml
.get_object('label')
2006 label
.set_markup(self
.prompt
)
2007 self
.set_entry(self
.gc_control
.nick
+ \
2008 gajim
.config
.get('gc_proposed_nick_char'))
2010 def check_next(self
):
2011 if len(self
.room_queue
) == 0:
2012 self
.cancel_handler
= None
2013 self
.dialog
.destroy()
2014 if 'change_nick_dialog' in gajim
.interface
.instances
:
2015 del gajim
.interface
.instances
['change_nick_dialog']
2017 self
.account
, self
.room_jid
, self
.prompt
, self
.change_nick
= \
2018 self
.room_queue
.pop(0)
2021 if gajim
.new_room_nick
is not None and not gajim
.gc_connected
[
2022 self
.account
][self
.room_jid
] and self
.gc_control
.nick
!= \
2023 gajim
.new_room_nick
:
2025 self
.on_ok(gajim
.new_room_nick
, True)
2029 def on_okbutton_clicked(self
, widget
):
2030 nick
= self
.get_text()
2032 nick
= nick
.decode('utf-8')
2033 # send presence to room
2035 nick
= helpers
.parse_resource(nick
)
2038 ErrorDialog(_('Invalid nickname'),
2039 _('The nickname has not allowed characters.'))
2041 self
.on_ok(nick
, self
.is_checked())
2043 def on_ok(self
, nick
, is_checked
):
2045 gajim
.new_room_nick
= nick
2046 gajim
.connections
[self
.account
].join_gc(nick
, self
.room_jid
, None,
2047 change_nick
=self
.change_nick
)
2048 if gajim
.gc_connected
[self
.account
][self
.room_jid
]:
2049 # We are changing nick, we will change self.nick when we receive
2050 # presence that inform that it works
2051 self
.gc_control
.new_nick
= nick
2053 # We are connecting, we will not get a changed nick presence so
2054 # change it NOW. We don't already have a nick so it's harmless
2055 self
.gc_control
.nick
= nick
2058 def on_cancelbutton_clicked(self
, widget
):
2059 self
.gc_control
.new_nick
= ''
2062 def add_room(self
, account
, room_jid
, prompt
, change_nick
=False):
2063 if (account
, room_jid
, prompt
, change_nick
) not in self
.room_queue
:
2064 self
.room_queue
.append((account
, room_jid
, prompt
, change_nick
))
2066 class InputTextDialog(CommonInputDialog
):
2068 Class for multilines Input dialog (more place than InputDialog)
2071 def __init__(self
, title
, label_str
, input_str
=None, is_modal
=True,
2072 ok_handler
=None, cancel_handler
=None):
2073 self
.xml
= gtkgui_helpers
.get_gtk_builder('input_text_dialog.ui')
2074 CommonInputDialog
.__init
__(self
, title
, label_str
, is_modal
, ok_handler
,
2076 self
.input_buffer
= self
.xml
.get_object('input_textview').get_buffer()
2078 self
.input_buffer
.set_text(input_str
)
2079 start_iter
, end_iter
= self
.input_buffer
.get_bounds()
2080 self
.input_buffer
.select_range(start_iter
, end_iter
) # select all
2083 start_iter
, end_iter
= self
.input_buffer
.get_bounds()
2084 return self
.input_buffer
.get_text(start_iter
, end_iter
).decode('utf-8')
2086 class DoubleInputDialog
:
2088 Class for Double Input dialog
2091 def __init__(self
, title
, label_str1
, label_str2
, input_str1
=None,
2092 input_str2
=None, is_modal
=True, ok_handler
=None, cancel_handler
=None):
2093 self
.xml
= gtkgui_helpers
.get_gtk_builder('dubbleinput_dialog.ui')
2094 self
.dialog
= self
.xml
.get_object('dubbleinput_dialog')
2095 label1
= self
.xml
.get_object('label1')
2096 self
.input_entry1
= self
.xml
.get_object('input_entry1')
2097 label2
= self
.xml
.get_object('label2')
2098 self
.input_entry2
= self
.xml
.get_object('input_entry2')
2099 self
.dialog
.set_title(title
)
2100 label1
.set_markup(label_str1
)
2101 label2
.set_markup(label_str2
)
2102 self
.cancel_handler
= cancel_handler
2104 self
.input_entry1
.set_text(input_str1
)
2105 self
.input_entry1
.select_region(0, -1) # select all
2107 self
.input_entry2
.set_text(input_str2
)
2108 self
.input_entry2
.select_region(0, -1) # select all
2110 self
.dialog
.set_modal(is_modal
)
2112 self
.ok_handler
= ok_handler
2113 okbutton
= self
.xml
.get_object('okbutton')
2114 okbutton
.connect('clicked', self
.on_okbutton_clicked
)
2115 cancelbutton
= self
.xml
.get_object('cancelbutton')
2116 cancelbutton
.connect('clicked', self
.on_cancelbutton_clicked
)
2117 self
.xml
.connect_signals(self
)
2118 self
.dialog
.show_all()
2120 def on_dubbleinput_dialog_destroy(self
, widget
):
2121 if not self
.cancel_handler
:
2123 if isinstance(self
.cancel_handler
, tuple):
2124 self
.cancel_handler
[0](*self
.cancel_handler
[1:])
2126 self
.cancel_handler()
2128 def on_okbutton_clicked(self
, widget
):
2129 user_input1
= self
.input_entry1
.get_text().decode('utf-8')
2130 user_input2
= self
.input_entry2
.get_text().decode('utf-8')
2131 self
.dialog
.destroy()
2132 if not self
.ok_handler
:
2134 if isinstance(self
.ok_handler
, tuple):
2135 self
.ok_handler
[0](user_input1
, user_input2
, *self
.ok_handler
[1:])
2137 self
.ok_handler(user_input1
, user_input2
)
2139 def on_cancelbutton_clicked(self
, widget
):
2140 self
.dialog
.destroy()
2141 if not self
.cancel_handler
:
2143 if isinstance(self
.cancel_handler
, tuple):
2144 self
.cancel_handler
[0](*self
.cancel_handler
[1:])
2146 self
.cancel_handler()
2148 class SubscriptionRequestWindow
:
2149 def __init__(self
, jid
, text
, account
, user_nick
=None):
2150 xml
= gtkgui_helpers
.get_gtk_builder('subscription_request_window.ui')
2151 self
.window
= xml
.get_object('subscription_request_window')
2153 self
.account
= account
2154 self
.user_nick
= user_nick
2155 if len(gajim
.connections
) >= 2:
2157 _('Subscription request for account %(account)s from %(jid)s')\
2158 % {'account': account
, 'jid': self
.jid
}
2160 prompt_text
= _('Subscription request from %s') % self
.jid
2161 xml
.get_object('from_label').set_text(prompt_text
)
2162 xml
.get_object('message_textview').get_buffer().set_text(text
)
2163 xml
.connect_signals(self
)
2164 self
.window
.show_all()
2166 def prepare_popup_menu(self
):
2167 xml
= gtkgui_helpers
.get_gtk_builder('subscription_request_popup_menu.ui')
2168 menu
= xml
.get_object('subscription_request_popup_menu')
2169 xml
.connect_signals(self
)
2172 def on_close_button_clicked(self
, widget
):
2173 self
.window
.destroy()
2175 def on_authorize_button_clicked(self
, widget
):
2179 gajim
.connections
[self
.account
].send_authorization(self
.jid
)
2180 self
.window
.destroy()
2181 contact
= gajim
.contacts
.get_contact(self
.account
, self
.jid
)
2182 if not contact
or _('Not in Roster') in contact
.groups
:
2183 AddNewContactWindow(self
.account
, self
.jid
, self
.user_nick
)
2185 def on_contact_info_activate(self
, widget
):
2189 if self
.jid
in gajim
.interface
.instances
[self
.account
]['infos']:
2190 gajim
.interface
.instances
[self
.account
]['infos'][self
.jid
].window
.present()
2192 contact
= gajim
.contacts
.create_contact(jid
=self
.jid
, account
=self
.account
)
2193 gajim
.interface
.instances
[self
.account
]['infos'][self
.jid
] = \
2194 vcard
.VcardWindow(contact
, self
.account
)
2195 # Remove jabber page
2196 gajim
.interface
.instances
[self
.account
]['infos'][self
.jid
].xml
.\
2197 get_object('information_notebook').remove_page(0)
2199 def on_start_chat_activate(self
, widget
):
2203 gajim
.interface
.new_chat_from_jid(self
.account
, self
.jid
)
2205 def on_deny_button_clicked(self
, widget
):
2209 gajim
.connections
[self
.account
].refuse_authorization(self
.jid
)
2210 contact
= gajim
.contacts
.get_contact(self
.account
, self
.jid
)
2211 if contact
and _('Not in Roster') in contact
.get_shown_groups():
2212 gajim
.interface
.roster
.remove_contact(self
.jid
, self
.account
)
2213 self
.window
.destroy()
2215 def on_actions_button_clicked(self
, widget
):
2219 menu
= self
.prepare_popup_menu()
2221 gtkgui_helpers
.popup_emoticons_under_button(menu
, widget
,
2225 class JoinGroupchatWindow
:
2226 def __init__(self
, account
=None, room_jid
='', nick
='', password
='',
2229 Automatic is a dict like {'invities': []}. If automatic is not empty,
2230 this means room must be automaticaly configured and when done, invities
2231 must be automatically invited
2234 if room_jid
!= '' and room_jid
in gajim
.gc_connected
[account
] and\
2235 gajim
.gc_connected
[account
][room_jid
]:
2236 ErrorDialog(_('You are already in group chat %s') % room_jid
)
2237 raise GajimGeneralException
, 'You are already in this group chat'
2239 nick
= gajim
.nicks
[account
]
2240 if gajim
.connections
[account
].connected
< 2:
2241 ErrorDialog(_('You are not connected to the server'),
2242 _('You can not join a group chat unless you are connected.'))
2243 raise GajimGeneralException
, 'You must be connected to join a groupchat'
2245 self
.xml
= gtkgui_helpers
.get_gtk_builder('join_groupchat_window.ui')
2247 account_label
= self
.xml
.get_object('account_label')
2248 account_combobox
= self
.xml
.get_object('account_combobox')
2249 account_label
.set_no_show_all(False)
2250 account_combobox
.set_no_show_all(False)
2251 liststore
= gtk
.ListStore(str)
2252 account_combobox
.set_model(liststore
)
2253 cell
= gtk
.CellRendererText()
2254 account_combobox
.pack_start(cell
, True)
2255 account_combobox
.add_attribute(cell
, 'text', 0)
2256 account_combobox
.set_active(-1)
2258 # Add accounts, set current as active if it matches 'account'
2259 for acct
in [a
for a
in gajim
.connections
if \
2260 gajim
.account_is_connected(a
)]:
2261 if gajim
.connections
[acct
].is_zeroconf
:
2263 account_combobox
.append_text(acct
)
2264 if account
and account
== acct
:
2265 account_combobox
.set_active(liststore
.iter_n_children(None)-1)
2267 self
.account
= account
2268 self
.automatic
= automatic
2269 self
._empty
_required
_widgets
= []
2271 self
.window
= self
.xml
.get_object('join_groupchat_window')
2272 self
.window
.set_transient_for(gajim
.interface
.roster
.window
)
2273 self
._room
_jid
_entry
= self
.xml
.get_object('room_jid_entry')
2274 self
._nickname
_entry
= self
.xml
.get_object('nickname_entry')
2275 self
._password
_entry
= self
.xml
.get_object('password_entry')
2277 self
._nickname
_entry
.set_text(nick
)
2279 self
._password
_entry
.set_text(password
)
2280 self
.xml
.connect_signals(self
)
2283 # now add us to open windows
2284 gajim
.interface
.instances
[account
]['join_gc'] = self
2285 if len(gajim
.connections
) > 1:
2286 title
= _('Join Group Chat with account %s') % account
2288 title
= _('Join Group Chat')
2289 self
.window
.set_title(title
)
2291 self
.server_comboboxentry
= self
.xml
.get_object('server_comboboxentry')
2292 self
.server_model
= self
.server_comboboxentry
.get_model()
2294 # get the muc server of our server
2295 if 'jabber' in gajim
.connections
[account
].muc_jid
:
2296 server_list
.append(gajim
.connections
[account
].muc_jid
['jabber'])
2298 self
.recently_combobox
= self
.xml
.get_object('recently_combobox')
2299 liststore
= gtk
.ListStore(str)
2300 self
.recently_combobox
.set_model(liststore
)
2301 cell
= gtk
.CellRendererText()
2302 self
.recently_combobox
.pack_start(cell
, True)
2303 self
.recently_combobox
.add_attribute(cell
, 'text', 0)
2304 self
.recently_groupchat
= gajim
.config
.get('recently_groupchat').split()
2305 for g
in self
.recently_groupchat
:
2306 self
.recently_combobox
.append_text(g
)
2307 server
= gajim
.get_server_from_jid(g
)
2308 if server
not in server_list
and not server
.startswith('irc'):
2309 server_list
.append(server
)
2311 for s
in server_list
:
2312 self
.server_model
.append([s
])
2313 self
.server_comboboxentry
.set_active(0)
2315 self
._set
_room
_jid
(room_jid
)
2317 if len(self
.recently_groupchat
) == 0:
2318 self
.recently_combobox
.set_sensitive(False)
2319 elif room_jid
== '':
2320 self
.recently_combobox
.set_active(0)
2321 self
._room
_jid
_entry
.select_region(0, -1)
2322 elif room_jid
!= '':
2323 self
.xml
.get_object('join_button').grab_focus()
2325 if not self
._room
_jid
_entry
.get_text():
2326 self
._empty
_required
_widgets
.append(self
._room
_jid
_entry
)
2327 if not self
._nickname
_entry
.get_text():
2328 self
._empty
_required
_widgets
.append(self
._nickname
_entry
)
2329 if len(self
._empty
_required
_widgets
):
2330 self
.xml
.get_object('join_button').set_sensitive(False)
2332 if account
and not gajim
.connections
[account
].private_storage_supported
:
2333 self
.xml
.get_object('bookmark_checkbutton').set_sensitive(False)
2335 self
.window
.show_all()
2337 def on_join_groupchat_window_destroy(self
, widget
):
2341 if self
.account
and 'join_gc' in gajim
.interface
.instances
[self
.account
]:
2342 # remove us from open windows
2343 del gajim
.interface
.instances
[self
.account
]['join_gc']
2345 def on_join_groupchat_window_key_press_event(self
, widget
, event
):
2346 if event
.keyval
== gtk
.keysyms
.Escape
: # ESCAPE
2349 def on_required_entry_changed(self
, widget
):
2350 if not widget
.get_text():
2351 self
._empty
_required
_widgets
.append(widget
)
2352 self
.xml
.get_object('join_button').set_sensitive(False)
2354 if widget
in self
._empty
_required
_widgets
:
2355 self
._empty
_required
_widgets
.remove(widget
)
2356 if not self
._empty
_required
_widgets
and self
.account
:
2357 self
.xml
.get_object('join_button').set_sensitive(True)
2358 text
= self
._room
_jid
_entry
.get_text()
2359 if widget
== self
._room
_jid
_entry
and '@' in text
:
2360 # Don't allow @ char in room entry
2361 room_jid
, server
= text
.split('@', 1)
2362 self
._room
_jid
_entry
.set_text(room_jid
)
2364 self
.server_comboboxentry
.child
.set_text(server
)
2365 self
.server_comboboxentry
.grab_focus()
2367 def on_account_combobox_changed(self
, widget
):
2368 model
= widget
.get_model()
2369 iter_
= widget
.get_active_iter()
2370 self
.account
= model
[iter_
][0].decode('utf-8')
2371 self
.on_required_entry_changed(self
._nickname
_entry
)
2373 def _set_room_jid(self
, room_jid
):
2374 room
, server
= gajim
.get_name_and_server_from_jid(room_jid
)
2375 self
._room
_jid
_entry
.set_text(room
)
2376 self
.server_comboboxentry
.child
.set_text(server
)
2378 def on_recently_combobox_changed(self
, widget
):
2379 model
= widget
.get_model()
2380 iter_
= widget
.get_active_iter()
2381 room_jid
= model
[iter_
][0].decode('utf-8')
2382 self
._set
_room
_jid
(room_jid
)
2384 def on_browse_rooms_button_clicked(self
, widget
):
2385 server
= self
.server_comboboxentry
.child
.get_text().decode('utf-8')
2386 if server
in gajim
.interface
.instances
[self
.account
]['disco']:
2387 gajim
.interface
.instances
[self
.account
]['disco'][server
].window
.\
2391 # Object will add itself to the window dict
2393 disco
.ServiceDiscoveryWindow(self
.account
, server
,
2394 initial_identities
=[{'category': 'conference',
2396 except GajimGeneralException
:
2399 def on_cancel_button_clicked(self
, widget
):
2401 When Cancel button is clicked
2403 self
.window
.destroy()
2405 def on_bookmark_checkbutton_toggled(self
, widget
):
2406 auto_join_checkbutton
= self
.xml
.get_object('auto_join_checkbutton')
2407 if widget
.get_active():
2408 auto_join_checkbutton
.set_sensitive(True)
2410 auto_join_checkbutton
.set_sensitive(False)
2412 def on_join_button_clicked(self
, widget
):
2414 When Join button is clicked
2416 if not self
.account
:
2417 ErrorDialog(_('Invalid Account'),
2418 _('You have to choose an account from which you want to join the '
2421 nickname
= self
._nickname
_entry
.get_text().decode('utf-8')
2422 server
= self
.server_comboboxentry
.child
.get_text().decode('utf-8')
2423 room
= self
._room
_jid
_entry
.get_text().decode('utf-8')
2424 room_jid
= room
+ '@' + server
2425 password
= self
._password
_entry
.get_text().decode('utf-8')
2427 nickname
= helpers
.parse_resource(nickname
)
2429 ErrorDialog(_('Invalid Nickname'),
2430 _('The nickname has not allowed characters.'))
2432 user
, server
, resource
= helpers
.decompose_jid(room_jid
)
2433 if not user
or not server
or resource
:
2434 ErrorDialog(_('Invalid group chat Jabber ID'),
2435 _('Please enter the group chat Jabber ID as room@server.'))
2438 room_jid
= helpers
.parse_jid(room_jid
)
2440 ErrorDialog(_('Invalid group chat Jabber ID'),
2441 _('The group chat Jabber ID has not allowed characters.'))
2444 if gajim
.interface
.msg_win_mgr
.has_window(room_jid
, self
.account
):
2445 ctrl
= gajim
.interface
.msg_win_mgr
.get_gc_control(room_jid
,
2447 if ctrl
.type_id
!= message_control
.TYPE_GC
:
2448 ErrorDialog(_('This is not a group chat'),
2449 _('%s is not the name of a group chat.') % room_jid
)
2451 if room_jid
in self
.recently_groupchat
:
2452 self
.recently_groupchat
.remove(room_jid
)
2453 self
.recently_groupchat
.insert(0, room_jid
)
2454 if len(self
.recently_groupchat
) > 10:
2455 self
.recently_groupchat
= self
.recently_groupchat
[0:10]
2456 gajim
.config
.set('recently_groupchat',
2457 ' '.join(self
.recently_groupchat
))
2459 if self
.xml
.get_object('bookmark_checkbutton').get_active():
2460 if self
.xml
.get_object('auto_join_checkbutton').get_active():
2464 # Add as bookmark, with autojoin and not minimized
2465 name
= gajim
.get_nick_from_jid(room_jid
)
2466 gajim
.interface
.add_gc_bookmark(self
.account
, name
, room_jid
, autojoin
,
2467 '0', password
, nickname
)
2470 gajim
.automatic_rooms
[self
.account
][room_jid
] = self
.automatic
2472 gajim
.interface
.join_gc_room(self
.account
, room_jid
, nickname
, password
)
2474 self
.window
.destroy()
2476 class SynchroniseSelectAccountDialog
:
2477 def __init__(self
, account
):
2478 # 'account' can be None if we are about to create our first one
2479 if not account
or gajim
.connections
[account
].connected
< 2:
2480 ErrorDialog(_('You are not connected to the server'),
2481 _('Without a connection, you can not synchronise your contacts.'))
2482 raise GajimGeneralException
, 'You are not connected to the server'
2483 self
.account
= account
2484 self
.xml
= gtkgui_helpers
.get_gtk_builder('synchronise_select_account_dialog.ui')
2485 self
.dialog
= self
.xml
.get_object('synchronise_select_account_dialog')
2486 self
.accounts_treeview
= self
.xml
.get_object('accounts_treeview')
2487 model
= gtk
.ListStore(str, str, bool)
2488 self
.accounts_treeview
.set_model(model
)
2490 renderer
= gtk
.CellRendererText()
2491 self
.accounts_treeview
.insert_column_with_attributes(-1, _('Name'),
2493 renderer
= gtk
.CellRendererText()
2494 self
.accounts_treeview
.insert_column_with_attributes(-1, _('Server'),
2497 self
.xml
.connect_signals(self
)
2498 self
.init_accounts()
2499 self
.dialog
.show_all()
2501 def on_accounts_window_key_press_event(self
, widget
, event
):
2502 if event
.keyval
== gtk
.keysyms
.Escape
:
2503 self
.window
.destroy()
2505 def init_accounts(self
):
2507 Initialize listStore with existing accounts
2509 model
= self
.accounts_treeview
.get_model()
2511 for remote_account
in gajim
.connections
:
2512 if remote_account
== self
.account
:
2513 # Do not show the account we're sync'ing
2515 iter_
= model
.append()
2516 model
.set(iter_
, 0, remote_account
, 1,
2517 gajim
.get_hostname_from_account(remote_account
))
2519 def on_cancel_button_clicked(self
, widget
):
2520 self
.dialog
.destroy()
2522 def on_ok_button_clicked(self
, widget
):
2523 sel
= self
.accounts_treeview
.get_selection()
2524 (model
, iter_
) = sel
.get_selected()
2527 remote_account
= model
.get_value(iter_
, 0).decode('utf-8')
2529 if gajim
.connections
[remote_account
].connected
< 2:
2530 ErrorDialog(_('This account is not connected to the server'),
2531 _('You cannot synchronize with an account unless it is connected.'))
2535 SynchroniseSelectContactsDialog(self
.account
, remote_account
)
2536 except GajimGeneralException
:
2537 # if we showed ErrorDialog, there will not be dialog instance
2539 self
.dialog
.destroy()
2541 class SynchroniseSelectContactsDialog
:
2542 def __init__(self
, account
, remote_account
):
2543 self
.local_account
= account
2544 self
.remote_account
= remote_account
2545 self
.xml
= gtkgui_helpers
.get_gtk_builder(
2546 'synchronise_select_contacts_dialog.ui')
2547 self
.dialog
= self
.xml
.get_object('synchronise_select_contacts_dialog')
2548 self
.contacts_treeview
= self
.xml
.get_object('contacts_treeview')
2549 model
= gtk
.ListStore(bool, str)
2550 self
.contacts_treeview
.set_model(model
)
2552 renderer1
= gtk
.CellRendererToggle()
2553 renderer1
.set_property('activatable', True)
2554 renderer1
.connect('toggled', self
.toggled_callback
)
2555 self
.contacts_treeview
.insert_column_with_attributes(-1,
2556 _('Synchronise'), renderer1
, active
=0)
2557 renderer2
= gtk
.CellRendererText()
2558 self
.contacts_treeview
.insert_column_with_attributes(-1, _('Name'),
2561 self
.xml
.connect_signals(self
)
2562 self
.init_contacts()
2563 self
.dialog
.show_all()
2565 def toggled_callback(self
, cell
, path
):
2566 model
= self
.contacts_treeview
.get_model()
2567 iter_
= model
.get_iter(path
)
2568 model
[iter_
][0] = not cell
.get_active()
2570 def on_contacts_window_key_press_event(self
, widget
, event
):
2571 if event
.keyval
== gtk
.keysyms
.Escape
:
2572 self
.window
.destroy()
2574 def init_contacts(self
):
2576 Initialize listStore with existing accounts
2578 model
= self
.contacts_treeview
.get_model()
2581 # recover local contacts
2582 local_jid_list
= gajim
.contacts
.get_contacts_jid_list(self
.local_account
)
2584 remote_jid_list
= gajim
.contacts
.get_contacts_jid_list(
2585 self
.remote_account
)
2586 for remote_jid
in remote_jid_list
:
2587 if remote_jid
not in local_jid_list
:
2588 iter_
= model
.append()
2589 model
.set(iter_
, 0, True, 1, remote_jid
)
2591 def on_cancel_button_clicked(self
, widget
):
2592 self
.dialog
.destroy()
2594 def on_ok_button_clicked(self
, widget
):
2595 model
= self
.contacts_treeview
.get_model()
2596 iter_
= model
.get_iter_root()
2600 remote_jid
= model
[iter_
][1].decode('utf-8')
2601 message
= 'I\'m synchronizing my contacts from my %s account, could you please add this address to your contact list?' % \
2602 gajim
.get_hostname_from_account(self
.remote_account
)
2603 remote_contact
= gajim
.contacts
.get_first_contact_from_jid(
2604 self
.remote_account
, remote_jid
)
2605 # keep same groups and same nickname
2606 gajim
.interface
.roster
.req_sub(self
, remote_jid
, message
,
2607 self
.local_account
, groups
= remote_contact
.groups
,
2608 nickname
= remote_contact
.name
, auto_auth
= True)
2609 iter_
= model
.iter_next(iter_
)
2610 self
.dialog
.destroy()
2612 class NewChatDialog(InputDialog
):
2613 def __init__(self
, account
):
2614 self
.account
= account
2616 if len(gajim
.connections
) > 1:
2617 title
= _('Start Chat with account %s') % account
2619 title
= _('Start Chat')
2620 prompt_text
= _('Fill in the nickname or the Jabber ID of the contact you would like\nto send a chat message to:')
2621 InputDialog
.__init
__(self
, title
, prompt_text
, is_modal
=False)
2623 self
.completion_dict
= {}
2624 liststore
= gtkgui_helpers
.get_completion_liststore(self
.input_entry
)
2625 self
.completion_dict
= helpers
.get_contact_dict_for_account(account
)
2626 # add all contacts to the model
2627 keys
= sorted(self
.completion_dict
.keys())
2629 contact
= self
.completion_dict
[jid
]
2630 img
= gajim
.interface
.jabber_state_images
['16'][contact
.show
]
2631 liststore
.append((img
.get_pixbuf(), jid
))
2633 self
.ok_handler
= self
.new_chat_response
2634 okbutton
= self
.xml
.get_object('okbutton')
2635 okbutton
.connect('clicked', self
.on_okbutton_clicked
)
2636 cancelbutton
= self
.xml
.get_object('cancelbutton')
2637 cancelbutton
.connect('clicked', self
.on_cancelbutton_clicked
)
2638 self
.dialog
.set_transient_for(gajim
.interface
.roster
.window
)
2639 self
.dialog
.show_all()
2641 def new_chat_response(self
, jid
):
2643 Called when ok button is clicked
2645 if gajim
.connections
[self
.account
].connected
<= 1:
2646 #if offline or connecting
2647 ErrorDialog(_('Connection not available'),
2648 _('Please make sure you are connected with "%s".') % self
.account
)
2651 if jid
in self
.completion_dict
:
2652 jid
= self
.completion_dict
[jid
].jid
2655 jid
= helpers
.parse_jid(jid
)
2656 except helpers
.InvalidFormat
, e
:
2657 ErrorDialog(_('Invalid JID'), e
[0])
2660 ErrorDialog(_('Invalid JID'), _('Unable to parse "%s".') % jid
)
2662 gajim
.interface
.new_chat_from_jid(self
.account
, jid
)
2664 class ChangePasswordDialog
:
2665 def __init__(self
, account
, on_response
):
2666 # 'account' can be None if we are about to create our first one
2667 if not account
or gajim
.connections
[account
].connected
< 2:
2668 ErrorDialog(_('You are not connected to the server'),
2669 _('Without a connection, you can not change your password.'))
2670 raise GajimGeneralException
, 'You are not connected to the server'
2671 self
.account
= account
2672 self
.on_response
= on_response
2673 self
.xml
= gtkgui_helpers
.get_gtk_builder('change_password_dialog.ui')
2674 self
.dialog
= self
.xml
.get_object('change_password_dialog')
2675 self
.password1_entry
= self
.xml
.get_object('password1_entry')
2676 self
.password2_entry
= self
.xml
.get_object('password2_entry')
2677 self
.dialog
.connect('response', self
.on_dialog_response
)
2679 self
.dialog
.show_all()
2681 def on_dialog_response(self
, dialog
, response
):
2682 if response
!= gtk
.RESPONSE_OK
:
2684 self
.on_response(None)
2686 password1
= self
.password1_entry
.get_text().decode('utf-8')
2688 ErrorDialog(_('Invalid password'), _('You must enter a password.'))
2690 password2
= self
.password2_entry
.get_text().decode('utf-8')
2691 if password1
!= password2
:
2692 ErrorDialog(_('Passwords do not match'),
2693 _('The passwords typed in both fields must be identical.'))
2696 self
.on_response(password1
)
2698 class PopupNotificationWindow
:
2699 def __init__(self
, event_type
, jid
, account
, msg_type
='',
2700 path_to_image
=None, title
=None, text
=None):
2701 self
.account
= account
2703 self
.msg_type
= msg_type
2705 xml
= gtkgui_helpers
.get_gtk_builder('popup_notification_window.ui')
2706 self
.window
= xml
.get_object('popup_notification_window')
2707 self
.window
.set_type_hint(gtk
.gdk
.WINDOW_TYPE_HINT_TOOLTIP
)
2708 close_button
= xml
.get_object('close_button')
2709 event_type_label
= xml
.get_object('event_type_label')
2710 event_description_label
= xml
.get_object('event_description_label')
2711 eventbox
= xml
.get_object('eventbox')
2712 image
= xml
.get_object('notification_image')
2715 text
= gajim
.get_name_from_jid(account
, jid
) # default value of text
2719 event_type_label
.set_markup(
2720 '<span foreground="black" weight="bold">%s</span>' %
2721 gobject
.markup_escape_text(title
))
2723 # set colors [ http://www.pitt.edu/~nisg/cis/web/cgi/rgb.html ]
2724 self
.window
.modify_bg(gtk
.STATE_NORMAL
, gtk
.gdk
.color_parse('black'))
2727 if not path_to_image
:
2728 path_to_image
= gtkgui_helpers
.get_icon_path('gajim-chat_msg_recv', 48)
2730 if event_type
== _('Contact Signed In'):
2731 bg_color
= 'limegreen'
2732 elif event_type
== _('Contact Signed Out'):
2734 elif event_type
in (_('New Message'), _('New Single Message'),
2735 _('New Private Message'), _('New E-mail')):
2736 bg_color
= 'dodgerblue'
2737 elif event_type
== _('File Transfer Request'):
2739 elif event_type
== _('File Transfer Error'):
2740 bg_color
= 'firebrick'
2741 elif event_type
in (_('File Transfer Completed'),
2742 _('File Transfer Stopped')):
2743 bg_color
= 'yellowgreen'
2744 elif event_type
== _('Groupchat Invitation'):
2746 elif event_type
== _('Contact Changed Status'):
2747 bg_color
= 'thistle2'
2748 else: # Unknown event! Shouldn't happen but deal with it
2750 popup_bg_color
= gtk
.gdk
.color_parse(bg_color
)
2751 close_button
.modify_bg(gtk
.STATE_NORMAL
, popup_bg_color
)
2752 eventbox
.modify_bg(gtk
.STATE_NORMAL
, popup_bg_color
)
2753 event_description_label
.set_markup('<span foreground="black">%s</span>' %
2754 gobject
.markup_escape_text(text
))
2757 image
.set_from_file(path_to_image
)
2759 # position the window to bottom-right of screen
2760 window_width
, self
.window_height
= self
.window
.get_size()
2761 gajim
.interface
.roster
.popups_notification_height
+= self
.window_height
2762 pos_x
= gajim
.config
.get('notification_position_x')
2764 pos_x
= gtk
.gdk
.screen_width() - window_width
+ pos_x
+ 1
2765 pos_y
= gajim
.config
.get('notification_position_y')
2767 pos_y
= gtk
.gdk
.screen_height() - \
2768 gajim
.interface
.roster
.popups_notification_height
+ pos_y
+ 1
2769 self
.window
.move(pos_x
, pos_y
)
2771 xml
.connect_signals(self
)
2772 self
.window
.show_all()
2773 timeout
= gajim
.config
.get('notification_timeout')
2774 gobject
.timeout_add_seconds(timeout
, self
.on_timeout
)
2776 def on_close_button_clicked(self
, widget
):
2777 self
.adjust_height_and_move_popup_notification_windows()
2779 def on_timeout(self
):
2780 self
.adjust_height_and_move_popup_notification_windows()
2782 def adjust_height_and_move_popup_notification_windows(self
):
2784 gajim
.interface
.roster
.popups_notification_height
-= self
.window_height
2785 self
.window
.destroy()
2787 if len(gajim
.interface
.roster
.popup_notification_windows
) > 0:
2788 # we want to remove the first window added in the list
2789 gajim
.interface
.roster
.popup_notification_windows
.pop(0)
2791 # move the rest of popup windows
2792 gajim
.interface
.roster
.popups_notification_height
= 0
2793 for window_instance
in gajim
.interface
.roster
.popup_notification_windows
:
2794 window_width
, window_height
= window_instance
.window
.get_size()
2795 gajim
.interface
.roster
.popups_notification_height
+= window_height
2796 window_instance
.window
.move(gtk
.gdk
.screen_width() - window_width
,
2797 gtk
.gdk
.screen_height() - \
2798 gajim
.interface
.roster
.popups_notification_height
)
2800 def on_popup_notification_window_button_press_event(self
, widget
, event
):
2801 if event
.button
!= 1:
2802 self
.window
.destroy()
2804 gajim
.interface
.handle_event(self
.account
, self
.jid
, self
.msg_type
)
2805 self
.adjust_height_and_move_popup_notification_windows()
2807 class SingleMessageWindow
:
2809 SingleMessageWindow can send or show a received singled message depending on
2810 action argument which can be 'send' or 'receive'
2812 # Keep a reference on windows so garbage collector don't restroy them
2814 def __init__(self
, account
, to
='', action
='', from_whom
='', subject
='',
2815 message
='', resource
='', session
=None, form_node
=None):
2816 self
.instances
.append(self
)
2817 self
.account
= account
2818 self
.action
= action
2820 self
.subject
= subject
2821 self
.message
= message
2823 self
.from_whom
= from_whom
2824 self
.resource
= resource
2825 self
.session
= session
2827 self
.xml
= gtkgui_helpers
.get_gtk_builder('single_message_window.ui')
2828 self
.window
= self
.xml
.get_object('single_message_window')
2829 self
.count_chars_label
= self
.xml
.get_object('count_chars_label')
2830 self
.from_label
= self
.xml
.get_object('from_label')
2831 self
.from_entry
= self
.xml
.get_object('from_entry')
2832 self
.to_label
= self
.xml
.get_object('to_label')
2833 self
.to_entry
= self
.xml
.get_object('to_entry')
2834 self
.subject_entry
= self
.xml
.get_object('subject_entry')
2835 self
.message_scrolledwindow
= self
.xml
.get_object(
2836 'message_scrolledwindow')
2837 self
.message_textview
= self
.xml
.get_object('message_textview')
2838 self
.message_tv_buffer
= self
.message_textview
.get_buffer()
2839 self
.conversation_scrolledwindow
= self
.xml
.get_object(
2840 'conversation_scrolledwindow')
2841 self
.conversation_textview
= conversation_textview
.ConversationTextview(
2843 self
.conversation_textview
.tv
.show()
2844 self
.conversation_tv_buffer
= self
.conversation_textview
.tv
.get_buffer()
2845 self
.xml
.get_object('conversation_scrolledwindow').add(
2846 self
.conversation_textview
.tv
)
2848 self
.form_widget
= None
2849 parent_box
= self
.xml
.get_object('conversation_scrolledwindow').\
2852 dataform
= dataforms
.ExtendForm(node
=form_node
)
2853 self
.form_widget
= dataforms_widget
.DataFormWidget(dataform
)
2854 self
.form_widget
.show_all()
2855 parent_box
.add(self
.form_widget
)
2856 parent_box
.child_set_property(self
.form_widget
, 'position',
2857 parent_box
.child_get_property(self
.xml
.get_object(
2858 'conversation_scrolledwindow'), 'position'))
2859 self
.action
= 'form'
2861 self
.send_button
= self
.xml
.get_object('send_button')
2862 self
.reply_button
= self
.xml
.get_object('reply_button')
2863 self
.send_and_close_button
= self
.xml
.get_object('send_and_close_button')
2864 self
.cancel_button
= self
.xml
.get_object('cancel_button')
2865 self
.close_button
= self
.xml
.get_object('close_button')
2866 self
.message_tv_buffer
.connect('changed', self
.update_char_counter
)
2867 if isinstance(to
, list):
2868 jid
= ', '.join( [i
[0].get_full_jid() for i
in to
])
2869 self
.to_entry
.set_text(jid
)
2870 self
.to_entry
.set_sensitive(False)
2872 self
.to_entry
.set_text(to
)
2874 if gajim
.config
.get('use_speller') and HAS_GTK_SPELL
and action
== 'send':
2876 lang
= gajim
.config
.get('speller_language')
2879 gtkspell
.Spell(self
.conversation_textview
.tv
, lang
)
2880 gtkspell
.Spell(self
.message_textview
, lang
)
2881 except (gobject
.GError
, TypeError, RuntimeError, OSError):
2882 AspellDictError(lang
)
2884 self
.prepare_widgets_for(self
.action
)
2886 # set_text(None) raises TypeError exception
2887 if self
.subject
is None:
2889 self
.subject_entry
.set_text(self
.subject
)
2893 liststore
= gtkgui_helpers
.get_completion_liststore(self
.to_entry
)
2894 self
.completion_dict
= helpers
.get_contact_dict_for_account(account
)
2895 keys
= sorted(self
.completion_dict
.keys())
2897 contact
= self
.completion_dict
[jid
]
2898 img
= gajim
.interface
.jabber_state_images
['16'][contact
.show
]
2899 liststore
.append((img
.get_pixbuf(), jid
))
2901 self
.completion_dict
= {}
2902 self
.xml
.connect_signals(self
)
2904 # get window position and size from config
2905 gtkgui_helpers
.resize_window(self
.window
,
2906 gajim
.config
.get('single-msg-width'),
2907 gajim
.config
.get('single-msg-height'))
2908 gtkgui_helpers
.move_window(self
.window
,
2909 gajim
.config
.get('single-msg-x-position'),
2910 gajim
.config
.get('single-msg-y-position'))
2912 self
.window
.show_all()
2914 def on_single_message_window_destroy(self
, widget
):
2915 self
.instances
.remove(self
)
2916 c
= gajim
.contacts
.get_contact_with_highest_priority(self
.account
,
2919 # Groupchat is maybe already destroyed
2921 if c
.is_groupchat() and not self
.from_whom
in \
2922 gajim
.interface
.minimized_controls
[self
.account
] and self
.action
== \
2923 'receive' and gajim
.events
.get_nb_roster_events(self
.account
,
2924 self
.from_whom
, types
=['chat', 'normal']) == 0:
2925 gajim
.interface
.roster
.remove_groupchat(self
.from_whom
, self
.account
)
2927 def set_cursor_to_end(self
):
2928 end_iter
= self
.message_tv_buffer
.get_end_iter()
2929 self
.message_tv_buffer
.place_cursor(end_iter
)
2932 # save the window size and position
2933 x
, y
= self
.window
.get_position()
2934 gajim
.config
.set('single-msg-x-position', x
)
2935 gajim
.config
.set('single-msg-y-position', y
)
2936 width
, height
= self
.window
.get_size()
2937 gajim
.config
.set('single-msg-width', width
)
2938 gajim
.config
.set('single-msg-height', height
)
2939 gajim
.interface
.save_config()
2941 def on_single_message_window_delete_event(self
, window
, ev
):
2944 def prepare_widgets_for(self
, action
):
2945 if len(gajim
.connections
) > 1:
2946 if action
== 'send':
2947 title
= _('Single Message using account %s') % self
.account
2949 title
= _('Single Message in account %s') % self
.account
2951 title
= _('Single Message')
2953 if action
== 'send': # prepare UI for Sending
2954 title
= _('Send %s') % title
2955 self
.send_button
.show()
2956 self
.send_and_close_button
.show()
2957 self
.to_label
.show()
2958 self
.to_entry
.show()
2959 self
.reply_button
.hide()
2960 self
.from_label
.hide()
2961 self
.from_entry
.hide()
2962 self
.conversation_scrolledwindow
.hide()
2963 self
.message_scrolledwindow
.show()
2965 if self
.message
: # we come from a reply?
2966 self
.message_textview
.grab_focus()
2967 self
.cancel_button
.hide()
2968 self
.close_button
.show()
2969 self
.message_tv_buffer
.set_text(self
.message
)
2970 gobject
.idle_add(self
.set_cursor_to_end
)
2971 else: # we write a new message (not from reply)
2972 self
.close_button
.hide()
2973 if self
.to
: # do we already have jid?
2974 self
.subject_entry
.grab_focus()
2976 elif action
== 'receive': # prepare UI for Receiving
2977 title
= _('Received %s') % title
2978 self
.reply_button
.show()
2979 self
.from_label
.show()
2980 self
.from_entry
.show()
2981 self
.send_button
.hide()
2982 self
.send_and_close_button
.hide()
2983 self
.to_label
.hide()
2984 self
.to_entry
.hide()
2985 self
.conversation_scrolledwindow
.show()
2986 self
.message_scrolledwindow
.hide()
2989 self
.conversation_textview
.print_real_text(self
.message
)
2990 fjid
= self
.from_whom
2992 fjid
+= '/' + self
.resource
# Full jid of sender (with resource)
2993 self
.from_entry
.set_text(fjid
)
2994 self
.from_entry
.set_property('editable', False)
2995 self
.subject_entry
.set_property('editable', False)
2996 self
.reply_button
.grab_focus()
2997 self
.cancel_button
.hide()
2998 self
.close_button
.show()
2999 elif action
== 'form': # prepare UI for Receiving
3000 title
= _('Form %s') % title
3001 self
.send_button
.show()
3002 self
.send_and_close_button
.show()
3003 self
.to_label
.show()
3004 self
.to_entry
.show()
3005 self
.reply_button
.hide()
3006 self
.from_label
.hide()
3007 self
.from_entry
.hide()
3008 self
.conversation_scrolledwindow
.hide()
3009 self
.message_scrolledwindow
.hide()
3011 self
.window
.set_title(title
)
3013 def on_cancel_button_clicked(self
, widget
):
3015 self
.window
.destroy()
3017 def on_close_button_clicked(self
, widget
):
3019 self
.window
.destroy()
3021 def update_char_counter(self
, widget
):
3022 characters_no
= self
.message_tv_buffer
.get_char_count()
3023 self
.count_chars_label
.set_text(unicode(characters_no
))
3025 def send_single_message(self
):
3026 if gajim
.connections
[self
.account
].connected
<= 1:
3027 # if offline or connecting
3028 ErrorDialog(_('Connection not available'),
3029 _('Please make sure you are connected with "%s".') % self
.account
)
3031 if isinstance(self
.to
, list):
3032 sender_list
= [i
[0].jid
+ '/' + i
[0].resource
for i
in self
.to
]
3034 sender_list
= [self
.to_entry
.get_text().decode('utf-8')]
3036 for to_whom_jid
in sender_list
:
3037 if to_whom_jid
in self
.completion_dict
:
3038 to_whom_jid
= self
.completion_dict
[to_whom_jid
].jid
3040 to_whom_jid
= helpers
.parse_jid(to_whom_jid
)
3041 except helpers
.InvalidFormat
:
3042 ErrorDialog(_('Invalid Jabber ID'),
3043 _('It is not possible to send a message to %s, this JID is not '
3044 'valid.') % to_whom_jid
)
3047 subject
= self
.subject_entry
.get_text().decode('utf-8')
3048 begin
, end
= self
.message_tv_buffer
.get_bounds()
3049 message
= self
.message_tv_buffer
.get_text(begin
, end
).decode('utf-8')
3051 if '/announce/' in to_whom_jid
:
3052 gajim
.connections
[self
.account
].send_motd(to_whom_jid
, subject
,
3057 session
= self
.session
3059 session
= gajim
.connections
[self
.account
].make_new_session(
3062 if self
.form_widget
:
3063 form_node
= self
.form_widget
.data_form
3066 # FIXME: allow GPG message some day
3067 gajim
.connections
[self
.account
].send_message(to_whom_jid
, message
,
3068 keyID
=None, type_
='normal', subject
=subject
, session
=session
,
3069 form_node
=form_node
)
3071 self
.subject_entry
.set_text('') # we sent ok, clear the subject
3072 self
.message_tv_buffer
.set_text('') # we sent ok, clear the textview
3074 def on_send_button_clicked(self
, widget
):
3075 self
.send_single_message()
3077 def on_reply_button_clicked(self
, widget
):
3078 # we create a new blank window to send and we preset RE: and to jid
3079 self
.subject
= _('RE: %s') % self
.subject
3080 self
.message
= _('%s wrote:\n') % self
.from_whom
+ self
.message
3081 # add > at the begining of each line
3082 self
.message
= self
.message
.replace('\n', '\n> ') + '\n\n'
3083 self
.window
.destroy()
3084 SingleMessageWindow(self
.account
, to
=self
.from_whom
, action
='send',
3085 from_whom
=self
.from_whom
, subject
=self
.subject
, message
=self
.message
,
3086 session
=self
.session
)
3088 def on_send_and_close_button_clicked(self
, widget
):
3089 self
.send_single_message()
3091 self
.window
.destroy()
3093 def on_single_message_window_key_press_event(self
, widget
, event
):
3094 if event
.keyval
== gtk
.keysyms
.Escape
: # ESCAPE
3096 self
.window
.destroy()
3098 class XMLConsoleWindow
:
3099 def __init__(self
, account
):
3100 self
.account
= account
3102 self
.xml
= gtkgui_helpers
.get_gtk_builder('xml_console_window.ui')
3103 self
.window
= self
.xml
.get_object('xml_console_window')
3104 self
.input_textview
= self
.xml
.get_object('input_textview')
3105 self
.stanzas_log_textview
= self
.xml
.get_object('stanzas_log_textview')
3106 self
.input_tv_buffer
= self
.input_textview
.get_buffer()
3107 buffer_
= self
.stanzas_log_textview
.get_buffer()
3108 end_iter
= buffer_
.get_end_iter()
3109 buffer_
.create_mark('end', end_iter
, False)
3111 self
.tagIn
= buffer_
.create_tag('incoming')
3112 color
= gajim
.config
.get('inmsgcolor')
3113 self
.tagIn
.set_property('foreground', color
)
3114 self
.tagInPresence
= buffer_
.create_tag('incoming_presence')
3115 self
.tagInPresence
.set_property('foreground', color
)
3116 self
.tagInMessage
= buffer_
.create_tag('incoming_message')
3117 self
.tagInMessage
.set_property('foreground', color
)
3118 self
.tagInIq
= buffer_
.create_tag('incoming_iq')
3119 self
.tagInIq
.set_property('foreground', color
)
3121 self
.tagOut
= buffer_
.create_tag('outgoing')
3122 color
= gajim
.config
.get('outmsgcolor')
3123 self
.tagOut
.set_property('foreground', color
)
3124 self
.tagOutPresence
= buffer_
.create_tag('outgoing_presence')
3125 self
.tagOutPresence
.set_property('foreground', color
)
3126 self
.tagOutMessage
= buffer_
.create_tag('outgoing_message')
3127 self
.tagOutMessage
.set_property('foreground', color
)
3128 self
.tagOutIq
= buffer_
.create_tag('outgoing_iq')
3129 self
.tagOutIq
.set_property('foreground', color
)
3130 buffer_
.create_tag('') # Default tag
3133 self
.xml
.get_object('enable_checkbutton').set_active(True)
3135 self
.input_textview
.modify_text(
3136 gtk
.STATE_NORMAL
, gtk
.gdk
.color_parse(color
))
3138 if len(gajim
.connections
) > 1:
3139 title
= _('XML Console for %s') % self
.account
3141 title
= _('XML Console')
3143 self
.window
.set_title(title
)
3144 self
.window
.show_all()
3145 gajim
.ged
.register_event_handler('stanza-received', ged
.GUI1
,
3146 self
._nec
_stanza
_received
)
3147 gajim
.ged
.register_event_handler('stanza-sent', ged
.GUI1
,
3148 self
._nec
_stanza
_sent
)
3150 self
.xml
.connect_signals(self
)
3152 def on_xml_console_window_destroy(self
, widget
):
3153 del gajim
.interface
.instances
[self
.account
]['xml_console']
3154 gajim
.ged
.remove_event_handler('stanza-received', ged
.GUI1
,
3155 self
._nec
_stanza
_received
)
3156 gajim
.ged
.remove_event_handler('stanza-sent', ged
.GUI1
,
3157 self
._nec
_stanza
_sent
)
3159 def on_clear_button_clicked(self
, widget
):
3160 buffer_
= self
.stanzas_log_textview
.get_buffer()
3161 buffer_
.set_text('')
3163 def on_enable_checkbutton_toggled(self
, widget
):
3164 self
.enabled
= widget
.get_active()
3166 def on_in_stanza_checkbutton_toggled(self
, widget
):
3167 active
= widget
.get_active()
3168 self
.tagIn
.set_property('invisible', active
)
3169 self
.tagInPresence
.set_property('invisible', active
)
3170 self
.tagInMessage
.set_property('invisible', active
)
3171 self
.tagInIq
.set_property('invisible', active
)
3173 def on_presence_stanza_checkbutton_toggled(self
, widget
):
3174 active
= widget
.get_active()
3175 self
.tagInPresence
.set_property('invisible', active
)
3176 self
.tagOutPresence
.set_property('invisible', active
)
3178 def on_out_stanza_checkbutton_toggled(self
, widget
):
3179 active
= widget
.get_active()
3180 self
.tagOut
.set_property('invisible', active
)
3181 self
.tagOutPresence
.set_property('invisible', active
)
3182 self
.tagOutMessage
.set_property('invisible', active
)
3183 self
.tagOutIq
.set_property('invisible', active
)
3185 def on_message_stanza_checkbutton_toggled(self
, widget
):
3186 active
= widget
.get_active()
3187 self
.tagInMessage
.set_property('invisible', active
)
3188 self
.tagOutMessage
.set_property('invisible', active
)
3190 def on_iq_stanza_checkbutton_toggled(self
, widget
):
3191 active
= widget
.get_active()
3192 self
.tagInIq
.set_property('invisible', active
)
3193 self
.tagOutIq
.set_property('invisible', active
)
3195 def scroll_to_end(self
, ):
3196 parent
= self
.stanzas_log_textview
.get_parent()
3197 buffer_
= self
.stanzas_log_textview
.get_buffer()
3198 end_mark
= buffer_
.get_mark('end')
3201 self
.stanzas_log_textview
.scroll_to_mark(end_mark
, 0, True, 0, 1)
3202 adjustment
= parent
.get_hadjustment()
3203 adjustment
.set_value(0)
3206 def print_stanza(self
, stanza
, kind
):
3207 # kind must be 'incoming' or 'outgoing'
3208 if not self
.enabled
:
3213 buffer = self
.stanzas_log_textview
.get_buffer()
3215 end_iter
= buffer.get_end_iter()
3216 end_rect
= self
.stanzas_log_textview
.get_iter_location(end_iter
)
3217 visible_rect
= self
.stanzas_log_textview
.get_visible_rect()
3218 if end_rect
.y
<= (visible_rect
.y
+ visible_rect
.height
):
3220 end_iter
= buffer.get_end_iter()
3223 if stanza
[1:9] == 'presence':
3225 elif stanza
[1:8] == 'message':
3227 elif stanza
[1:3] == 'iq':
3231 type_
= kind
+ '_' + type_
3233 type_
= kind
# 'incoming' or 'outgoing'
3235 if kind
== 'incoming':
3236 buffer.insert_with_tags_by_name(end_iter
, '<!-- In -->\n', type_
)
3237 elif kind
== 'outgoing':
3238 buffer.insert_with_tags_by_name(end_iter
, '<!-- Out -->\n', type_
)
3239 end_iter
= buffer.get_end_iter()
3240 buffer.insert_with_tags_by_name(end_iter
, stanza
.replace('><', '>\n<') \
3243 gobject
.idle_add(self
.scroll_to_end
)
3245 def _nec_stanza_received(self
, obj
):
3246 if obj
.conn
.name
!= self
.account
:
3248 self
.print_stanza(obj
.stanza_str
, 'incoming')
3250 def _nec_stanza_sent(self
, obj
):
3251 if obj
.conn
.name
!= self
.account
:
3253 self
.print_stanza(obj
.stanza_str
, 'outgoing')
3255 def on_send_button_clicked(self
, widget
):
3256 if gajim
.connections
[self
.account
].connected
<= 1:
3257 # if offline or connecting
3258 ErrorDialog(_('Connection not available'),
3259 _('Please make sure you are connected with "%s".') % \
3262 begin_iter
, end_iter
= self
.input_tv_buffer
.get_bounds()
3263 stanza
= self
.input_tv_buffer
.get_text(begin_iter
, end_iter
).decode(
3266 gajim
.connections
[self
.account
].send_stanza(stanza
)
3267 self
.input_tv_buffer
.set_text('') # we sent ok, clear the textview
3269 def on_presence_button_clicked(self
, widget
):
3270 self
.input_tv_buffer
.set_text(
3271 '<presence><show></show><status></status><priority></priority>'
3274 def on_iq_button_clicked(self
, widget
):
3275 self
.input_tv_buffer
.set_text(
3276 '<iq to="" type=""><query xmlns=""></query></iq>')
3278 def on_message_button_clicked(self
, widget
):
3279 self
.input_tv_buffer
.set_text(
3280 '<message to="" type=""><body></body></message>')
3282 def on_expander_activate(self
, widget
):
3283 if not widget
.get_expanded(): # it's the opposite!
3285 self
.input_textview
.grab_focus()
3287 #Action that can be done with an incoming list of contacts
3288 TRANSLATED_ACTION
= {'add': _('add'), 'modify': _('modify'),
3289 'remove': _('remove')}
3290 class RosterItemExchangeWindow
:
3292 Windows used when someone send you a exchange contact suggestion
3295 def __init__(self
, account
, action
, exchange_list
, jid_from
,
3297 self
.account
= account
3298 self
.action
= action
3299 self
.exchange_list
= exchange_list
3300 self
.message_body
= message_body
3301 self
.jid_from
= jid_from
3305 # Connect to gtk builder
3306 self
.xml
= gtkgui_helpers
.get_gtk_builder(
3307 'roster_item_exchange_window.ui')
3308 self
.window
= self
.xml
.get_object('roster_item_exchange_window')
3311 for widget_to_add
in ['accept_button_label', 'type_label',
3312 'body_scrolledwindow', 'body_textview', 'items_list_treeview']:
3313 self
.__dict
__[widget_to_add
] = self
.xml
.get_object(widget_to_add
)
3316 # self.action can be 'add', 'modify' or 'remove'
3317 self
.type_label
.set_label(
3318 _('<b>%(jid)s</b> would like you to <b>%(action)s</b> some contacts '
3319 'in your roster.') % {'jid': jid_from
,
3320 'action': TRANSLATED_ACTION
[self
.action
]})
3322 buffer_
= self
.body_textview
.get_buffer()
3323 buffer_
.set_text(self
.message_body
)
3325 self
.body_scrolledwindow
.hide()
3327 model
= gtk
.ListStore(bool, str, str, str, str)
3328 self
.items_list_treeview
.set_model(model
)
3330 renderer1
= gtk
.CellRendererToggle()
3331 renderer1
.set_property('activatable', True)
3332 renderer1
.connect('toggled', self
.toggled_callback
)
3333 if self
.action
== 'add':
3335 elif self
.action
== 'modify':
3337 elif self
.action
== 'delete':
3339 self
.items_list_treeview
.insert_column_with_attributes(-1, title
,
3340 renderer1
, active
=0)
3341 renderer2
= gtk
.CellRendererText()
3342 self
.items_list_treeview
.insert_column_with_attributes(-1, _('Jabber ID'),
3344 renderer3
= gtk
.CellRendererText()
3345 self
.items_list_treeview
.insert_column_with_attributes(-1, _('Name'),
3347 renderer4
= gtk
.CellRendererText()
3348 self
.items_list_treeview
.insert_column_with_attributes(-1, _('Groups'),
3352 model
= self
.items_list_treeview
.get_model()
3356 for jid
in self
.exchange_list
:
3359 contact
= gajim
.contacts
.get_contact_with_highest_priority(
3362 is_in_roster
= False
3363 name
= self
.exchange_list
[jid
][0]
3364 num_list
= len(self
.exchange_list
[jid
][1])
3366 for group
in self
.exchange_list
[jid
][1]:
3368 if contact
and not group
in contact
.groups
:
3369 is_in_roster
= False
3370 if current
== num_list
:
3371 groups
= groups
+ group
3373 groups
= groups
+ group
+ ', '
3374 if not is_in_roster
:
3376 iter_
= model
.append()
3377 model
.set(iter_
, 0, True, 1, jid
, 2, name
, 3, groups
)
3379 # Change label for accept_button to action name instead of 'OK'.
3380 self
.accept_button_label
.set_label(_('Add'))
3381 elif action
== 'modify':
3382 for jid
in self
.exchange_list
:
3386 contact
= gajim
.contacts
.get_contact_with_highest_priority(
3388 name
= self
.exchange_list
[jid
][0]
3390 is_in_roster
= False
3393 if name
!= contact
.name
:
3395 num_list
= len(self
.exchange_list
[jid
][1])
3397 for group
in self
.exchange_list
[jid
][1]:
3399 if contact
and not group
in contact
.groups
:
3401 if current
== num_list
:
3402 groups
= groups
+ group
3404 groups
= groups
+ group
+ ', '
3405 if not is_right
and is_in_roster
:
3407 iter_
= model
.append()
3408 model
.set(iter_
, 0, True, 1, jid
, 2, name
, 3, groups
)
3410 # Change label for accept_button to action name instead of 'OK'.
3411 self
.accept_button_label
.set_label(_('Modify'))
3412 elif action
== 'delete':
3413 for jid
in self
.exchange_list
:
3416 contact
= gajim
.contacts
.get_contact_with_highest_priority(
3418 name
= self
.exchange_list
[jid
][0]
3420 is_in_roster
= False
3421 num_list
= len(self
.exchange_list
[jid
][1])
3423 for group
in self
.exchange_list
[jid
][1]:
3425 if current
== num_list
:
3426 groups
= groups
+ group
3428 groups
= groups
+ group
+ ', '
3431 iter_
= model
.append()
3432 model
.set(iter_
, 0, True, 1, jid
, 2, name
, 3, groups
)
3434 # Change label for accept_button to action name instead of 'OK'.
3435 self
.accept_button_label
.set_label(_('Delete'))
3438 self
.window
.show_all()
3439 self
.xml
.connect_signals(self
)
3441 def toggled_callback(self
, cell
, path
):
3442 model
= self
.items_list_treeview
.get_model()
3443 iter_
= model
.get_iter(path
)
3444 model
[iter_
][0] = not cell
.get_active()
3446 def on_accept_button_clicked(self
, widget
):
3447 model
= self
.items_list_treeview
.get_model()
3448 iter_
= model
.get_iter_root()
3449 if self
.action
== 'add':
3455 #remote_jid = model[iter_][1].decode('utf-8')
3456 message
= _('%s suggested me to add you in my roster.'
3458 # keep same groups and same nickname
3459 groups
= model
[iter_
][3].split(', ')
3462 jid
= model
[iter_
][1].decode('utf-8')
3463 if gajim
.jid_is_transport(self
.jid_from
):
3464 gajim
.connections
[self
.account
].automatically_added
.append(
3466 gajim
.interface
.roster
.req_sub(self
, jid
, message
,
3467 self
.account
, groups
=groups
, nickname
=model
[iter_
][2],
3469 iter_
= model
.iter_next(iter_
)
3470 InformationDialog(_('Added %s contacts') % str(a
))
3471 elif self
.action
== 'modify':
3477 jid
= model
[iter_
][1].decode('utf-8')
3478 # keep same groups and same nickname
3479 groups
= model
[iter_
][3].split(', ')
3482 for u
in gajim
.contacts
.get_contact(self
.account
, jid
):
3483 u
.name
= model
[iter_
][2]
3484 gajim
.connections
[self
.account
].update_contact(jid
,
3485 model
[iter_
][2], groups
)
3486 self
.draw_contact(jid
, self
.account
)
3487 # Update opened chat
3488 ctrl
= gajim
.interface
.msg_win_mgr
.get_control(jid
, self
.account
)
3491 win
= gajim
.interface
.msg_win_mgr
.get_window(jid
,
3493 win
.redraw_tab(ctrl
)
3495 iter_
= model
.iter_next(iter_
)
3496 elif self
.action
== 'delete':
3502 jid
= model
[iter_
][1].decode('utf-8')
3503 gajim
.connections
[self
.account
].unsubscribe(jid
)
3504 gajim
.interface
.roster
.remove_contact(jid
, self
.account
)
3505 gajim
.contacts
.remove_jid(self
.account
, jid
)
3506 iter_
= model
.iter_next(iter_
)
3507 InformationDialog(_('Removed %s contacts') % str(a
))
3508 self
.window
.destroy()
3510 def on_cancel_button_clicked(self
, widget
):
3511 self
.window
.destroy()
3514 class ItemArchivingPreferencesWindow
:
3515 otr_name
= ('approve', 'concede', 'forbid', 'oppose', 'prefer', 'require')
3516 otr_index
= dict([(j
, i
) for i
, j
in enumerate(otr_name
)])
3517 save_name
= ('body', 'false', 'message', 'stream')
3518 save_index
= dict([(j
, i
) for i
, j
in enumerate(save_name
)])
3520 def __init__(self
, account
, item
):
3521 self
.account
= account
3523 if self
.item
and self
.item
!= 'Default':
3524 self
.item_config
= gajim
.connections
[self
.account
].items
[self
.item
]
3526 self
.item_config
= gajim
.connections
[self
.account
].default
3529 # Connect to gtk builder
3530 self
.xml
= gtkgui_helpers
.get_gtk_builder(
3531 'item_archiving_preferences_window.ui')
3532 self
.window
= self
.xml
.get_object('item_archiving_preferences_window')
3535 for widget_to_add
in ('jid_entry', 'expire_entry', 'otr_combobox',
3536 'save_combobox', 'cancel_button', 'ok_button', 'progressbar'):
3537 self
.__dict
__[widget_to_add
] = self
.xml
.get_object(widget_to_add
)
3540 self
.jid_entry
.set_text(self
.item
)
3541 expire_value
= self
.item_config
['expire'] or ''
3542 self
.otr_combobox
.set_active(self
.otr_index
[self
.item_config
['otr']])
3543 self
.save_combobox
.set_active(
3544 self
.save_index
[self
.item_config
['save']])
3545 self
.expire_entry
.set_text(expire_value
)
3547 self
.window
.set_title(_('Archiving Preferences for %s') % self
.account
)
3549 self
.window
.show_all()
3550 self
.progressbar
.hide()
3551 self
.xml
.connect_signals(self
)
3553 def update_progressbar(self
):
3555 self
.progressbar
.pulse()
3559 def on_otr_combobox_changed(self
, widget
):
3560 otr
= self
.otr_name
[self
.otr_combobox
.get_active()]
3561 if otr
== 'require':
3562 self
.save_combobox
.set_active(self
.save_index
['false'])
3564 def on_ok_button_clicked(self
, widget
):
3565 # Return directly if operation in progress
3569 item
= self
.jid_entry
.get_text()
3570 otr
= self
.otr_name
[self
.otr_combobox
.get_active()]
3571 save
= self
.save_name
[self
.save_combobox
.get_active()]
3572 expire
= self
.expire_entry
.get_text()
3574 if self
.item
!= 'Default':
3576 item
= helpers
.parse_jid(item
)
3577 except helpers
.InvalidFormat
, s
:
3578 pritext
= _('Invalid User ID')
3579 ErrorDialog(pritext
, str(s
))
3584 if int(expire
) < 0 or str(int(expire
)) != expire
:
3587 pritext
= _('Invalid expire value')
3588 sectext
= _('Expire must be a valid positive integer.')
3589 ErrorDialog(pritext
, sectext
)
3592 if not (item
== self
.item
and expire
== self
.item_config
['expire'] and
3593 otr
== self
.item_config
['otr'] and save
== self
.item_config
['save']):
3594 if not self
.item
or self
.item
== item
:
3595 if self
.item
== 'Default':
3596 self
.waiting
= 'default'
3597 gajim
.connections
[self
.account
].set_default(
3600 self
.waiting
= 'item'
3601 gajim
.connections
[self
.account
].append_or_update_item(
3602 item
, otr
, save
, expire
)
3604 self
.waiting
= 'item'
3605 gajim
.connections
[self
.account
].append_or_update_item(
3606 item
, otr
, save
, expire
)
3607 gajim
.connections
[self
.account
].remove_item(self
.item
)
3608 self
.launch_progressbar()
3609 #self.window.destroy()
3611 def on_cancel_button_clicked(self
, widget
):
3612 self
.window
.destroy()
3614 def on_item_archiving_preferences_window_destroy(self
, widget
):
3616 key_name
= 'edit_item_archiving_preferences_%s' % self
.item
3618 key_name
= 'new_item_archiving_preferences'
3619 if key_name
in gajim
.interface
.instances
[self
.account
]:
3620 del gajim
.interface
.instances
[self
.account
][key_name
]
3622 def launch_progressbar(self
):
3623 self
.progressbar
.show()
3624 self
.update_progressbar_timeout_id
= gobject
.timeout_add(
3625 100, self
.update_progressbar
)
3627 def response_arrived(self
, data
):
3629 self
.window
.destroy()
3631 def error_arrived(self
, error
):
3634 self
.progressbar
.hide()
3635 pritext
= _('There is an error with the form')
3637 ErrorDialog(pritext
, sectext
)
3640 class ArchivingPreferencesWindow
:
3641 auto_name
= ('false', 'true')
3642 auto_index
= dict([(j
, i
) for i
, j
in enumerate(auto_name
)])
3643 method_foo_name
= ('prefer', 'concede', 'forbid')
3644 method_foo_index
= dict([(j
, i
) for i
, j
in enumerate(method_foo_name
)])
3646 def __init__(self
, account
):
3647 self
.account
= account
3651 self
.xml
= gtkgui_helpers
.get_gtk_builder(
3652 'archiving_preferences_window.ui')
3653 self
.window
= self
.xml
.get_object('archiving_preferences_window')
3656 for widget_to_add
in ('auto_combobox', 'method_auto_combobox',
3657 'method_local_combobox', 'method_manual_combobox', 'close_button',
3658 'item_treeview', 'item_notebook', 'otr_combobox', 'save_combobox',
3659 'expire_entry', 'remove_button', 'edit_button'):
3660 self
.__dict
__[widget_to_add
] = self
.xml
.get_object(widget_to_add
)
3662 self
.auto_combobox
.set_active(
3663 self
.auto_index
[gajim
.connections
[self
.account
].auto
])
3664 self
.method_auto_combobox
.set_active(
3665 self
.method_foo_index
[gajim
.connections
[self
.account
].method_auto
])
3666 self
.method_local_combobox
.set_active(
3667 self
.method_foo_index
[gajim
.connections
[self
.account
].method_local
])
3668 self
.method_manual_combobox
.set_active(
3669 self
.method_foo_index
[gajim
.connections
[self
.account
].\
3672 model
= gtk
.ListStore(str, str, str, str)
3673 self
.item_treeview
.set_model(model
)
3674 col
= gtk
.TreeViewColumn('jid')
3675 self
.item_treeview
.append_column(col
)
3676 renderer
= gtk
.CellRendererText()
3677 col
.pack_start(renderer
, True)
3678 col
.set_attributes(renderer
, text
=0)
3680 col
= gtk
.TreeViewColumn('expire')
3681 col
.pack_start(renderer
, True)
3682 col
.set_attributes(renderer
, text
=1)
3683 self
.item_treeview
.append_column(col
)
3685 col
= gtk
.TreeViewColumn('otr')
3686 col
.pack_start(renderer
, True)
3687 col
.set_attributes(renderer
, text
=2)
3688 self
.item_treeview
.append_column(col
)
3690 col
= gtk
.TreeViewColumn('save')
3691 col
.pack_start(renderer
, True)
3692 col
.set_attributes(renderer
, text
=3)
3693 self
.item_treeview
.append_column(col
)
3697 self
.current_item
= None
3699 def sort_items(model
, iter1
, iter2
):
3700 item1
= model
.get_value(iter1
, 0)
3701 item2
= model
.get_value(iter2
, 0)
3702 if item1
== 'Default':
3704 if item2
== 'Default':
3707 if '@' not in item2
:
3715 # item1 == item2 ? WTF?
3718 model
.set_sort_column_id(0, gtk
.SORT_ASCENDING
)
3719 model
.set_sort_func(0, sort_items
)
3721 self
.remove_button
.set_sensitive(False)
3722 self
.edit_button
.set_sensitive(False)
3724 self
.window
.set_title(_('Archiving Preferences for %s') % self
.account
)
3726 gajim
.ged
.register_event_handler(
3727 'archiving-preferences-changed-received', ged
.GUI1
,
3728 self
._nec
_archiving
_changed
_received
)
3729 gajim
.ged
.register_event_handler('archiving-error-received', ged
.GUI1
,
3730 self
._nec
_archiving
_error
)
3732 self
.window
.show_all()
3734 self
.xml
.connect_signals(self
)
3736 def on_add_item_button_clicked(self
, widget
):
3737 key_name
= 'new_item_archiving_preferences'
3738 if key_name
in gajim
.interface
.instances
[self
.account
]:
3739 gajim
.interface
.instances
[self
.account
][key_name
].window
.present()
3741 gajim
.interface
.instances
[self
.account
][key_name
] = \
3742 ItemArchivingPreferencesWindow(self
.account
, '')
3744 def on_remove_item_button_clicked(self
, widget
):
3745 if not self
.current_item
:
3748 self
.waiting
.append('itemremove')
3749 sel
= self
.item_treeview
.get_selection()
3750 (model
, iter_
) = sel
.get_selected()
3751 gajim
.connections
[self
.account
].remove_item(model
[iter_
][0])
3753 self
.remove_button
.set_sensitive(False)
3754 self
.edit_button
.set_sensitive(False)
3756 def on_edit_item_button_clicked(self
, widget
):
3757 if not self
.current_item
:
3760 key_name
= 'edit_item_archiving_preferences_%s' % self
.current_item
3761 if key_name
in gajim
.interface
.instances
[self
.account
]:
3762 gajim
.interface
.instances
[self
.account
][key_name
].window
.present()
3764 gajim
.interface
.instances
[self
.account
][key_name
] = \
3765 ItemArchivingPreferencesWindow(self
.account
, self
.current_item
)
3767 def on_item_treeview_cursor_changed(self
, widget
):
3768 sel
= self
.item_treeview
.get_selection()
3769 (model
, iter_
) = sel
.get_selected()
3772 item
= model
[iter_
][0]
3773 if self
.current_item
and self
.current_item
== item
:
3776 self
.current_item
= item
3777 if self
.current_item
== 'Default':
3778 self
.remove_button
.set_sensitive(False)
3779 self
.edit_button
.set_sensitive(True)
3780 elif self
.current_item
:
3781 self
.remove_button
.set_sensitive(True)
3782 self
.edit_button
.set_sensitive(True)
3784 self
.remove_button
.set_sensitive(False)
3785 self
.edit_button
.set_sensitive(False)
3787 def on_auto_combobox_changed(self
, widget
):
3788 save
= self
.auto_name
[widget
.get_active()]
3789 gajim
.connections
[self
.account
].set_auto(save
)
3791 def on_method_foo_combobox_changed(self
, widget
):
3792 # We retrieve method type from widget name
3793 # ('foo' in 'method_foo_combobox')
3794 method_type
= widget
.name
.split('_')[1]
3795 use
= self
.method_foo_name
[widget
.get_active()]
3796 self
.waiting
.append('method_%s' % method_type
)
3797 gajim
.connections
[self
.account
].set_method(method_type
, use
)
3799 def get_child_window(self
):
3800 edit_key_name
= 'edit_item_archiving_preferences_%s' % self
.current_item
3801 new_key_name
= 'new_item_archiving_preferences'
3803 if edit_key_name
in gajim
.interface
.instances
[self
.account
]:
3804 return gajim
.interface
.instances
[self
.account
][edit_key_name
]
3806 if new_key_name
in gajim
.interface
.instances
[self
.account
]:
3807 return gajim
.interface
.instances
[self
.account
][new_key_name
]
3809 def _nec_archiving_changed_received(self
, obj
):
3810 if obj
.conn
.name
!= self
.account
:
3812 for key
in ('auto', 'method_auto', 'method_local', 'method_manual'):
3813 if key
in obj
.conf
and key
in self
.waiting
:
3814 self
.waiting
.remove(key
)
3815 if 'default' in obj
.conf
:
3816 key_name
= 'edit_item_archiving_preferences_%s' % \
3818 if key_name
in gajim
.interface
.instances
[self
.account
]:
3819 gajim
.interface
.instances
[self
.account
][key_name
].\
3820 response_arrived(obj
.conf
['default'])
3821 self
.fill_items(True)
3822 for jid
, pref
in obj
.new_items
.items():
3823 child
= self
.get_child_window()
3825 is_new
= not child
.item
3826 child
.response_arrived(pref
)
3828 model
= self
.item_treeview
.get_model()
3829 model
.append((jid
, pref
['expire'], pref
['otr'],
3832 self
.fill_items(True)
3833 if 'itemremove' in self
.waiting
and obj
.removed_items
:
3834 self
.waiting
.remove('itemremove')
3835 self
.fill_items(True)
3837 def fill_items(self
, clear
=False):
3838 model
= self
.item_treeview
.get_model()
3841 default_config
= gajim
.connections
[self
.account
].default
3842 expire_value
= default_config
['expire'] or ''
3843 model
.append(('Default', expire_value
,
3844 default_config
['otr'], default_config
['save']))
3845 for item
, item_config
in \
3846 gajim
.connections
[self
.account
].items
.items():
3847 expire_value
= item_config
['expire'] or ''
3848 model
.append((item
, expire_value
, item_config
['otr'],
3849 item_config
['save']))
3851 def _nec_archiving_error(self
, obj
):
3852 if obj
.conn
.name
!= self
.account
:
3855 pritext
= _('There is an error')
3856 sectext
= obj
.error_msg
3857 ErrorDialog(pritext
, sectext
)
3860 child
= self
.get_child_window()
3862 child
.error_arrived(obj
.error_msg
)
3864 def on_close_button_clicked(self
, widget
):
3865 self
.window
.destroy()
3867 def on_archiving_preferences_window_destroy(self
, widget
):
3868 gajim
.ged
.remove_event_handler(
3869 'archiving-preferences-changed-received', ged
.GUI1
,
3870 self
._nec
_archiving
_changed
_received
)
3871 gajim
.ged
.remove_event_handler('archiving-error-received', ged
.GUI1
,
3872 self
._nec
_archiving
_error
)
3873 if 'archiving_preferences' in gajim
.interface
.instances
[self
.account
]:
3874 del gajim
.interface
.instances
[self
.account
]['archiving_preferences']
3877 class PrivacyListWindow
:
3879 Window that is used for creating NEW or EDITING already there privacy lists
3882 def __init__(self
, account
, privacy_list_name
, action
):
3883 '''action is 'EDIT' or 'NEW' depending on if we create a new priv list
3884 or edit an already existing one'''
3885 self
.account
= account
3886 self
.privacy_list_name
= privacy_list_name
3888 # Dicts and Default Values
3889 self
.active_rule
= ''
3890 self
.global_rules
= {}
3891 self
.list_of_groups
= {}
3895 # Default Edit Values
3896 self
.edit_rule_type
= 'jid'
3897 self
.allow_deny
= 'allow'
3899 # Connect to gtk builder
3900 self
.xml
= gtkgui_helpers
.get_gtk_builder('privacy_list_window.ui')
3901 self
.window
= self
.xml
.get_object('privacy_list_edit_window')
3905 for widget_to_add
in ('title_hbox', 'privacy_lists_title_label',
3906 'list_of_rules_label', 'add_edit_rule_label', 'delete_open_buttons_hbox',
3907 'privacy_list_active_checkbutton', 'privacy_list_default_checkbutton',
3908 'list_of_rules_combobox', 'delete_open_buttons_hbox',
3909 'delete_rule_button', 'open_rule_button', 'edit_allow_radiobutton',
3910 'edit_deny_radiobutton', 'edit_type_jabberid_radiobutton',
3911 'edit_type_jabberid_entry', 'edit_type_group_radiobutton',
3912 'edit_type_group_combobox', 'edit_type_subscription_radiobutton',
3913 'edit_type_subscription_combobox', 'edit_type_select_all_radiobutton',
3914 'edit_queries_send_checkbutton', 'edit_send_messages_checkbutton',
3915 'edit_view_status_checkbutton', 'edit_all_checkbutton',
3916 'edit_order_spinbutton', 'new_rule_button', 'save_rule_button',
3917 'privacy_list_refresh_button', 'privacy_list_close_button',
3918 'edit_send_status_checkbutton', 'add_edit_vbox',
3919 'privacy_list_active_checkbutton', 'privacy_list_default_checkbutton'):
3920 self
.__dict
__[widget_to_add
] = self
.xml
.get_object(widget_to_add
)
3922 self
.privacy_lists_title_label
.set_label(
3923 _('Privacy List <b><i>%s</i></b>') % \
3924 gobject
.markup_escape_text(self
.privacy_list_name
))
3926 if len(gajim
.connections
) > 1:
3927 title
= _('Privacy List for %s') % self
.account
3929 title
= _('Privacy List')
3931 self
.delete_rule_button
.set_sensitive(False)
3932 self
.open_rule_button
.set_sensitive(False)
3933 self
.privacy_list_active_checkbutton
.set_sensitive(False)
3934 self
.privacy_list_default_checkbutton
.set_sensitive(False)
3935 self
.list_of_rules_combobox
.set_sensitive(False)
3937 # set jabber id completion
3938 jids_list_store
= gtk
.ListStore(gobject
.TYPE_STRING
)
3939 for jid
in gajim
.contacts
.get_jid_list(self
.account
):
3940 jids_list_store
.append([jid
])
3941 jid_entry_completion
= gtk
.EntryCompletion()
3942 jid_entry_completion
.set_text_column(0)
3943 jid_entry_completion
.set_model(jids_list_store
)
3944 jid_entry_completion
.set_popup_completion(True)
3945 self
.edit_type_jabberid_entry
.set_completion(jid_entry_completion
)
3946 if action
== 'EDIT':
3947 self
.refresh_rules()
3950 for group
in gajim
.groups
[self
.account
]:
3951 self
.list_of_groups
[group
] = count
3953 self
.edit_type_group_combobox
.append_text(group
)
3954 self
.edit_type_group_combobox
.set_active(0)
3956 self
.window
.set_title(title
)
3958 gajim
.ged
.register_event_handler('privacy-list-received', ged
.GUI1
,
3959 self
._nec
_privacy
_list
_received
)
3960 gajim
.ged
.register_event_handler('privacy-list-active-default',
3961 ged
.GUI1
, self
._nec
_privacy
_list
_active
_default
)
3963 self
.window
.show_all()
3964 self
.add_edit_vbox
.hide()
3966 self
.xml
.connect_signals(self
)
3968 def on_privacy_list_edit_window_destroy(self
, widget
):
3969 key_name
= 'privacy_list_%s' % self
.privacy_list_name
3970 if key_name
in gajim
.interface
.instances
[self
.account
]:
3971 del gajim
.interface
.instances
[self
.account
][key_name
]
3972 gajim
.ged
.remove_event_handler('privacy-list-received', ged
.GUI1
,
3973 self
._nec
_privacy
_list
_received
)
3974 gajim
.ged
.remove_event_handler('privacy-list-active-default',
3975 ged
.GUI1
, self
._nec
_privacy
_list
_active
_default
)
3977 def _nec_privacy_list_active_default(self
, obj
):
3978 if obj
.conn
.name
!= self
.account
:
3980 if obj
.active_list
== self
.privacy_list_name
:
3981 self
.privacy_list_active_checkbutton
.set_active(True)
3983 self
.privacy_list_active_checkbutton
.set_active(False)
3984 if obj
.default_list
== self
.privacy_list_name
:
3985 self
.privacy_list_default_checkbutton
.set_active(True)
3987 self
.privacy_list_default_checkbutton
.set_active(False)
3989 def privacy_list_received(self
, rules
):
3990 self
.list_of_rules_combobox
.get_model().clear()
3991 self
.global_rules
= {}
3994 text_item
= _('Order: %(order)s, action: %(action)s, type: %(type)s'
3995 ', value: %(value)s') % {'order': rule
['order'],
3996 'action': rule
['action'], 'type': rule
['type'],
3997 'value': rule
['value']}
3999 text_item
= _('Order: %(order)s, action: %(action)s') % \
4000 {'order': rule
['order'], 'action': rule
['action']}
4001 if int(rule
['order']) > self
.max_order
:
4002 self
.max_order
= int(rule
['order'])
4003 self
.global_rules
[text_item
] = rule
4004 self
.list_of_rules_combobox
.append_text(text_item
)
4006 self
.title_hbox
.set_sensitive(False)
4007 self
.list_of_rules_combobox
.set_sensitive(False)
4008 self
.delete_rule_button
.set_sensitive(False)
4009 self
.open_rule_button
.set_sensitive(False)
4010 self
.privacy_list_active_checkbutton
.set_sensitive(False)
4011 self
.privacy_list_default_checkbutton
.set_sensitive(False)
4013 self
.list_of_rules_combobox
.set_active(0)
4014 self
.title_hbox
.set_sensitive(True)
4015 self
.list_of_rules_combobox
.set_sensitive(True)
4016 self
.delete_rule_button
.set_sensitive(True)
4017 self
.open_rule_button
.set_sensitive(True)
4018 self
.privacy_list_active_checkbutton
.set_sensitive(True)
4019 self
.privacy_list_default_checkbutton
.set_sensitive(True)
4021 gajim
.connections
[self
.account
].get_active_default_lists()
4023 def _nec_privacy_list_received(self
, obj
):
4024 if obj
.conn
.name
!= self
.account
:
4026 if obj
.list_name
!= self
.privacy_list_name
:
4028 self
.privacy_list_received(obj
.rules
)
4030 def refresh_rules(self
):
4031 gajim
.connections
[self
.account
].get_privacy_list(self
.privacy_list_name
)
4033 def on_delete_rule_button_clicked(self
, widget
):
4035 for rule
in self
.global_rules
:
4036 if rule
!= self
.list_of_rules_combobox
.get_active_text():
4037 tags
.append(self
.global_rules
[rule
])
4038 gajim
.connections
[self
.account
].set_privacy_list(
4039 self
.privacy_list_name
, tags
)
4040 self
.privacy_list_received(tags
)
4041 self
.add_edit_vbox
.hide()
4042 if not tags
: # we removed latest rule
4043 if 'privacy_lists' in gajim
.interface
.instances
[self
.account
]:
4044 win
= gajim
.interface
.instances
[self
.account
]['privacy_lists']
4045 win
.remove_privacy_list_from_combobox(self
.privacy_list_name
)
4048 def on_open_rule_button_clicked(self
, widget
):
4049 self
.add_edit_rule_label
.set_label(
4050 _('<b>Edit a rule</b>'))
4051 active_num
= self
.list_of_rules_combobox
.get_active()
4052 if active_num
== -1:
4053 self
.active_rule
= ''
4055 self
.active_rule
= \
4056 self
.list_of_rules_combobox
.get_active_text().decode('utf-8')
4057 if self
.active_rule
!= '':
4058 rule_info
= self
.global_rules
[self
.active_rule
]
4059 self
.edit_order_spinbutton
.set_value(int(rule_info
['order']))
4060 if 'type' in rule_info
:
4061 if rule_info
['type'] == 'jid':
4062 self
.edit_type_jabberid_radiobutton
.set_active(True)
4063 self
.edit_type_jabberid_entry
.set_text(rule_info
['value'])
4064 elif rule_info
['type'] == 'group':
4065 self
.edit_type_group_radiobutton
.set_active(True)
4066 if rule_info
['value'] in self
.list_of_groups
:
4067 self
.edit_type_group_combobox
.set_active(
4068 self
.list_of_groups
[rule_info
['value']])
4070 self
.edit_type_group_combobox
.set_active(0)
4071 elif rule_info
['type'] == 'subscription':
4072 self
.edit_type_subscription_radiobutton
.set_active(True)
4073 sub_value
= rule_info
['value']
4074 if sub_value
== 'none':
4075 self
.edit_type_subscription_combobox
.set_active(0)
4076 elif sub_value
== 'both':
4077 self
.edit_type_subscription_combobox
.set_active(1)
4078 elif sub_value
== 'from':
4079 self
.edit_type_subscription_combobox
.set_active(2)
4080 elif sub_value
== 'to':
4081 self
.edit_type_subscription_combobox
.set_active(3)
4083 self
.edit_type_select_all_radiobutton
.set_active(True)
4085 self
.edit_type_select_all_radiobutton
.set_active(True)
4086 self
.edit_send_messages_checkbutton
.set_active(False)
4087 self
.edit_queries_send_checkbutton
.set_active(False)
4088 self
.edit_view_status_checkbutton
.set_active(False)
4089 self
.edit_send_status_checkbutton
.set_active(False)
4090 self
.edit_all_checkbutton
.set_active(False)
4091 if not rule_info
['child']:
4092 self
.edit_all_checkbutton
.set_active(True)
4094 if 'presence-out' in rule_info
['child']:
4095 self
.edit_send_status_checkbutton
.set_active(True)
4096 if 'presence-in' in rule_info
['child']:
4097 self
.edit_view_status_checkbutton
.set_active(True)
4098 if 'iq' in rule_info
['child']:
4099 self
.edit_queries_send_checkbutton
.set_active(True)
4100 if 'message' in rule_info
['child']:
4101 self
.edit_send_messages_checkbutton
.set_active(True)
4103 if rule_info
['action'] == 'allow':
4104 self
.edit_allow_radiobutton
.set_active(True)
4106 self
.edit_deny_radiobutton
.set_active(True)
4107 self
.add_edit_vbox
.show()
4109 def on_edit_all_checkbutton_toggled(self
, widget
):
4110 if widget
.get_active():
4111 self
.edit_send_messages_checkbutton
.set_active(True)
4112 self
.edit_queries_send_checkbutton
.set_active(True)
4113 self
.edit_view_status_checkbutton
.set_active(True)
4114 self
.edit_send_status_checkbutton
.set_active(True)
4115 self
.edit_send_messages_checkbutton
.set_sensitive(False)
4116 self
.edit_queries_send_checkbutton
.set_sensitive(False)
4117 self
.edit_view_status_checkbutton
.set_sensitive(False)
4118 self
.edit_send_status_checkbutton
.set_sensitive(False)
4120 self
.edit_send_messages_checkbutton
.set_active(False)
4121 self
.edit_queries_send_checkbutton
.set_active(False)
4122 self
.edit_view_status_checkbutton
.set_active(False)
4123 self
.edit_send_status_checkbutton
.set_active(False)
4124 self
.edit_send_messages_checkbutton
.set_sensitive(True)
4125 self
.edit_queries_send_checkbutton
.set_sensitive(True)
4126 self
.edit_view_status_checkbutton
.set_sensitive(True)
4127 self
.edit_send_status_checkbutton
.set_sensitive(True)
4129 def on_privacy_list_active_checkbutton_toggled(self
, widget
):
4130 if widget
.get_active():
4131 gajim
.connections
[self
.account
].set_active_list(
4132 self
.privacy_list_name
)
4134 gajim
.connections
[self
.account
].set_active_list(None)
4136 def on_privacy_list_default_checkbutton_toggled(self
, widget
):
4137 if widget
.get_active():
4138 gajim
.connections
[self
.account
].set_default_list(
4139 self
.privacy_list_name
)
4141 gajim
.connections
[self
.account
].set_default_list(None)
4143 def on_new_rule_button_clicked(self
, widget
):
4145 self
.add_edit_vbox
.show()
4147 def reset_fields(self
):
4148 self
.edit_type_jabberid_entry
.set_text('')
4149 self
.edit_allow_radiobutton
.set_active(True)
4150 self
.edit_type_jabberid_radiobutton
.set_active(True)
4151 self
.active_rule
= ''
4152 self
.edit_send_messages_checkbutton
.set_active(False)
4153 self
.edit_queries_send_checkbutton
.set_active(False)
4154 self
.edit_view_status_checkbutton
.set_active(False)
4155 self
.edit_send_status_checkbutton
.set_active(False)
4156 self
.edit_all_checkbutton
.set_active(False)
4157 self
.edit_order_spinbutton
.set_value(self
.max_order
+ 1)
4158 self
.edit_type_group_combobox
.set_active(0)
4159 self
.edit_type_subscription_combobox
.set_active(0)
4160 self
.add_edit_rule_label
.set_label(
4161 _('<b>Add a rule</b>'))
4163 def get_current_tags(self
):
4164 if self
.edit_type_jabberid_radiobutton
.get_active():
4166 edit_value
= self
.edit_type_jabberid_entry
.get_text()
4167 elif self
.edit_type_group_radiobutton
.get_active():
4169 edit_value
= self
.edit_type_group_combobox
.get_active_text()
4170 elif self
.edit_type_subscription_radiobutton
.get_active():
4171 edit_type
= 'subscription'
4172 subs
= ['none', 'both', 'from', 'to']
4173 edit_value
= subs
[self
.edit_type_subscription_combobox
.get_active()]
4174 elif self
.edit_type_select_all_radiobutton
.get_active():
4177 edit_order
= str(self
.edit_order_spinbutton
.get_value_as_int())
4178 if self
.edit_allow_radiobutton
.get_active():
4183 if not self
.edit_all_checkbutton
.get_active():
4184 if self
.edit_send_messages_checkbutton
.get_active():
4185 child
.append('message')
4186 if self
.edit_queries_send_checkbutton
.get_active():
4188 if self
.edit_send_status_checkbutton
.get_active():
4189 child
.append('presence-out')
4190 if self
.edit_view_status_checkbutton
.get_active():
4191 child
.append('presence-in')
4193 return {'order': edit_order
, 'action': edit_deny
,
4194 'type': edit_type
, 'value': edit_value
, 'child': child
}
4195 return {'order': edit_order
, 'action': edit_deny
, 'child': child
}
4197 def on_save_rule_button_clicked(self
, widget
):
4199 current_tags
= self
.get_current_tags()
4200 if int(current_tags
['order']) > self
.max_order
:
4201 self
.max_order
= int(current_tags
['order'])
4202 if self
.active_rule
== '':
4203 tags
.append(current_tags
)
4205 for rule
in self
.global_rules
:
4206 if rule
!= self
.active_rule
:
4207 tags
.append(self
.global_rules
[rule
])
4209 tags
.append(current_tags
)
4211 gajim
.connections
[self
.account
].set_privacy_list(
4212 self
.privacy_list_name
, tags
)
4213 self
.refresh_rules()
4214 self
.add_edit_vbox
.hide()
4215 if 'privacy_lists' in gajim
.interface
.instances
[self
.account
]:
4216 win
= gajim
.interface
.instances
[self
.account
]['privacy_lists']
4217 win
.add_privacy_list_to_combobox(self
.privacy_list_name
)
4220 def on_list_of_rules_combobox_changed(self
, widget
):
4221 self
.add_edit_vbox
.hide()
4223 def on_edit_type_radiobutton_changed(self
, widget
, radiobutton
):
4224 active_bool
= widget
.get_active()
4226 self
.edit_rule_type
= radiobutton
4228 def on_edit_allow_radiobutton_changed(self
, widget
, radiobutton
):
4229 active_bool
= widget
.get_active()
4231 self
.allow_deny
= radiobutton
4233 def on_close_button_clicked(self
, widget
):
4234 self
.window
.destroy()
4236 class PrivacyListsWindow
:
4238 Window that is the main window for Privacy Lists; we can list there the
4239 privacy lists and ask to create a new one or edit an already there one
4241 def __init__(self
, account
):
4242 self
.account
= account
4243 self
.privacy_lists_save
= []
4245 self
.xml
= gtkgui_helpers
.get_gtk_builder('privacy_lists_window.ui')
4247 self
.window
= self
.xml
.get_object('privacy_lists_first_window')
4248 for widget_to_add
in ('list_of_privacy_lists_combobox',
4249 'delete_privacy_list_button', 'open_privacy_list_button',
4250 'new_privacy_list_button', 'new_privacy_list_entry',
4251 'privacy_lists_refresh_button', 'close_privacy_lists_window_button'):
4252 self
.__dict
__[widget_to_add
] = self
.xml
.get_object(widget_to_add
)
4254 self
.draw_privacy_lists_in_combobox([])
4255 self
.privacy_lists_refresh()
4259 if len(gajim
.connections
) > 1:
4260 title
= _('Privacy Lists for %s') % self
.account
4262 title
= _('Privacy Lists')
4264 self
.window
.set_title(title
)
4266 gajim
.ged
.register_event_handler('privacy-lists-received', ged
.GUI1
,
4267 self
._nec
_privacy
_lists
_received
)
4268 gajim
.ged
.register_event_handler('privacy-lists-removed', ged
.GUI1
,
4269 self
._nec
_privacy
_lists
_removed
)
4271 self
.window
.show_all()
4273 self
.xml
.connect_signals(self
)
4275 def on_privacy_lists_first_window_destroy(self
, widget
):
4276 if 'privacy_lists' in gajim
.interface
.instances
[self
.account
]:
4277 del gajim
.interface
.instances
[self
.account
]['privacy_lists']
4278 gajim
.ged
.remove_event_handler('privacy-lists-received', ged
.GUI1
,
4279 self
._nec
_privacy
_lists
_received
)
4280 gajim
.ged
.remove_event_handler('privacy-lists-removed', ged
.GUI1
,
4281 self
._nec
_privacy
_lists
_removed
)
4283 def remove_privacy_list_from_combobox(self
, privacy_list
):
4284 if privacy_list
not in self
.privacy_lists_save
:
4286 privacy_list_index
= self
.privacy_lists_save
.index(privacy_list
)
4287 self
.list_of_privacy_lists_combobox
.remove_text(privacy_list_index
)
4288 self
.privacy_lists_save
.remove(privacy_list
)
4290 def add_privacy_list_to_combobox(self
, privacy_list
):
4291 if privacy_list
in self
.privacy_lists_save
:
4293 self
.list_of_privacy_lists_combobox
.append_text(privacy_list
)
4294 self
.privacy_lists_save
.append(privacy_list
)
4296 def draw_privacy_lists_in_combobox(self
, privacy_lists
):
4297 self
.list_of_privacy_lists_combobox
.set_active(-1)
4298 self
.list_of_privacy_lists_combobox
.get_model().clear()
4299 self
.privacy_lists_save
= []
4300 for add_item
in privacy_lists
:
4301 self
.add_privacy_list_to_combobox(add_item
)
4304 def draw_widgets(self
):
4305 if len(self
.privacy_lists_save
) == 0:
4306 self
.list_of_privacy_lists_combobox
.set_sensitive(False)
4307 self
.open_privacy_list_button
.set_sensitive(False)
4308 self
.delete_privacy_list_button
.set_sensitive(False)
4310 self
.list_of_privacy_lists_combobox
.set_sensitive(True)
4311 self
.list_of_privacy_lists_combobox
.set_active(0)
4312 self
.open_privacy_list_button
.set_sensitive(True)
4313 self
.delete_privacy_list_button
.set_sensitive(True)
4315 def on_close_button_clicked(self
, widget
):
4316 self
.window
.destroy()
4318 def on_delete_privacy_list_button_clicked(self
, widget
):
4319 active_list
= self
.privacy_lists_save
[
4320 self
.list_of_privacy_lists_combobox
.get_active()]
4321 gajim
.connections
[self
.account
].del_privacy_list(active_list
)
4323 def privacy_list_removed(self
, active_list
):
4324 self
.privacy_lists_save
.remove(active_list
)
4325 self
.privacy_lists_received({'lists': self
.privacy_lists_save
})
4327 def _nec_privacy_lists_removed(self
, obj
):
4328 if obj
.conn
.name
!= self
.account
:
4330 self
.privacy_list_removed(obj
.lists_list
)
4332 def privacy_lists_received(self
, lists
):
4336 for privacy_list
in lists
['lists']:
4337 privacy_lists
.append(privacy_list
)
4338 self
.draw_privacy_lists_in_combobox(privacy_lists
)
4340 def _nec_privacy_lists_received(self
, obj
):
4341 if obj
.conn
.name
!= self
.account
:
4343 self
.privacy_lists_received(obj
.lists_list
)
4345 def privacy_lists_refresh(self
):
4346 gajim
.connections
[self
.account
].get_privacy_lists()
4348 def on_new_privacy_list_button_clicked(self
, widget
):
4349 name
= self
.new_privacy_list_entry
.get_text()
4351 ErrorDialog(_('Invalid List Name'),
4352 _('You must enter a name to create a privacy list.'))
4354 key_name
= 'privacy_list_%s' % name
4355 if key_name
in gajim
.interface
.instances
[self
.account
]:
4356 gajim
.interface
.instances
[self
.account
][key_name
].window
.present()
4358 gajim
.interface
.instances
[self
.account
][key_name
] = \
4359 PrivacyListWindow(self
.account
, name
, 'NEW')
4360 self
.new_privacy_list_entry
.set_text('')
4362 def on_privacy_lists_refresh_button_clicked(self
, widget
):
4363 self
.privacy_lists_refresh()
4365 def on_open_privacy_list_button_clicked(self
, widget
):
4366 name
= self
.privacy_lists_save
[
4367 self
.list_of_privacy_lists_combobox
.get_active()]
4368 key_name
= 'privacy_list_%s' % name
4369 if key_name
in gajim
.interface
.instances
[self
.account
]:
4370 gajim
.interface
.instances
[self
.account
][key_name
].window
.present()
4372 gajim
.interface
.instances
[self
.account
][key_name
] = \
4373 PrivacyListWindow(self
.account
, name
, 'EDIT')
4375 class InvitationReceivedDialog
:
4376 def __init__(self
, account
, room_jid
, contact_jid
, password
=None,
4377 comment
=None, is_continued
=False):
4379 self
.room_jid
= room_jid
4380 self
.account
= account
4381 self
.password
= password
4382 self
.is_continued
= is_continued
4384 pritext
= _('''You are invited to a groupchat''')
4385 #Don't translate $Contact
4387 sectext
= _('$Contact has invited you to join a discussion')
4389 sectext
= _('$Contact has invited you to group chat %(room_jid)s')\
4390 % {'room_jid': room_jid
}
4391 contact
= gajim
.contacts
.get_first_contact_from_jid(account
, contact_jid
)
4392 contact_text
= contact
and contact
.name
or contact_jid
4393 sectext
= sectext
.replace('$Contact', contact_text
)
4395 if comment
: # only if not None and not ''
4396 comment
= gobject
.markup_escape_text(comment
)
4397 comment
= _('Comment: %s') % comment
4398 sectext
+= '\n\n%s' % comment
4399 sectext
+= '\n\n' + _('Do you want to accept the invitation?')
4401 def on_yes(checked
):
4403 if self
.is_continued
:
4404 gajim
.interface
.join_gc_room(self
.account
, self
.room_jid
,
4405 gajim
.nicks
[self
.account
], None, is_continued
=True)
4407 JoinGroupchatWindow(self
.account
, self
.room_jid
)
4408 except GajimGeneralException
:
4411 YesNoDialog(pritext
, sectext
, on_response_yes
=on_yes
)
4413 class ProgressDialog
:
4414 def __init__(self
, title_text
, during_text
, messages_queue
):
4416 During text is what to show during the procedure, messages_queue has the
4417 message to show in the textview
4419 self
.xml
= gtkgui_helpers
.get_gtk_builder('progress_dialog.ui')
4420 self
.dialog
= self
.xml
.get_object('progress_dialog')
4421 self
.label
= self
.xml
.get_object('label')
4422 self
.label
.set_markup('<big>' + during_text
+ '</big>')
4423 self
.progressbar
= self
.xml
.get_object('progressbar')
4424 self
.dialog
.set_title(title_text
)
4425 self
.dialog
.set_default_size(450, 250)
4426 self
.window
.set_position(gtk
.WIN_POS_CENTER_ON_PARENT
)
4427 self
.dialog
.show_all()
4428 self
.xml
.connect_signals(self
)
4430 self
.update_progressbar_timeout_id
= gobject
.timeout_add(100,
4431 self
.update_progressbar
)
4433 def update_progressbar(self
):
4435 self
.progressbar
.pulse()
4436 return True # loop forever
4439 def on_progress_dialog_delete_event(self
, widget
, event
):
4440 return True # WM's X button or Escape key should not destroy the window
4443 class ClientCertChooserDialog(FileChooserDialog
):
4444 def __init__(self
, path_to_clientcert_file
='', on_response_ok
=None,
4445 on_response_cancel
=None):
4447 optionally accepts path_to_clientcert_file so it has that as selected
4449 def on_ok(widget
, callback
):
4451 check if file exists and call callback
4453 path_to_clientcert_file
= self
.get_filename()
4454 path_to_clientcert_file
= \
4455 gtkgui_helpers
.decode_filechooser_file_paths(
4456 (path_to_clientcert_file
,))[0]
4457 if os
.path
.exists(path_to_clientcert_file
):
4458 callback(widget
, path_to_clientcert_file
)
4460 FileChooserDialog
.__init
__(self
,
4461 title_text
=_('Choose Client Cert #PCKS12'),
4462 action
=gtk
.FILE_CHOOSER_ACTION_OPEN
,
4463 buttons
=(gtk
.STOCK_CANCEL
, gtk
.RESPONSE_CANCEL
,
4464 gtk
.STOCK_OPEN
, gtk
.RESPONSE_OK
),
4466 default_response
=gtk
.RESPONSE_OK
,
4467 on_response_ok
=(on_ok
, on_response_ok
),
4468 on_response_cancel
=on_response_cancel
)
4470 filter_
= gtk
.FileFilter()
4471 filter_
.set_name(_('All files'))
4472 filter_
.add_pattern('*')
4473 self
.add_filter(filter_
)
4475 filter_
= gtk
.FileFilter()
4476 filter_
.set_name(_('PKCS12 Files'))
4477 filter_
.add_pattern('*.p12')
4478 self
.add_filter(filter_
)
4479 self
.set_filter(filter_
)
4481 if path_to_clientcert_file
:
4482 # set_filename accept only absolute path
4483 path_to_clientcert_file
= os
.path
.abspath(path_to_clientcert_file
)
4484 self
.set_filename(path_to_clientcert_file
)
4487 class SoundChooserDialog(FileChooserDialog
):
4488 def __init__(self
, path_to_snd_file
='', on_response_ok
=None,
4489 on_response_cancel
=None):
4491 Optionally accepts path_to_snd_file so it has that as selected
4493 def on_ok(widget
, callback
):
4495 Check if file exists and call callback
4497 path_to_snd_file
= self
.get_filename()
4498 path_to_snd_file
= gtkgui_helpers
.decode_filechooser_file_paths(
4499 (path_to_snd_file
,))[0]
4500 if os
.path
.exists(path_to_snd_file
):
4501 callback(widget
, path_to_snd_file
)
4503 FileChooserDialog
.__init
__(self
, title_text
= _('Choose Sound'),
4504 action
= gtk
.FILE_CHOOSER_ACTION_OPEN
,
4505 buttons
= (gtk
.STOCK_CANCEL
, gtk
.RESPONSE_CANCEL
,
4506 gtk
.STOCK_OPEN
, gtk
.RESPONSE_OK
),
4507 default_response
= gtk
.RESPONSE_OK
,
4508 current_folder
= gajim
.config
.get('last_sounds_dir'),
4509 on_response_ok
= (on_ok
, on_response_ok
),
4510 on_response_cancel
= on_response_cancel
)
4512 filter_
= gtk
.FileFilter()
4513 filter_
.set_name(_('All files'))
4514 filter_
.add_pattern('*')
4515 self
.add_filter(filter_
)
4517 filter_
= gtk
.FileFilter()
4518 filter_
.set_name(_('Wav Sounds'))
4519 filter_
.add_pattern('*.wav')
4520 self
.add_filter(filter_
)
4521 self
.set_filter(filter_
)
4523 path_to_snd_file
= helpers
.check_soundfile_path(path_to_snd_file
)
4524 if path_to_snd_file
:
4525 # set_filename accept only absolute path
4526 path_to_snd_file
= os
.path
.abspath(path_to_snd_file
)
4527 self
.set_filename(path_to_snd_file
)
4529 class ImageChooserDialog(FileChooserDialog
):
4530 def __init__(self
, path_to_file
='', on_response_ok
=None,
4531 on_response_cancel
=None):
4533 Optionally accepts path_to_snd_file so it has that as selected
4535 def on_ok(widget
, callback
):
4536 '''check if file exists and call callback'''
4537 path_to_file
= self
.get_filename()
4538 if not path_to_file
:
4540 path_to_file
= gtkgui_helpers
.decode_filechooser_file_paths(
4542 if os
.path
.exists(path_to_file
):
4543 if isinstance(callback
, tuple):
4544 callback
[0](widget
, path_to_file
, *callback
[1:])
4546 callback(widget
, path_to_file
)
4550 path
= helpers
.get_my_pictures_path()
4552 path
= os
.environ
['HOME']
4555 FileChooserDialog
.__init
__(self
,
4556 title_text
= _('Choose Image'),
4557 action
= gtk
.FILE_CHOOSER_ACTION_OPEN
,
4558 buttons
= (gtk
.STOCK_CANCEL
, gtk
.RESPONSE_CANCEL
,
4559 gtk
.STOCK_OPEN
, gtk
.RESPONSE_OK
),
4560 default_response
= gtk
.RESPONSE_OK
,
4561 current_folder
= path
,
4562 on_response_ok
= (on_ok
, on_response_ok
),
4563 on_response_cancel
= on_response_cancel
)
4565 if on_response_cancel
:
4566 self
.connect('destroy', on_response_cancel
)
4568 filter_
= gtk
.FileFilter()
4569 filter_
.set_name(_('All files'))
4570 filter_
.add_pattern('*')
4571 self
.add_filter(filter_
)
4573 filter_
= gtk
.FileFilter()
4574 filter_
.set_name(_('Images'))
4575 filter_
.add_mime_type('image/png')
4576 filter_
.add_mime_type('image/jpeg')
4577 filter_
.add_mime_type('image/gif')
4578 filter_
.add_mime_type('image/tiff')
4579 filter_
.add_mime_type('image/svg+xml')
4580 filter_
.add_mime_type('image/x-xpixmap') # xpm
4581 self
.add_filter(filter_
)
4582 self
.set_filter(filter_
)
4585 self
.set_filename(path_to_file
)
4587 self
.set_use_preview_label(False)
4588 self
.set_preview_widget(gtk
.Image())
4589 self
.connect('selection-changed', self
.update_preview
)
4591 def update_preview(self
, widget
):
4592 path_to_file
= widget
.get_preview_filename()
4593 if path_to_file
is None or os
.path
.isdir(path_to_file
):
4594 # nothing to preview or directory
4595 # make sure you clean image do show nothing
4596 widget
.get_preview_widget().set_from_file(None)
4599 pixbuf
= gtk
.gdk
.pixbuf_new_from_file_at_size(path_to_file
, 100, 100)
4600 except gobject
.GError
:
4602 widget
.get_preview_widget().set_from_pixbuf(pixbuf
)
4604 class AvatarChooserDialog(ImageChooserDialog
):
4605 def __init__(self
, path_to_file
='', on_response_ok
=None,
4606 on_response_cancel
=None, on_response_clear
=None):
4607 ImageChooserDialog
.__init
__(self
, path_to_file
, on_response_ok
,
4609 button
= gtk
.Button(None, gtk
.STOCK_CLEAR
)
4610 self
.response_clear
= on_response_clear
4611 if on_response_clear
:
4612 button
.connect('clicked', self
.on_clear
)
4614 self
.action_area
.pack_start(button
)
4615 self
.action_area
.reorder_child(button
, 0)
4617 def on_clear(self
, widget
):
4618 if isinstance(self
.response_clear
, tuple):
4619 self
.response_clear
[0](widget
, *self
.response_clear
[1:])
4621 self
.response_clear(widget
)
4624 class ArchiveChooserDialog(FileChooserDialog
):
4625 def __init__(self
, on_response_ok
=None, on_response_cancel
=None):
4627 def on_ok(widget
, callback
):
4628 '''check if file exists and call callback'''
4629 path_to_file
= self
.get_filename()
4630 if not path_to_file
:
4632 path_to_file
= gtkgui_helpers
.decode_filechooser_file_paths(
4634 if os
.path
.exists(path_to_file
):
4635 if isinstance(callback
, tuple):
4636 callback
[0](path_to_file
, *callback
[1:])
4638 callback(path_to_file
)
4641 path
= helpers
.get_documents_path()
4643 FileChooserDialog
.__init
__(self
,
4644 title_text
=_('Choose Archive'),
4645 action
=gtk
.FILE_CHOOSER_ACTION_OPEN
,
4646 buttons
=(gtk
.STOCK_CANCEL
, gtk
.RESPONSE_CANCEL
,
4647 gtk
.STOCK_OPEN
, gtk
.RESPONSE_OK
),
4648 default_response
=gtk
.RESPONSE_OK
,
4649 current_folder
=path
,
4650 on_response_ok
=(on_ok
, on_response_ok
),
4651 on_response_cancel
=on_response_cancel
)
4653 if on_response_cancel
:
4654 self
.connect('destroy', on_response_cancel
)
4656 filter_
= gtk
.FileFilter()
4657 filter_
.set_name(_('All files'))
4658 filter_
.add_pattern('*')
4659 self
.add_filter(filter_
)
4661 filter_
= gtk
.FileFilter()
4662 filter_
.set_name(_('Zip files'))
4663 filter_
.add_pattern('*.zip')
4665 self
.add_filter(filter_
)
4666 self
.set_filter(filter_
)
4669 class AddSpecialNotificationDialog
:
4670 def __init__(self
, jid
):
4672 jid is the jid for which we want to add special notification (sound and
4673 notification popups)
4675 self
.xml
= gtkgui_helpers
.get_gtk_builder(
4676 'add_special_notification_window.ui')
4677 self
.window
= self
.xml
.get_object('add_special_notification_window')
4678 self
.condition_combobox
= self
.xml
.get_object('condition_combobox')
4679 self
.condition_combobox
.set_active(0)
4680 self
.notification_popup_yes_no_combobox
= self
.xml
.get_object(
4681 'notification_popup_yes_no_combobox')
4682 self
.notification_popup_yes_no_combobox
.set_active(0)
4683 self
.listen_sound_combobox
= self
.xml
.get_object('listen_sound_combobox')
4684 self
.listen_sound_combobox
.set_active(0)
4687 self
.xml
.get_object('when_foo_becomes_label').set_text(
4688 _('When %s becomes:') % self
.jid
)
4690 self
.window
.set_title(_('Adding Special Notification for %s') % jid
)
4691 self
.window
.show_all()
4692 self
.xml
.connect_signals(self
)
4694 def on_cancel_button_clicked(self
, widget
):
4695 self
.window
.destroy()
4697 def on_add_special_notification_window_delete_event(self
, widget
, event
):
4698 self
.window
.destroy()
4700 def on_listen_sound_combobox_changed(self
, widget
):
4701 active
= widget
.get_active()
4702 if active
== 1: # user selected 'choose sound'
4703 def on_ok(widget
, path_to_snd_file
):
4705 #print path_to_snd_file
4707 def on_cancel(widget
):
4708 widget
.set_active(0) # go back to No Sound
4710 self
.dialog
= SoundChooserDialog(on_response_ok
=on_ok
,
4711 on_response_cancel
=on_cancel
)
4713 def on_ok_button_clicked(self
, widget
):
4714 conditions
= ('online', 'chat', 'online_and_chat',
4715 'away', 'xa', 'away_and_xa', 'dnd', 'xa_and_dnd', 'offline')
4716 active
= self
.condition_combobox
.get_active()
4718 active_iter
= self
.listen_sound_combobox
.get_active_iter()
4719 listen_sound_model
= self
.listen_sound_combobox
.get_model()
4721 class AdvancedNotificationsWindow
:
4722 events_list
= ['message_received', 'contact_connected',
4723 'contact_disconnected', 'contact_change_status', 'gc_msg_highlight',
4724 'gc_msg', 'ft_request', 'ft_started', 'ft_finished']
4725 recipient_types_list
= ['contact', 'group', 'all']
4726 config_options
= ['event', 'recipient_type', 'recipients', 'status',
4727 'tab_opened', 'sound', 'sound_file', 'popup', 'auto_open',
4728 'run_command', 'command', 'systray', 'roster', 'urgency_hint']
4730 self
.xml
= gtkgui_helpers
.get_gtk_builder(
4731 'advanced_notifications_window.ui')
4732 self
.window
= self
.xml
.get_object('advanced_notifications_window')
4733 for w
in ('conditions_treeview', 'config_vbox', 'event_combobox',
4734 'recipient_type_combobox', 'recipient_list_entry', 'delete_button',
4735 'status_hbox', 'use_sound_cb', 'disable_sound_cb', 'use_popup_cb',
4736 'disable_popup_cb', 'use_auto_open_cb', 'disable_auto_open_cb',
4737 'use_systray_cb', 'disable_systray_cb', 'use_roster_cb',
4738 'disable_roster_cb', 'tab_opened_cb', 'not_tab_opened_cb',
4739 'sound_entry', 'sound_file_hbox', 'up_button', 'down_button',
4740 'run_command_cb', 'command_entry', 'urgency_hint_cb'):
4741 self
.__dict
__[w
] = self
.xml
.get_object(w
)
4743 # Contains status checkboxes
4744 childs
= self
.status_hbox
.get_children()
4746 self
.all_status_rb
= childs
[0]
4747 self
.special_status_rb
= childs
[1]
4748 self
.online_cb
= childs
[2]
4749 self
.away_cb
= childs
[3]
4750 self
.xa_cb
= childs
[4]
4751 self
.dnd_cb
= childs
[5]
4752 self
.invisible_cb
= childs
[6]
4754 model
= gtk
.ListStore(int, str)
4755 model
.set_sort_column_id(0, gtk
.SORT_ASCENDING
)
4757 self
.conditions_treeview
.set_model(model
)
4760 col
= gtk
.TreeViewColumn(_('#'))
4761 self
.conditions_treeview
.append_column(col
)
4762 renderer
= gtk
.CellRendererText()
4763 col
.pack_start(renderer
, expand
=False)
4764 col
.set_attributes(renderer
, text
=0)
4766 col
= gtk
.TreeViewColumn(_('Condition'))
4767 self
.conditions_treeview
.append_column(col
)
4768 renderer
= gtk
.CellRendererText()
4769 col
.pack_start(renderer
, expand
=True)
4770 col
.set_attributes(renderer
, text
=1)
4772 self
.xml
.connect_signals(self
)
4774 # Fill conditions_treeview
4776 while gajim
.config
.get_per('notifications', str(num
)):
4777 iter_
= model
.append((num
, ''))
4778 path
= model
.get_path(iter_
)
4779 self
.conditions_treeview
.set_cursor(path
)
4780 self
.active_num
= num
4781 self
.initiate_rule_state()
4782 self
.set_treeview_string()
4785 # No rule selected at init time
4786 self
.conditions_treeview
.get_selection().unselect_all()
4787 self
.active_num
= -1
4788 self
.config_vbox
.set_sensitive(False)
4789 self
.delete_button
.set_sensitive(False)
4790 self
.down_button
.set_sensitive(False)
4791 self
.up_button
.set_sensitive(False)
4793 self
.window
.show_all()
4795 def initiate_rule_state(self
):
4797 Set values for all widgets
4799 if self
.active_num
< 0:
4802 value
= gajim
.config
.get_per('notifications', str(self
.active_num
),
4805 self
.event_combobox
.set_active(self
.events_list
.index(value
))
4807 self
.event_combobox
.set_active(-1)
4809 value
= gajim
.config
.get_per('notifications', str(self
.active_num
),
4812 self
.recipient_type_combobox
.set_active(
4813 self
.recipient_types_list
.index(value
))
4815 self
.recipient_type_combobox
.set_active(-1)
4817 value
= gajim
.config
.get_per('notifications', str(self
.active_num
),
4821 self
.recipient_list_entry
.set_text(value
)
4823 value
= gajim
.config
.get_per('notifications', str(self
.active_num
),
4826 self
.all_status_rb
.set_active(True)
4828 self
.special_status_rb
.set_active(True)
4829 values
= value
.split()
4830 for v
in ('online', 'away', 'xa', 'dnd', 'invisible'):
4832 self
.__dict
__[v
+ '_cb'].set_active(True)
4834 self
.__dict
__[v
+ '_cb'].set_active(False)
4835 self
.on_status_radiobutton_toggled(self
.all_status_rb
)
4837 value
= gajim
.config
.get_per('notifications', str(self
.active_num
),
4839 self
.tab_opened_cb
.set_active(True)
4840 self
.not_tab_opened_cb
.set_active(True)
4842 self
.tab_opened_cb
.set_active(False)
4843 elif value
== 'yes':
4844 self
.not_tab_opened_cb
.set_active(False)
4846 value
= gajim
.config
.get_per('notifications', str(self
.active_num
),
4848 self
.sound_entry
.set_text(value
)
4849 # sound, popup, auto_open, systray, roster
4850 for option
in ('sound', 'popup', 'auto_open', 'systray', 'roster'):
4851 value
= gajim
.config
.get_per('notifications', str(self
.active_num
),
4854 self
.__dict
__['use_' + option
+ '_cb'].set_active(True)
4856 self
.__dict
__['use_' + option
+ '_cb'].set_active(False)
4858 self
.__dict
__['disable_' + option
+ '_cb'].set_active(True)
4860 self
.__dict
__['disable_' + option
+ '_cb'].set_active(False)
4862 value
= gajim
.config
.get_per('notifications', str(self
.active_num
),
4864 self
.run_command_cb
.set_active(value
)
4866 value
= gajim
.config
.get_per('notifications', str(self
.active_num
),
4868 self
.command_entry
.set_text(value
)
4870 value
= gajim
.config
.get_per('notifications', str(self
.active_num
),
4872 self
.urgency_hint_cb
.set_active(value
)
4874 def set_treeview_string(self
):
4875 (model
, iter_
) = self
.conditions_treeview
.get_selection().get_selected()
4878 event
= self
.event_combobox
.get_active_text()
4879 recipient_type
= self
.recipient_type_combobox
.get_active_text()
4881 if recipient_type
!= 'everybody':
4882 recipient
= self
.recipient_list_entry
.get_text()
4883 if self
.all_status_rb
.get_active():
4886 status
= _('when I am ')
4887 for st
in ('online', 'away', 'xa', 'dnd', 'invisible'):
4888 if self
.__dict
__[st
+ '_cb'].get_active():
4889 status
+= helpers
.get_uf_show(st
) + ' '
4890 model
[iter_
][1] = "When %s for %s %s %s" % (event
, recipient_type
,
4893 def on_conditions_treeview_cursor_changed(self
, widget
):
4894 (model
, iter_
) = widget
.get_selection().get_selected()
4896 self
.active_num
= -1
4898 self
.active_num
= model
[iter_
][0]
4899 if self
.active_num
== 0:
4900 self
.up_button
.set_sensitive(False)
4902 self
.up_button
.set_sensitive(True)
4903 max = self
.conditions_treeview
.get_model().iter_n_children(None)
4904 if self
.active_num
== max - 1:
4905 self
.down_button
.set_sensitive(False)
4907 self
.down_button
.set_sensitive(True)
4908 self
.initiate_rule_state()
4909 self
.config_vbox
.set_sensitive(True)
4910 self
.delete_button
.set_sensitive(True)
4912 def on_new_button_clicked(self
, widget
):
4913 model
= self
.conditions_treeview
.get_model()
4914 num
= self
.conditions_treeview
.get_model().iter_n_children(None)
4915 gajim
.config
.add_per('notifications', str(num
))
4916 iter_
= model
.append((num
, ''))
4917 path
= model
.get_path(iter_
)
4918 self
.conditions_treeview
.set_cursor(path
)
4919 self
.active_num
= num
4920 self
.set_treeview_string()
4921 self
.config_vbox
.set_sensitive(True)
4923 def on_delete_button_clicked(self
, widget
):
4924 (model
, iter_
) = self
.conditions_treeview
.get_selection().get_selected()
4928 iter2
= model
.iter_next(iter_
)
4929 num
= self
.active_num
4931 num
= model
[iter2
][0]
4932 model
[iter2
][0] = num
- 1
4933 for opt
in self
.config_options
:
4934 val
= gajim
.config
.get_per('notifications', str(num
), opt
)
4935 gajim
.config
.set_per('notifications', str(num
- 1), opt
, val
)
4936 iter2
= model
.iter_next(iter2
)
4938 gajim
.config
.del_per('notifications', str(num
)) # delete latest
4939 self
.active_num
= -1
4940 self
.config_vbox
.set_sensitive(False)
4941 self
.delete_button
.set_sensitive(False)
4942 self
.up_button
.set_sensitive(False)
4943 self
.down_button
.set_sensitive(False)
4945 def on_up_button_clicked(self
, widget
):
4946 (model
, iter_
) = self
.conditions_treeview
.get_selection().\
4950 for opt
in self
.config_options
:
4951 val
= gajim
.config
.get_per('notifications', str(self
.active_num
),
4953 val2
= gajim
.config
.get_per('notifications',
4954 str(self
.active_num
- 1), opt
)
4955 gajim
.config
.set_per('notifications', str(self
.active_num
), opt
,
4957 gajim
.config
.set_per('notifications', str(self
.active_num
- 1), opt
,
4960 model
[iter_
][0] = self
.active_num
- 1
4962 path
= model
.get_path(iter_
)
4963 iter_
= model
.get_iter((path
[0] - 1,))
4964 model
[iter_
][0] = self
.active_num
4965 self
.on_conditions_treeview_cursor_changed(self
.conditions_treeview
)
4967 def on_down_button_clicked(self
, widget
):
4968 (model
, iter_
) = self
.conditions_treeview
.get_selection().get_selected()
4971 for opt
in self
.config_options
:
4972 val
= gajim
.config
.get_per('notifications', str(self
.active_num
),
4974 val2
= gajim
.config
.get_per('notifications',
4975 str(self
.active_num
+ 1), opt
)
4976 gajim
.config
.set_per('notifications', str(self
.active_num
), opt
,
4978 gajim
.config
.set_per('notifications', str(self
.active_num
+ 1), opt
,
4981 model
[iter_
][0] = self
.active_num
+ 1
4982 iter_
= model
.iter_next(iter_
)
4983 model
[iter_
][0] = self
.active_num
4984 self
.on_conditions_treeview_cursor_changed(self
.conditions_treeview
)
4986 def on_event_combobox_changed(self
, widget
):
4987 if self
.active_num
< 0:
4989 active
= self
.event_combobox
.get_active()
4993 event
= self
.events_list
[active
]
4994 gajim
.config
.set_per('notifications', str(self
.active_num
), 'event',
4996 self
.set_treeview_string()
4998 def on_recipient_type_combobox_changed(self
, widget
):
4999 if self
.active_num
< 0:
5001 recipient_type
= self
.recipient_types_list
[self
.recipient_type_combobox
.\
5003 gajim
.config
.set_per('notifications', str(self
.active_num
),
5004 'recipient_type', recipient_type
)
5005 if recipient_type
== 'all':
5006 self
.recipient_list_entry
.hide()
5008 self
.recipient_list_entry
.show()
5009 self
.set_treeview_string()
5011 def on_recipient_list_entry_changed(self
, widget
):
5012 if self
.active_num
< 0:
5014 recipients
= widget
.get_text().decode('utf-8')
5015 #TODO: do some check
5016 gajim
.config
.set_per('notifications', str(self
.active_num
),
5017 'recipients', recipients
)
5018 self
.set_treeview_string()
5020 def set_status_config(self
):
5021 if self
.active_num
< 0:
5024 for st
in ('online', 'away', 'xa', 'dnd', 'invisible'):
5025 if self
.__dict
__[st
+ '_cb'].get_active():
5028 status
= status
[:-1]
5029 gajim
.config
.set_per('notifications', str(self
.active_num
), 'status',
5031 self
.set_treeview_string()
5033 def on_status_radiobutton_toggled(self
, widget
):
5034 if self
.active_num
< 0:
5036 if self
.all_status_rb
.get_active():
5037 gajim
.config
.set_per('notifications', str(self
.active_num
), 'status',
5039 # 'All status' clicked
5040 for st
in ('online', 'away', 'xa', 'dnd', 'invisible'):
5041 self
.__dict
__[st
+ '_cb'].hide()
5043 self
.special_status_rb
.show()
5045 self
.set_status_config()
5046 # 'special status' clicked
5047 for st
in ('online', 'away', 'xa', 'dnd', 'invisible'):
5048 self
.__dict
__[st
+ '_cb'].show()
5050 self
.special_status_rb
.hide()
5051 self
.set_treeview_string()
5053 def on_status_cb_toggled(self
, widget
):
5054 if self
.active_num
< 0:
5056 self
.set_status_config()
5058 # tab_opened OR (not xor) not_tab_opened must be active
5059 def on_tab_opened_cb_toggled(self
, widget
):
5060 if self
.active_num
< 0:
5062 if self
.tab_opened_cb
.get_active():
5063 if self
.not_tab_opened_cb
.get_active():
5064 gajim
.config
.set_per('notifications', str(self
.active_num
),
5065 'tab_opened', 'both')
5067 gajim
.config
.set_per('notifications', str(self
.active_num
),
5068 'tab_opened', 'yes')
5069 elif not self
.not_tab_opened_cb
.get_active():
5070 self
.not_tab_opened_cb
.set_active(True)
5071 gajim
.config
.set_per('notifications', str(self
.active_num
),
5074 def on_not_tab_opened_cb_toggled(self
, widget
):
5075 if self
.active_num
< 0:
5077 if self
.not_tab_opened_cb
.get_active():
5078 if self
.tab_opened_cb
.get_active():
5079 gajim
.config
.set_per('notifications', str(self
.active_num
),
5080 'tab_opened', 'both')
5082 gajim
.config
.set_per('notifications', str(self
.active_num
),
5084 elif not self
.tab_opened_cb
.get_active():
5085 self
.tab_opened_cb
.set_active(True)
5086 gajim
.config
.set_per('notifications', str(self
.active_num
),
5087 'tab_opened', 'yes')
5089 def on_use_it_toggled(self
, widget
, oposite_widget
, option
):
5090 if widget
.get_active():
5091 if oposite_widget
.get_active():
5092 oposite_widget
.set_active(False)
5093 gajim
.config
.set_per('notifications', str(self
.active_num
), option
,
5095 elif oposite_widget
.get_active():
5096 gajim
.config
.set_per('notifications', str(self
.active_num
), option
,
5099 gajim
.config
.set_per('notifications', str(self
.active_num
),
5102 def on_disable_it_toggled(self
, widget
, oposite_widget
, option
):
5103 if widget
.get_active():
5104 if oposite_widget
.get_active():
5105 oposite_widget
.set_active(False)
5106 gajim
.config
.set_per('notifications', str(self
.active_num
), option
,
5108 elif oposite_widget
.get_active():
5109 gajim
.config
.set_per('notifications', str(self
.active_num
), option
,
5112 gajim
.config
.set_per('notifications', str(self
.active_num
), option
,
5115 def on_use_sound_cb_toggled(self
, widget
):
5116 self
.on_use_it_toggled(widget
, self
.disable_sound_cb
, 'sound')
5117 if widget
.get_active():
5118 self
.sound_file_hbox
.set_sensitive(True)
5120 self
.sound_file_hbox
.set_sensitive(False)
5122 def on_browse_for_sounds_button_clicked(self
, widget
, data
=None):
5123 if self
.active_num
< 0:
5126 def on_ok(widget
, path_to_snd_file
):
5128 if not path_to_snd_file
:
5129 path_to_snd_file
= ''
5130 gajim
.config
.set_per('notifications', str(self
.active_num
),
5131 'sound_file', path_to_snd_file
)
5132 self
.sound_entry
.set_text(path_to_snd_file
)
5134 path_to_snd_file
= self
.sound_entry
.get_text().decode('utf-8')
5135 path_to_snd_file
= os
.path
.join(os
.getcwd(), path_to_snd_file
)
5136 dialog
= SoundChooserDialog(path_to_snd_file
, on_ok
)
5138 def on_play_button_clicked(self
, widget
):
5139 helpers
.play_sound_file(self
.sound_entry
.get_text().decode('utf-8'))
5141 def on_disable_sound_cb_toggled(self
, widget
):
5142 self
.on_disable_it_toggled(widget
, self
.use_sound_cb
, 'sound')
5144 def on_sound_entry_changed(self
, widget
):
5145 gajim
.config
.set_per('notifications', str(self
.active_num
),
5146 'sound_file', widget
.get_text().decode('utf-8'))
5148 def on_use_popup_cb_toggled(self
, widget
):
5149 self
.on_use_it_toggled(widget
, self
.disable_popup_cb
, 'popup')
5151 def on_disable_popup_cb_toggled(self
, widget
):
5152 self
.on_disable_it_toggled(widget
, self
.use_popup_cb
, 'popup')
5154 def on_use_auto_open_cb_toggled(self
, widget
):
5155 self
.on_use_it_toggled(widget
, self
.disable_auto_open_cb
, 'auto_open')
5157 def on_disable_auto_open_cb_toggled(self
, widget
):
5158 self
.on_disable_it_toggled(widget
, self
.use_auto_open_cb
, 'auto_open')
5160 def on_run_command_cb_toggled(self
, widget
):
5161 gajim
.config
.set_per('notifications', str(self
.active_num
),
5162 'run_command', widget
.get_active())
5163 if widget
.get_active():
5164 self
.command_entry
.set_sensitive(True)
5166 self
.command_entry
.set_sensitive(False)
5168 def on_command_entry_changed(self
, widget
):
5169 gajim
.config
.set_per('notifications', str(self
.active_num
), 'command',
5170 widget
.get_text().decode('utf-8'))
5172 def on_use_systray_cb_toggled(self
, widget
):
5173 self
.on_use_it_toggled(widget
, self
.disable_systray_cb
, 'systray')
5175 def on_disable_systray_cb_toggled(self
, widget
):
5176 self
.on_disable_it_toggled(widget
, self
.use_systray_cb
, 'systray')
5178 def on_use_roster_cb_toggled(self
, widget
):
5179 self
.on_use_it_toggled(widget
, self
.disable_roster_cb
, 'roster')
5181 def on_disable_roster_cb_toggled(self
, widget
):
5182 self
.on_disable_it_toggled(widget
, self
.use_roster_cb
, 'roster')
5184 def on_urgency_hint_cb_toggled(self
, widget
):
5185 gajim
.config
.set_per('notifications', str(self
.active_num
),
5186 'uregency_hint', widget
.get_active())
5188 def on_close_window(self
, widget
):
5189 self
.window
.destroy()
5191 class TransformChatToMUC
:
5192 # Keep a reference on windows so garbage collector don't restroy them
5194 def __init__(self
, account
, jids
, preselected
=None):
5196 This window is used to trasform a one-to-one chat to a MUC. We do 2
5197 things: first select the server and then make a guests list
5200 self
.instances
.append(self
)
5201 self
.account
= account
5202 self
.auto_jids
= jids
5203 self
.preselected_jids
= preselected
5205 self
.xml
= gtkgui_helpers
.get_gtk_builder('chat_to_muc_window.ui')
5206 self
.window
= self
.xml
.get_object('chat_to_muc_window')
5208 for widget_to_add
in ('invite_button', 'cancel_button',
5209 'server_list_comboboxentry', 'guests_treeview',
5210 'server_and_guests_hseparator', 'server_select_label'):
5211 self
.__dict
__[widget_to_add
] = self
.xml
.get_object(widget_to_add
)
5214 self
.servers
= gtk
.ListStore(str)
5215 self
.server_list_comboboxentry
.set_model(self
.servers
)
5217 self
.server_list_comboboxentry
.set_text_column(0)
5219 # get the muc server of our server
5220 if 'jabber' in gajim
.connections
[account
].muc_jid
:
5221 server_list
.append(gajim
.connections
[account
].muc_jid
['jabber'])
5222 # add servers or recently joined groupchats
5223 recently_groupchat
= gajim
.config
.get('recently_groupchat').split()
5224 for g
in recently_groupchat
:
5225 server
= gajim
.get_server_from_jid(g
)
5226 if server
not in server_list
and not server
.startswith('irc'):
5227 server_list
.append(server
)
5228 # add a default server
5230 server_list
.append('conference.jabber.org')
5232 for s
in server_list
:
5233 self
.servers
.append([s
])
5235 self
.server_list_comboboxentry
.set_active(0)
5239 self
.store
= gtk
.ListStore(gtk
.gdk
.Pixbuf
, str, str)
5240 self
.store
.set_sort_column_id(1, gtk
.SORT_ASCENDING
)
5241 self
.guests_treeview
.set_model(self
.store
)
5243 renderer1
= gtk
.CellRendererText()
5244 renderer2
= gtk
.CellRendererPixbuf()
5245 column
= gtk
.TreeViewColumn('Status', renderer2
, pixbuf
=0)
5246 self
.guests_treeview
.append_column(column
)
5247 column
= gtk
.TreeViewColumn('Name', renderer1
, text
=1)
5248 self
.guests_treeview
.append_column(column
)
5250 self
.guests_treeview
.get_selection().set_mode(gtk
.SELECTION_MULTIPLE
)
5252 # All contacts beside the following can be invited:
5253 # transports, zeroconf contacts, minimized groupchats
5254 def invitable(contact
, contact_transport
=None):
5255 return (contact
.jid
not in self
.auto_jids
and
5256 contact
.jid
!= gajim
.get_jid_from_account(self
.account
) and
5257 contact
.jid
not in gajim
.interface
.minimized_controls
[account
] and
5258 not contact
.is_transport() and
5259 not contact_transport
)
5261 # set jabber id and pseudos
5262 for account
in gajim
.contacts
.get_accounts():
5263 if gajim
.connections
[account
].is_zeroconf
:
5265 for jid
in gajim
.contacts
.get_jid_list(account
):
5266 contact
= gajim
.contacts
.get_contact_with_highest_priority(
5268 contact_transport
= gajim
.get_transport_name_from_jid(jid
)
5269 # Add contact if it can be invited
5270 if invitable(contact
, contact_transport
) and \
5271 contact
.show
not in ('offline', 'error'):
5272 img
= gajim
.interface
.jabber_state_images
['16'][contact
.show
]
5275 name
= jid
.split('@')[0]
5276 iter_
= self
.store
.append([img
.get_pixbuf(), name
, jid
])
5277 # preselect treeview rows
5278 if self
.preselected_jids
and jid
in self
.preselected_jids
:
5279 path
= self
.store
.get_path(iter_
)
5280 self
.guests_treeview
.get_selection().select_path(path
)
5282 gajim
.ged
.register_event_handler('unique-room-id-supported', ged
.GUI1
,
5283 self
._nec
_unique
_room
_id
_supported
)
5284 gajim
.ged
.register_event_handler('unique-room-id-not-supported',
5285 ged
.GUI1
, self
._nec
_unique
_room
_id
_not
_supported
)
5288 self
.window
.show_all()
5290 self
.xml
.connect_signals(self
)
5292 def on_chat_to_muc_window_destroy(self
, widget
):
5293 gajim
.ged
.remove_event_handler('unique-room-id-supported', ged
.GUI1
,
5294 self
._nec
_unique
_room
_id
_supported
)
5295 gajim
.ged
.remove_event_handler('unique-room-id-not-supported', ged
.GUI1
,
5296 self
._nec
_unique
_room
_id
_not
_supported
)
5297 self
.instances
.remove(self
)
5299 def on_chat_to_muc_window_key_press_event(self
, widget
, event
):
5300 if event
.keyval
== gtk
.keysyms
.Escape
: # ESCAPE
5301 self
.window
.destroy()
5303 def on_invite_button_clicked(self
, widget
):
5304 server
= self
.server_list_comboboxentry
.get_active_text()
5307 gajim
.connections
[self
.account
].check_unique_room_id_support(server
, self
)
5309 def _nec_unique_room_id_supported(self
, obj
):
5310 if obj
.instance
!= self
:
5313 guests
= self
.guests_treeview
.get_selection().get_selected_rows()
5314 for guest
in guests
[1]:
5315 iter_
= self
.store
.get_iter(guest
)
5316 guest_list
.append(self
.store
[iter_
][2].decode('utf-8'))
5317 for guest
in self
.auto_jids
:
5318 guest_list
.append(guest
)
5319 room_jid
= obj
.room_id
+ '@' + obj
.server
5320 gajim
.automatic_rooms
[self
.account
][room_jid
] = {}
5321 gajim
.automatic_rooms
[self
.account
][room_jid
]['invities'] = guest_list
5322 gajim
.automatic_rooms
[self
.account
][room_jid
]['continue_tag'] = True
5323 gajim
.interface
.join_gc_room(self
.account
, room_jid
,
5324 gajim
.nicks
[self
.account
], None, is_continued
=True)
5325 self
.window
.destroy()
5327 def on_cancel_button_clicked(self
, widget
):
5328 self
.window
.destroy()
5330 def _nec_unique_room_id_not_supported(self
, obj
):
5331 if obj
.instance
!= self
:
5333 obj
.room_id
= gajim
.nicks
[self
.account
].lower().replace(' ', '') + \
5334 str(randrange(9999999))
5335 self
._nec
_unique
_room
_id
_supported
(obj
)
5337 class DataFormWindow(Dialog
):
5338 def __init__(self
, form
, on_response_ok
):
5339 self
.df_response_ok
= on_response_ok
5340 Dialog
.__init
__(self
, None, 'test', [(gtk
.STOCK_CANCEL
,
5341 gtk
.RESPONSE_REJECT
), (gtk
.STOCK_OK
, gtk
.RESPONSE_ACCEPT
)],
5342 on_response_ok
=self
.on_ok
)
5343 self
.set_resizable(True)
5344 gtkgui_helpers
.resize_window(self
, 600, 400)
5345 self
.dataform_widget
= dataforms_widget
.DataFormWidget()
5346 self
.dataform
= dataforms
.ExtendForm(node
=form
)
5347 self
.dataform_widget
.set_sensitive(True)
5348 self
.dataform_widget
.data_form
= self
.dataform
5349 self
.dataform_widget
.show_all()
5350 self
.vbox
.pack_start(self
.dataform_widget
)
5353 form
= self
.dataform_widget
.data_form
5354 if isinstance(self
.df_response_ok
, tuple):
5355 self
.df_response_ok
[0](form
, *self
.df_response_ok
[1:])
5357 self
.df_response_ok(form
)
5360 class ESessionInfoWindow
:
5362 Class for displaying information about a XEP-0116 encrypted session
5364 def __init__(self
, session
):
5365 self
.session
= session
5367 self
.xml
= gtkgui_helpers
.get_gtk_builder('esession_info_window.ui')
5368 self
.xml
.connect_signals(self
)
5370 self
.security_image
= self
.xml
.get_object('security_image')
5371 self
.verify_now_button
= self
.xml
.get_object('verify_now_button')
5372 self
.button_label
= self
.xml
.get_object('button_label')
5373 self
.window
= self
.xml
.get_object('esession_info_window')
5377 self
.window
.show_all()
5379 def update_info(self
):
5380 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
}
5382 if self
.session
.verified_identity
:
5383 labeltext
+= '\n\n' + _('''You have already verified this contact's identity.''')
5384 security_image
= 'gajim-security_high'
5385 if self
.session
.control
:
5386 self
.session
.control
._show
_lock
_image
(True, 'E2E', True,
5387 self
.session
.is_loggable(), True)
5389 verification_status
= _('''Contact's identity verified''')
5390 self
.window
.set_title(verification_status
)
5391 self
.xml
.get_object('verification_status_label').set_markup(
5392 '<b><span size="x-large">%s</span></b>' % verification_status
)
5394 self
.xml
.get_object('dialog-action_area1').set_no_show_all(True)
5395 self
.button_label
.set_text(_('Verify again...'))
5397 if self
.session
.control
:
5398 self
.session
.control
._show
_lock
_image
(True, 'E2E', True,
5399 self
.session
.is_loggable(), False)
5400 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.''')
5401 security_image
= 'gajim-security_low'
5403 verification_status
= _('''Contact's identity NOT verified''')
5404 self
.window
.set_title(verification_status
)
5405 self
.xml
.get_object('verification_status_label').set_markup(
5406 '<b><span size="x-large">%s</span></b>' % verification_status
)
5408 self
.button_label
.set_text(_('Verify...'))
5410 path
= gtkgui_helpers
.get_icon_path(security_image
, 32)
5411 self
.security_image
.set_from_file(path
)
5413 self
.xml
.get_object('info_display').set_markup(labeltext
)
5415 def on_close_button_clicked(self
, widget
):
5416 self
.window
.destroy()
5418 def on_verify_now_button_clicked(self
, widget
):
5419 pritext
= _('''Have you verified the contact's identity?''')
5420 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
}
5421 sectext
+= '\n\n' + _('Did you talk to the remote contact and verify the SAS?')
5423 def on_yes(checked
):
5424 self
.session
._verified
_srs
_cb
()
5425 self
.session
.verified_identity
= True
5429 self
.session
._unverified
_srs
_cb
()
5430 self
.session
.verified_identity
= False
5433 YesNoDialog(pritext
, sectext
, on_response_yes
=on_yes
, on_response_no
=on_no
)
5435 class GPGInfoWindow
:
5437 Class for displaying information about a XEP-0116 encrypted session
5439 def __init__(self
, control
):
5440 xml
= gtkgui_helpers
.get_gtk_builder('esession_info_window.ui')
5441 security_image
= xml
.get_object('security_image')
5442 status_label
= xml
.get_object('verification_status_label')
5443 info_label
= xml
.get_object('info_display')
5444 verify_now_button
= xml
.get_object('verify_now_button')
5445 self
.window
= xml
.get_object('esession_info_window')
5446 account
= control
.account
5447 keyID
= control
.contact
.keyID
5450 verify_now_button
.set_no_show_all(True)
5451 verify_now_button
.hide()
5453 if keyID
.endswith('MISMATCH'):
5454 verification_status
= _('''Contact's identity NOT verified''')
5455 info
= _('The contact\'s key (%s) <b>does not match</b> the key '
5456 'assigned in Gajim.') % keyID
[:8]
5457 image
= 'gajim-security_low'
5459 # No key assigned nor a key is used by remote contact
5460 verification_status
= _('No GPG key assigned')
5461 info
= _('No GPG key is assigned to this contact. So you cannot '
5462 'encrypt messages.')
5463 image
= 'gajim-security_low'
5465 error
= gajim
.connections
[account
].gpg
.encrypt('test', [keyID
])[1]
5467 verification_status
= _('''Contact's identity NOT verified''')
5468 info
= _('GPG key is assigned to this contact, but <b>you do not '
5469 'trust his key</b>, so message <b>cannot</b> be encrypted. Use '
5470 'your GPG client to trust this key.')
5471 image
= 'gajim-security_low'
5473 verification_status
= _('''Contact's identity verified''')
5474 info
= _('GPG Key is assigned to this contact, and you trust his '
5475 'key, so messages will be encrypted.')
5476 image
= 'gajim-security_high'
5478 status_label
.set_markup('<b><span size="x-large">%s</span></b>' % \
5479 verification_status
)
5480 info_label
.set_markup(info
)
5482 path
= gtkgui_helpers
.get_icon_path(image
, 32)
5483 security_image
.set_from_file(path
)
5485 xml
.connect_signals(self
)
5486 self
.window
.show_all()
5488 def on_close_button_clicked(self
, widget
):
5489 self
.window
.destroy()
5493 class ResourceConflictDialog(TimeoutDialog
, InputDialog
):
5494 def __init__(self
, title
, text
, resource
, ok_handler
):
5495 TimeoutDialog
.__init
__(self
, 15, self
.on_timeout
)
5496 InputDialog
.__init
__(self
, title
, text
, input_str
=resource
,
5497 is_modal
=False, ok_handler
=ok_handler
)
5498 self
.title_text
= title
5501 def on_timeout(self
):
5502 self
.on_okbutton_clicked(None)
5506 class VoIPCallReceivedDialog(object):
5508 def __init__(self
, account
, contact_jid
, sid
, content_types
):
5509 self
.instances
[(contact_jid
, sid
)] = self
5510 self
.account
= account
5511 self
.fjid
= contact_jid
5513 self
.content_types
= content_types
5515 xml
= gtkgui_helpers
.get_gtk_builder('voip_call_received_dialog.ui')
5516 xml
.connect_signals(self
)
5518 jid
= gajim
.get_jid_without_resource(self
.fjid
)
5519 contact
= gajim
.contacts
.get_first_contact_from_jid(account
, jid
)
5520 if contact
and contact
.name
:
5521 self
.contact_text
= '%s (%s)' % (contact
.name
, jid
)
5523 self
.contact_text
= contact_jid
5525 self
.dialog
= xml
.get_object('voip_call_received_messagedialog')
5526 self
.set_secondary_text()
5528 self
.dialog
.show_all()
5531 def get_dialog(cls
, jid
, sid
):
5532 if (jid
, sid
) in cls
.instances
:
5533 return cls
.instances
[(jid
, sid
)]
5537 def set_secondary_text(self
):
5538 if 'audio' in self
.content_types
and 'video' in self
.content_types
:
5539 types_text
= _('an audio and video')
5540 elif 'audio' in self
.content_types
:
5541 types_text
= _('an audio')
5542 elif 'video' in self
.content_types
:
5543 types_text
= _('a video')
5545 # do the substitution
5546 self
.dialog
.set_property('secondary-text',
5547 _('%(contact)s wants to start %(type)s session with you. Do you want '
5548 'to answer the call?') % {'contact': self
.contact_text
,
5549 'type': types_text
})
5551 def add_contents(self
, content_types
):
5552 for type_
in content_types
:
5553 if type_
not in self
.content_types
:
5554 self
.content_types
.add(type_
)
5555 self
.set_secondary_text()
5557 def remove_contents(self
, content_types
):
5558 for type_
in content_types
:
5559 if type_
in self
.content_types
:
5560 self
.content_types
.remove(type_
)
5561 if not self
.content_types
:
5562 self
.dialog
.destroy()
5564 self
.set_secondary_text()
5566 def on_voip_call_received_messagedialog_destroy(self
, dialog
):
5567 if (self
.fjid
, self
.sid
) in self
.instances
:
5568 del self
.instances
[(self
.fjid
, self
.sid
)]
5570 def on_voip_call_received_messagedialog_close(self
, dialog
):
5571 return self
.on_voip_call_received_messagedialog_response(dialog
,
5574 def on_voip_call_received_messagedialog_response(self
, dialog
, response
):
5575 # we've got response from user, either stop connecting or accept the call
5576 session
= gajim
.connections
[self
.account
].get_jingle_session(self
.fjid
,
5580 if response
== gtk
.RESPONSE_YES
:
5581 #TODO: Ensure that ctrl.contact.resource == resource
5582 jid
= gajim
.get_jid_without_resource(self
.fjid
)
5583 resource
= gajim
.get_resource_from_jid(self
.fjid
)
5584 ctrl
= (gajim
.interface
.msg_win_mgr
.get_control(self
.fjid
, self
.account
)
5585 or gajim
.interface
.msg_win_mgr
.get_control(jid
, self
.account
)
5586 or gajim
.interface
.new_chat_from_jid(self
.account
, jid
))
5588 # Chat control opened, update content's status
5589 audio
= session
.get_content('audio')
5590 video
= session
.get_content('video')
5591 if audio
and not audio
.negotiated
:
5592 ctrl
.set_audio_state('connecting', self
.sid
)
5593 if video
and not video
.negotiated
:
5594 ctrl
.set_video_state('connecting', self
.sid
)
5595 # Now, accept the content/sessions.
5596 # This should be done after the chat control is running
5597 if not session
.accepted
:
5598 session
.approve_session()
5599 for content
in self
.content_types
:
5600 session
.approve_content(content
)
5601 else: # response==gtk.RESPONSE_NO
5602 if not session
.accepted
:
5603 session
.decline_session()
5605 for content
in self
.content_types
:
5606 session
.reject_content(content
)
5610 class CertificatDialog(InformationDialog
):
5611 def __init__(self
, parent
, account
, cert
):
5612 issuer
= cert
.get_issuer()
5613 subject
= cert
.get_subject()
5614 InformationDialog
.__init
__(self
,
5615 _('Certificate for account %s') % account
, _('''<b>Issued to:</b>
5616 Common Name (CN): %(scn)s
5617 Organization (O): %(sorg)s
5618 Organizationl Unit (OU): %(sou)s
5619 Serial Number: %(sn)s
5622 Common Name (CN): %(icn)s
5623 Organization (O): %(iorg)s
5624 Organizationl Unit (OU): %(iou)s
5631 SHA1 Fingerprint: %(sha1)s''') % {
5632 'scn': subject
.commonName
, 'sorg': subject
.organizationName
,
5633 'sou': subject
.organizationalUnitName
,
5634 'sn': cert
.get_serial_number(), 'icn': issuer
.commonName
,
5635 'iorg': issuer
.organizationName
,
5636 'iou': issuer
.organizationalUnitName
,
5637 'io': cert
.get_notBefore(), 'eo': cert
.get_notAfter(),
5638 'sha1': cert
.digest('sha1')})
5639 self
.set_transient_for(parent
)
5642 class CheckFingerprintDialog(YesNoDialog
):
5643 def __init__(self
, pritext
='', sectext
='', checktext
='',
5644 on_response_yes
=None, on_response_no
=None, account
=None, certificate
=None):
5645 self
.account
= account
5646 self
.cert
= certificate
5647 YesNoDialog
.__init
__(self
, pritext
, sectext
, checktext
, on_response_yes
,
5649 b
= gtk
.Button('View cert...')
5650 b
.connect('clicked', self
.on_cert_clicked
)
5652 area
= self
.get_action_area()
5655 def on_cert_clicked(self
, button
):
5656 d
= CertificatDialog(self
, self
.account
, self
.cert
)