[kepi] ability to use subkeys. Fixes #6051
[gajim.git] / src / config.py
blobdaef842c32fb398c7240416b196dd99ae016f3ee
1 # -*- coding:utf-8 -*-
2 ## src/config.py
3 ##
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 Podaras <bigpod AT gmail.com>
7 ## Stéphan Kochen <stephan AT kochen.nl>
8 ## Copyright (C) 2005-2006 Dimitur Kirov <dkirov AT gmail.com>
9 ## Nikos Kouremenos <kourem AT gmail.com>
10 ## Copyright (C) 2006 Junglecow J <junglecow AT gmail.com>
11 ## Copyright (C) 2006-2007 Travis Shirk <travis AT pobox.com>
12 ## Stefan Bethge <stefan AT lanpartei.de>
13 ## Copyright (C) 2006-2008 Jean-Marie Traissard <jim AT lapin.org>
14 ## Copyright (C) 2007 James Newton <redshodan AT gmail.com>
15 ## Julien Pivotto <roidelapluie AT gmail.com>
16 ## Copyright (C) 2007-2008 Stephan Erb <steve-e AT h3c.de>
17 ## Copyright (C) 2008 Jonathan Schleifer <js-gajim AT webkeks.org>
19 ## This file is part of Gajim.
21 ## Gajim is free software; you can redistribute it and/or modify
22 ## it under the terms of the GNU General Public License as published
23 ## by the Free Software Foundation; version 3 only.
25 ## Gajim is distributed in the hope that it will be useful,
26 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
27 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 ## GNU General Public License for more details.
30 ## You should have received a copy of the GNU General Public License
31 ## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
34 import gtk
35 import gobject
36 import os, sys
37 import common.config
38 import common.sleepy
39 from common.i18n import Q_
41 import gtkgui_helpers
42 import dialogs
43 import cell_renderer_image
44 import message_control
45 import chat_control
46 import dataforms_widget
48 try:
49 import gtkspell
50 HAS_GTK_SPELL = True
51 except ImportError:
52 HAS_GTK_SPELL = False
54 from common import helpers
55 from common import gajim
56 from common import connection
57 from common import passwords
58 from common.zeroconf import connection_zeroconf
59 from common import dataforms
60 from common import gpg
61 from common import ged
63 try:
64 from common.multimedia_helpers import AudioInputManager, AudioOutputManager
65 from common.multimedia_helpers import VideoInputManager, VideoOutputManager
66 HAS_GST = True
67 except ImportError:
68 HAS_GST = False
70 from common.exceptions import GajimGeneralException
72 #---------- PreferencesWindow class -------------#
73 class PreferencesWindow:
74 """
75 Class for Preferences window
76 """
78 def on_preferences_window_destroy(self, widget):
79 """
80 Close window
81 """
82 del gajim.interface.instances['preferences']
84 def on_close_button_clicked(self, widget):
85 self.window.destroy()
87 def __init__(self):
88 """
89 Initialize Preferences window
90 """
91 self.xml = gtkgui_helpers.get_gtk_builder('preferences_window.ui')
92 self.window = self.xml.get_object('preferences_window')
93 self.window.set_transient_for(gajim.interface.roster.window)
94 self.notebook = self.xml.get_object('preferences_notebook')
95 self.one_window_type_combobox =\
96 self.xml.get_object('one_window_type_combobox')
97 self.iconset_combobox = self.xml.get_object('iconset_combobox')
98 self.notify_on_signin_checkbutton = self.xml.get_object(
99 'notify_on_signin_checkbutton')
100 self.notify_on_signout_checkbutton = self.xml.get_object(
101 'notify_on_signout_checkbutton')
102 self.auto_popup_away_checkbutton = self.xml.get_object(
103 'auto_popup_away_checkbutton')
104 self.sound_dnd_checkbutton = self.xml.get_object('sound_dnd_checkbutton')
105 self.auto_away_checkbutton = self.xml.get_object('auto_away_checkbutton')
106 self.auto_away_time_spinbutton = self.xml.get_object(
107 'auto_away_time_spinbutton')
108 self.auto_away_message_entry = self.xml.get_object(
109 'auto_away_message_entry')
110 self.auto_xa_checkbutton = self.xml.get_object('auto_xa_checkbutton')
111 self.auto_xa_time_spinbutton = self.xml.get_object(
112 'auto_xa_time_spinbutton')
113 self.auto_xa_message_entry = self.xml.get_object('auto_xa_message_entry')
115 ### General tab ###
116 # Display avatars in roster
117 st = gajim.config.get('show_avatars_in_roster')
118 self.xml.get_object('show_avatars_in_roster_checkbutton'). \
119 set_active(st)
121 # Display status msg under contact name in roster
122 st = gajim.config.get('show_status_msgs_in_roster')
123 self.xml.get_object('show_status_msgs_in_roster_checkbutton'). \
124 set_active( st)
126 # Display mood in roster
127 st = gajim.config.get('show_mood_in_roster')
128 self.xml.get_object('show_mood_in_roster_checkbutton'). \
129 set_active(st)
131 # Display activity in roster
132 st = gajim.config.get('show_activity_in_roster')
133 self.xml.get_object('show_activity_in_roster_checkbutton'). \
134 set_active(st)
136 # Display tunes in roster
137 st = gajim.config.get('show_tunes_in_roster')
138 self.xml.get_object('show_tunes_in_roster_checkbutton'). \
139 set_active(st)
141 # Display location in roster
142 st = gajim.config.get('show_location_in_roster')
143 self.xml.get_object('show_location_in_roster_checkbutton'). \
144 set_active(st)
146 # Sort contacts by show
147 st = gajim.config.get('sort_by_show_in_roster')
148 self.xml.get_object('sort_by_show_in_roster_checkbutton').set_active(st)
149 st = gajim.config.get('sort_by_show_in_muc')
150 self.xml.get_object('sort_by_show_in_muc_checkbutton').set_active(st)
152 # emoticons
153 emoticons_combobox = self.xml.get_object('emoticons_combobox')
154 emoticons_list = os.listdir(os.path.join(gajim.DATA_DIR, 'emoticons'))
155 # user themes
156 if os.path.isdir(gajim.MY_EMOTS_PATH):
157 emoticons_list += os.listdir(gajim.MY_EMOTS_PATH)
158 renderer_text = gtk.CellRendererText()
159 emoticons_combobox.pack_start(renderer_text, True)
160 emoticons_combobox.add_attribute(renderer_text, 'text', 0)
161 model = gtk.ListStore(str)
162 emoticons_combobox.set_model(model)
163 l = []
164 for dir_ in emoticons_list:
165 if not os.path.isdir(os.path.join(gajim.DATA_DIR, 'emoticons', dir_)) \
166 and not os.path.isdir(os.path.join(gajim.MY_EMOTS_PATH, dir_)) :
167 continue
168 if dir_ != '.svn':
169 l.append(dir_)
170 l.append(_('Disabled'))
171 for i in xrange(len(l)):
172 model.append([l[i]])
173 if gajim.config.get('emoticons_theme') == l[i]:
174 emoticons_combobox.set_active(i)
175 if not gajim.config.get('emoticons_theme'):
176 emoticons_combobox.set_active(len(l)-1)
178 # Set default for single window type
179 choices = common.config.opt_one_window_types
180 type_ = gajim.config.get('one_message_window')
181 if type_ in choices:
182 self.one_window_type_combobox.set_active(choices.index(type_))
183 else:
184 self.one_window_type_combobox.set_active(0)
186 # Show roster on startup
187 show_roster_combobox = self.xml.get_object('show_roster_on_startup')
188 choices = common.config.opt_show_roster_on_startup
189 type_ = gajim.config.get('show_roster_on_startup')
190 if type_ in choices:
191 show_roster_combobox.set_active(choices.index(type_))
192 else:
193 show_roster_combobox.set_active(0)
195 # Compact View
196 st = gajim.config.get('compact_view')
197 self.xml.get_object('compact_view_checkbutton').set_active(st)
199 # Ignore XHTML
200 st = gajim.config.get('ignore_incoming_xhtml')
201 self.xml.get_object('xhtml_checkbutton').set_active(st)
203 # use speller
204 if HAS_GTK_SPELL:
205 st = gajim.config.get('use_speller')
206 self.xml.get_object('speller_checkbutton').set_active(st)
207 else:
208 self.xml.get_object('speller_checkbutton').set_sensitive(False)
210 ### Style tab ###
211 # Themes
212 theme_combobox = self.xml.get_object('theme_combobox')
213 cell = gtk.CellRendererText()
214 theme_combobox.pack_start(cell, True)
215 theme_combobox.add_attribute(cell, 'text', 0)
216 self.update_theme_list()
218 # iconset
219 iconsets_list = os.listdir(os.path.join(gajim.DATA_DIR, 'iconsets'))
220 if os.path.isdir(gajim.MY_ICONSETS_PATH):
221 iconsets_list += os.listdir(gajim.MY_ICONSETS_PATH)
222 # new model, image in 0, string in 1
223 model = gtk.ListStore(gtk.Image, str)
224 renderer_image = cell_renderer_image.CellRendererImage(0, 0)
225 renderer_text = gtk.CellRendererText()
226 renderer_text.set_property('xpad', 5)
227 self.iconset_combobox.pack_start(renderer_image, expand = False)
228 self.iconset_combobox.pack_start(renderer_text, expand = True)
229 self.iconset_combobox.set_attributes(renderer_text, text = 1)
230 self.iconset_combobox.add_attribute(renderer_image, 'image', 0)
231 self.iconset_combobox.set_model(model)
232 l = []
233 for dir in iconsets_list:
234 if not os.path.isdir(os.path.join(gajim.DATA_DIR, 'iconsets', dir)) \
235 and not os.path.isdir(os.path.join(gajim.MY_ICONSETS_PATH, dir)):
236 continue
237 if dir != '.svn' and dir != 'transports':
238 l.append(dir)
239 if l.count == 0:
240 l.append(' ')
241 for i in xrange(len(l)):
242 preview = gtk.Image()
243 files = []
244 files.append(os.path.join(helpers.get_iconset_path(l[i]), '16x16',
245 'online.png'))
246 files.append(os.path.join(helpers.get_iconset_path(l[i]), '16x16',
247 'online.gif'))
248 for file_ in files:
249 if os.path.exists(file_):
250 preview.set_from_file(file_)
251 model.append([preview, l[i]])
252 if gajim.config.get('iconset') == l[i]:
253 self.iconset_combobox.set_active(i)
255 # Use transports iconsets
256 st = gajim.config.get('use_transports_iconsets')
257 self.xml.get_object('transports_iconsets_checkbutton').set_active(st)
259 # Color widgets
260 self.draw_color_widgets()
262 # Font for messages
263 font = gajim.config.get('conversation_font')
264 # try to set default font for the current desktop env
265 fontbutton = self.xml.get_object('conversation_fontbutton')
266 if font == '':
267 fontbutton.set_sensitive(False)
268 self.xml.get_object('default_chat_font').set_active(True)
269 else:
270 fontbutton.set_font_name(font)
272 ### Personal Events tab ###
273 # outgoing send chat state notifications
274 st = gajim.config.get('outgoing_chat_state_notifications')
275 combo = self.xml.get_object('outgoing_chat_states_combobox')
276 if st == 'all':
277 combo.set_active(0)
278 elif st == 'composing_only':
279 combo.set_active(1)
280 else: # disabled
281 combo.set_active(2)
283 # displayed send chat state notifications
284 st = gajim.config.get('displayed_chat_state_notifications')
285 combo = self.xml.get_object('displayed_chat_states_combobox')
286 if st == 'all':
287 combo.set_active(0)
288 elif st == 'composing_only':
289 combo.set_active(1)
290 else: # disabled
291 combo.set_active(2)
294 ### Notifications tab ###
295 # On new event
296 on_event_combobox = self.xml.get_object('on_event_combobox')
297 if gajim.config.get('autopopup'):
298 on_event_combobox.set_active(0)
299 elif gajim.config.get('notify_on_new_message'):
300 on_event_combobox.set_active(1)
301 else:
302 on_event_combobox.set_active(2)
304 # notify on online statuses
305 st = gajim.config.get('notify_on_signin')
306 self.notify_on_signin_checkbutton.set_active(st)
308 # notify on offline statuses
309 st = gajim.config.get('notify_on_signout')
310 self.notify_on_signout_checkbutton.set_active(st)
312 # autopopupaway
313 st = gajim.config.get('autopopupaway')
314 self.auto_popup_away_checkbutton.set_active(st)
316 # sounddnd
317 st = gajim.config.get('sounddnd')
318 self.sound_dnd_checkbutton.set_active(st)
320 # Systray
321 systray_combobox = self.xml.get_object('systray_combobox')
322 if gajim.config.get('trayicon') == 'never':
323 systray_combobox.set_active(0)
324 elif gajim.config.get('trayicon') == 'on_event':
325 systray_combobox.set_active(1)
326 else:
327 systray_combobox.set_active(2)
329 # sounds
330 if gajim.config.get('sounds_on'):
331 self.xml.get_object('play_sounds_checkbutton').set_active(True)
332 else:
333 self.xml.get_object('manage_sounds_button').set_sensitive(False)
335 # Notify user of new gmail e-mail messages,
336 # make checkbox sensitive if user has a gtalk account
337 frame_gmail = self.xml.get_object('frame_gmail')
338 notify_gmail_checkbutton = self.xml.get_object('notify_gmail_checkbutton')
339 notify_gmail_extra_checkbutton = self.xml.get_object(
340 'notify_gmail_extra_checkbutton')
342 for account in gajim.config.get_per('accounts'):
343 jid = gajim.get_jid_from_account(account)
344 if gajim.get_server_from_jid(jid) in gajim.gmail_domains:
345 frame_gmail.set_sensitive(True)
346 st = gajim.config.get('notify_on_new_gmail_email')
347 notify_gmail_checkbutton.set_active(st)
348 st = gajim.config.get('notify_on_new_gmail_email_extra')
349 notify_gmail_extra_checkbutton.set_active(st)
350 break
352 #### Status tab ###
353 # Autoaway
354 st = gajim.config.get('autoaway')
355 self.auto_away_checkbutton.set_active(st)
357 # Autoawaytime
358 st = gajim.config.get('autoawaytime')
359 self.auto_away_time_spinbutton.set_value(st)
360 self.auto_away_time_spinbutton.set_sensitive(gajim.config.get('autoaway'))
362 # autoaway message
363 st = gajim.config.get('autoaway_message')
364 self.auto_away_message_entry.set_text(st)
365 self.auto_away_message_entry.set_sensitive(gajim.config.get('autoaway'))
367 # Autoxa
368 st = gajim.config.get('autoxa')
369 self.auto_xa_checkbutton.set_active(st)
371 # Autoxatime
372 st = gajim.config.get('autoxatime')
373 self.auto_xa_time_spinbutton.set_value(st)
374 self.auto_xa_time_spinbutton.set_sensitive(gajim.config.get('autoxa'))
376 # autoxa message
377 st = gajim.config.get('autoxa_message')
378 self.auto_xa_message_entry.set_text(st)
379 self.auto_xa_message_entry.set_sensitive(gajim.config.get('autoxa'))
381 from common import sleepy
382 if not sleepy.SUPPORTED:
383 self.xml.get_object('autoaway_table').set_sensitive(False)
385 # ask_status when online / offline
386 st = gajim.config.get('ask_online_status')
387 self.xml.get_object('prompt_online_status_message_checkbutton').\
388 set_active(st)
389 st = gajim.config.get('ask_offline_status')
390 self.xml.get_object('prompt_offline_status_message_checkbutton').\
391 set_active(st)
393 # Default Status messages
394 self.default_msg_tree = self.xml.get_object('default_msg_treeview')
395 col2 = self.default_msg_tree.rc_get_style().bg[gtk.STATE_ACTIVE].\
396 to_string()
397 # (status, translated_status, message, enabled)
398 model = gtk.ListStore(str, str, str, bool)
399 self.default_msg_tree.set_model(model)
400 col = gtk.TreeViewColumn(_('Status'))
401 col.set_resizable(True)
402 self.default_msg_tree.append_column(col)
403 renderer = gtk.CellRendererText()
404 col.pack_start(renderer, False)
405 col.set_attributes(renderer, text = 1)
406 col = gtk.TreeViewColumn(_('Default Message'))
407 col.set_resizable(True)
408 self.default_msg_tree.append_column(col)
409 renderer = gtk.CellRendererText()
410 col.pack_start(renderer, True)
411 col.set_attributes(renderer, text = 2)
412 renderer.connect('edited', self.on_default_msg_cell_edited)
413 renderer.set_property('editable', True)
414 renderer.set_property('cell-background', col2)
415 col = gtk.TreeViewColumn(_('Enabled'))
416 col.set_resizable(True)
417 self.default_msg_tree.append_column(col)
418 renderer = gtk.CellRendererToggle()
419 col.pack_start(renderer, False)
420 col.set_attributes(renderer, active = 3)
421 renderer.set_property('activatable', True)
422 renderer.connect('toggled', self.default_msg_toggled_cb)
423 self.fill_default_msg_treeview()
425 # Status messages
426 self.msg_tree = self.xml.get_object('msg_treeview')
427 model = gtk.ListStore(str, str, str, str, str, str, str)
428 self.msg_tree.set_model(model)
429 col = gtk.TreeViewColumn('name')
430 self.msg_tree.append_column(col)
431 renderer = gtk.CellRendererText()
432 col.pack_start(renderer, True)
433 col.set_attributes(renderer, text = 0)
434 renderer.connect('edited', self.on_msg_cell_edited)
435 renderer.set_property('editable', True)
436 self.fill_msg_treeview()
437 buf = self.xml.get_object('msg_textview').get_buffer()
438 buf.connect('changed', self.on_msg_textview_changed)
440 ### Audio / Video tab ###
441 def create_av_combobox(opt_name, device_dict, config_name=None,
442 key=None):
443 combobox = self.xml.get_object(opt_name + '_combobox')
444 cell = gtk.CellRendererText()
445 combobox.pack_start(cell, True)
446 combobox.add_attribute(cell, 'text', 0)
447 model = gtk.ListStore(str, str)
448 combobox.set_model(model)
449 if config_name:
450 config = gajim.config.get(config_name)
451 else:
452 config = gajim.config.get(opt_name + '_device')
454 for index, (name, value) in enumerate(sorted(device_dict.\
455 iteritems(), key=key)):
456 model.append((name, value))
457 if config == value:
458 combobox.set_active(index)
460 if HAS_GST:
461 create_av_combobox('audio_input', AudioInputManager().get_devices())
462 create_av_combobox('audio_output', AudioOutputManager().get_devices(
464 create_av_combobox('video_input', VideoInputManager().get_devices())
465 create_av_combobox('video_output', VideoOutputManager().get_devices(
468 create_av_combobox('video_framerate', {_('Default'): '',
469 '15fps': '15/1', '10fps': '10/1', '5fps': '5/1',
470 '2.5fps': '5/2'}, 'video_framerate', key=lambda x: -1 if \
471 not x[1] else float(x[0][:-3]))
472 create_av_combobox('video_size', {_('Default'): '',
473 '800x600': '800x600', '640x480': '640x480',
474 '320x240': '320x240'}, 'video_size', key=lambda x: -1 if \
475 not x[1] else int(x[0][:3]))
477 else:
478 for opt_name in ('audio_input', 'audio_output', 'video_input',
479 'video_output', 'video_framerate', 'video_size'):
480 combobox = self.xml.get_object(opt_name + '_combobox')
481 combobox.set_sensitive(False)
483 # STUN
484 cb = self.xml.get_object('stun_checkbutton')
485 st = gajim.config.get('use_stun_server')
486 cb.set_active(st)
488 entry = self.xml.get_object('stun_server_entry')
489 entry.set_text(gajim.config.get('stun_server'))
490 if not st:
491 entry.set_sensitive(False)
493 ### Advanced tab ###
494 # open links with
495 if os.name == 'nt':
496 applications_frame = self.xml.get_object('applications_frame')
497 applications_frame.set_no_show_all(True)
498 applications_frame.hide()
499 else:
500 self.applications_combobox = self.xml.get_object(
501 'applications_combobox')
502 self.xml.get_object('custom_apps_frame').hide()
503 self.xml.get_object('custom_apps_frame').set_no_show_all(True)
505 if gajim.config.get('autodetect_browser_mailer'):
506 self.applications_combobox.set_active(0)
507 # else autodetect_browser_mailer is False.
508 # so user has 'Always Use GNOME/KDE/Xfce' or Custom
509 elif gajim.config.get('openwith') == 'custom':
510 self.applications_combobox.set_active(1)
511 self.xml.get_object('custom_apps_frame').show()
513 self.xml.get_object('custom_browser_entry').set_text(
514 gajim.config.get('custombrowser'))
515 self.xml.get_object('custom_mail_client_entry').set_text(
516 gajim.config.get('custommailapp'))
517 self.xml.get_object('custom_file_manager_entry').set_text(
518 gajim.config.get('custom_file_manager'))
520 # log status changes of contacts
521 st = gajim.config.get('log_contact_status_changes')
522 self.xml.get_object('log_show_changes_checkbutton').set_active(st)
524 # log encrypted chat sessions
525 w = self.xml.get_object('log_encrypted_chats_checkbutton')
526 st = self.get_per_account_option('log_encrypted_sessions')
527 if st == 'mixed':
528 w.set_inconsistent(True)
529 else:
530 w.set_active(st)
532 # send os info
533 w = self.xml.get_object('send_os_info_checkbutton')
534 st = self.get_per_account_option('send_os_info')
535 if st == 'mixed':
536 w.set_inconsistent(True)
537 else:
538 w.set_active(st)
540 # send idle time
541 w = self.xml.get_object('send_idle_time_checkbutton')
542 st = self.get_per_account_option('send_idle_time')
543 if st == 'mixed':
544 w.set_inconsistent(True)
545 else:
546 w.set_active(st)
548 # check if gajm is default
549 st = gajim.config.get('check_if_gajim_is_default')
550 self.xml.get_object('check_default_client_checkbutton').set_active(st)
552 # Ignore messages from unknown contacts
553 w = self.xml.get_object('ignore_events_from_unknown_contacts_checkbutton')
554 st = self.get_per_account_option('ignore_unknown_contacts')
555 if st == 'mixed':
556 w.set_inconsistent(True)
557 else:
558 w.set_active(st)
560 self.xml.connect_signals(self)
562 self.msg_tree.get_model().connect('row-changed',
563 self.on_msg_treemodel_row_changed)
564 self.msg_tree.get_model().connect('row-deleted',
565 self.on_msg_treemodel_row_deleted)
566 self.default_msg_tree.get_model().connect('row-changed',
567 self.on_default_msg_treemodel_row_changed)
569 self.theme_preferences = None
570 self.sounds_preferences = None
572 self.notebook.set_current_page(0)
574 self.window.show_all()
575 gtkgui_helpers.possibly_move_window_in_current_desktop(self.window)
577 def on_preferences_window_key_press_event(self, widget, event):
578 if event.keyval == gtk.keysyms.Escape:
579 self.window.hide()
581 def get_per_account_option(self, opt):
583 Return the value of the option opt if it's the same in all accounts else
584 returns "mixed"
586 if len(gajim.connections) == 0:
587 # a non existant key return default value
588 return gajim.config.get_per('accounts', '__default__', opt)
589 val = None
590 for account in gajim.connections:
591 v = gajim.config.get_per('accounts', account, opt)
592 if val is None:
593 val = v
594 elif val != v:
595 return 'mixed'
596 return val
598 def on_checkbutton_toggled(self, widget, config_name,
599 change_sensitivity_widgets=None):
600 gajim.config.set(config_name, widget.get_active())
601 if change_sensitivity_widgets:
602 for w in change_sensitivity_widgets:
603 w.set_sensitive(widget.get_active())
604 gajim.interface.save_config()
606 def on_per_account_checkbutton_toggled(self, widget, config_name,
607 change_sensitivity_widgets=None):
608 for account in gajim.connections:
609 gajim.config.set_per('accounts', account, config_name,
610 widget.get_active())
611 if change_sensitivity_widgets:
612 for w in change_sensitivity_widgets:
613 w.set_sensitive(widget.get_active())
614 gajim.interface.save_config()
616 def _get_all_controls(self):
617 for ctrl in gajim.interface.msg_win_mgr.get_controls():
618 yield ctrl
619 for account in gajim.connections:
620 for ctrl in gajim.interface.minimized_controls[account].values():
621 yield ctrl
623 def _get_all_muc_controls(self):
624 for ctrl in gajim.interface.msg_win_mgr.get_controls(
625 message_control.TYPE_GC):
626 yield ctrl
627 for account in gajim.connections:
628 for ctrl in gajim.interface.minimized_controls[account].values():
629 yield ctrl
631 def on_sort_by_show_in_roster_checkbutton_toggled(self, widget):
632 self.on_checkbutton_toggled(widget, 'sort_by_show_in_roster')
633 gajim.interface.roster.setup_and_draw_roster()
635 def on_sort_by_show_in_muc_checkbutton_toggled(self, widget):
636 self.on_checkbutton_toggled(widget, 'sort_by_show_in_muc')
637 # Redraw groupchats
638 for ctrl in self._get_all_muc_controls():
639 ctrl.draw_roster()
641 def on_show_avatars_in_roster_checkbutton_toggled(self, widget):
642 self.on_checkbutton_toggled(widget, 'show_avatars_in_roster')
643 gajim.interface.roster.setup_and_draw_roster()
644 # Redraw groupchats (in an ugly way)
645 for ctrl in self._get_all_muc_controls():
646 ctrl.draw_roster()
648 def on_show_status_msgs_in_roster_checkbutton_toggled(self, widget):
649 self.on_checkbutton_toggled(widget, 'show_status_msgs_in_roster')
650 gajim.interface.roster.setup_and_draw_roster()
651 for ctrl in self._get_all_muc_controls():
652 ctrl.update_ui()
654 def on_show_mood_in_roster_checkbutton_toggled(self, widget):
655 self.on_checkbutton_toggled(widget, 'show_mood_in_roster')
656 gajim.interface.roster.setup_and_draw_roster()
658 def on_show_activity_in_roster_checkbutton_toggled(self, widget):
659 self.on_checkbutton_toggled(widget, 'show_activity_in_roster')
660 gajim.interface.roster.setup_and_draw_roster()
662 def on_show_tunes_in_roster_checkbutton_toggled(self, widget):
663 self.on_checkbutton_toggled(widget, 'show_tunes_in_roster')
664 gajim.interface.roster.setup_and_draw_roster()
666 def on_show_location_in_roster_checkbutton_toggled(self, widget):
667 self.on_checkbutton_toggled(widget, 'show_location_in_roster')
668 gajim.interface.roster.setup_and_draw_roster()
670 def on_emoticons_combobox_changed(self, widget):
671 active = widget.get_active()
672 model = widget.get_model()
673 emot_theme = model[active][0].decode('utf-8')
674 if emot_theme == _('Disabled'):
675 gajim.config.set('emoticons_theme', '')
676 else:
677 gajim.config.set('emoticons_theme', emot_theme)
679 gajim.interface.init_emoticons(need_reload = True)
680 gajim.interface.make_regexps()
681 self.toggle_emoticons()
683 def toggle_emoticons(self):
685 Update emoticons state in Opened Chat Windows
687 for ctrl in self._get_all_controls():
688 ctrl.toggle_emoticons()
690 def on_one_window_type_combo_changed(self, widget):
691 active = widget.get_active()
692 config_type = common.config.opt_one_window_types[active]
693 gajim.config.set('one_message_window', config_type)
694 gajim.interface.save_config()
695 gajim.interface.msg_win_mgr.reconfig()
697 def on_show_roster_on_startup_changed(self, widget):
698 active = widget.get_active()
699 config_type = common.config.opt_show_roster_on_startup[active]
700 gajim.config.set('show_roster_on_startup', config_type)
701 gajim.interface.save_config()
703 def on_compact_view_checkbutton_toggled(self, widget):
704 active = widget.get_active()
705 for ctrl in self._get_all_controls():
706 ctrl.chat_buttons_set_visible(active)
707 gajim.config.set('compact_view', active)
708 gajim.interface.save_config()
710 def on_xhtml_checkbutton_toggled(self, widget):
711 self.on_checkbutton_toggled(widget, 'ignore_incoming_xhtml')
712 helpers.update_optional_features()
714 def apply_speller(self):
715 for ctrl in self._get_all_controls():
716 if isinstance(ctrl, chat_control.ChatControlBase):
717 try:
718 spell_obj = gtkspell.get_from_text_view(ctrl.msg_textview)
719 except (TypeError, RuntimeError, OSError):
720 spell_obj = None
722 if not spell_obj:
723 ctrl.set_speller()
725 def remove_speller(self):
726 for ctrl in self._get_all_controls():
727 if isinstance(ctrl, chat_control.ChatControlBase):
728 try:
729 spell_obj = gtkspell.get_from_text_view(ctrl.msg_textview)
730 except (TypeError, RuntimeError):
731 spell_obj = None
732 if spell_obj:
733 spell_obj.detach()
735 def on_speller_checkbutton_toggled(self, widget):
736 active = widget.get_active()
737 gajim.config.set('use_speller', active)
738 gajim.interface.save_config()
739 if active:
740 lang = gajim.config.get('speller_language')
741 if not lang:
742 lang = gajim.LANG
743 tv = gtk.TextView()
744 try:
745 gtkspell.Spell(tv, lang)
746 except (TypeError, RuntimeError, OSError):
747 dialogs.ErrorDialog(
748 _('Dictionary for lang %s not available') % lang,
749 _('You have to install %s dictionary to use spellchecking, or '
750 'choose another language by setting the speller_language option.'
751 ) % lang)
752 gajim.config.set('use_speller', False)
753 widget.set_active(False)
754 else:
755 gajim.config.set('speller_language', lang)
756 self.apply_speller()
757 else:
758 self.remove_speller()
760 def on_theme_combobox_changed(self, widget):
761 model = widget.get_model()
762 active = widget.get_active()
763 config_theme = model[active][0].decode('utf-8').replace(' ', '_')
765 gajim.config.set('roster_theme', config_theme)
767 # begin repainting themed widgets throughout
768 gajim.interface.roster.repaint_themed_widgets()
769 gajim.interface.roster.change_roster_style(None)
770 gajim.interface.save_config()
772 def update_theme_list(self):
773 theme_combobox = self.xml.get_object('theme_combobox')
774 model = gtk.ListStore(str)
775 theme_combobox.set_model(model)
776 i = 0
777 for config_theme in gajim.config.get_per('themes'):
778 theme = config_theme.replace('_', ' ')
779 model.append([theme])
780 if gajim.config.get('roster_theme') == config_theme:
781 theme_combobox.set_active(i)
782 i += 1
784 def on_manage_theme_button_clicked(self, widget):
785 if self.theme_preferences is None:
786 self.theme_preferences = dialogs.GajimThemesWindow()
787 else:
788 self.theme_preferences.window.present()
789 self.theme_preferences.select_active_theme()
791 def on_iconset_combobox_changed(self, widget):
792 model = widget.get_model()
793 active = widget.get_active()
794 icon_string = model[active][1].decode('utf-8')
795 gajim.config.set('iconset', icon_string)
796 gtkgui_helpers.reload_jabber_state_images()
797 gajim.interface.save_config()
799 def on_transports_iconsets_checkbutton_toggled(self, widget):
800 self.on_checkbutton_toggled(widget, 'use_transports_iconsets')
801 gtkgui_helpers.reload_jabber_state_images()
803 def on_outgoing_chat_states_combobox_changed(self, widget):
804 active = widget.get_active()
805 old_value = gajim.config.get('outgoing_chat_state_notifications')
806 if active == 0: # all
807 gajim.config.set('outgoing_chat_state_notifications', 'all')
808 elif active == 1: # only composing
809 gajim.config.set('outgoing_chat_state_notifications', 'composing_only')
810 else: # disabled
811 gajim.config.set('outgoing_chat_state_notifications', 'disabled')
812 new_value = gajim.config.get('outgoing_chat_state_notifications')
813 if 'disabled' in (old_value, new_value):
814 # we changed from disabled to sth else or vice versa
815 helpers.update_optional_features()
817 def on_displayed_chat_states_combobox_changed(self, widget):
818 active = widget.get_active()
819 if active == 0: # all
820 gajim.config.set('displayed_chat_state_notifications', 'all')
821 elif active == 1: # only composing
822 gajim.config.set('displayed_chat_state_notifications',
823 'composing_only')
824 else: # disabled
825 gajim.config.set('displayed_chat_state_notifications', 'disabled')
827 def on_ignore_events_from_unknown_contacts_checkbutton_toggled(self, widget):
828 widget.set_inconsistent(False)
829 self.on_per_account_checkbutton_toggled(widget, 'ignore_unknown_contacts')
831 def on_on_event_combobox_changed(self, widget):
832 active = widget.get_active()
833 if active == 0:
834 gajim.config.set('autopopup', True)
835 gajim.config.set('notify_on_new_message', False)
836 elif active == 1:
837 gajim.config.set('autopopup', False)
838 gajim.config.set('notify_on_new_message', True)
839 else:
840 gajim.config.set('autopopup', False)
841 gajim.config.set('notify_on_new_message', False)
843 def on_notify_on_signin_checkbutton_toggled(self, widget):
844 self.on_checkbutton_toggled(widget, 'notify_on_signin')
846 def on_notify_on_signout_checkbutton_toggled(self, widget):
847 self.on_checkbutton_toggled(widget, 'notify_on_signout')
849 def on_auto_popup_away_checkbutton_toggled(self, widget):
850 self.on_checkbutton_toggled(widget, 'autopopupaway')
852 def on_sound_dnd_checkbutton_toggled(self, widget):
853 self.on_checkbutton_toggled(widget, 'sounddnd')
855 def on_systray_combobox_changed(self, widget):
856 active = widget.get_active()
857 if active == 0:
858 gajim.config.set('trayicon', 'never')
859 gajim.interface.systray_enabled = False
860 gajim.interface.systray.hide_icon()
861 elif active == 1:
862 gajim.config.set('trayicon', 'on_event')
863 gajim.interface.systray_enabled = True
864 gajim.interface.systray.show_icon()
865 else:
866 gajim.config.set('trayicon', 'always')
867 gajim.interface.systray_enabled = True
868 gajim.interface.systray.show_icon()
870 def on_advanced_notifications_button_clicked(self, widget):
871 dialogs.AdvancedNotificationsWindow()
873 def on_play_sounds_checkbutton_toggled(self, widget):
874 self.on_checkbutton_toggled(widget, 'sounds_on',
875 [self.xml.get_object('manage_sounds_button')])
877 def on_manage_sounds_button_clicked(self, widget):
878 if self.sounds_preferences is None:
879 self.sounds_preferences = ManageSoundsWindow()
880 else:
881 self.sounds_preferences.window.present()
883 def update_text_tags(self):
885 Update color tags in opened chat windows
887 for ctrl in self._get_all_controls():
888 ctrl.update_tags()
890 def on_preference_widget_color_set(self, widget, text):
891 color = widget.get_color()
892 color_string = gtkgui_helpers.make_color_string(color)
893 gajim.config.set(text, color_string)
894 self.update_text_tags()
895 gajim.interface.save_config()
897 def on_preference_widget_font_set(self, widget, text):
898 if widget:
899 font = widget.get_font_name()
900 else:
901 font = ''
902 gajim.config.set(text, font)
903 self.update_text_font()
904 gajim.interface.save_config()
906 def update_text_font(self):
908 Update text font in opened chat windows
910 for ctrl in self._get_all_controls():
911 ctrl.update_font()
913 def on_incoming_nick_colorbutton_color_set(self, widget):
914 self.on_preference_widget_color_set(widget, 'inmsgcolor')
916 def on_outgoing_nick_colorbutton_color_set(self, widget):
917 self.on_preference_widget_color_set(widget, 'outmsgcolor')
919 def on_incoming_msg_colorbutton_color_set(self, widget):
920 self.on_preference_widget_color_set(widget, 'inmsgtxtcolor')
922 def on_outgoing_msg_colorbutton_color_set(self, widget):
923 self.on_preference_widget_color_set(widget, 'outmsgtxtcolor')
925 def on_url_msg_colorbutton_color_set(self, widget):
926 self.on_preference_widget_color_set(widget, 'urlmsgcolor')
928 def on_status_msg_colorbutton_color_set(self, widget):
929 self.on_preference_widget_color_set(widget, 'statusmsgcolor')
931 def on_conversation_fontbutton_font_set(self, widget):
932 self.on_preference_widget_font_set(widget, 'conversation_font')
934 def on_default_chat_font_toggled(self, widget):
935 font_widget = self.xml.get_object('conversation_fontbutton')
936 if widget.get_active():
937 font_widget.set_sensitive(False)
938 font_widget = None
939 else:
940 font_widget.set_sensitive(True)
941 self.on_preference_widget_font_set(font_widget, 'conversation_font')
943 def draw_color_widgets(self):
944 col_to_widget = {'inmsgcolor': 'incoming_nick_colorbutton',
945 'outmsgcolor': 'outgoing_nick_colorbutton',
946 'inmsgtxtcolor': ['incoming_msg_colorbutton',
947 'incoming_msg_checkbutton'],
948 'outmsgtxtcolor': ['outgoing_msg_colorbutton',
949 'outgoing_msg_checkbutton'],
950 'statusmsgcolor': 'status_msg_colorbutton',
951 'urlmsgcolor': 'url_msg_colorbutton'}
952 for c in col_to_widget:
953 col = gajim.config.get(c)
954 if col:
955 if isinstance(col_to_widget[c], list):
956 self.xml.get_object(col_to_widget[c][0]).set_color(
957 gtk.gdk.color_parse(col))
958 self.xml.get_object(col_to_widget[c][0]).set_sensitive(True)
959 self.xml.get_object(col_to_widget[c][1]).set_active(True)
960 else:
961 self.xml.get_object(col_to_widget[c]).set_color(
962 gtk.gdk.color_parse(col))
963 else:
964 if isinstance(col_to_widget[c], list):
965 self.xml.get_object(col_to_widget[c][0]).set_color(
966 gtk.gdk.color_parse('#000000'))
967 self.xml.get_object(col_to_widget[c][0]).set_sensitive(False)
968 self.xml.get_object(col_to_widget[c][1]).set_active(False)
969 else:
970 self.xml.get_object(col_to_widget[c]).set_color(
971 gtk.gdk.color_parse('#000000'))
973 def on_reset_colors_button_clicked(self, widget):
974 col_to_widget = {'inmsgcolor': 'incoming_nick_colorbutton',
975 'outmsgcolor': 'outgoing_nick_colorbutton',
976 'inmsgtxtcolor': 'incoming_msg_colorbutton',
977 'outmsgtxtcolor': 'outgoing_msg_colorbutton',
978 'statusmsgcolor': 'status_msg_colorbutton',
979 'urlmsgcolor': 'url_msg_colorbutton'}
980 for c in col_to_widget:
981 gajim.config.set(c, gajim.interface.default_colors[c])
982 self.draw_color_widgets()
984 self.update_text_tags()
985 gajim.interface.save_config()
987 def _set_color(self, state, widget_name, option):
989 Set color value in prefs and update the UI
991 if state:
992 color = self.xml.get_object(widget_name).get_color()
993 color_string = gtkgui_helpers.make_color_string(color)
994 else:
995 color_string = ''
996 gajim.config.set(option, color_string)
997 gajim.interface.save_config()
999 def on_incoming_msg_checkbutton_toggled(self, widget):
1000 state = widget.get_active()
1001 self.xml.get_object('incoming_msg_colorbutton').set_sensitive(state)
1002 self._set_color(state, 'incoming_msg_colorbutton', 'inmsgtxtcolor')
1004 def on_outgoing_msg_checkbutton_toggled(self, widget):
1005 state = widget.get_active()
1006 self.xml.get_object('outgoing_msg_colorbutton').set_sensitive(state)
1007 self._set_color(state, 'outgoing_msg_colorbutton', 'outmsgtxtcolor')
1009 def on_auto_away_checkbutton_toggled(self, widget):
1010 self.on_checkbutton_toggled(widget, 'autoaway',
1011 [self.auto_away_time_spinbutton, self.auto_away_message_entry])
1013 def on_auto_away_time_spinbutton_value_changed(self, widget):
1014 aat = widget.get_value_as_int()
1015 gajim.config.set('autoawaytime', aat)
1016 gajim.interface.sleeper = common.sleepy.Sleepy(
1017 gajim.config.get('autoawaytime') * 60,
1018 gajim.config.get('autoxatime') * 60)
1019 gajim.interface.save_config()
1021 def on_auto_away_message_entry_changed(self, widget):
1022 gajim.config.set('autoaway_message', widget.get_text().decode('utf-8'))
1024 def on_auto_xa_checkbutton_toggled(self, widget):
1025 self.on_checkbutton_toggled(widget, 'autoxa',
1026 [self.auto_xa_time_spinbutton, self.auto_xa_message_entry])
1028 def on_auto_xa_time_spinbutton_value_changed(self, widget):
1029 axt = widget.get_value_as_int()
1030 gajim.config.set('autoxatime', axt)
1031 gajim.interface.sleeper = common.sleepy.Sleepy(
1032 gajim.config.get('autoawaytime') * 60,
1033 gajim.config.get('autoxatime') * 60)
1034 gajim.interface.save_config()
1036 def on_auto_xa_message_entry_changed(self, widget):
1037 gajim.config.set('autoxa_message', widget.get_text().decode('utf-8'))
1039 def on_prompt_online_status_message_checkbutton_toggled(self, widget):
1040 self.on_checkbutton_toggled(widget, 'ask_online_status')
1042 def on_prompt_offline_status_message_checkbutton_toggled(self, widget):
1043 self.on_checkbutton_toggled(widget, 'ask_offline_status')
1045 def fill_default_msg_treeview(self):
1046 model = self.default_msg_tree.get_model()
1047 model.clear()
1048 status = []
1049 for status_ in gajim.config.get_per('defaultstatusmsg'):
1050 status.append(status_)
1051 status.sort()
1052 for status_ in status:
1053 msg = gajim.config.get_per('defaultstatusmsg', status_, 'message')
1054 msg = helpers.from_one_line(msg)
1055 enabled = gajim.config.get_per('defaultstatusmsg', status_, 'enabled')
1056 iter_ = model.append()
1057 uf_show = helpers.get_uf_show(status_)
1058 model.set(iter_, 0, status_, 1, uf_show, 2, msg, 3, enabled)
1060 def on_default_msg_cell_edited(self, cell, row, new_text):
1061 model = self.default_msg_tree.get_model()
1062 iter_ = model.get_iter_from_string(row)
1063 model.set_value(iter_, 2, new_text)
1065 def default_msg_toggled_cb(self, cell, path):
1066 model = self.default_msg_tree.get_model()
1067 model[path][3] = not model[path][3]
1069 def on_default_msg_treemodel_row_changed(self, model, path, iter_):
1070 status = model[iter_][0]
1071 message = model[iter_][2].decode('utf-8')
1072 message = helpers.to_one_line(message)
1073 gajim.config.set_per('defaultstatusmsg', status, 'enabled',
1074 model[iter_][3])
1075 gajim.config.set_per('defaultstatusmsg', status, 'message', message)
1077 def on_default_status_expander_activate(self, expander):
1078 eventbox = self.xml.get_object('default_status_eventbox')
1079 vbox = self.xml.get_object('status_vbox')
1080 vbox.set_child_packing(eventbox, not expander.get_expanded(), True, 0,
1081 gtk.PACK_START)
1083 def save_status_messages(self, model):
1084 for msg in gajim.config.get_per('statusmsg'):
1085 gajim.config.del_per('statusmsg', msg)
1086 iter_ = model.get_iter_first()
1087 while iter_:
1088 val = model[iter_][0].decode('utf-8')
1089 if model[iter_][1]: # we have a preset message
1090 if not val: # no title, use message text for title
1091 val = model[iter_][1]
1092 gajim.config.add_per('statusmsg', val)
1093 msg = helpers.to_one_line(model[iter_][1].decode('utf-8'))
1094 gajim.config.set_per('statusmsg', val, 'message', msg)
1095 i = 2
1096 # store mood / activity
1097 for subname in ('activity', 'subactivity', 'activity_text',
1098 'mood', 'mood_text'):
1099 gajim.config.set_per('statusmsg', val, subname,
1100 model[iter_][i].decode('utf-8'))
1101 i += 1
1102 iter_ = model.iter_next(iter_)
1103 gajim.interface.save_config()
1105 def on_msg_treemodel_row_changed(self, model, path, iter_):
1106 self.save_status_messages(model)
1108 def on_msg_treemodel_row_deleted(self, model, path):
1109 self.save_status_messages(model)
1111 def on_av_combobox_changed(self, combobox, config_name):
1112 model = combobox.get_model()
1113 active = combobox.get_active()
1114 device = model[active][1].decode('utf-8')
1115 gajim.config.set(config_name, device)
1117 def on_audio_input_combobox_changed(self, widget):
1118 self.on_av_combobox_changed(widget, 'audio_input_device')
1120 def on_audio_output_combobox_changed(self, widget):
1121 self.on_av_combobox_changed(widget, 'audio_output_device')
1123 def on_video_input_combobox_changed(self, widget):
1124 self.on_av_combobox_changed(widget, 'video_input_device')
1126 def on_video_output_combobox_changed(self, widget):
1127 self.on_av_combobox_changed(widget, 'video_output_device')
1129 def on_video_framerate_combobox_changed(self, widget):
1130 self.on_av_combobox_changed(widget, 'video_framerate')
1132 def on_video_size_combobox_changed(self, widget):
1133 self.on_av_combobox_changed(widget, 'video_size')
1135 def on_stun_checkbutton_toggled(self, widget):
1136 self.on_checkbutton_toggled(widget, 'use_stun_server',
1137 [self.xml.get_object('stun_server_entry')])
1139 def stun_server_entry_changed(self, widget):
1140 gajim.config.set('stun_server', widget.get_text().decode('utf-8'))
1142 def on_applications_combobox_changed(self, widget):
1143 if widget.get_active() == 0:
1144 gajim.config.set('autodetect_browser_mailer', True)
1145 self.xml.get_object('custom_apps_frame').hide()
1146 elif widget.get_active() == 1:
1147 gajim.config.set('autodetect_browser_mailer', False)
1148 self.xml.get_object('custom_apps_frame').show()
1149 gajim.config.set('openwith', 'custom')
1150 gajim.interface.save_config()
1152 def on_custom_browser_entry_changed(self, widget):
1153 gajim.config.set('custombrowser', widget.get_text().decode('utf-8'))
1154 gajim.interface.save_config()
1156 def on_custom_mail_client_entry_changed(self, widget):
1157 gajim.config.set('custommailapp', widget.get_text().decode('utf-8'))
1158 gajim.interface.save_config()
1160 def on_custom_file_manager_entry_changed(self, widget):
1161 gajim.config.set('custom_file_manager', widget.get_text().decode('utf-8'))
1162 gajim.interface.save_config()
1164 def on_log_show_changes_checkbutton_toggled(self, widget):
1165 self.on_checkbutton_toggled(widget, 'log_contact_status_changes')
1167 def on_log_encrypted_chats_checkbutton_toggled(self, widget):
1168 widget.set_inconsistent(False)
1169 self.on_per_account_checkbutton_toggled(widget, 'log_encrypted_sessions')
1171 def on_send_os_info_checkbutton_toggled(self, widget):
1172 widget.set_inconsistent(False)
1173 self.on_per_account_checkbutton_toggled(widget, 'send_os_info')
1175 def on_send_idle_time_checkbutton_toggled(self, widget):
1176 widget.set_inconsistent(False)
1177 self.on_per_account_checkbutton_toggled(widget, 'send_idle_time')
1179 def on_check_default_client_checkbutton_toggled(self, widget):
1180 self.on_checkbutton_toggled(widget, 'check_if_gajim_is_default')
1182 def on_notify_gmail_checkbutton_toggled(self, widget):
1183 self.on_checkbutton_toggled(widget, 'notify_on_new_gmail_email')
1185 def on_notify_gmail_extra_checkbutton_toggled(self, widget):
1186 self.on_checkbutton_toggled(widget, 'notify_on_new_gmail_email_extra')
1188 def fill_msg_treeview(self):
1189 self.xml.get_object('delete_msg_button').set_sensitive(False)
1190 model = self.msg_tree.get_model()
1191 model.clear()
1192 preset_status = []
1193 for msg_name in gajim.config.get_per('statusmsg'):
1194 if msg_name.startswith('_last_'):
1195 continue
1196 preset_status.append(msg_name)
1197 preset_status.sort()
1198 for msg_name in preset_status:
1199 msg_text = gajim.config.get_per('statusmsg', msg_name, 'message')
1200 msg_text = helpers.from_one_line(msg_text)
1201 activity = gajim.config.get_per('statusmsg', msg_name, 'activity')
1202 subactivity = gajim.config.get_per('statusmsg', msg_name,
1203 'subactivity')
1204 activity_text = gajim.config.get_per('statusmsg', msg_name,
1205 'activity_text')
1206 mood = gajim.config.get_per('statusmsg', msg_name, 'mood')
1207 mood_text = gajim.config.get_per('statusmsg', msg_name, 'mood_text')
1208 iter_ = model.append()
1209 model.set(iter_, 0, msg_name, 1, msg_text, 2, activity, 3,
1210 subactivity, 4, activity_text, 5, mood, 6, mood_text)
1212 def on_msg_cell_edited(self, cell, row, new_text):
1213 model = self.msg_tree.get_model()
1214 iter_ = model.get_iter_from_string(row)
1215 model.set_value(iter_, 0, new_text)
1217 def on_msg_treeview_cursor_changed(self, widget, data = None):
1218 (model, iter_) = self.msg_tree.get_selection().get_selected()
1219 if not iter_:
1220 return
1221 self.xml.get_object('delete_msg_button').set_sensitive(True)
1222 buf = self.xml.get_object('msg_textview').get_buffer()
1223 msg = model[iter_][1]
1224 buf.set_text(msg)
1226 def on_new_msg_button_clicked(self, widget, data = None):
1227 model = self.msg_tree.get_model()
1228 iter_ = model.append()
1229 model.set(iter_, 0, _('status message title'), 1, _('status message text'))
1230 self.msg_tree.set_cursor(model.get_path(iter_))
1232 def on_delete_msg_button_clicked(self, widget, data = None):
1233 (model, iter_) = self.msg_tree.get_selection().get_selected()
1234 if not iter_:
1235 return
1236 buf = self.xml.get_object('msg_textview').get_buffer()
1237 model.remove(iter_)
1238 buf.set_text('')
1239 self.xml.get_object('delete_msg_button').set_sensitive(False)
1241 def on_msg_textview_changed(self, widget, data = None):
1242 (model, iter_) = self.msg_tree.get_selection().get_selected()
1243 if not iter_:
1244 return
1245 buf = self.xml.get_object('msg_textview').get_buffer()
1246 first_iter, end_iter = buf.get_bounds()
1247 model.set_value(iter_, 1, buf.get_text(first_iter, end_iter))
1249 def on_msg_treeview_key_press_event(self, widget, event):
1250 if event.keyval == gtk.keysyms.Delete:
1251 self.on_delete_msg_button_clicked(widget)
1253 def on_open_advanced_editor_button_clicked(self, widget, data = None):
1254 if 'advanced_config' in gajim.interface.instances:
1255 gajim.interface.instances['advanced_config'].window.present()
1256 else:
1257 gajim.interface.instances['advanced_config'] = \
1258 dialogs.AdvancedConfigurationWindow()
1260 #---------- ManageProxiesWindow class -------------#
1261 class ManageProxiesWindow:
1262 def __init__(self):
1263 self.xml = gtkgui_helpers.get_gtk_builder('manage_proxies_window.ui')
1264 self.window = self.xml.get_object('manage_proxies_window')
1265 self.window.set_transient_for(gajim.interface.roster.window)
1266 self.proxies_treeview = self.xml.get_object('proxies_treeview')
1267 self.proxyname_entry = self.xml.get_object('proxyname_entry')
1268 self.proxytype_combobox = self.xml.get_object('proxytype_combobox')
1270 self.init_list()
1271 self.block_signal = False
1272 self.xml.connect_signals(self)
1273 self.window.show_all()
1274 # hide the BOSH fields by default
1275 self.show_bosh_fields()
1277 def show_bosh_fields(self, show=True):
1278 if show:
1279 self.xml.get_object('boshuri_entry').show()
1280 self.xml.get_object('boshuri_label').show()
1281 self.xml.get_object('boshuseproxy_checkbutton').show()
1282 else:
1283 cb = self.xml.get_object('boshuseproxy_checkbutton')
1284 cb.hide()
1285 cb.set_active(True)
1286 self.on_boshuseproxy_checkbutton_toggled(cb)
1287 self.xml.get_object('boshuri_entry').hide()
1288 self.xml.get_object('boshuri_label').hide()
1291 def fill_proxies_treeview(self):
1292 model = self.proxies_treeview.get_model()
1293 model.clear()
1294 iter_ = model.append()
1295 model.set(iter_, 0, _('None'))
1296 for p in gajim.config.get_per('proxies'):
1297 iter_ = model.append()
1298 model.set(iter_, 0, p)
1300 def init_list(self):
1301 self.xml.get_object('remove_proxy_button').set_sensitive(False)
1302 self.proxytype_combobox.set_sensitive(False)
1303 self.xml.get_object('proxy_table').set_sensitive(False)
1304 model = gtk.ListStore(str)
1305 self.proxies_treeview.set_model(model)
1306 col = gtk.TreeViewColumn('Proxies')
1307 self.proxies_treeview.append_column(col)
1308 renderer = gtk.CellRendererText()
1309 col.pack_start(renderer, True)
1310 col.set_attributes(renderer, text = 0)
1311 self.fill_proxies_treeview()
1312 self.xml.get_object('proxytype_combobox').set_active(0)
1314 def on_manage_proxies_window_destroy(self, widget):
1315 if 'accounts' in gajim.interface.instances:
1316 gajim.interface.instances['accounts'].\
1317 update_proxy_list()
1318 del gajim.interface.instances['manage_proxies']
1320 def on_add_proxy_button_clicked(self, widget):
1321 model = self.proxies_treeview.get_model()
1322 proxies = gajim.config.get_per('proxies')
1323 i = 1
1324 while ('proxy' + unicode(i)) in proxies:
1325 i += 1
1326 iter_ = model.append()
1327 model.set(iter_, 0, 'proxy' + unicode(i))
1328 gajim.config.add_per('proxies', 'proxy' + unicode(i))
1329 self.proxies_treeview.set_cursor(model.get_path(iter_))
1331 def on_remove_proxy_button_clicked(self, widget):
1332 (model, iter_) = self.proxies_treeview.get_selection().get_selected()
1333 if not iter_:
1334 return
1335 proxy = model[iter_][0].decode('utf-8')
1336 model.remove(iter_)
1337 gajim.config.del_per('proxies', proxy)
1338 self.xml.get_object('remove_proxy_button').set_sensitive(False)
1339 self.block_signal = True
1340 self.on_proxies_treeview_cursor_changed(self.proxies_treeview)
1341 self.block_signal = False
1343 def on_close_button_clicked(self, widget):
1344 self.window.destroy()
1346 def on_useauth_checkbutton_toggled(self, widget):
1347 if self.block_signal:
1348 return
1349 act = widget.get_active()
1350 proxy = self.proxyname_entry.get_text().decode('utf-8')
1351 gajim.config.set_per('proxies', proxy, 'useauth', act)
1352 self.xml.get_object('proxyuser_entry').set_sensitive(act)
1353 self.xml.get_object('proxypass_entry').set_sensitive(act)
1355 def on_boshuseproxy_checkbutton_toggled(self, widget):
1356 if self.block_signal:
1357 return
1358 act = widget.get_active()
1359 proxy = self.proxyname_entry.get_text().decode('utf-8')
1360 gajim.config.set_per('proxies', proxy, 'bosh_useproxy', act)
1361 self.xml.get_object('proxyhost_entry').set_sensitive(act)
1362 self.xml.get_object('proxyport_entry').set_sensitive(act)
1364 def on_proxies_treeview_cursor_changed(self, widget):
1365 #FIXME: check if off proxy settings are correct (see
1366 # http://trac.gajim.org/changeset/1921#file2 line 1221
1367 proxyhost_entry = self.xml.get_object('proxyhost_entry')
1368 proxyport_entry = self.xml.get_object('proxyport_entry')
1369 proxyuser_entry = self.xml.get_object('proxyuser_entry')
1370 proxypass_entry = self.xml.get_object('proxypass_entry')
1371 boshuri_entry = self.xml.get_object('boshuri_entry')
1372 useauth_checkbutton = self.xml.get_object('useauth_checkbutton')
1373 boshuseproxy_checkbutton = self.xml.get_object('boshuseproxy_checkbutton')
1374 self.block_signal = True
1375 proxyhost_entry.set_text('')
1376 proxyport_entry.set_text('')
1377 proxyuser_entry.set_text('')
1378 proxypass_entry.set_text('')
1379 boshuri_entry.set_text('')
1381 #boshuseproxy_checkbutton.set_active(False)
1382 #self.on_boshuseproxy_checkbutton_toggled(boshuseproxy_checkbutton)
1384 #useauth_checkbutton.set_active(False)
1385 #self.on_useauth_checkbutton_toggled(useauth_checkbutton)
1387 (model, iter_) = widget.get_selection().get_selected()
1388 if not iter_:
1389 self.xml.get_object('proxyname_entry').set_text('')
1390 self.xml.get_object('proxytype_combobox').set_sensitive(False)
1391 self.xml.get_object('proxy_table').set_sensitive(False)
1392 self.block_signal = False
1393 return
1395 proxy = model[iter_][0]
1396 self.xml.get_object('proxyname_entry').set_text(proxy)
1398 if proxy == _('None'): # special proxy None
1399 self.show_bosh_fields(False)
1400 self.proxyname_entry.set_editable(False)
1401 self.xml.get_object('remove_proxy_button').set_sensitive(False)
1402 self.xml.get_object('proxytype_combobox').set_sensitive(False)
1403 self.xml.get_object('proxy_table').set_sensitive(False)
1404 else:
1405 proxytype = gajim.config.get_per('proxies', proxy, 'type')
1407 self.show_bosh_fields(proxytype=='bosh')
1409 self.proxyname_entry.set_editable(True)
1410 self.xml.get_object('remove_proxy_button').set_sensitive(True)
1411 self.xml.get_object('proxytype_combobox').set_sensitive(True)
1412 self.xml.get_object('proxy_table').set_sensitive(True)
1413 proxyhost_entry.set_text(gajim.config.get_per('proxies', proxy,
1414 'host'))
1415 proxyport_entry.set_text(unicode(gajim.config.get_per('proxies',
1416 proxy, 'port')))
1417 proxyuser_entry.set_text(gajim.config.get_per('proxies', proxy,
1418 'user'))
1419 proxypass_entry.set_text(gajim.config.get_per('proxies', proxy,
1420 'pass'))
1421 boshuri_entry.set_text(gajim.config.get_per('proxies', proxy,
1422 'bosh_uri'))
1423 types = ['http', 'socks5', 'bosh']
1424 self.proxytype_combobox.set_active(types.index(proxytype))
1425 boshuseproxy_checkbutton.set_active(
1426 gajim.config.get_per('proxies', proxy, 'bosh_useproxy'))
1427 useauth_checkbutton.set_active(
1428 gajim.config.get_per('proxies', proxy, 'useauth'))
1429 self.block_signal = False
1431 def on_proxies_treeview_key_press_event(self, widget, event):
1432 if event.keyval == gtk.keysyms.Delete:
1433 self.on_remove_proxy_button_clicked(widget)
1435 def on_proxyname_entry_changed(self, widget):
1436 if self.block_signal:
1437 return
1438 (model, iter_) = self.proxies_treeview.get_selection().get_selected()
1439 if not iter_:
1440 return
1441 old_name = model.get_value(iter_, 0).decode('utf-8')
1442 new_name = widget.get_text().decode('utf-8')
1443 if new_name == '':
1444 return
1445 if new_name == old_name:
1446 return
1447 config = gajim.config.get_per('proxies', old_name)
1448 gajim.config.del_per('proxies', old_name)
1449 gajim.config.add_per('proxies', new_name)
1450 for option in config:
1451 gajim.config.set_per('proxies', new_name, option,
1452 config[option][common.config.OPT_VAL])
1453 model.set_value(iter_, 0, new_name)
1455 def on_proxytype_combobox_changed(self, widget):
1456 if self.block_signal:
1457 return
1458 types = ['http', 'socks5', 'bosh']
1459 type_ = self.proxytype_combobox.get_active()
1460 self.show_bosh_fields(types[type_]=='bosh')
1461 proxy = self.proxyname_entry.get_text().decode('utf-8')
1462 gajim.config.set_per('proxies', proxy, 'type', types[type_])
1464 def on_proxyhost_entry_changed(self, widget):
1465 if self.block_signal:
1466 return
1467 value = widget.get_text().decode('utf-8')
1468 proxy = self.proxyname_entry.get_text().decode('utf-8')
1469 gajim.config.set_per('proxies', proxy, 'host', value)
1471 def on_proxyport_entry_changed(self, widget):
1472 if self.block_signal:
1473 return
1474 value = widget.get_text().decode('utf-8')
1475 proxy = self.proxyname_entry.get_text().decode('utf-8')
1476 gajim.config.set_per('proxies', proxy, 'port', value)
1478 def on_proxyuser_entry_changed(self, widget):
1479 if self.block_signal:
1480 return
1481 value = widget.get_text().decode('utf-8')
1482 proxy = self.proxyname_entry.get_text().decode('utf-8')
1483 gajim.config.set_per('proxies', proxy, 'user', value)
1485 def on_boshuri_entry_changed(self, widget):
1486 if self.block_signal:
1487 return
1488 value = widget.get_text().decode('utf-8')
1489 proxy = self.proxyname_entry.get_text().decode('utf-8')
1490 gajim.config.set_per('proxies', proxy, 'bosh_uri', value)
1492 def on_proxypass_entry_changed(self, widget):
1493 if self.block_signal:
1494 return
1495 value = widget.get_text().decode('utf-8')
1496 proxy = self.proxyname_entry.get_text().decode('utf-8')
1497 gajim.config.set_per('proxies', proxy, 'pass', value)
1500 #---------- AccountsWindow class -------------#
1501 class AccountsWindow:
1503 Class for accounts window: list of accounts
1506 def on_accounts_window_destroy(self, widget):
1507 del gajim.interface.instances['accounts']
1509 def on_close_button_clicked(self, widget):
1510 self.check_resend_relog()
1511 self.window.destroy()
1513 def __init__(self):
1514 self.xml = gtkgui_helpers.get_gtk_builder('accounts_window.ui')
1515 self.window = self.xml.get_object('accounts_window')
1516 self.window.set_transient_for(gajim.interface.roster.window)
1517 self.accounts_treeview = self.xml.get_object('accounts_treeview')
1518 self.remove_button = self.xml.get_object('remove_button')
1519 self.rename_button = self.xml.get_object('rename_button')
1520 path_to_kbd_input_img = gtkgui_helpers.get_icon_path('gajim-kbd_input')
1521 img = self.xml.get_object('rename_image')
1522 img.set_from_file(path_to_kbd_input_img)
1523 self.notebook = self.xml.get_object('notebook')
1524 # Name
1525 model = gtk.ListStore(str)
1526 self.accounts_treeview.set_model(model)
1527 # column
1528 renderer = gtk.CellRendererText()
1529 self.accounts_treeview.insert_column_with_attributes(-1, _('Name'),
1530 renderer, text=0)
1532 self.current_account = None
1533 # When we fill info, we don't want to handle the changed signals
1534 self.ignore_events = False
1535 self.need_relogin = False
1536 self.resend_presence = False
1538 self.update_proxy_list()
1539 self.xml.connect_signals(self)
1540 self.init_accounts()
1541 self.window.show_all()
1543 # Merge accounts
1544 st = gajim.config.get('mergeaccounts')
1545 checkbutton = self.xml.get_object('merge_checkbutton')
1546 checkbutton.set_active(st)
1547 # prevent roster redraws by connecting the signal after button state is
1548 # set
1549 checkbutton.connect('toggled', self.on_merge_checkbutton_toggled)
1551 self.avahi_available = True
1552 try:
1553 import avahi
1554 except ImportError:
1555 self.avahi_available = False
1557 def on_accounts_window_key_press_event(self, widget, event):
1558 if event.keyval == gtk.keysyms.Escape:
1559 self.check_resend_relog()
1560 self.window.destroy()
1562 def select_account(self, account):
1563 model = self.accounts_treeview.get_model()
1564 iter_ = model.get_iter_root()
1565 while iter_:
1566 acct = model[iter_][0].decode('utf-8')
1567 if account == acct:
1568 self.accounts_treeview.set_cursor(model.get_path(iter_))
1569 return
1570 iter_ = model.iter_next(iter_)
1572 def init_accounts(self):
1574 Initialize listStore with existing accounts
1576 self.remove_button.set_sensitive(False)
1577 self.rename_button.set_sensitive(False)
1578 self.current_account = None
1579 model = self.accounts_treeview.get_model()
1580 model.clear()
1581 for account in gajim.config.get_per('accounts'):
1582 iter_ = model.append()
1583 model.set(iter_, 0, account)
1585 def resend(self, account):
1586 if not account in gajim.connections:
1587 return
1588 show = gajim.SHOW_LIST[gajim.connections[account].connected]
1589 status = gajim.connections[account].status
1590 gajim.connections[account].change_status(show, status)
1592 def check_resend_relog(self):
1593 if self.need_relogin and self.current_account == gajim.ZEROCONF_ACC_NAME:
1594 if gajim.ZEROCONF_ACC_NAME in gajim.connections:
1595 gajim.connections[gajim.ZEROCONF_ACC_NAME].update_details()
1596 return
1598 elif self.need_relogin and self.current_account and \
1599 gajim.connections[self.current_account].connected > 0:
1600 def login(account, show_before, status_before):
1602 Login with previous status
1604 # first make sure connection is really closed,
1605 # 0.5 may not be enough
1606 gajim.connections[account].disconnect(True)
1607 gajim.interface.roster.send_status(account, show_before,
1608 status_before)
1610 def relog(account):
1611 self.dialog.destroy()
1612 show_before = gajim.SHOW_LIST[gajim.connections[account].connected]
1613 status_before = gajim.connections[account].status
1614 gajim.interface.roster.send_status(account, 'offline',
1615 _('Be right back.'))
1616 gobject.timeout_add(500, login, account, show_before, status_before)
1618 def on_yes(checked, account):
1619 relog(account)
1620 def on_no(account):
1621 if self.resend_presence:
1622 self.resend(account)
1623 if self.current_account in gajim.connections:
1624 self.dialog = dialogs.YesNoDialog(_('Relogin now?'),
1625 _('If you want all the changes to apply instantly, '
1626 'you must relogin.'), on_response_yes=(on_yes,
1627 self.current_account), on_response_no=(on_no,
1628 self.current_account))
1629 elif self.resend_presence:
1630 self.resend(self.current_account)
1632 self.need_relogin = False
1633 self.resend_presence = False
1635 def on_accounts_treeview_cursor_changed(self, widget):
1637 Activate modify buttons when a row is selected, update accounts info
1639 sel = self.accounts_treeview.get_selection()
1640 (model, iter_) = sel.get_selected()
1641 if iter_:
1642 account = model[iter_][0].decode('utf-8')
1643 else:
1644 account = None
1645 if self.current_account and self.current_account == account:
1646 # We're comming back to our current account, no need to update widgets
1647 return
1648 # Save config for previous account if needed cause focus_out event is
1649 # called after the changed event
1650 if self.current_account and self.window.get_focus():
1651 focused_widget = self.window.get_focus()
1652 focused_widget_name = focused_widget.get_name()
1653 if focused_widget_name in ('jid_entry1', 'resource_entry1',
1654 'custom_port_entry', 'cert_entry1'):
1655 if focused_widget_name == 'jid_entry1':
1656 func = self.on_jid_entry1_focus_out_event
1657 elif focused_widget_name == 'resource_entry1':
1658 func = self.on_resource_entry1_focus_out_event
1659 elif focused_widget_name == 'custom_port_entry':
1660 func = self.on_custom_port_entry_focus_out_event
1661 elif focused_widget_name == 'cert_entry1':
1662 func = self.on_cert_entry1_focus_out_event
1663 if func(focused_widget, None):
1664 # Error detected in entry, don't change account, re-put cursor on
1665 # previous row
1666 self.select_account(self.current_account)
1667 return True
1668 self.window.set_focus(widget)
1670 self.check_resend_relog()
1672 if account:
1673 self.remove_button.set_sensitive(True)
1674 self.rename_button.set_sensitive(True)
1675 else:
1676 self.remove_button.set_sensitive(False)
1677 self.rename_button.set_sensitive(False)
1678 if iter_:
1679 self.current_account = account
1680 if account == gajim.ZEROCONF_ACC_NAME:
1681 self.remove_button.set_sensitive(False)
1682 self.init_account()
1683 self.update_proxy_list()
1685 def on_browse_for_client_cert_button_clicked(self, widget, data=None):
1686 def on_ok(widget, path_to_clientcert_file):
1687 self.dialog.destroy()
1688 if not path_to_clientcert_file:
1689 return
1690 self.xml.get_object('cert_entry1').set_text(path_to_clientcert_file)
1691 gajim.config.set_per('accounts', self.current_account,
1692 'client_cert', path_to_clientcert_file)
1694 def on_cancel(widget):
1695 self.dialog.destroy()
1697 path_to_clientcert_file = self.xml.get_object('cert_entry1').get_text()
1698 self.dialog = dialogs.ClientCertChooserDialog(path_to_clientcert_file,
1699 on_ok, on_cancel)
1701 def update_proxy_list(self):
1702 if self.current_account:
1703 our_proxy = gajim.config.get_per('accounts', self.current_account,
1704 'proxy')
1705 else:
1706 our_proxy = ''
1708 if not our_proxy:
1709 our_proxy = _('None')
1710 proxy_combobox = self.xml.get_object('proxies_combobox1')
1711 model = gtk.ListStore(str)
1712 proxy_combobox.set_model(model)
1713 l = gajim.config.get_per('proxies')
1714 l.insert(0, _('None'))
1715 for i in xrange(len(l)):
1716 model.append([l[i]])
1717 if our_proxy == l[i]:
1718 proxy_combobox.set_active(i)
1720 def init_account(self):
1721 if not self.current_account:
1722 self.notebook.set_current_page(0)
1723 return
1724 if gajim.config.get_per('accounts', self.current_account, 'is_zeroconf'):
1725 self.ignore_events = True
1726 self.init_zeroconf_account()
1727 self.ignore_events = False
1728 self.notebook.set_current_page(2)
1729 return
1730 self.ignore_events = True
1731 self.init_normal_account()
1732 self.ignore_events = False
1733 self.notebook.set_current_page(1)
1735 def init_zeroconf_account(self):
1736 active = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME,
1737 'active')
1738 self.xml.get_object('enable_zeroconf_checkbutton2').set_active(active)
1739 if not gajim.HAVE_ZEROCONF:
1740 self.xml.get_object('enable_zeroconf_checkbutton2').set_sensitive(
1741 False)
1742 self.xml.get_object('zeroconf_notebook').set_sensitive(active)
1743 # General tab
1744 st = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME,
1745 'autoconnect')
1746 self.xml.get_object('autoconnect_checkbutton2').set_active(st)
1748 list_no_log_for = gajim.config.get_per('accounts',
1749 gajim.ZEROCONF_ACC_NAME, 'no_log_for').split()
1750 if gajim.ZEROCONF_ACC_NAME in list_no_log_for:
1751 self.xml.get_object('log_history_checkbutton2').set_active(0)
1752 else:
1753 self.xml.get_object('log_history_checkbutton2').set_active(1)
1755 st = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME,
1756 'sync_with_global_status')
1757 self.xml.get_object('sync_with_global_status_checkbutton2').set_active(st)
1759 st = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME,
1760 'use_custom_host')
1761 self.xml.get_object('custom_port_checkbutton2').set_active(st)
1762 self.xml.get_object('custom_port_entry2').set_sensitive(st)
1764 st = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME,
1765 'custom_port')
1766 if not st:
1767 gajim.config.set_per('accounts', gajim.ZEROCONF_ACC_NAME,
1768 'custom_port', '5298')
1769 st = '5298'
1770 self.xml.get_object('custom_port_entry2').set_text(str(st))
1772 # Personal tab
1773 gpg_key_label = self.xml.get_object('gpg_key_label2')
1774 if gajim.ZEROCONF_ACC_NAME in gajim.connections and \
1775 gajim.connections[gajim.ZEROCONF_ACC_NAME].gpg:
1776 self.xml.get_object('gpg_choose_button2').set_sensitive(True)
1777 self.init_account_gpg()
1778 else:
1779 gpg_key_label.set_text(_('OpenPGP is not usable on this computer'))
1780 self.xml.get_object('gpg_choose_button2').set_sensitive(False)
1782 for opt in ('first_name', 'last_name', 'jabber_id', 'email'):
1783 st = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME,
1784 'zeroconf_' + opt)
1785 self.xml.get_object(opt + '_entry2').set_text(st)
1787 def init_account_gpg(self):
1788 account = self.current_account
1789 keyid = gajim.config.get_per('accounts', account, 'keyid')
1790 keyname = gajim.config.get_per('accounts', account, 'keyname')
1791 use_gpg_agent = gajim.config.get('use_gpg_agent')
1793 if account == gajim.ZEROCONF_ACC_NAME:
1794 widget_name_add = '2'
1795 else:
1796 widget_name_add = '1'
1798 gpg_key_label = self.xml.get_object('gpg_key_label' + widget_name_add)
1799 gpg_name_label = self.xml.get_object('gpg_name_label' + widget_name_add)
1800 use_gpg_agent_checkbutton = self.xml.get_object(
1801 'use_gpg_agent_checkbutton' + widget_name_add)
1803 if not keyid:
1804 use_gpg_agent_checkbutton.set_sensitive(False)
1805 gpg_key_label.set_text(_('No key selected'))
1806 gpg_name_label.set_text('')
1807 return
1809 gpg_key_label.set_text(keyid)
1810 gpg_name_label.set_text(keyname)
1811 use_gpg_agent_checkbutton.set_sensitive(True)
1812 use_gpg_agent_checkbutton.set_active(use_gpg_agent)
1814 def draw_normal_jid(self):
1815 account = self.current_account
1816 self.ignore_events = True
1817 active = gajim.config.get_per('accounts', account, 'active')
1818 self.xml.get_object('enable_checkbutton1').set_active(active)
1819 self.xml.get_object('normal_notebook1').set_sensitive(active)
1820 if gajim.config.get_per('accounts', account, 'anonymous_auth'):
1821 self.xml.get_object('anonymous_checkbutton1').set_active(True)
1822 self.xml.get_object('jid_label1').set_text(_('Server:'))
1823 save_password = self.xml.get_object('save_password_checkbutton1')
1824 save_password.set_active(False)
1825 save_password.set_sensitive(False)
1826 password_entry = self.xml.get_object('password_entry1')
1827 password_entry.set_text('')
1828 password_entry.set_sensitive(False)
1829 jid = gajim.config.get_per('accounts', account, 'hostname')
1830 else:
1831 self.xml.get_object('anonymous_checkbutton1').set_active(False)
1832 self.xml.get_object('jid_label1').set_text(_('Jabber ID:'))
1833 savepass = gajim.config.get_per('accounts', account, 'savepass')
1834 save_password = self.xml.get_object('save_password_checkbutton1')
1835 save_password.set_sensitive(True)
1836 save_password.set_active(savepass)
1837 password_entry = self.xml.get_object('password_entry1')
1838 if savepass:
1839 passstr = passwords.get_password(account) or ''
1840 password_entry.set_sensitive(True)
1841 else:
1842 passstr = ''
1843 password_entry.set_sensitive(False)
1844 password_entry.set_text(passstr)
1846 jid = gajim.config.get_per('accounts', account, 'name') \
1847 + '@' + gajim.config.get_per('accounts', account, 'hostname')
1848 self.xml.get_object('jid_entry1').set_text(jid)
1849 self.ignore_events = False
1851 def init_normal_account(self):
1852 account = self.current_account
1853 # Account tab
1854 self.draw_normal_jid()
1855 self.xml.get_object('resource_entry1').set_text(gajim.config.get_per(
1856 'accounts', account, 'resource'))
1858 client_cert = gajim.config.get_per('accounts', account, 'client_cert')
1859 self.xml.get_object('cert_entry1').set_text(client_cert)
1861 self.xml.get_object('adjust_priority_with_status_checkbutton1').\
1862 set_active(gajim.config.get_per('accounts', account,
1863 'adjust_priority_with_status'))
1864 spinbutton = self.xml.get_object('priority_spinbutton1')
1865 if gajim.config.get('enable_negative_priority'):
1866 spinbutton.set_range(-128, 127)
1867 else:
1868 spinbutton.set_range(0, 127)
1869 spinbutton.set_value(gajim.config.get_per('accounts', account,
1870 'priority'))
1872 # Connection tab
1873 use_env_http_proxy = gajim.config.get_per('accounts', account,
1874 'use_env_http_proxy')
1875 self.xml.get_object('use_env_http_proxy_checkbutton1').set_active(
1876 use_env_http_proxy)
1877 self.xml.get_object('proxy_hbox1').set_sensitive(not use_env_http_proxy)
1879 warn_when_insecure_ssl = gajim.config.get_per('accounts', account,
1880 'warn_when_insecure_ssl_connection')
1881 self.xml.get_object('warn_when_insecure_connection_checkbutton1').\
1882 set_active(warn_when_insecure_ssl)
1884 self.xml.get_object('send_keepalive_checkbutton1').set_active(
1885 gajim.config.get_per('accounts', account, 'keep_alives_enabled'))
1887 use_custom_host = gajim.config.get_per('accounts', account,
1888 'use_custom_host')
1889 self.xml.get_object('custom_host_port_checkbutton1').set_active(
1890 use_custom_host)
1891 custom_host = gajim.config.get_per('accounts', account, 'custom_host')
1892 if not custom_host:
1893 custom_host = gajim.config.get_per('accounts', account, 'hostname')
1894 gajim.config.set_per('accounts', account, 'custom_host', custom_host)
1895 self.xml.get_object('custom_host_entry1').set_text(custom_host)
1896 custom_port = gajim.config.get_per('accounts', account, 'custom_port')
1897 if not custom_port:
1898 custom_port = 5222
1899 gajim.config.set_per('accounts', account, 'custom_port', custom_port)
1900 self.xml.get_object('custom_port_entry1').set_text(unicode(custom_port))
1902 # Personal tab
1903 gpg_key_label = self.xml.get_object('gpg_key_label1')
1904 if gajim.HAVE_GPG:
1905 self.xml.get_object('gpg_choose_button1').set_sensitive(True)
1906 self.init_account_gpg()
1907 else:
1908 gpg_key_label.set_text(_('OpenPGP is not usable on this computer'))
1909 self.xml.get_object('gpg_choose_button1').set_sensitive(False)
1911 # General tab
1912 self.xml.get_object('autoconnect_checkbutton1').set_active(gajim.config.\
1913 get_per('accounts', account, 'autoconnect'))
1914 self.xml.get_object('autoreconnect_checkbutton1').set_active(gajim.
1915 config.get_per('accounts', account, 'autoreconnect'))
1917 list_no_log_for = gajim.config.get_per('accounts', account,
1918 'no_log_for').split()
1919 if account in list_no_log_for:
1920 self.xml.get_object('log_history_checkbutton1').set_active(False)
1921 else:
1922 self.xml.get_object('log_history_checkbutton1').set_active(True)
1924 self.xml.get_object('sync_with_global_status_checkbutton1').set_active(
1925 gajim.config.get_per('accounts', account, 'sync_with_global_status'))
1926 self.xml.get_object('use_ft_proxies_checkbutton1').set_active(
1927 gajim.config.get_per('accounts', account, 'use_ft_proxies'))
1929 def on_add_button_clicked(self, widget):
1931 When add button is clicked: open an account information window
1933 if 'account_creation_wizard' in gajim.interface.instances:
1934 gajim.interface.instances['account_creation_wizard'].window.present()
1935 else:
1936 gajim.interface.instances['account_creation_wizard'] = \
1937 AccountCreationWizardWindow()
1939 def on_remove_button_clicked(self, widget):
1941 When delete button is clicked: Remove an account from the listStore and
1942 from the config file
1944 if not self.current_account:
1945 return
1946 account = self.current_account
1947 if len(gajim.events.get_events(account)):
1948 dialogs.ErrorDialog(_('Unread events'),
1949 _('Read all pending events before removing this account.'))
1950 return
1952 if gajim.config.get_per('accounts', account, 'is_zeroconf'):
1953 # Should never happen as button is insensitive
1954 return
1956 win_opened = False
1957 if gajim.interface.msg_win_mgr.get_controls(acct=account):
1958 win_opened = True
1959 elif account in gajim.interface.instances:
1960 for key in gajim.interface.instances[account]:
1961 if gajim.interface.instances[account][key] and key != \
1962 'remove_account':
1963 win_opened = True
1964 break
1965 # Detect if we have opened windows for this account
1966 def remove(account):
1967 if account in gajim.interface.instances and \
1968 'remove_account' in gajim.interface.instances[account]:
1969 gajim.interface.instances[account]['remove_account'].window.\
1970 present()
1971 else:
1972 if not account in gajim.interface.instances:
1973 gajim.interface.instances[account] = {}
1974 gajim.interface.instances[account]['remove_account'] = \
1975 RemoveAccountWindow(account)
1976 if win_opened:
1977 dialogs.ConfirmationDialog(
1978 _('You have opened chat in account %s') % account,
1979 _('All chat and groupchat windows will be closed. Do you want to '
1980 'continue?'),
1981 on_response_ok = (remove, account))
1982 else:
1983 remove(account)
1985 def on_rename_button_clicked(self, widget):
1986 if not self.current_account:
1987 return
1988 active = gajim.config.get_per('accounts', self.current_account, 'active')
1989 if active and gajim.connections[self.current_account].connected != 0:
1990 dialogs.ErrorDialog(
1991 _('You are currently connected to the server'),
1992 _('To change the account name, you must be disconnected.'))
1993 return
1994 if len(gajim.events.get_events(self.current_account)):
1995 dialogs.ErrorDialog(_('Unread events'),
1996 _('To change the account name, you must read all pending '
1997 'events.'))
1998 return
1999 # Get the new name
2000 def on_renamed(new_name, old_name):
2001 if new_name in gajim.connections:
2002 dialogs.ErrorDialog(_('Account Name Already Used'),
2003 _('This name is already used by another of your accounts. '
2004 'Please choose another name.'))
2005 return
2006 if (new_name == ''):
2007 dialogs.ErrorDialog(_('Invalid account name'),
2008 _('Account name cannot be empty.'))
2009 return
2010 if new_name.find(' ') != -1:
2011 dialogs.ErrorDialog(_('Invalid account name'),
2012 _('Account name cannot contain spaces.'))
2013 return
2014 if active:
2015 # update variables
2016 gajim.interface.instances[new_name] = gajim.interface.instances[
2017 old_name]
2018 gajim.interface.minimized_controls[new_name] = \
2019 gajim.interface.minimized_controls[old_name]
2020 gajim.nicks[new_name] = gajim.nicks[old_name]
2021 gajim.block_signed_in_notifications[new_name] = \
2022 gajim.block_signed_in_notifications[old_name]
2023 gajim.groups[new_name] = gajim.groups[old_name]
2024 gajim.gc_connected[new_name] = gajim.gc_connected[old_name]
2025 gajim.automatic_rooms[new_name] = gajim.automatic_rooms[old_name]
2026 gajim.newly_added[new_name] = gajim.newly_added[old_name]
2027 gajim.to_be_removed[new_name] = gajim.to_be_removed[old_name]
2028 gajim.sleeper_state[new_name] = gajim.sleeper_state[old_name]
2029 gajim.encrypted_chats[new_name] = gajim.encrypted_chats[old_name]
2030 gajim.last_message_time[new_name] = \
2031 gajim.last_message_time[old_name]
2032 gajim.status_before_autoaway[new_name] = \
2033 gajim.status_before_autoaway[old_name]
2034 gajim.transport_avatar[new_name] = gajim.transport_avatar[old_name]
2035 gajim.gajim_optional_features[new_name] = \
2036 gajim.gajim_optional_features[old_name]
2037 gajim.caps_hash[new_name] = gajim.caps_hash[old_name]
2039 gajim.contacts.change_account_name(old_name, new_name)
2040 gajim.events.change_account_name(old_name, new_name)
2042 # change account variable for chat / gc controls
2043 gajim.interface.msg_win_mgr.change_account_name(old_name, new_name)
2044 # upgrade account variable in opened windows
2045 for kind in ('infos', 'disco', 'gc_config', 'search',
2046 'online_dialog'):
2047 for j in gajim.interface.instances[new_name][kind]:
2048 gajim.interface.instances[new_name][kind][j].account = \
2049 new_name
2051 # ServiceCache object keep old property account
2052 if hasattr(gajim.connections[old_name], 'services_cache'):
2053 gajim.connections[old_name].services_cache.account = new_name
2054 del gajim.interface.instances[old_name]
2055 del gajim.interface.minimized_controls[old_name]
2056 del gajim.nicks[old_name]
2057 del gajim.block_signed_in_notifications[old_name]
2058 del gajim.groups[old_name]
2059 del gajim.gc_connected[old_name]
2060 del gajim.automatic_rooms[old_name]
2061 del gajim.newly_added[old_name]
2062 del gajim.to_be_removed[old_name]
2063 del gajim.sleeper_state[old_name]
2064 del gajim.encrypted_chats[old_name]
2065 del gajim.last_message_time[old_name]
2066 del gajim.status_before_autoaway[old_name]
2067 del gajim.transport_avatar[old_name]
2068 del gajim.gajim_optional_features[old_name]
2069 del gajim.caps_hash[old_name]
2070 gajim.connections[old_name].name = new_name
2071 gajim.connections[old_name].pep_change_account_name(new_name)
2072 gajim.connections[old_name].caps_change_account_name(new_name)
2073 gajim.connections[new_name] = gajim.connections[old_name]
2074 del gajim.connections[old_name]
2075 gajim.config.add_per('accounts', new_name)
2076 old_config = gajim.config.get_per('accounts', old_name)
2077 for opt in old_config:
2078 gajim.config.set_per('accounts', new_name, opt, old_config[opt][1])
2079 gajim.config.del_per('accounts', old_name)
2080 if self.current_account == old_name:
2081 self.current_account = new_name
2082 if old_name == gajim.ZEROCONF_ACC_NAME:
2083 gajim.ZEROCONF_ACC_NAME = new_name
2084 # refresh roster
2085 gajim.interface.roster.setup_and_draw_roster()
2086 self.init_accounts()
2087 self.select_account(new_name)
2089 title = _('Rename Account')
2090 message = _('Enter a new name for account %s') % self.current_account
2091 old_text = self.current_account
2092 dialogs.InputDialog(title, message, old_text, is_modal=False,
2093 ok_handler=(on_renamed, self.current_account))
2095 def option_changed(self, option, value):
2096 return gajim.config.get_per('accounts', self.current_account, option) != \
2097 value
2099 def on_jid_entry1_focus_out_event(self, widget, event):
2100 if self.ignore_events:
2101 return
2102 jid = widget.get_text()
2103 # check if jid is conform to RFC and stringprep it
2104 try:
2105 jid = helpers.parse_jid(jid)
2106 except helpers.InvalidFormat, s:
2107 if not widget.is_focus():
2108 pritext = _('Invalid Jabber ID')
2109 dialogs.ErrorDialog(pritext, str(s))
2110 gobject.idle_add(lambda: widget.grab_focus())
2111 return True
2113 jid_splited = jid.split('@', 1)
2114 if len(jid_splited) != 2 and not gajim.config.get_per('accounts',
2115 self.current_account, 'anonymous_auth'):
2116 if not widget.is_focus():
2117 pritext = _('Invalid Jabber ID')
2118 sectext = _('A Jabber ID must be in the form "user@servername".')
2119 dialogs.ErrorDialog(pritext, sectext)
2120 gobject.idle_add(lambda: widget.grab_focus())
2121 return True
2124 if gajim.config.get_per('accounts', self.current_account,
2125 'anonymous_auth'):
2126 gajim.config.set_per('accounts', self.current_account, 'hostname',
2127 jid_splited[0])
2128 if self.option_changed('hostname', jid_splited[0]):
2129 self.need_relogin = True
2130 else:
2131 if self.option_changed('name', jid_splited[0]) or \
2132 self.option_changed('hostname', jid_splited[1]):
2133 self.need_relogin = True
2135 gajim.config.set_per('accounts', self.current_account, 'name',
2136 jid_splited[0])
2137 gajim.config.set_per('accounts', self.current_account, 'hostname',
2138 jid_splited[1])
2140 def on_cert_entry1_focus_out_event(self, widget, event):
2141 if self.ignore_events:
2142 return
2143 client_cert = widget.get_text()
2144 if self.option_changed('client_cert', client_cert):
2145 self.need_relogin = True
2146 gajim.config.set_per('accounts', self.current_account, 'client_cert',
2147 client_cert)
2149 def on_anonymous_checkbutton1_toggled(self, widget):
2150 if self.ignore_events:
2151 return
2152 active = widget.get_active()
2153 gajim.config.set_per('accounts', self.current_account, 'anonymous_auth',
2154 active)
2155 self.draw_normal_jid()
2157 def on_password_entry1_changed(self, widget):
2158 if self.ignore_events:
2159 return
2160 passwords.save_password(self.current_account, widget.get_text().decode(
2161 'utf-8'))
2163 def on_save_password_checkbutton1_toggled(self, widget):
2164 if self.ignore_events:
2165 return
2166 active = widget.get_active()
2167 password_entry = self.xml.get_object('password_entry1')
2168 password_entry.set_sensitive(active)
2169 gajim.config.set_per('accounts', self.current_account, 'savepass', active)
2170 if active:
2171 password = password_entry.get_text()
2172 passwords.save_password(self.current_account, password)
2173 else:
2174 passwords.save_password(self.current_account, '')
2176 def on_resource_entry1_focus_out_event(self, widget, event):
2177 if self.ignore_events:
2178 return
2179 resource = self.xml.get_object('resource_entry1').get_text().decode(
2180 'utf-8')
2181 try:
2182 resource = helpers.parse_resource(resource)
2183 except helpers.InvalidFormat, s:
2184 if not widget.is_focus():
2185 pritext = _('Invalid Jabber ID')
2186 dialogs.ErrorDialog(pritext, str(s))
2187 gobject.idle_add(lambda: widget.grab_focus())
2188 return True
2190 if self.option_changed('resource', resource):
2191 self.need_relogin = True
2193 gajim.config.set_per('accounts', self.current_account, 'resource',
2194 resource)
2196 def on_adjust_priority_with_status_checkbutton1_toggled(self, widget):
2197 self.xml.get_object('priority_spinbutton1').set_sensitive(
2198 not widget.get_active())
2199 self.on_checkbutton_toggled(widget, 'adjust_priority_with_status',
2200 account = self.current_account)
2202 def on_priority_spinbutton1_value_changed(self, widget):
2203 prio = widget.get_value_as_int()
2205 if self.option_changed('priority', prio):
2206 self.resend_presence = True
2208 gajim.config.set_per('accounts', self.current_account, 'priority', prio)
2210 def on_synchronise_contacts_button1_clicked(self, widget):
2211 try:
2212 dialogs.SynchroniseSelectAccountDialog(self.current_account)
2213 except GajimGeneralException:
2214 # If we showed ErrorDialog, there will not be dialog instance
2215 return
2217 def on_change_password_button1_clicked(self, widget):
2218 def on_changed(new_password):
2219 if new_password is not None:
2220 gajim.connections[self.current_account].change_password(
2221 new_password)
2222 if self.xml.get_object('save_password_checkbutton1').get_active():
2223 self.xml.get_object('password_entry1').set_text(new_password)
2225 try:
2226 dialogs.ChangePasswordDialog(self.current_account, on_changed)
2227 except GajimGeneralException:
2228 # if we showed ErrorDialog, there will not be dialog instance
2229 return
2231 def on_autoconnect_checkbutton_toggled(self, widget):
2232 if self.ignore_events:
2233 return
2234 self.on_checkbutton_toggled(widget, 'autoconnect',
2235 account=self.current_account)
2237 def on_autoreconnect_checkbutton_toggled(self, widget):
2238 if self.ignore_events:
2239 return
2240 self.on_checkbutton_toggled(widget, 'autoreconnect',
2241 account=self.current_account)
2243 def on_log_history_checkbutton_toggled(self, widget):
2244 if self.ignore_events:
2245 return
2246 list_no_log_for = gajim.config.get_per('accounts', self.current_account,
2247 'no_log_for').split()
2248 if self.current_account in list_no_log_for:
2249 list_no_log_for.remove(self.current_account)
2251 if not widget.get_active():
2252 list_no_log_for.append(self.current_account)
2253 gajim.config.set_per('accounts', self.current_account, 'no_log_for',
2254 ' '.join(list_no_log_for))
2256 def on_sync_with_global_status_checkbutton_toggled(self, widget):
2257 if self.ignore_events:
2258 return
2259 self.on_checkbutton_toggled(widget, 'sync_with_global_status',
2260 account=self.current_account)
2261 gajim.interface.roster.update_status_combobox()
2263 def on_use_ft_proxies_checkbutton1_toggled(self, widget):
2264 if self.ignore_events:
2265 return
2266 self.on_checkbutton_toggled(widget, 'use_ft_proxies',
2267 account=self.current_account)
2269 def on_use_env_http_proxy_checkbutton1_toggled(self, widget):
2270 if self.ignore_events:
2271 return
2272 self.on_checkbutton_toggled(widget, 'use_env_http_proxy',
2273 account=self.current_account)
2274 hbox = self.xml.get_object('proxy_hbox1')
2275 hbox.set_sensitive(not widget.get_active())
2277 def on_proxies_combobox1_changed(self, widget):
2278 active = widget.get_active()
2279 proxy = widget.get_model()[active][0].decode('utf-8')
2280 if proxy == _('None'):
2281 proxy = ''
2283 if self.option_changed('proxy', proxy):
2284 self.need_relogin = True
2286 gajim.config.set_per('accounts', self.current_account, 'proxy', proxy)
2288 def on_manage_proxies_button1_clicked(self, widget):
2289 if 'manage_proxies' in gajim.interface.instances:
2290 gajim.interface.instances['manage_proxies'].window.present()
2291 else:
2292 gajim.interface.instances['manage_proxies'] = ManageProxiesWindow()
2294 def on_warn_when_insecure_connection_checkbutton1_toggled(self, widget):
2295 if self.ignore_events:
2296 return
2298 self.on_checkbutton_toggled(widget, 'warn_when_insecure_ssl_connection',
2299 account=self.current_account)
2301 def on_send_keepalive_checkbutton1_toggled(self, widget):
2302 if self.ignore_events:
2303 return
2304 self.on_checkbutton_toggled(widget, 'keep_alives_enabled',
2305 account=self.current_account)
2306 gajim.config.set_per('accounts', self.current_account,
2307 'ping_alives_enabled', widget.get_active())
2309 def on_custom_host_port_checkbutton1_toggled(self, widget):
2310 if self.option_changed('use_custom_host', widget.get_active()):
2311 self.need_relogin = True
2313 self.on_checkbutton_toggled(widget, 'use_custom_host',
2314 account=self.current_account)
2315 active = widget.get_active()
2316 self.xml.get_object('custom_host_port_hbox1').set_sensitive(active)
2318 def on_custom_host_entry1_changed(self, widget):
2319 if self.ignore_events:
2320 return
2321 host = widget.get_text().decode('utf-8')
2322 if self.option_changed('custom_host', host):
2323 self.need_relogin = True
2324 gajim.config.set_per('accounts', self.current_account, 'custom_host',
2325 host)
2327 def on_custom_port_entry_focus_out_event(self, widget, event):
2328 if self.ignore_events:
2329 return
2330 custom_port = widget.get_text()
2331 try:
2332 custom_port = int(custom_port)
2333 except Exception:
2334 if not widget.is_focus():
2335 dialogs.ErrorDialog(_('Invalid entry'),
2336 _('Custom port must be a port number.'))
2337 gobject.idle_add(lambda: widget.grab_focus())
2338 return True
2339 if self.option_changed('custom_port', custom_port):
2340 self.need_relogin = True
2341 gajim.config.set_per('accounts', self.current_account, 'custom_port',
2342 custom_port)
2344 def on_gpg_choose_button_clicked(self, widget, data = None):
2345 if self.current_account in gajim.connections and \
2346 gajim.connections[self.current_account].gpg:
2347 secret_keys = gajim.connections[self.current_account].\
2348 ask_gpg_secrete_keys()
2350 # self.current_account is None and/or gajim.connections is {}
2351 else:
2352 if gajim.HAVE_GPG:
2353 secret_keys = gpg.GnuPG().get_secret_keys()
2354 else:
2355 secret_keys = []
2356 if not secret_keys:
2357 dialogs.ErrorDialog(_('Failed to get secret keys'),
2358 _('There is no OpenPGP secret key available.'))
2359 secret_keys[_('None')] = _('None')
2361 def on_key_selected(keyID):
2362 if keyID is None:
2363 return
2364 if self.current_account == gajim.ZEROCONF_ACC_NAME:
2365 wiget_name_ext = '2'
2366 else:
2367 wiget_name_ext = '1'
2368 gpg_key_label = self.xml.get_object('gpg_key_label' + wiget_name_ext)
2369 gpg_name_label = self.xml.get_object('gpg_name_label' + wiget_name_ext)
2370 use_gpg_agent_checkbutton = self.xml.get_object(
2371 'use_gpg_agent_checkbutton' + wiget_name_ext)
2372 if keyID[0] == _('None'):
2373 gpg_key_label.set_text(_('No key selected'))
2374 gpg_name_label.set_text('')
2375 use_gpg_agent_checkbutton.set_sensitive(False)
2376 if self.option_changed('keyid', ''):
2377 self.need_relogin = True
2378 gajim.config.set_per('accounts', self.current_account, 'keyname',
2380 gajim.config.set_per('accounts', self.current_account, 'keyid', '')
2381 else:
2382 gpg_key_label.set_text(keyID[0])
2383 gpg_name_label.set_text(keyID[1])
2384 use_gpg_agent_checkbutton.set_sensitive(True)
2385 if self.option_changed('keyid', keyID[0]):
2386 self.need_relogin = True
2387 gajim.config.set_per('accounts', self.current_account, 'keyname',
2388 keyID[1])
2389 gajim.config.set_per('accounts', self.current_account, 'keyid',
2390 keyID[0])
2392 dialogs.ChooseGPGKeyDialog(_('OpenPGP Key Selection'),
2393 _('Choose your OpenPGP key'), secret_keys, on_key_selected)
2395 def on_use_gpg_agent_checkbutton_toggled(self, widget):
2396 self.on_checkbutton_toggled(widget, 'use_gpg_agent')
2398 def on_edit_details_button1_clicked(self, widget):
2399 if self.current_account not in gajim.interface.instances:
2400 dialogs.ErrorDialog(_('No such account available'),
2401 _('You must create your account before editing your personal '
2402 'information.'))
2403 return
2405 # show error dialog if account is newly created (not in gajim.connections)
2406 if self.current_account not in gajim.connections or \
2407 gajim.connections[self.current_account].connected < 2:
2408 dialogs.ErrorDialog(_('You are not connected to the server'),
2409 _('Without a connection, you can not edit your personal information.'))
2410 return
2412 if not gajim.connections[self.current_account].vcard_supported:
2413 dialogs.ErrorDialog(_("Your server doesn't support Vcard"),
2414 _("Your server can't save your personal information."))
2415 return
2417 gajim.interface.edit_own_details(self.current_account)
2419 def on_checkbutton_toggled(self, widget, config_name,
2420 change_sensitivity_widgets = None, account = None):
2421 if account:
2422 gajim.config.set_per('accounts', account, config_name,
2423 widget.get_active())
2424 else:
2425 gajim.config.set(config_name, widget.get_active())
2426 if change_sensitivity_widgets:
2427 for w in change_sensitivity_widgets:
2428 w.set_sensitive(widget.get_active())
2429 gajim.interface.save_config()
2431 def on_merge_checkbutton_toggled(self, widget):
2432 self.on_checkbutton_toggled(widget, 'mergeaccounts')
2433 if len(gajim.connections) >= 2: # Do not merge accounts if only one active
2434 gajim.interface.roster.regroup = gajim.config.get('mergeaccounts')
2435 else:
2436 gajim.interface.roster.regroup = False
2437 gajim.interface.roster.setup_and_draw_roster()
2439 def _disable_account(self, account):
2440 gajim.interface.roster.close_all(account)
2441 if account == gajim.ZEROCONF_ACC_NAME:
2442 gajim.connections[account].disable_account()
2443 del gajim.connections[account]
2444 gajim.interface.save_config()
2445 del gajim.interface.instances[account]
2446 del gajim.interface.minimized_controls[account]
2447 del gajim.nicks[account]
2448 del gajim.block_signed_in_notifications[account]
2449 del gajim.groups[account]
2450 gajim.contacts.remove_account(account)
2451 del gajim.gc_connected[account]
2452 del gajim.automatic_rooms[account]
2453 del gajim.to_be_removed[account]
2454 del gajim.newly_added[account]
2455 del gajim.sleeper_state[account]
2456 del gajim.encrypted_chats[account]
2457 del gajim.last_message_time[account]
2458 del gajim.status_before_autoaway[account]
2459 del gajim.transport_avatar[account]
2460 del gajim.gajim_optional_features[account]
2461 del gajim.caps_hash[account]
2462 if len(gajim.connections) >= 2:
2463 # Do not merge accounts if only one exists
2464 gajim.interface.roster.regroup = gajim.config.get('mergeaccounts')
2465 else:
2466 gajim.interface.roster.regroup = False
2467 gajim.interface.roster.setup_and_draw_roster()
2468 gajim.interface.roster.set_actions_menu_needs_rebuild()
2470 def _enable_account(self, account):
2471 if account == gajim.ZEROCONF_ACC_NAME:
2472 gajim.connections[account] = connection_zeroconf.ConnectionZeroconf(
2473 account)
2474 if gajim.connections[account].gpg:
2475 self.xml.get_object('gpg_choose_button2').set_sensitive(True)
2476 else:
2477 gajim.connections[account] = common.connection.Connection(account)
2478 if gajim.connections[account].gpg:
2479 self.xml.get_object('gpg_choose_button1').set_sensitive(True)
2480 self.init_account_gpg()
2481 # update variables
2482 gajim.interface.instances[account] = {'infos': {},
2483 'disco': {}, 'gc_config': {}, 'search': {}, 'online_dialog': {}}
2484 gajim.interface.minimized_controls[account] = {}
2485 gajim.connections[account].connected = 0
2486 gajim.groups[account] = {}
2487 gajim.contacts.add_account(account)
2488 gajim.gc_connected[account] = {}
2489 gajim.automatic_rooms[account] = {}
2490 gajim.newly_added[account] = []
2491 gajim.to_be_removed[account] = []
2492 if account == gajim.ZEROCONF_ACC_NAME:
2493 gajim.nicks[account] = gajim.ZEROCONF_ACC_NAME
2494 else:
2495 gajim.nicks[account] = gajim.config.get_per('accounts', account,
2496 'name')
2497 gajim.block_signed_in_notifications[account] = True
2498 gajim.sleeper_state[account] = 'off'
2499 gajim.encrypted_chats[account] = []
2500 gajim.last_message_time[account] = {}
2501 gajim.status_before_autoaway[account] = ''
2502 gajim.transport_avatar[account] = {}
2503 gajim.gajim_optional_features[account] = []
2504 gajim.caps_hash[account] = ''
2505 # refresh roster
2506 if len(gajim.connections) >= 2:
2507 # Do not merge accounts if only one exists
2508 gajim.interface.roster.regroup = gajim.config.get('mergeaccounts')
2509 else:
2510 gajim.interface.roster.regroup = False
2511 gajim.interface.roster.setup_and_draw_roster()
2512 gajim.interface.roster.set_actions_menu_needs_rebuild()
2513 gajim.interface.save_config()
2515 def on_enable_zeroconf_checkbutton2_toggled(self, widget):
2516 # don't do anything if there is an account with the local name but is a
2517 # normal account
2518 if self.ignore_events:
2519 return
2520 if self.current_account in gajim.connections and \
2521 gajim.connections[self.current_account].connected > 0:
2522 self.ignore_events = True
2523 self.xml.get_object('enable_zeroconf_checkbutton2').set_active(True)
2524 self.ignore_events = False
2525 dialogs.ErrorDialog(
2526 _('You are currently connected to the server'),
2527 _('To disable the account, you must be disconnected.'))
2528 return
2529 if gajim.ZEROCONF_ACC_NAME in gajim.connections and not \
2530 gajim.connections[gajim.ZEROCONF_ACC_NAME].is_zeroconf:
2531 gajim.connections[gajim.ZEROCONF_ACC_NAME].dispatch('ERROR',
2532 (_('Account Local already exists.'),
2533 _('Please rename or remove it before enabling link-local messaging'
2534 '.')))
2535 return
2537 if gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME, 'active') \
2538 and not widget.get_active():
2539 self.xml.get_object('zeroconf_notebook').set_sensitive(False)
2540 # disable
2541 self._disable_account(gajim.ZEROCONF_ACC_NAME)
2543 elif not gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME,
2544 'active') and widget.get_active():
2545 self.xml.get_object('zeroconf_notebook').set_sensitive(True)
2546 # enable (will create new account if not present)
2547 self._enable_account(gajim.ZEROCONF_ACC_NAME)
2549 self.on_checkbutton_toggled(widget, 'active',
2550 account=gajim.ZEROCONF_ACC_NAME)
2552 def on_enable_checkbutton1_toggled(self, widget):
2553 if self.ignore_events:
2554 return
2555 if self.current_account in gajim.connections and \
2556 gajim.connections[self.current_account].connected > 0:
2557 # connecting or connected
2558 self.ignore_events = True
2559 self.xml.get_object('enable_checkbutton1').set_active(True)
2560 self.ignore_events = False
2561 dialogs.ErrorDialog(
2562 _('You are currently connected to the server'),
2563 _('To disable the account, you must be disconnected.'))
2564 return
2565 # add/remove account in roster and all variables
2566 if widget.get_active():
2567 # enable
2568 self._enable_account(self.current_account)
2569 else:
2570 # disable
2571 self._disable_account(self.current_account)
2572 self.on_checkbutton_toggled(widget, 'active',
2573 account=self.current_account, change_sensitivity_widgets=[
2574 self.xml.get_object('normal_notebook1')])
2576 def on_custom_port_checkbutton2_toggled(self, widget):
2577 self.xml.get_object('custom_port_entry2').set_sensitive(
2578 widget.get_active())
2579 self.on_checkbutton_toggled(widget, 'use_custom_host',
2580 account = self.current_account)
2581 if not widget.get_active():
2582 self.xml.get_object('custom_port_entry2').set_text('5298')
2584 def on_first_name_entry2_changed(self, widget):
2585 if self.ignore_events:
2586 return
2587 name = widget.get_text().decode('utf-8')
2588 if self.option_changed('zeroconf_first_name', name):
2589 self.need_relogin = True
2590 gajim.config.set_per('accounts', self.current_account,
2591 'zeroconf_first_name', name)
2593 def on_last_name_entry2_changed(self, widget):
2594 if self.ignore_events:
2595 return
2596 name = widget.get_text().decode('utf-8')
2597 if self.option_changed('zeroconf_last_name', name):
2598 self.need_relogin = True
2599 gajim.config.set_per('accounts', self.current_account,
2600 'zeroconf_last_name', name)
2602 def on_jabber_id_entry2_changed(self, widget):
2603 if self.ignore_events:
2604 return
2605 id_ = widget.get_text().decode('utf-8')
2606 if self.option_changed('zeroconf_jabber_id', id_):
2607 self.need_relogin = True
2608 gajim.config.set_per('accounts', self.current_account,
2609 'zeroconf_jabber_id', id_)
2611 def on_email_entry2_changed(self, widget):
2612 if self.ignore_events:
2613 return
2614 email = widget.get_text().decode('utf-8')
2615 if self.option_changed('zeroconf_email', email):
2616 self.need_relogin = True
2617 gajim.config.set_per('accounts', self.current_account,
2618 'zeroconf_email', email)
2620 class FakeDataForm(gtk.Table, object):
2622 Class for forms that are in XML format <entry1>value1</entry1> infos in a
2623 table {entry1: value1}
2626 def __init__(self, infos):
2627 gtk.Table.__init__(self)
2628 self.infos = infos
2629 self.entries = {}
2630 self._draw_table()
2632 def _draw_table(self):
2634 Draw the table
2636 nbrow = 0
2637 if 'instructions' in self.infos:
2638 nbrow = 1
2639 self.resize(rows = nbrow, columns = 2)
2640 label = gtk.Label(self.infos['instructions'])
2641 self.attach(label, 0, 2, 0, 1, 0, 0, 0, 0)
2642 for name in self.infos.keys():
2643 if name in ('key', 'instructions', 'x', 'registered'):
2644 continue
2645 if not name:
2646 continue
2648 nbrow = nbrow + 1
2649 self.resize(rows = nbrow, columns = 2)
2650 label = gtk.Label(name.capitalize() + ':')
2651 self.attach(label, 0, 1, nbrow - 1, nbrow, 0, 0, 0, 0)
2652 entry = gtk.Entry()
2653 entry.set_activates_default(True)
2654 if self.infos[name]:
2655 entry.set_text(self.infos[name])
2656 if name == 'password':
2657 entry.set_visibility(False)
2658 self.attach(entry, 1, 2, nbrow - 1, nbrow, 0, 0, 0, 0)
2659 self.entries[name] = entry
2660 if nbrow == 1:
2661 entry.grab_focus()
2663 def get_infos(self):
2664 for name in self.entries.keys():
2665 self.infos[name] = self.entries[name].get_text().decode('utf-8')
2666 return self.infos
2668 class ServiceRegistrationWindow:
2670 Class for Service registration window. Window that appears when we want to
2671 subscribe to a service if is_form we use dataforms_widget else we use
2672 service_registarion_window
2674 def __init__(self, service, infos, account, is_form):
2675 self.service = service
2676 self.account = account
2677 self.is_form = is_form
2678 self.xml = gtkgui_helpers.get_gtk_builder('service_registration_window.ui')
2679 self.window = self.xml.get_object('service_registration_window')
2680 self.window.set_transient_for(gajim.interface.roster.window)
2681 if self.is_form:
2682 dataform = dataforms.ExtendForm(node = infos)
2683 self.data_form_widget = dataforms_widget.DataFormWidget(dataform)
2684 if self.data_form_widget.title:
2685 self.window.set_title('%s - Gajim' % self.data_form_widget.title)
2686 table = self.xml.get_object('table')
2687 table.attach(self.data_form_widget, 0, 2, 0, 1)
2688 else:
2689 if 'registered' in infos:
2690 self.window.set_title(_('Edit %s') % service)
2691 else:
2692 self.window.set_title(_('Register to %s') % service)
2693 self.data_form_widget = FakeDataForm(infos)
2694 table = self.xml.get_object('table')
2695 table.attach(self.data_form_widget, 0, 2, 0, 1)
2697 self.xml.connect_signals(self)
2698 self.window.show_all()
2700 def on_cancel_button_clicked(self, widget):
2701 self.window.destroy()
2703 def on_ok_button_clicked(self, widget):
2704 # send registration info to the core
2705 if self.is_form:
2706 form = self.data_form_widget.data_form
2707 gajim.connections[self.account].register_agent(self.service,
2708 form, True) # True is for is_form
2709 else:
2710 infos = self.data_form_widget.get_infos()
2711 if 'instructions' in infos:
2712 del infos['instructions']
2713 if 'registered' in infos:
2714 del infos['registered']
2715 gajim.connections[self.account].register_agent(self.service, infos)
2717 self.window.destroy()
2719 class GroupchatConfigWindow:
2721 def __init__(self, account, room_jid, form=None):
2722 self.account = account
2723 self.room_jid = room_jid
2724 self.form = form
2725 self.remove_button = {}
2726 self.affiliation_treeview = {}
2727 self.start_users_dict = {} # list at the beginning
2728 self.affiliation_labels = {'outcast': _('Ban List'),
2729 'member': _('Member List'), 'owner': _('Owner List'),
2730 'admin':_('Administrator List')}
2732 self.xml = gtkgui_helpers.get_gtk_builder('data_form_window.ui',
2733 'data_form_window')
2734 self.window = self.xml.get_object('data_form_window')
2735 self.window.set_transient_for(gajim.interface.roster.window)
2737 if self.form:
2738 config_vbox = self.xml.get_object('config_vbox')
2739 self.data_form_widget = dataforms_widget.DataFormWidget(self.form)
2740 # hide scrollbar of this data_form_widget, we already have in this
2741 # widget
2742 sw = self.data_form_widget.xml.get_object(
2743 'single_form_scrolledwindow')
2744 sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_NEVER)
2745 if self.form.title:
2746 self.xml.get_object('title_label').set_text(self.form.title)
2747 else:
2748 self.xml.get_object('title_hseparator').set_no_show_all(True)
2749 self.xml.get_object('title_hseparator').hide()
2751 self.data_form_widget.show()
2752 config_vbox.pack_start(self.data_form_widget)
2753 else:
2754 self.xml.get_object('title_label').set_no_show_all(True)
2755 self.xml.get_object('title_label').hide()
2756 self.xml.get_object('title_hseparator').set_no_show_all(True)
2757 self.xml.get_object('title_hseparator').hide()
2758 self.xml.get_object('config_hseparator').set_no_show_all(True)
2759 self.xml.get_object('config_hseparator').hide()
2761 # Draw the edit affiliation list things
2762 add_on_vbox = self.xml.get_object('add_on_vbox')
2764 for affiliation in self.affiliation_labels.keys():
2765 self.start_users_dict[affiliation] = {}
2766 hbox = gtk.HBox(spacing=5)
2767 add_on_vbox.pack_start(hbox, False)
2769 label = gtk.Label(self.affiliation_labels[affiliation])
2770 hbox.pack_start(label, False)
2772 bb = gtk.HButtonBox()
2773 bb.set_layout(gtk.BUTTONBOX_END)
2774 bb.set_spacing(5)
2775 hbox.pack_start(bb)
2776 add_button = gtk.Button(stock=gtk.STOCK_ADD)
2777 add_button.connect('clicked', self.on_add_button_clicked,
2778 affiliation)
2779 bb.pack_start(add_button)
2780 self.remove_button[affiliation] = gtk.Button(stock=gtk.STOCK_REMOVE)
2781 self.remove_button[affiliation].set_sensitive(False)
2782 self.remove_button[affiliation].connect('clicked',
2783 self.on_remove_button_clicked, affiliation)
2784 bb.pack_start(self.remove_button[affiliation])
2786 # jid, reason, nick, role
2787 liststore = gtk.ListStore(str, str, str, str)
2788 self.affiliation_treeview[affiliation] = gtk.TreeView(liststore)
2789 self.affiliation_treeview[affiliation].get_selection().set_mode(
2790 gtk.SELECTION_MULTIPLE)
2791 self.affiliation_treeview[affiliation].connect('cursor-changed',
2792 self.on_affiliation_treeview_cursor_changed, affiliation)
2793 renderer = gtk.CellRendererText()
2794 col = gtk.TreeViewColumn(_('JID'), renderer)
2795 col.add_attribute(renderer, 'text', 0)
2796 col.set_resizable(True)
2797 col.set_sort_column_id(0)
2798 self.affiliation_treeview[affiliation].append_column(col)
2800 if affiliation == 'outcast':
2801 renderer = gtk.CellRendererText()
2802 renderer.set_property('editable', True)
2803 renderer.connect('edited', self.on_cell_edited)
2804 col = gtk.TreeViewColumn(_('Reason'), renderer)
2805 col.add_attribute(renderer, 'text', 1)
2806 col.set_resizable(True)
2807 col.set_sort_column_id(1)
2808 self.affiliation_treeview[affiliation].append_column(col)
2809 elif affiliation == 'member':
2810 renderer = gtk.CellRendererText()
2811 col = gtk.TreeViewColumn(_('Nick'), renderer)
2812 col.add_attribute(renderer, 'text', 2)
2813 col.set_resizable(True)
2814 col.set_sort_column_id(2)
2815 self.affiliation_treeview[affiliation].append_column(col)
2816 renderer = gtk.CellRendererText()
2817 col = gtk.TreeViewColumn(_('Role'), renderer)
2818 col.add_attribute(renderer, 'text', 3)
2819 col.set_resizable(True)
2820 col.set_sort_column_id(3)
2821 self.affiliation_treeview[affiliation].append_column(col)
2823 sw = gtk.ScrolledWindow()
2824 sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_NEVER)
2825 sw.add(self.affiliation_treeview[affiliation])
2826 add_on_vbox.pack_start(sw)
2827 gajim.connections[self.account].get_affiliation_list(self.room_jid,
2828 affiliation)
2830 self.xml.connect_signals(self)
2831 self.window.show_all()
2833 def on_cancel_button_clicked(self, widget):
2834 self.window.destroy()
2836 def on_cell_edited(self, cell, path, new_text):
2837 model = self.affiliation_treeview['outcast'].get_model()
2838 new_text = new_text.decode('utf-8')
2839 iter_ = model.get_iter(path)
2840 model[iter_][1] = new_text
2842 def on_add_button_clicked(self, widget, affiliation):
2843 if affiliation == 'outcast':
2844 title = _('Banning...')
2845 #You can move '\n' before user@domain if that line is TOO BIG
2846 prompt = _('<b>Whom do you want to ban?</b>\n\n')
2847 elif affiliation == 'member':
2848 title = _('Adding Member...')
2849 prompt = _('<b>Whom do you want to make a member?</b>\n\n')
2850 elif affiliation == 'owner':
2851 title = _('Adding Owner...')
2852 prompt = _('<b>Whom do you want to make an owner?</b>\n\n')
2853 else:
2854 title = _('Adding Administrator...')
2855 prompt = _('<b>Whom do you want to make an administrator?</b>\n\n')
2856 prompt += _('Can be one of the following:\n'
2857 '1. user@domain/resource (only that resource matches).\n'
2858 '2. user@domain (any resource matches).\n'
2859 '3. domain/resource (only that resource matches).\n'
2860 '4. domain (the domain itself matches, as does any user@domain,\n'
2861 'domain/resource, or address containing a subdomain).')
2863 def on_ok(jid):
2864 if not jid:
2865 return
2866 model = self.affiliation_treeview[affiliation].get_model()
2867 model.append((jid, '', '', ''))
2868 dialogs.InputDialog(title, prompt, ok_handler=on_ok)
2870 def on_remove_button_clicked(self, widget, affiliation):
2871 selection = self.affiliation_treeview[affiliation].get_selection()
2872 model, paths = selection.get_selected_rows()
2873 row_refs = []
2874 for path in paths:
2875 row_refs.append(gtk.TreeRowReference(model, path))
2876 for row_ref in row_refs:
2877 path = row_ref.get_path()
2878 iter_ = model.get_iter(path)
2879 model.remove(iter_)
2880 self.remove_button[affiliation].set_sensitive(False)
2882 def on_affiliation_treeview_cursor_changed(self, widget, affiliation):
2883 self.remove_button[affiliation].set_sensitive(True)
2885 def affiliation_list_received(self, users_dict):
2887 Fill the affiliation treeview
2889 for jid in users_dict:
2890 affiliation = users_dict[jid]['affiliation']
2891 if affiliation not in self.affiliation_labels.keys():
2892 # Unknown affiliation or 'none' affiliation, do not show it
2893 continue
2894 self.start_users_dict[affiliation][jid] = users_dict[jid]
2895 tv = self.affiliation_treeview[affiliation]
2896 model = tv.get_model()
2897 reason = users_dict[jid].get('reason', '')
2898 nick = users_dict[jid].get('nick', '')
2899 role = users_dict[jid].get('role', '')
2900 model.append((jid, reason, nick, role))
2902 def on_data_form_window_destroy(self, widget):
2903 del gajim.interface.instances[self.account]['gc_config'][self.room_jid]
2905 def on_ok_button_clicked(self, widget):
2906 if self.form:
2907 form = self.data_form_widget.data_form
2908 gajim.connections[self.account].send_gc_config(self.room_jid, form)
2909 for affiliation in self.affiliation_labels.keys():
2910 users_dict = {}
2911 actual_jid_list = []
2912 model = self.affiliation_treeview[affiliation].get_model()
2913 iter_ = model.get_iter_first()
2914 # add new jid
2915 while iter_:
2916 jid = model[iter_][0].decode('utf-8')
2917 actual_jid_list.append(jid)
2918 if jid not in self.start_users_dict[affiliation] or \
2919 (affiliation == 'outcast' and 'reason' in self.start_users_dict[
2920 affiliation][jid] and self.start_users_dict[affiliation][jid]\
2921 ['reason'] != model[iter_][1].decode('utf-8')):
2922 users_dict[jid] = {'affiliation': affiliation}
2923 if affiliation == 'outcast':
2924 users_dict[jid]['reason'] = model[iter_][1].decode(
2925 'utf-8')
2926 iter_ = model.iter_next(iter_)
2927 # remove removed one
2928 for jid in self.start_users_dict[affiliation]:
2929 if jid not in actual_jid_list:
2930 users_dict[jid] = {'affiliation': 'none'}
2931 if users_dict:
2932 gajim.connections[self.account].send_gc_affiliation_list(
2933 self.room_jid, users_dict)
2934 self.window.destroy()
2936 #---------- RemoveAccountWindow class -------------#
2937 class RemoveAccountWindow:
2939 Ask for removing from gajim only or from gajim and server too and do
2940 removing of the account given
2943 def on_remove_account_window_destroy(self, widget):
2944 if self.account in gajim.interface.instances:
2945 del gajim.interface.instances[self.account]['remove_account']
2947 def on_cancel_button_clicked(self, widget):
2948 self.window.destroy()
2950 def __init__(self, account):
2951 self.account = account
2952 xml = gtkgui_helpers.get_gtk_builder('remove_account_window.ui')
2953 self.window = xml.get_object('remove_account_window')
2954 self.window.set_transient_for(gajim.interface.roster.window)
2955 self.remove_and_unregister_radiobutton = xml.get_object(
2956 'remove_and_unregister_radiobutton')
2957 self.window.set_title(_('Removing %s account') % self.account)
2958 xml.connect_signals(self)
2959 self.window.show_all()
2961 def on_remove_button_clicked(self, widget):
2962 def remove():
2963 if self.account in gajim.connections and \
2964 gajim.connections[self.account].connected and \
2965 not self.remove_and_unregister_radiobutton.get_active():
2966 # change status to offline only if we will not remove this JID from
2967 # server
2968 gajim.connections[self.account].change_status('offline', 'offline')
2969 if self.remove_and_unregister_radiobutton.get_active():
2970 if not self.account in gajim.connections:
2971 dialogs.ErrorDialog(
2972 _('Account is disabled'),
2973 _('To unregister from a server, account must be '
2974 'enabled.'))
2975 return
2976 if not gajim.connections[self.account].password:
2977 def on_ok(passphrase, checked):
2978 if passphrase == -1:
2979 # We don't remove account cause we canceled pw window
2980 return
2981 gajim.connections[self.account].password = passphrase
2982 gajim.connections[self.account].unregister_account(
2983 self._on_remove_success)
2985 dialogs.PassphraseDialog(
2986 _('Password Required'),
2987 _('Enter your password for account %s') % self.account,
2988 _('Save password'), ok_handler=on_ok)
2989 return
2990 gajim.connections[self.account].unregister_account(
2991 self._on_remove_success)
2992 else:
2993 self._on_remove_success(True)
2995 if self.account in gajim.connections and \
2996 gajim.connections[self.account].connected:
2997 dialogs.ConfirmationDialog(
2998 _('Account "%s" is connected to the server') % self.account,
2999 _('If you remove it, the connection will be lost.'),
3000 on_response_ok=remove)
3001 else:
3002 remove()
3004 def on_remove_responce_ok(self, is_checked):
3005 if is_checked[0]:
3006 self._on_remove_success(True)
3008 def _on_remove_success(self, res):
3009 # action of unregistration has failed, we don't remove the account
3010 # Error message is send by connect_and_auth()
3011 if not res:
3012 dialogs.ConfirmationDialogDoubleRadio(
3013 _('Connection to server %s failed') % self.account,
3014 _('What would you like to do?'),
3015 _('Remove only from Gajim'),
3016 _('Don\'t remove anything. I\'ll try again later'),
3017 on_response_ok=self.on_remove_responce_ok, is_modal=False)
3018 return
3019 # Close all opened windows
3020 gajim.interface.roster.close_all(self.account, force=True)
3021 if self.account in gajim.connections:
3022 gajim.connections[self.account].disconnect(on_purpose=True)
3023 gajim.connections[self.account].cleanup()
3024 del gajim.connections[self.account]
3025 gajim.logger.remove_roster(gajim.get_jid_from_account(self.account))
3026 gajim.config.del_per('accounts', self.account)
3027 gajim.interface.save_config()
3028 del gajim.interface.instances[self.account]
3029 if self.account in gajim.nicks:
3030 del gajim.interface.minimized_controls[self.account]
3031 del gajim.nicks[self.account]
3032 del gajim.block_signed_in_notifications[self.account]
3033 del gajim.groups[self.account]
3034 gajim.contacts.remove_account(self.account)
3035 del gajim.gc_connected[self.account]
3036 del gajim.automatic_rooms[self.account]
3037 del gajim.to_be_removed[self.account]
3038 del gajim.newly_added[self.account]
3039 del gajim.sleeper_state[self.account]
3040 del gajim.encrypted_chats[self.account]
3041 del gajim.last_message_time[self.account]
3042 del gajim.status_before_autoaway[self.account]
3043 del gajim.transport_avatar[self.account]
3044 del gajim.gajim_optional_features[self.account]
3045 del gajim.caps_hash[self.account]
3046 if len(gajim.connections) >= 2: # Do not merge accounts if only one exists
3047 gajim.interface.roster.regroup = gajim.config.get('mergeaccounts')
3048 else:
3049 gajim.interface.roster.regroup = False
3050 gajim.interface.roster.setup_and_draw_roster()
3051 gajim.interface.roster.set_actions_menu_needs_rebuild()
3052 if 'accounts' in gajim.interface.instances:
3053 gajim.interface.instances['accounts'].init_accounts()
3054 gajim.interface.instances['accounts'].init_account()
3055 self.window.destroy()
3057 #---------- ManageBookmarksWindow class -------------#
3058 class ManageBookmarksWindow:
3059 def __init__(self):
3060 self.xml = gtkgui_helpers.get_gtk_builder('manage_bookmarks_window.ui')
3061 self.window = self.xml.get_object('manage_bookmarks_window')
3062 self.window.set_transient_for(gajim.interface.roster.window)
3064 # Account-JID, RoomName, Room-JID, Autojoin, Minimize, Passowrd, Nick,
3065 # Show_Status
3066 self.treestore = gtk.TreeStore(str, str, str, bool, bool, str, str, str)
3067 self.treestore.set_sort_column_id(1, gtk.SORT_ASCENDING)
3069 # Store bookmarks in treeview.
3070 for account in gajim.connections:
3071 if gajim.connections[account].connected <= 1:
3072 continue
3073 if gajim.connections[account].is_zeroconf:
3074 continue
3075 if not gajim.connections[account].private_storage_supported:
3076 continue
3077 iter_ = self.treestore.append(None, [None, account, None, None,
3078 None, None, None, None])
3080 for bookmark in gajim.connections[account].bookmarks:
3081 if bookmark['name'] == '':
3082 # No name was given for this bookmark.
3083 # Use the first part of JID instead...
3084 name = bookmark['jid'].split("@")[0]
3085 bookmark['name'] = name
3087 # make '1', '0', 'true', 'false' (or other) to True/False
3088 autojoin = helpers.from_xs_boolean_to_python_boolean(
3089 bookmark['autojoin'])
3091 minimize = helpers.from_xs_boolean_to_python_boolean(
3092 bookmark['minimize'])
3094 print_status = bookmark.get('print_status', '')
3095 if print_status not in ('', 'all', 'in_and_out', 'none'):
3096 print_status = ''
3097 self.treestore.append(iter_, [
3098 account,
3099 bookmark['name'],
3100 bookmark['jid'],
3101 autojoin,
3102 minimize,
3103 bookmark['password'],
3104 bookmark['nick'],
3105 print_status ])
3107 self.print_status_combobox = self.xml.get_object('print_status_combobox')
3108 model = gtk.ListStore(str, str)
3110 self.option_list = {'': _('Default'), 'all': Q_('?print_status:All'),
3111 'in_and_out': _('Enter and leave only'),
3112 'none': Q_('?print_status:None')}
3113 opts = sorted(self.option_list.keys())
3114 for opt in opts:
3115 model.append([self.option_list[opt], opt])
3117 self.print_status_combobox.set_model(model)
3118 self.print_status_combobox.set_active(1)
3120 self.view = self.xml.get_object('bookmarks_treeview')
3121 self.view.set_model(self.treestore)
3122 self.view.expand_all()
3124 renderer = gtk.CellRendererText()
3125 column = gtk.TreeViewColumn('Bookmarks', renderer, text=1)
3126 self.view.append_column(column)
3128 self.selection = self.view.get_selection()
3129 self.selection.connect('changed', self.bookmark_selected)
3131 #Prepare input fields
3132 self.title_entry = self.xml.get_object('title_entry')
3133 self.title_entry.connect('changed', self.on_title_entry_changed)
3134 self.nick_entry = self.xml.get_object('nick_entry')
3135 self.nick_entry.connect('changed', self.on_nick_entry_changed)
3136 self.server_entry = self.xml.get_object('server_entry')
3137 self.server_entry.connect('changed', self.on_server_entry_changed)
3138 self.room_entry = self.xml.get_object('room_entry')
3139 self.room_entry.connect('changed', self.on_room_entry_changed)
3140 self.pass_entry = self.xml.get_object('pass_entry')
3141 self.pass_entry.connect('changed', self.on_pass_entry_changed)
3142 self.autojoin_checkbutton = self.xml.get_object('autojoin_checkbutton')
3143 self.minimize_checkbutton = self.xml.get_object('minimize_checkbutton')
3145 self.xml.connect_signals(self)
3146 self.window.show_all()
3147 # select root iter
3148 self.selection.select_iter(self.treestore.get_iter_root())
3150 def on_bookmarks_treeview_button_press_event(self, widget, event):
3151 (model, iter_) = self.selection.get_selected()
3152 if not iter_:
3153 # Removed a bookmark before
3154 return
3156 if model.iter_parent(iter_):
3157 # The currently selected node is a bookmark
3158 return not self.check_valid_bookmark()
3160 def on_manage_bookmarks_window_destroy(self, widget, event):
3161 del gajim.interface.instances['manage_bookmarks']
3163 def on_add_bookmark_button_clicked(self, widget):
3165 Add a new bookmark
3167 # Get the account that is currently used
3168 # (the parent of the currently selected item)
3169 (model, iter_) = self.selection.get_selected()
3170 if not iter_: # Nothing selected, do nothing
3171 return
3173 parent = model.iter_parent(iter_)
3175 if parent:
3176 # We got a bookmark selected, so we add_to the parent
3177 add_to = parent
3178 else:
3179 # No parent, so we got an account -> add to this.
3180 add_to = iter_
3182 account = model[add_to][1].decode('utf-8')
3183 nick = gajim.nicks[account]
3184 iter_ = self.treestore.append(add_to, [account, _('New Group Chat'),
3185 '@', False, False, '', nick, 'in_and_out'])
3187 self.view.expand_row(model.get_path(add_to), True)
3188 self.view.set_cursor(model.get_path(iter_))
3190 def on_remove_bookmark_button_clicked(self, widget):
3192 Remove selected bookmark
3194 (model, iter_) = self.selection.get_selected()
3195 if not iter_: # Nothing selected
3196 return
3198 if not model.iter_parent(iter_):
3199 # Don't remove account iters
3200 return
3202 model.remove(iter_)
3203 self.clear_fields()
3205 def check_valid_bookmark(self):
3207 Check if all neccessary fields are entered correctly
3209 (model, iter_) = self.selection.get_selected()
3211 if not model.iter_parent(iter_):
3212 #Account data can't be changed
3213 return
3215 if self.server_entry.get_text().decode('utf-8') == '' or \
3216 self.room_entry.get_text().decode('utf-8') == '':
3217 dialogs.ErrorDialog(_('This bookmark has invalid data'),
3218 _('Please be sure to fill out server and room fields or remove this'
3219 ' bookmark.'))
3220 return False
3222 return True
3224 def on_ok_button_clicked(self, widget):
3226 Parse the treestore data into our new bookmarks array, then send the new
3227 bookmarks to the server.
3229 (model, iter_) = self.selection.get_selected()
3230 if iter_ and model.iter_parent(iter_):
3231 #bookmark selected, check it
3232 if not self.check_valid_bookmark():
3233 return
3235 for account in self.treestore:
3236 account_unicode = account[1].decode('utf-8')
3237 gajim.connections[account_unicode].bookmarks = []
3239 for bm in account.iterchildren():
3240 # Convert True/False/None to '1' or '0'
3241 autojoin = unicode(int(bm[3]))
3242 minimize = unicode(int(bm[4]))
3243 name = bm[1]
3244 if name:
3245 name = name.decode('utf-8')
3246 jid = bm[2]
3247 if jid:
3248 jid = jid.decode('utf-8')
3249 pw = bm[5]
3250 if pw:
3251 pw = pw.decode('utf-8')
3252 nick = bm[6]
3253 if nick:
3254 nick = nick.decode('utf-8')
3256 # create the bookmark-dict
3257 bmdict = { 'name': name, 'jid': jid, 'autojoin': autojoin,
3258 'minimize': minimize, 'password': pw, 'nick': nick,
3259 'print_status': bm[7]}
3261 gajim.connections[account_unicode].bookmarks.append(bmdict)
3263 gajim.connections[account_unicode].store_bookmarks()
3264 gajim.interface.roster.set_actions_menu_needs_rebuild()
3265 self.window.destroy()
3267 def on_cancel_button_clicked(self, widget):
3268 self.window.destroy()
3270 def bookmark_selected(self, selection):
3272 Fill in the bookmark's data into the fields.
3274 (model, iter_) = selection.get_selected()
3276 if not iter_:
3277 # After removing the last bookmark for one account
3278 # this will be None, so we will just:
3279 return
3281 widgets = [ self.title_entry, self.nick_entry, self.room_entry,
3282 self.server_entry, self.pass_entry, self.autojoin_checkbutton,
3283 self.minimize_checkbutton, self.print_status_combobox]
3285 if model.iter_parent(iter_):
3286 # make the fields sensitive
3287 for field in widgets:
3288 field.set_sensitive(True)
3289 else:
3290 # Top-level has no data (it's the account fields)
3291 # clear fields & make them insensitive
3292 self.clear_fields()
3293 for field in widgets:
3294 field.set_sensitive(False)
3295 return
3297 # Fill in the data for childs
3298 self.title_entry.set_text(model[iter_][1])
3299 room_jid = model[iter_][2].decode('utf-8')
3300 (room, server) = room_jid.split('@')
3301 self.room_entry.set_text(room)
3302 self.server_entry.set_text(server)
3304 self.autojoin_checkbutton.set_active(model[iter_][3])
3305 self.minimize_checkbutton.set_active(model[iter_][4])
3306 # sensitive only if auto join is checked
3307 self.minimize_checkbutton.set_sensitive(model[iter_][3])
3309 if model[iter_][5] is not None:
3310 password = model[iter_][5].decode('utf-8')
3311 else:
3312 password = None
3314 if password:
3315 self.pass_entry.set_text(password)
3316 else:
3317 self.pass_entry.set_text('')
3318 nick = model[iter_][6]
3319 if nick:
3320 nick = nick.decode('utf-8')
3321 self.nick_entry.set_text(nick)
3322 else:
3323 self.nick_entry.set_text('')
3325 print_status = model[iter_][7]
3326 opts = sorted(self.option_list.keys())
3327 self.print_status_combobox.set_active(opts.index(print_status))
3329 def on_title_entry_changed(self, widget):
3330 (model, iter_) = self.selection.get_selected()
3331 if iter_: # After removing a bookmark, we got nothing selected
3332 if model.iter_parent(iter_):
3333 # Don't clear the title field for account nodes
3334 model[iter_][1] = self.title_entry.get_text()
3336 def on_nick_entry_changed(self, widget):
3337 (model, iter_) = self.selection.get_selected()
3338 if iter_:
3339 nick = self.nick_entry.get_text().decode('utf-8')
3340 try:
3341 nick = helpers.parse_resource(nick)
3342 except helpers.InvalidFormat, e:
3343 dialogs.ErrorDialog(_('Invalid nickname'),
3344 _('Character not allowed'))
3345 self.nick_entry.set_text(model[iter_][6])
3346 return True
3347 model[iter_][6] = nick
3349 def on_server_entry_changed(self, widget):
3350 (model, iter_) = self.selection.get_selected()
3351 if not iter_:
3352 return
3353 server = widget.get_text().decode('utf-8')
3354 if '@' in server:
3355 dialogs.ErrorDialog(_('Invalid server'), _('Character not allowed'))
3356 widget.set_text(server.replace('@', ''))
3358 room_jid = self.room_entry.get_text().decode('utf-8').strip() + '@' + \
3359 server.strip()
3360 try:
3361 room_jid = helpers.parse_resource(room_jid)
3362 except helpers.InvalidFormat, e:
3363 dialogs.ErrorDialog(_('Invalid server'),
3364 _('Character not allowed'))
3365 self.server_entry.set_text(model[iter_][2].split('@')[1])
3366 return True
3367 model[iter_][2] = room_jid
3369 def on_room_entry_changed(self, widget):
3370 (model, iter_) = self.selection.get_selected()
3371 if not iter_:
3372 return
3373 room = widget.get_text().decode('utf-8')
3374 if '@' in room:
3375 dialogs.ErrorDialog(_('Invalid server'), _('Character not allowed'))
3376 widget.set_text(room.replace('@', ''))
3377 room_jid = room.strip() + '@' + \
3378 self.server_entry.get_text().decode('utf-8').strip()
3379 try:
3380 room_jid = helpers.parse_resource(room_jid)
3381 except helpers.InvalidFormat, e:
3382 dialogs.ErrorDialog(_('Invalid room'),
3383 _('Character not allowed'))
3384 self.room_entry.set_text(model[iter_][2].split('@')[0])
3385 return True
3386 model[iter_][2] = room_jid
3388 def on_pass_entry_changed(self, widget):
3389 (model, iter_) = self.selection.get_selected()
3390 if iter_:
3391 model[iter_][5] = self.pass_entry.get_text()
3393 def on_autojoin_checkbutton_toggled(self, widget):
3394 (model, iter_) = self.selection.get_selected()
3395 if iter_:
3396 model[iter_][3] = self.autojoin_checkbutton.get_active()
3397 self.minimize_checkbutton.set_sensitive(model[iter_][3])
3399 def on_minimize_checkbutton_toggled(self, widget):
3400 (model, iter_) = self.selection.get_selected()
3401 if iter_:
3402 model[iter_][4] = self.minimize_checkbutton.get_active()
3404 def on_print_status_combobox_changed(self, widget):
3405 active = widget.get_active()
3406 model = widget.get_model()
3407 print_status = model[active][1]
3408 (model2, iter_) = self.selection.get_selected()
3409 if iter_:
3410 model2[iter_][7] = print_status
3412 def clear_fields(self):
3413 widgets = [ self.title_entry, self.nick_entry, self.room_entry,
3414 self.server_entry, self.pass_entry ]
3415 for field in widgets:
3416 field.set_text('')
3417 self.autojoin_checkbutton.set_active(False)
3418 self.minimize_checkbutton.set_active(False)
3419 self.print_status_combobox.set_active(1)
3421 class AccountCreationWizardWindow:
3422 def __init__(self):
3423 self.xml = gtkgui_helpers.get_gtk_builder(
3424 'account_creation_wizard_window.ui')
3425 self.window = self.xml.get_object('account_creation_wizard_window')
3426 self.window.set_transient_for(gajim.interface.roster.window)
3428 completion = gtk.EntryCompletion()
3429 completion1 = gtk.EntryCompletion()
3430 # Connect events from comboboxentry.child
3431 server_comboboxentry = self.xml.get_object('server_comboboxentry')
3432 entry = server_comboboxentry.child
3433 entry.connect('key_press_event',
3434 self.on_server_comboboxentry_key_press_event, server_comboboxentry)
3435 entry.set_completion(completion)
3436 # Do the same for the other server comboboxentry
3437 server_comboboxentry1 = self.xml.get_object('server_comboboxentry1')
3438 entry = server_comboboxentry1.child
3439 entry.set_completion(completion1)
3441 self.update_proxy_list()
3443 # parse servers.xml
3444 servers_xml = os.path.join(gajim.DATA_DIR, 'other', 'servers.xml')
3445 servers = gtkgui_helpers.parse_server_xml(servers_xml)
3446 servers_model = gtk.ListStore(str)
3447 for server in servers:
3448 servers_model.append((server,))
3450 completion.set_model(servers_model)
3451 completion.set_text_column(0)
3452 completion1.set_model(servers_model)
3453 completion1.set_text_column(0)
3455 # Put servers into comboboxentries
3456 server_comboboxentry.set_model(servers_model)
3457 server_comboboxentry.set_text_column(0)
3458 server_comboboxentry1.set_model(servers_model)
3459 server_comboboxentry1.set_text_column(0)
3461 # Generic widgets
3462 self.notebook = self.xml.get_object('notebook')
3463 self.cancel_button = self.xml.get_object('cancel_button')
3464 self.back_button = self.xml.get_object('back_button')
3465 self.forward_button = self.xml.get_object('forward_button')
3466 self.finish_button = self.xml.get_object('finish_button')
3467 self.advanced_button = self.xml.get_object('advanced_button')
3468 self.finish_label = self.xml.get_object('finish_label')
3469 self.go_online_checkbutton = self.xml.get_object(
3470 'go_online_checkbutton')
3471 self.show_vcard_checkbutton = self.xml.get_object(
3472 'show_vcard_checkbutton')
3473 self.progressbar = self.xml.get_object('progressbar')
3475 # some vars
3476 self.update_progressbar_timeout_id = None
3478 self.notebook.set_current_page(0)
3479 self.xml.connect_signals(self)
3480 self.window.show_all()
3481 gajim.ged.register_event_handler('new-account-connected', ged.GUI1,
3482 self._nec_new_acc_connected)
3483 gajim.ged.register_event_handler('new-account-not-connected', ged.GUI1,
3484 self._nec_new_acc_not_connected)
3485 gajim.ged.register_event_handler('account-created', ged.GUI1,
3486 self._nec_acc_is_ok)
3487 gajim.ged.register_event_handler('account-not-created', ged.GUI1,
3488 self._nec_acc_is_not_ok)
3490 def on_wizard_window_destroy(self, widget):
3491 page = self.notebook.get_current_page()
3492 if page in (4, 5) and self.account in gajim.connections:
3493 # connection instance is saved in gajim.connections and we canceled
3494 # the addition of the account
3495 del gajim.connections[self.account]
3496 if self.account in gajim.config.get_per('accounts'):
3497 gajim.config.del_per('accounts', self.account)
3498 gajim.ged.remove_event_handler('new-account-connected', ged.GUI1,
3499 self._nec_new_acc_connected)
3500 gajim.ged.remove_event_handler('new-account-not-connected', ged.GUI1,
3501 self._nec_new_acc_not_connected)
3502 gajim.ged.remove_event_handler('account-created', ged.GUI1,
3503 self._nec_acc_is_ok)
3504 gajim.ged.remove_event_handler('account-not-created', ged.GUI1,
3505 self._nec_acc_is_not_ok)
3506 del gajim.interface.instances['account_creation_wizard']
3508 def on_register_server_features_button_clicked(self, widget):
3509 helpers.launch_browser_mailer('url',
3510 'http://www.jabber.org/network/oldnetwork.shtml')
3512 def on_save_password_checkbutton_toggled(self, widget):
3513 self.xml.get_object('password_entry').grab_focus()
3515 def on_cancel_button_clicked(self, widget):
3516 self.window.destroy()
3518 def on_back_button_clicked(self, widget):
3519 cur_page = self.notebook.get_current_page()
3520 if cur_page in (1, 2):
3521 self.notebook.set_current_page(0)
3522 self.back_button.set_sensitive(False)
3523 elif cur_page == 3:
3524 self.xml.get_object('form_vbox').remove(self.data_form_widget)
3525 self.notebook.set_current_page(2) # show server page
3526 elif cur_page == 4:
3527 if self.account in gajim.connections:
3528 del gajim.connections[self.account]
3529 self.notebook.set_current_page(2)
3530 self.xml.get_object('form_vbox').remove(self.data_form_widget)
3531 elif cur_page == 6: # finish page
3532 self.forward_button.show()
3533 if self.modify:
3534 self.notebook.set_current_page(1) # Go to parameters page
3535 else:
3536 self.notebook.set_current_page(2) # Go to server page
3538 def on_anonymous_checkbutton1_toggled(self, widget):
3539 active = widget.get_active()
3540 self.xml.get_object('username_entry').set_sensitive(not active)
3541 self.xml.get_object('password_entry').set_sensitive(not active)
3542 self.xml.get_object('save_password_checkbutton').set_sensitive(
3543 not active)
3545 def show_finish_page(self):
3546 self.cancel_button.hide()
3547 self.back_button.hide()
3548 self.forward_button.hide()
3549 if self.modify:
3550 finish_text = '<big><b>%s</b></big>\n\n%s' % (
3551 _('Account has been added successfully'),
3552 _('You can set advanced account options by pressing the '
3553 'Advanced button, or later by choosing the Accounts menu item '
3554 'under the Edit menu from the main window.'))
3555 else:
3556 finish_text = '<big><b>%s</b></big>\n\n%s' % (
3557 _('Your new account has been created successfully'),
3558 _('You can set advanced account options by pressing the '
3559 'Advanced button, or later by choosing the Accounts menu item '
3560 'under the Edit menu from the main window.'))
3561 self.finish_label.set_markup(finish_text)
3562 self.finish_button.show()
3563 self.finish_button.set_property('has-default', True)
3564 self.advanced_button.show()
3565 self.go_online_checkbutton.show()
3566 img = self.xml.get_object('finish_image')
3567 if self.modify:
3568 img.set_from_stock(gtk.STOCK_APPLY, gtk.ICON_SIZE_DIALOG)
3569 else:
3570 path_to_file = gtkgui_helpers.get_icon_path('gajim', 48)
3571 img.set_from_file(path_to_file)
3572 self.show_vcard_checkbutton.set_active(not self.modify)
3573 self.notebook.set_current_page(6) # show finish page
3575 def on_forward_button_clicked(self, widget):
3576 cur_page = self.notebook.get_current_page()
3578 if cur_page == 0:
3579 widget = self.xml.get_object('use_existing_account_radiobutton')
3580 if widget.get_active():
3581 self.modify = True
3582 self.notebook.set_current_page(1)
3583 else:
3584 self.modify = False
3585 self.notebook.set_current_page(2)
3586 self.back_button.set_sensitive(True)
3587 return
3589 elif cur_page == 1:
3590 # We are adding an existing account
3591 anonymous = self.xml.get_object('anonymous_checkbutton1').\
3592 get_active()
3593 username = self.xml.get_object('username_entry').get_text().decode(
3594 'utf-8').strip()
3595 if not username and not anonymous:
3596 pritext = _('Invalid username')
3597 sectext = _(
3598 'You must provide a username to configure this account.')
3599 dialogs.ErrorDialog(pritext, sectext)
3600 return
3601 server = self.xml.get_object('server_comboboxentry').child.\
3602 get_text().decode('utf-8').strip()
3603 savepass = self.xml.get_object('save_password_checkbutton').\
3604 get_active()
3605 password = self.xml.get_object('password_entry').get_text().decode(
3606 'utf-8')
3608 jid = username + '@' + server
3609 # check if jid is conform to RFC and stringprep it
3610 try:
3611 jid = helpers.parse_jid(jid)
3612 except helpers.InvalidFormat, s:
3613 pritext = _('Invalid Jabber ID')
3614 dialogs.ErrorDialog(pritext, str(s))
3615 return
3617 self.account = server
3618 i = 1
3619 while self.account in gajim.connections:
3620 self.account = server + str(i)
3621 i += 1
3623 username, server = gajim.get_name_and_server_from_jid(jid)
3624 if self.xml.get_object('anonymous_checkbutton1').get_active():
3625 self.save_account('', server, False, '', anonymous=True)
3626 else:
3627 self.save_account(username, server, savepass, password)
3628 self.show_finish_page()
3629 elif cur_page == 2:
3630 # We are creating a new account
3631 server = self.xml.get_object('server_comboboxentry1').child.\
3632 get_text().decode('utf-8')
3634 if not server:
3635 dialogs.ErrorDialog(_('Invalid server'),
3636 _('Please provide a server on which you want to register.'))
3637 return
3638 self.account = server
3639 i = 1
3640 while self.account in gajim.connections:
3641 self.account = server + str(i)
3642 i += 1
3644 config = self.get_config('', server, '', '')
3645 # Get advanced options
3646 proxies_combobox = self.xml.get_object('proxies_combobox')
3647 active = proxies_combobox.get_active()
3648 proxy = proxies_combobox.get_model()[active][0].decode('utf-8')
3649 if proxy == _('None'):
3650 proxy = ''
3651 config['proxy'] = proxy
3653 config['use_custom_host'] = self.xml.get_object(
3654 'custom_host_port_checkbutton').get_active()
3655 custom_port = self.xml.get_object('custom_port_entry').get_text()
3656 try:
3657 custom_port = int(custom_port)
3658 except Exception:
3659 dialogs.ErrorDialog(_('Invalid entry'),
3660 _('Custom port must be a port number.'))
3661 return
3662 config['custom_port'] = custom_port
3663 config['custom_host'] = self.xml.get_object(
3664 'custom_host_entry').get_text().decode('utf-8')
3666 if self.xml.get_object('anonymous_checkbutton2').get_active():
3667 self.modify = True
3668 self.save_account('', server, False, '', anonymous=True)
3669 self.show_finish_page()
3670 else:
3671 self.notebook.set_current_page(5) # show creating page
3672 self.back_button.hide()
3673 self.forward_button.hide()
3674 self.update_progressbar_timeout_id = gobject.timeout_add(100,
3675 self.update_progressbar)
3676 # Get form from serveur
3677 con = connection.Connection(self.account)
3678 gajim.connections[self.account] = con
3679 con.new_account(self.account, config)
3680 elif cur_page == 3:
3681 checked = self.xml.get_object('ssl_checkbutton').get_active()
3682 if checked:
3683 hostname = gajim.connections[self.account].new_account_info[
3684 'hostname']
3685 # Check if cert is already in file
3686 certs = ''
3687 if os.path.isfile(gajim.MY_CACERTS):
3688 f = open(gajim.MY_CACERTS)
3689 certs = f.read()
3690 f.close()
3691 if self.ssl_cert in certs:
3692 dialogs.ErrorDialog(_('Certificate Already in File'),
3693 _('This certificate is already in file %s, so it\'s '
3694 'not added again.') % gajim.MY_CACERTS)
3695 else:
3696 f = open(gajim.MY_CACERTS, 'a')
3697 f.write(hostname + '\n')
3698 f.write(self.ssl_cert + '\n\n')
3699 f.close()
3700 gajim.connections[self.account].new_account_info[
3701 'ssl_fingerprint_sha1'] = self.ssl_fingerprint
3702 self.notebook.set_current_page(4) # show fom page
3703 elif cur_page == 4:
3704 if self.is_form:
3705 form = self.data_form_widget.data_form
3706 else:
3707 form = self.data_form_widget.get_infos()
3708 gajim.connections[self.account].send_new_account_infos(form,
3709 self.is_form)
3710 self.xml.get_object('form_vbox').remove(self.data_form_widget)
3711 self.xml.get_object('progressbar_label').set_markup(
3712 '<b>Account is being created</b>\n\nPlease wait...')
3713 self.notebook.set_current_page(5) # show creating page
3714 self.back_button.hide()
3715 self.forward_button.hide()
3716 self.update_progressbar_timeout_id = gobject.timeout_add(100,
3717 self.update_progressbar)
3719 def update_proxy_list(self):
3720 proxies_combobox = self.xml.get_object('proxies_combobox')
3721 model = gtk.ListStore(str)
3722 proxies_combobox.set_model(model)
3723 l = gajim.config.get_per('proxies')
3724 l.insert(0, _('None'))
3725 for i in xrange(len(l)):
3726 model.append([l[i]])
3727 proxies_combobox.set_active(0)
3729 def on_manage_proxies_button_clicked(self, widget):
3730 if 'manage_proxies' in gajim.interface.instances:
3731 gajim.interface.instances['manage_proxies'].window.present()
3732 else:
3733 gajim.interface.instances['manage_proxies'] = \
3734 ManageProxiesWindow()
3736 def on_custom_host_port_checkbutton_toggled(self, widget):
3737 self.xml.get_object('custom_host_hbox').set_sensitive(widget.\
3738 get_active())
3740 def update_progressbar(self):
3741 self.progressbar.pulse()
3742 return True # loop forever
3744 def _nec_new_acc_connected(self, obj):
3746 Connection to server succeded, present the form to the user
3748 # We receive events from all accounts from GED
3749 if obj.conn.name != self.account:
3750 return
3751 if self.update_progressbar_timeout_id is not None:
3752 gobject.source_remove(self.update_progressbar_timeout_id)
3753 self.back_button.show()
3754 self.forward_button.show()
3755 self.is_form = obj.is_form
3756 if obj.is_form:
3757 dataform = dataforms.ExtendForm(node=obj.config)
3758 self.data_form_widget = dataforms_widget.DataFormWidget(dataform)
3759 else:
3760 self.data_form_widget = FakeDataForm(obj.config)
3761 self.data_form_widget.show_all()
3762 self.xml.get_object('form_vbox').pack_start(self.data_form_widget)
3763 self.ssl_fingerprint = obj.ssl_fingerprint
3764 self.ssl_cert = obj.ssl_cert
3765 if obj.ssl_msg:
3766 # An SSL warning occured, show it
3767 hostname = gajim.connections[self.account].new_account_info[
3768 'hostname']
3769 self.xml.get_object('ssl_label').set_markup(_(
3770 '<b>Security Warning</b>'
3771 '\n\nThe authenticity of the %(hostname)s SSL certificate could'
3772 ' be invalid.\nSSL Error: %(error)s\n'
3773 'Do you still want to connect to this server?') % {
3774 'hostname': hostname, 'error': obj.ssl_msg})
3775 if obj.errnum in (18, 27):
3776 text = _('Add this certificate to the list of trusted '
3777 'certificates.\nSHA1 fingerprint of the certificate:\n%s') \
3778 % obj.ssl_fingerprint
3779 self.xml.get_object('ssl_checkbutton').set_label(text)
3780 else:
3781 self.xml.get_object('ssl_checkbutton').set_no_show_all(True)
3782 self.xml.get_object('ssl_checkbutton').hide()
3783 self.notebook.set_current_page(3) # show SSL page
3784 else:
3785 self.notebook.set_current_page(4) # show form page
3787 def _nec_new_acc_not_connected(self, obj):
3789 Account creation failed: connection to server failed
3791 # We receive events from all accounts from GED
3792 if obj.conn.name != self.account:
3793 return
3794 if self.account not in gajim.connections:
3795 return
3796 if self.update_progressbar_timeout_id is not None:
3797 gobject.source_remove(self.update_progressbar_timeout_id)
3798 del gajim.connections[self.account]
3799 if self.account in gajim.config.get_per('accounts'):
3800 gajim.config.del_per('accounts', self.account)
3801 self.back_button.show()
3802 self.cancel_button.show()
3803 self.go_online_checkbutton.hide()
3804 self.show_vcard_checkbutton.hide()
3805 img = self.xml.get_object('finish_image')
3806 img.set_from_stock(gtk.STOCK_DIALOG_ERROR, gtk.ICON_SIZE_DIALOG)
3807 finish_text = '<big><b>%s</b></big>\n\n%s' % (
3808 _('An error occurred during account creation'), obj.reason)
3809 self.finish_label.set_markup(finish_text)
3810 self.notebook.set_current_page(6) # show finish page
3812 def _nec_acc_is_ok(self, obj):
3814 Account creation succeeded
3816 # We receive events from all accounts from GED
3817 if obj.conn.name != self.account:
3818 return
3819 self.create_vars(obj.account_info)
3820 self.show_finish_page()
3822 if self.update_progressbar_timeout_id is not None:
3823 gobject.source_remove(self.update_progressbar_timeout_id)
3825 def _nec_acc_is_not_ok(self, obj):
3827 Account creation failed
3829 # We receive events from all accounts from GED
3830 if obj.conn.name != self.account:
3831 return
3832 self.back_button.show()
3833 self.cancel_button.show()
3834 self.go_online_checkbutton.hide()
3835 self.show_vcard_checkbutton.hide()
3836 del gajim.connections[self.account]
3837 if self.account in gajim.config.get_per('accounts'):
3838 gajim.config.del_per('accounts', self.account)
3839 img = self.xml.get_object('finish_image')
3840 img.set_from_stock(gtk.STOCK_DIALOG_ERROR, gtk.ICON_SIZE_DIALOG)
3841 finish_text = '<big><b>%s</b></big>\n\n%s' % (_(
3842 'An error occurred during account creation'), obj.reason)
3843 self.finish_label.set_markup(finish_text)
3844 self.notebook.set_current_page(6) # show finish page
3846 if self.update_progressbar_timeout_id is not None:
3847 gobject.source_remove(self.update_progressbar_timeout_id)
3849 def on_advanced_button_clicked(self, widget):
3850 if 'accounts' in gajim.interface.instances:
3851 gajim.interface.instances['accounts'].window.present()
3852 else:
3853 gajim.interface.instances['accounts'] = AccountsWindow()
3854 gajim.interface.instances['accounts'].select_account(self.account)
3855 self.window.destroy()
3857 def on_finish_button_clicked(self, widget):
3858 go_online = self.xml.get_object('go_online_checkbutton').get_active()
3859 show_vcard = self.xml.get_object('show_vcard_checkbutton').get_active()
3860 self.window.destroy()
3861 if show_vcard:
3862 gajim.interface.show_vcard_when_connect.append(self.account)
3863 if go_online:
3864 gajim.interface.roster.send_status(self.account, 'online', '')
3866 def on_username_entry_key_press_event(self, widget, event):
3867 # Check for pressed @ and jump to combobox if found
3868 if event.keyval == gtk.keysyms.at:
3869 combobox = self.xml.get_object('server_comboboxentry')
3870 combobox.grab_focus()
3871 combobox.child.set_position(-1)
3872 return True
3874 def on_server_comboboxentry_key_press_event(self, widget, event, combobox):
3875 # If backspace is pressed in empty field, return to the nick entry field
3876 backspace = event.keyval == gtk.keysyms.BackSpace
3877 empty = len(combobox.get_active_text()) == 0
3878 if backspace and empty and self.modify:
3879 username_entry = self.xml.get_object('username_entry')
3880 username_entry.grab_focus()
3881 username_entry.set_position(-1)
3882 return True
3884 def get_config(self, login, server, savepass, password, anonymous=False):
3885 config = {}
3886 config['name'] = login
3887 config['hostname'] = server
3888 config['savepass'] = savepass
3889 config['password'] = password
3890 config['resource'] = 'Gajim'
3891 config['anonymous_auth'] = anonymous
3892 config['priority'] = 5
3893 config['autoconnect'] = True
3894 config['no_log_for'] = ''
3895 config['sync_with_global_status'] = True
3896 config['proxy'] = ''
3897 config['usessl'] = False
3898 config['use_custom_host'] = False
3899 config['custom_port'] = 0
3900 config['custom_host'] = ''
3901 config['keyname'] = ''
3902 config['keyid'] = ''
3903 return config
3905 def save_account(self, login, server, savepass, password, anonymous=False):
3906 if self.account in gajim.connections:
3907 dialogs.ErrorDialog(_('Account name is in use'),
3908 _('You already have an account using this name.'))
3909 return
3910 con = connection.Connection(self.account)
3911 con.password = password
3913 config = self.get_config(login, server, savepass, password, anonymous)
3915 if not self.modify:
3916 con.new_account(self.account, config)
3917 return
3918 gajim.connections[self.account] = con
3919 self.create_vars(config)
3921 def create_vars(self, config):
3922 gajim.config.add_per('accounts', self.account)
3924 if not config['savepass']:
3925 config['password'] = ''
3927 for opt in config:
3928 gajim.config.set_per('accounts', self.account, opt, config[opt])
3930 # update variables
3931 gajim.interface.instances[self.account] = {'infos': {}, 'disco': {},
3932 'gc_config': {}, 'search': {}, 'online_dialog': {}}
3933 gajim.interface.minimized_controls[self.account] = {}
3934 gajim.connections[self.account].connected = 0
3935 gajim.connections[self.account].keepalives = gajim.config.get_per(
3936 'accounts', self.account, 'keep_alive_every_foo_secs')
3937 gajim.groups[self.account] = {}
3938 gajim.contacts.add_account(self.account)
3939 gajim.gc_connected[self.account] = {}
3940 gajim.automatic_rooms[self.account] = {}
3941 gajim.newly_added[self.account] = []
3942 gajim.to_be_removed[self.account] = []
3943 gajim.nicks[self.account] = config['name']
3944 gajim.block_signed_in_notifications[self.account] = True
3945 gajim.sleeper_state[self.account] = 'off'
3946 gajim.encrypted_chats[self.account] = []
3947 gajim.last_message_time[self.account] = {}
3948 gajim.status_before_autoaway[self.account] = ''
3949 gajim.transport_avatar[self.account] = {}
3950 gajim.gajim_optional_features[self.account] = []
3951 gajim.caps_hash[self.account] = ''
3952 # refresh accounts window
3953 if 'accounts' in gajim.interface.instances:
3954 gajim.interface.instances['accounts'].init_accounts()
3955 # refresh roster
3956 if len(gajim.connections) >= 2:
3957 # Do not merge accounts if only one exists
3958 gajim.interface.roster.regroup = gajim.config.get('mergeaccounts')
3959 else:
3960 gajim.interface.roster.regroup = False
3961 gajim.interface.roster.setup_and_draw_roster()
3962 gajim.interface.roster.set_actions_menu_needs_rebuild()
3963 gajim.interface.save_config()
3965 class ManagePEPServicesWindow:
3966 def __init__(self, account):
3967 self.xml = gtkgui_helpers.get_gtk_builder('manage_pep_services_window.ui')
3968 self.window = self.xml.get_object('manage_pep_services_window')
3969 self.window.set_transient_for(gajim.interface.roster.window)
3970 self.xml.get_object('configure_button').set_sensitive(False)
3971 self.xml.get_object('delete_button').set_sensitive(False)
3972 self.xml.connect_signals(self)
3973 self.account = account
3975 self.init_services()
3976 self.xml.get_object('services_treeview').get_selection().connect(
3977 'changed', self.on_services_selection_changed)
3979 gajim.ged.register_event_handler('pep-config-received', ged.GUI1,
3980 self._nec_pep_config_received)
3981 gajim.ged.register_event_handler('agent-items-received', ged.GUI1,
3982 self._nec_agent_items_received)
3984 self.window.show_all()
3986 def on_manage_pep_services_window_destroy(self, widget):
3987 '''close window'''
3988 del gajim.interface.instances[self.account]['pep_services']
3989 gajim.ged.remove_event_handler('pep-config-received', ged.GUI1,
3990 self._nec_pep_config_received)
3991 gajim.ged.remove_event_handler('agent-items-received', ged.GUI1,
3992 self._nec_agent_items_received)
3994 def on_close_button_clicked(self, widget):
3995 self.window.destroy()
3997 def on_services_selection_changed(self, sel):
3998 self.xml.get_object('configure_button').set_sensitive(True)
3999 self.xml.get_object('delete_button').set_sensitive(True)
4001 def init_services(self):
4002 self.treeview = self.xml.get_object('services_treeview')
4003 # service, access_model, group
4004 self.treestore = gtk.ListStore(str)
4005 self.treeview.set_model(self.treestore)
4007 col = gtk.TreeViewColumn('Service')
4008 self.treeview.append_column(col)
4010 cellrenderer_text = gtk.CellRendererText()
4011 col.pack_start(cellrenderer_text)
4012 col.add_attribute(cellrenderer_text, 'text', 0)
4014 our_jid = gajim.get_jid_from_account(self.account)
4015 gajim.connections[self.account].discoverItems(our_jid)
4017 def _nec_agent_items_received(self, obj):
4018 our_jid = gajim.get_jid_from_account(self.account)
4019 for item in obj.items:
4020 if 'jid' in item and item['jid'] == our_jid and 'node' in item:
4021 self.treestore.append([item['node']])
4023 def node_removed(self, jid, node):
4024 if jid != gajim.get_jid_from_account(self.account):
4025 return
4026 model = self.treeview.get_model()
4027 iter_ = model.get_iter_root()
4028 while iter_:
4029 if model[iter_][0] == node:
4030 model.remove(iter_)
4031 break
4032 iter_ = model.iter_next(iter_)
4034 def node_not_removed(self, jid, node, msg):
4035 if jid != gajim.get_jid_from_account(self.account):
4036 return
4037 dialogs.WarningDialog(_('PEP node was not removed'),
4038 _('PEP node %(node)s was not removed: %(message)s') % {'node': node,
4039 'message': msg})
4041 def on_delete_button_clicked(self, widget):
4042 selection = self.treeview.get_selection()
4043 if not selection:
4044 return
4045 model, iter_ = selection.get_selected()
4046 node = model[iter_][0]
4047 our_jid = gajim.get_jid_from_account(self.account)
4048 gajim.connections[self.account].send_pb_delete(our_jid, node,
4049 on_ok=self.node_removed, on_fail=self.node_not_removed)
4051 def on_configure_button_clicked(self, widget):
4052 selection = self.treeview.get_selection()
4053 if not selection:
4054 return
4055 model, iter_ = selection.get_selected()
4056 node = model[iter_][0]
4057 our_jid = gajim.get_jid_from_account(self.account)
4058 gajim.connections[self.account].request_pb_configuration(our_jid, node)
4060 def _nec_pep_config_received(self, obj):
4061 def on_ok(form, node):
4062 form.type = 'submit'
4063 our_jid = gajim.get_jid_from_account(self.account)
4064 gajim.connections[self.account].send_pb_configure(our_jid, node, form)
4065 window = dialogs.DataFormWindow(obj.form, (on_ok, obj.node))
4066 title = _('Configure %s') % obj.node
4067 window.set_title(title)
4068 window.show_all()
4070 class ManageSoundsWindow:
4071 def __init__(self):
4072 self.xml = gtkgui_helpers.get_gtk_builder('manage_sounds_window.ui')
4073 self.window = self.xml.get_object('manage_sounds_window')
4075 # sounds treeview
4076 self.sound_tree = self.xml.get_object('sounds_treeview')
4078 # active, event ui name, path to sound file, event_config_name
4079 model = gtk.ListStore(bool, str, str, str)
4080 self.sound_tree.set_model(model)
4082 col = gtk.TreeViewColumn(_('Active'))
4083 self.sound_tree.append_column(col)
4084 renderer = gtk.CellRendererToggle()
4085 renderer.set_property('activatable', True)
4086 renderer.connect('toggled', self.sound_toggled_cb)
4087 col.pack_start(renderer)
4088 col.set_attributes(renderer, active = 0)
4090 col = gtk.TreeViewColumn(_('Event'))
4091 self.sound_tree.append_column(col)
4092 renderer = gtk.CellRendererText()
4093 col.pack_start(renderer)
4094 col.set_attributes(renderer, text = 1)
4096 self.fill_sound_treeview()
4098 self.xml.connect_signals(self)
4100 self.sound_tree.get_model().connect('row-changed',
4101 self.on_sounds_treemodel_row_changed)
4103 self.window.show_all()
4105 def on_sounds_treemodel_row_changed(self, model, path, iter_):
4106 sound_event = model[iter_][3].decode('utf-8')
4107 gajim.config.set_per('soundevents', sound_event, 'enabled',
4108 bool(model[path][0]))
4109 gajim.config.set_per('soundevents', sound_event, 'path',
4110 model[iter_][2].decode('utf-8'))
4111 gajim.interface.save_config()
4113 def sound_toggled_cb(self, cell, path):
4114 model = self.sound_tree.get_model()
4115 model[path][0] = not model[path][0]
4117 def fill_sound_treeview(self):
4118 model = self.sound_tree.get_model()
4119 model.clear()
4120 model.set_sort_column_id(1, gtk.SORT_ASCENDING)
4122 # NOTE: sounds_ui_names MUST have all items of
4123 # sounds = gajim.config.get_per('soundevents') as keys
4124 sounds_dict = {
4125 'first_message_received': _('First Message Received'),
4126 'next_message_received_focused': _('Next Message Received Focused'),
4127 'next_message_received_unfocused':
4128 _('Next Message Received Unfocused'),
4129 'contact_connected': _('Contact Connected'),
4130 'contact_disconnected': _('Contact Disconnected'),
4131 'message_sent': _('Message Sent'),
4132 'muc_message_highlight': _('Group Chat Message Highlight'),
4133 'muc_message_received': _('Group Chat Message Received'),
4134 'gmail_received': _('GMail Email Received')
4137 for sound_event_config_name, sound_ui_name in sounds_dict.items():
4138 enabled = gajim.config.get_per('soundevents',
4139 sound_event_config_name, 'enabled')
4140 path = gajim.config.get_per('soundevents',
4141 sound_event_config_name, 'path')
4142 model.append((enabled, sound_ui_name, path, sound_event_config_name))
4144 def on_treeview_sounds_cursor_changed(self, widget, data = None):
4145 (model, iter_) = self.sound_tree.get_selection().get_selected()
4146 sounds_entry = self.xml.get_object('sounds_entry')
4147 if not iter_:
4148 sounds_entry.set_text('')
4149 return
4150 path_to_snd_file = model[iter_][2]
4151 sounds_entry.set_text(path_to_snd_file)
4153 def on_browse_for_sounds_button_clicked(self, widget, data = None):
4154 (model, iter_) = self.sound_tree.get_selection().get_selected()
4155 if not iter_:
4156 return
4157 def on_ok(widget, path_to_snd_file):
4158 self.dialog.destroy()
4159 model, iter_ = self.sound_tree.get_selection().get_selected()
4160 if not path_to_snd_file:
4161 model[iter_][2] = ''
4162 self.xml.get_object('sounds_entry').set_text('')
4163 model[iter_][0] = False
4164 return
4165 directory = os.path.dirname(path_to_snd_file)
4166 gajim.config.set('last_sounds_dir', directory)
4167 path_to_snd_file = helpers.strip_soundfile_path(path_to_snd_file)
4168 self.xml.get_object('sounds_entry').set_text(path_to_snd_file)
4170 model[iter_][2] = path_to_snd_file # set new path to sounds_model
4171 model[iter_][0] = True # set the sound to enabled
4173 def on_cancel(widget):
4174 self.dialog.destroy()
4176 path_to_snd_file = model[iter_][2].decode('utf-8')
4177 self.dialog = dialogs.SoundChooserDialog(path_to_snd_file, on_ok,
4178 on_cancel)
4180 def on_sounds_entry_changed(self, widget):
4181 path_to_snd_file = widget.get_text()
4182 model, iter_ = self.sound_tree.get_selection().get_selected()
4183 model[iter_][2] = path_to_snd_file # set new path to sounds_model
4185 def on_play_button_clicked(self, widget):
4186 model, iter_ = self.sound_tree.get_selection().get_selected()
4187 if not iter_:
4188 return
4189 snd_event_config_name = model[iter_][3]
4190 helpers.play_sound(snd_event_config_name)
4192 def on_close_button_clicked(self, widget):
4193 self.window.hide()
4195 def on_manage_sounds_window_delete_event(self, widget, event):
4196 self.window.hide()
4197 return True # do NOT destroy the window