ability to connect to a host that require a PCKS certificate that is encrypted.
[gajim.git] / src / config.py
blobcc3de416a5483a333895e932c9d2d48c2ccfdcb7
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:
508 self.applications_combobox.set_active(1)
509 self.xml.get_object('custom_apps_frame').show()
511 self.xml.get_object('custom_browser_entry').set_text(
512 gajim.config.get('custombrowser'))
513 self.xml.get_object('custom_mail_client_entry').set_text(
514 gajim.config.get('custommailapp'))
515 self.xml.get_object('custom_file_manager_entry').set_text(
516 gajim.config.get('custom_file_manager'))
518 # log status changes of contacts
519 st = gajim.config.get('log_contact_status_changes')
520 self.xml.get_object('log_show_changes_checkbutton').set_active(st)
522 # log encrypted chat sessions
523 w = self.xml.get_object('log_encrypted_chats_checkbutton')
524 st = self.get_per_account_option('log_encrypted_sessions')
525 if st == 'mixed':
526 w.set_inconsistent(True)
527 else:
528 w.set_active(st)
530 # send os info
531 w = self.xml.get_object('send_os_info_checkbutton')
532 st = self.get_per_account_option('send_os_info')
533 if st == 'mixed':
534 w.set_inconsistent(True)
535 else:
536 w.set_active(st)
538 # send idle time
539 w = self.xml.get_object('send_idle_time_checkbutton')
540 st = self.get_per_account_option('send_idle_time')
541 if st == 'mixed':
542 w.set_inconsistent(True)
543 else:
544 w.set_active(st)
546 # check if gajm is default
547 st = gajim.config.get('check_if_gajim_is_default')
548 self.xml.get_object('check_default_client_checkbutton').set_active(st)
550 # Ignore messages from unknown contacts
551 w = self.xml.get_object('ignore_events_from_unknown_contacts_checkbutton')
552 st = self.get_per_account_option('ignore_unknown_contacts')
553 if st == 'mixed':
554 w.set_inconsistent(True)
555 else:
556 w.set_active(st)
558 self.xml.connect_signals(self)
560 self.msg_tree.get_model().connect('row-changed',
561 self.on_msg_treemodel_row_changed)
562 self.msg_tree.get_model().connect('row-deleted',
563 self.on_msg_treemodel_row_deleted)
564 self.default_msg_tree.get_model().connect('row-changed',
565 self.on_default_msg_treemodel_row_changed)
567 self.theme_preferences = None
568 self.sounds_preferences = None
570 self.notebook.set_current_page(0)
572 self.window.show_all()
573 gtkgui_helpers.possibly_move_window_in_current_desktop(self.window)
575 def on_preferences_window_key_press_event(self, widget, event):
576 if event.keyval == gtk.keysyms.Escape:
577 self.window.hide()
579 def get_per_account_option(self, opt):
581 Return the value of the option opt if it's the same in all accounts else
582 returns "mixed"
584 if len(gajim.connections) == 0:
585 # a non existant key return default value
586 return gajim.config.get_per('accounts', '__default__', opt)
587 val = None
588 for account in gajim.connections:
589 v = gajim.config.get_per('accounts', account, opt)
590 if val is None:
591 val = v
592 elif val != v:
593 return 'mixed'
594 return val
596 def on_checkbutton_toggled(self, widget, config_name,
597 change_sensitivity_widgets=None):
598 gajim.config.set(config_name, widget.get_active())
599 if change_sensitivity_widgets:
600 for w in change_sensitivity_widgets:
601 w.set_sensitive(widget.get_active())
602 gajim.interface.save_config()
604 def on_per_account_checkbutton_toggled(self, widget, config_name,
605 change_sensitivity_widgets=None):
606 for account in gajim.connections:
607 gajim.config.set_per('accounts', account, config_name,
608 widget.get_active())
609 if change_sensitivity_widgets:
610 for w in change_sensitivity_widgets:
611 w.set_sensitive(widget.get_active())
612 gajim.interface.save_config()
614 def _get_all_controls(self):
615 for ctrl in gajim.interface.msg_win_mgr.get_controls():
616 yield ctrl
617 for account in gajim.connections:
618 for ctrl in gajim.interface.minimized_controls[account].values():
619 yield ctrl
621 def _get_all_muc_controls(self):
622 for ctrl in gajim.interface.msg_win_mgr.get_controls(
623 message_control.TYPE_GC):
624 yield ctrl
625 for account in gajim.connections:
626 for ctrl in gajim.interface.minimized_controls[account].values():
627 yield ctrl
629 def on_sort_by_show_in_roster_checkbutton_toggled(self, widget):
630 self.on_checkbutton_toggled(widget, 'sort_by_show_in_roster')
631 gajim.interface.roster.setup_and_draw_roster()
633 def on_sort_by_show_in_muc_checkbutton_toggled(self, widget):
634 self.on_checkbutton_toggled(widget, 'sort_by_show_in_muc')
635 # Redraw groupchats
636 for ctrl in self._get_all_muc_controls():
637 ctrl.draw_roster()
639 def on_show_avatars_in_roster_checkbutton_toggled(self, widget):
640 self.on_checkbutton_toggled(widget, 'show_avatars_in_roster')
641 gajim.interface.roster.setup_and_draw_roster()
642 # Redraw groupchats (in an ugly way)
643 for ctrl in self._get_all_muc_controls():
644 ctrl.draw_roster()
646 def on_show_status_msgs_in_roster_checkbutton_toggled(self, widget):
647 self.on_checkbutton_toggled(widget, 'show_status_msgs_in_roster')
648 gajim.interface.roster.setup_and_draw_roster()
649 for ctrl in self._get_all_muc_controls():
650 ctrl.update_ui()
652 def on_show_mood_in_roster_checkbutton_toggled(self, widget):
653 self.on_checkbutton_toggled(widget, 'show_mood_in_roster')
654 gajim.interface.roster.setup_and_draw_roster()
656 def on_show_activity_in_roster_checkbutton_toggled(self, widget):
657 self.on_checkbutton_toggled(widget, 'show_activity_in_roster')
658 gajim.interface.roster.setup_and_draw_roster()
660 def on_show_tunes_in_roster_checkbutton_toggled(self, widget):
661 self.on_checkbutton_toggled(widget, 'show_tunes_in_roster')
662 gajim.interface.roster.setup_and_draw_roster()
664 def on_show_location_in_roster_checkbutton_toggled(self, widget):
665 self.on_checkbutton_toggled(widget, 'show_location_in_roster')
666 gajim.interface.roster.setup_and_draw_roster()
668 def on_emoticons_combobox_changed(self, widget):
669 active = widget.get_active()
670 model = widget.get_model()
671 emot_theme = model[active][0].decode('utf-8')
672 if emot_theme == _('Disabled'):
673 gajim.config.set('emoticons_theme', '')
674 else:
675 gajim.config.set('emoticons_theme', emot_theme)
677 gajim.interface.init_emoticons(need_reload = True)
678 gajim.interface.make_regexps()
679 self.toggle_emoticons()
681 def toggle_emoticons(self):
683 Update emoticons state in Opened Chat Windows
685 for ctrl in self._get_all_controls():
686 ctrl.toggle_emoticons()
688 def on_one_window_type_combo_changed(self, widget):
689 active = widget.get_active()
690 config_type = common.config.opt_one_window_types[active]
691 gajim.config.set('one_message_window', config_type)
692 gajim.interface.save_config()
693 gajim.interface.msg_win_mgr.reconfig()
695 def on_show_roster_on_startup_changed(self, widget):
696 active = widget.get_active()
697 config_type = common.config.opt_show_roster_on_startup[active]
698 gajim.config.set('show_roster_on_startup', config_type)
699 gajim.interface.save_config()
701 def on_compact_view_checkbutton_toggled(self, widget):
702 active = widget.get_active()
703 for ctrl in self._get_all_controls():
704 ctrl.chat_buttons_set_visible(active)
705 gajim.config.set('compact_view', active)
706 gajim.interface.save_config()
708 def on_xhtml_checkbutton_toggled(self, widget):
709 self.on_checkbutton_toggled(widget, 'ignore_incoming_xhtml')
710 helpers.update_optional_features()
712 def apply_speller(self):
713 for ctrl in self._get_all_controls():
714 if isinstance(ctrl, chat_control.ChatControlBase):
715 try:
716 spell_obj = gtkspell.get_from_text_view(ctrl.msg_textview)
717 except (TypeError, RuntimeError, OSError):
718 spell_obj = None
720 if not spell_obj:
721 ctrl.set_speller()
723 def remove_speller(self):
724 for ctrl in self._get_all_controls():
725 if isinstance(ctrl, chat_control.ChatControlBase):
726 try:
727 spell_obj = gtkspell.get_from_text_view(ctrl.msg_textview)
728 except (TypeError, RuntimeError):
729 spell_obj = None
730 if spell_obj:
731 spell_obj.detach()
733 def on_speller_checkbutton_toggled(self, widget):
734 active = widget.get_active()
735 gajim.config.set('use_speller', active)
736 gajim.interface.save_config()
737 if active:
738 lang = gajim.config.get('speller_language')
739 if not lang:
740 lang = gajim.LANG
741 tv = gtk.TextView()
742 try:
743 gtkspell.Spell(tv, lang)
744 except (TypeError, RuntimeError, OSError):
745 dialogs.ErrorDialog(
746 _('Dictionary for lang %s not available') % lang,
747 _('You have to install %s dictionary to use spellchecking, or '
748 'choose another language by setting the speller_language option.'
749 ) % lang)
750 gajim.config.set('use_speller', False)
751 widget.set_active(False)
752 else:
753 gajim.config.set('speller_language', lang)
754 self.apply_speller()
755 else:
756 self.remove_speller()
758 def on_theme_combobox_changed(self, widget):
759 model = widget.get_model()
760 active = widget.get_active()
761 config_theme = model[active][0].decode('utf-8').replace(' ', '_')
763 gajim.config.set('roster_theme', config_theme)
765 # begin repainting themed widgets throughout
766 gajim.interface.roster.repaint_themed_widgets()
767 gajim.interface.roster.change_roster_style(None)
768 gajim.interface.save_config()
770 def update_theme_list(self):
771 theme_combobox = self.xml.get_object('theme_combobox')
772 model = gtk.ListStore(str)
773 theme_combobox.set_model(model)
774 i = 0
775 for config_theme in gajim.config.get_per('themes'):
776 theme = config_theme.replace('_', ' ')
777 model.append([theme])
778 if gajim.config.get('roster_theme') == config_theme:
779 theme_combobox.set_active(i)
780 i += 1
782 def on_manage_theme_button_clicked(self, widget):
783 if self.theme_preferences is None:
784 self.theme_preferences = dialogs.GajimThemesWindow()
785 else:
786 self.theme_preferences.window.present()
787 self.theme_preferences.select_active_theme()
789 def on_iconset_combobox_changed(self, widget):
790 model = widget.get_model()
791 active = widget.get_active()
792 icon_string = model[active][1].decode('utf-8')
793 gajim.config.set('iconset', icon_string)
794 gtkgui_helpers.reload_jabber_state_images()
795 gajim.interface.save_config()
797 def on_transports_iconsets_checkbutton_toggled(self, widget):
798 self.on_checkbutton_toggled(widget, 'use_transports_iconsets')
799 gtkgui_helpers.reload_jabber_state_images()
801 def on_outgoing_chat_states_combobox_changed(self, widget):
802 active = widget.get_active()
803 old_value = gajim.config.get('outgoing_chat_state_notifications')
804 if active == 0: # all
805 gajim.config.set('outgoing_chat_state_notifications', 'all')
806 elif active == 1: # only composing
807 gajim.config.set('outgoing_chat_state_notifications', 'composing_only')
808 else: # disabled
809 gajim.config.set('outgoing_chat_state_notifications', 'disabled')
810 new_value = gajim.config.get('outgoing_chat_state_notifications')
811 if 'disabled' in (old_value, new_value):
812 # we changed from disabled to sth else or vice versa
813 helpers.update_optional_features()
815 def on_displayed_chat_states_combobox_changed(self, widget):
816 active = widget.get_active()
817 if active == 0: # all
818 gajim.config.set('displayed_chat_state_notifications', 'all')
819 elif active == 1: # only composing
820 gajim.config.set('displayed_chat_state_notifications',
821 'composing_only')
822 else: # disabled
823 gajim.config.set('displayed_chat_state_notifications', 'disabled')
825 def on_ignore_events_from_unknown_contacts_checkbutton_toggled(self, widget):
826 widget.set_inconsistent(False)
827 self.on_per_account_checkbutton_toggled(widget, 'ignore_unknown_contacts')
829 def on_on_event_combobox_changed(self, widget):
830 active = widget.get_active()
831 if active == 0:
832 gajim.config.set('autopopup', True)
833 gajim.config.set('notify_on_new_message', False)
834 elif active == 1:
835 gajim.config.set('autopopup', False)
836 gajim.config.set('notify_on_new_message', True)
837 else:
838 gajim.config.set('autopopup', False)
839 gajim.config.set('notify_on_new_message', False)
841 def on_notify_on_signin_checkbutton_toggled(self, widget):
842 self.on_checkbutton_toggled(widget, 'notify_on_signin')
844 def on_notify_on_signout_checkbutton_toggled(self, widget):
845 self.on_checkbutton_toggled(widget, 'notify_on_signout')
847 def on_auto_popup_away_checkbutton_toggled(self, widget):
848 self.on_checkbutton_toggled(widget, 'autopopupaway')
850 def on_sound_dnd_checkbutton_toggled(self, widget):
851 self.on_checkbutton_toggled(widget, 'sounddnd')
853 def on_systray_combobox_changed(self, widget):
854 active = widget.get_active()
855 if active == 0:
856 gajim.config.set('trayicon', 'never')
857 gajim.interface.systray_enabled = False
858 gajim.interface.systray.hide_icon()
859 elif active == 1:
860 gajim.config.set('trayicon', 'on_event')
861 gajim.interface.systray_enabled = True
862 gajim.interface.systray.show_icon()
863 else:
864 gajim.config.set('trayicon', 'always')
865 gajim.interface.systray_enabled = True
866 gajim.interface.systray.show_icon()
868 def on_play_sounds_checkbutton_toggled(self, widget):
869 self.on_checkbutton_toggled(widget, 'sounds_on',
870 [self.xml.get_object('manage_sounds_button')])
872 def on_manage_sounds_button_clicked(self, widget):
873 if self.sounds_preferences is None:
874 self.sounds_preferences = ManageSoundsWindow()
875 else:
876 self.sounds_preferences.window.present()
878 def update_text_tags(self):
880 Update color tags in opened chat windows
882 for ctrl in self._get_all_controls():
883 ctrl.update_tags()
885 def on_preference_widget_color_set(self, widget, text):
886 color = widget.get_color()
887 color_string = gtkgui_helpers.make_color_string(color)
888 gajim.config.set(text, color_string)
889 self.update_text_tags()
890 gajim.interface.save_config()
892 def on_preference_widget_font_set(self, widget, text):
893 if widget:
894 font = widget.get_font_name()
895 else:
896 font = ''
897 gajim.config.set(text, font)
898 self.update_text_font()
899 gajim.interface.save_config()
901 def update_text_font(self):
903 Update text font in opened chat windows
905 for ctrl in self._get_all_controls():
906 ctrl.update_font()
908 def on_incoming_nick_colorbutton_color_set(self, widget):
909 self.on_preference_widget_color_set(widget, 'inmsgcolor')
911 def on_outgoing_nick_colorbutton_color_set(self, widget):
912 self.on_preference_widget_color_set(widget, 'outmsgcolor')
914 def on_incoming_msg_colorbutton_color_set(self, widget):
915 self.on_preference_widget_color_set(widget, 'inmsgtxtcolor')
917 def on_outgoing_msg_colorbutton_color_set(self, widget):
918 self.on_preference_widget_color_set(widget, 'outmsgtxtcolor')
920 def on_url_msg_colorbutton_color_set(self, widget):
921 self.on_preference_widget_color_set(widget, 'urlmsgcolor')
923 def on_status_msg_colorbutton_color_set(self, widget):
924 self.on_preference_widget_color_set(widget, 'statusmsgcolor')
926 def on_conversation_fontbutton_font_set(self, widget):
927 self.on_preference_widget_font_set(widget, 'conversation_font')
929 def on_default_chat_font_toggled(self, widget):
930 font_widget = self.xml.get_object('conversation_fontbutton')
931 if widget.get_active():
932 font_widget.set_sensitive(False)
933 font_widget = None
934 else:
935 font_widget.set_sensitive(True)
936 self.on_preference_widget_font_set(font_widget, 'conversation_font')
938 def draw_color_widgets(self):
939 col_to_widget = {'inmsgcolor': 'incoming_nick_colorbutton',
940 'outmsgcolor': 'outgoing_nick_colorbutton',
941 'inmsgtxtcolor': ['incoming_msg_colorbutton',
942 'incoming_msg_checkbutton'],
943 'outmsgtxtcolor': ['outgoing_msg_colorbutton',
944 'outgoing_msg_checkbutton'],
945 'statusmsgcolor': 'status_msg_colorbutton',
946 'urlmsgcolor': 'url_msg_colorbutton'}
947 for c in col_to_widget:
948 col = gajim.config.get(c)
949 if col:
950 if isinstance(col_to_widget[c], list):
951 self.xml.get_object(col_to_widget[c][0]).set_color(
952 gtk.gdk.color_parse(col))
953 self.xml.get_object(col_to_widget[c][0]).set_sensitive(True)
954 self.xml.get_object(col_to_widget[c][1]).set_active(True)
955 else:
956 self.xml.get_object(col_to_widget[c]).set_color(
957 gtk.gdk.color_parse(col))
958 else:
959 if isinstance(col_to_widget[c], list):
960 self.xml.get_object(col_to_widget[c][0]).set_color(
961 gtk.gdk.color_parse('#000000'))
962 self.xml.get_object(col_to_widget[c][0]).set_sensitive(False)
963 self.xml.get_object(col_to_widget[c][1]).set_active(False)
964 else:
965 self.xml.get_object(col_to_widget[c]).set_color(
966 gtk.gdk.color_parse('#000000'))
968 def on_reset_colors_button_clicked(self, widget):
969 col_to_widget = {'inmsgcolor': 'incoming_nick_colorbutton',
970 'outmsgcolor': 'outgoing_nick_colorbutton',
971 'inmsgtxtcolor': 'incoming_msg_colorbutton',
972 'outmsgtxtcolor': 'outgoing_msg_colorbutton',
973 'statusmsgcolor': 'status_msg_colorbutton',
974 'urlmsgcolor': 'url_msg_colorbutton'}
975 for c in col_to_widget:
976 gajim.config.set(c, gajim.interface.default_colors[c])
977 self.draw_color_widgets()
979 self.update_text_tags()
980 gajim.interface.save_config()
982 def _set_color(self, state, widget_name, option):
984 Set color value in prefs and update the UI
986 if state:
987 color = self.xml.get_object(widget_name).get_color()
988 color_string = gtkgui_helpers.make_color_string(color)
989 else:
990 color_string = ''
991 gajim.config.set(option, color_string)
992 gajim.interface.save_config()
994 def on_incoming_msg_checkbutton_toggled(self, widget):
995 state = widget.get_active()
996 self.xml.get_object('incoming_msg_colorbutton').set_sensitive(state)
997 self._set_color(state, 'incoming_msg_colorbutton', 'inmsgtxtcolor')
999 def on_outgoing_msg_checkbutton_toggled(self, widget):
1000 state = widget.get_active()
1001 self.xml.get_object('outgoing_msg_colorbutton').set_sensitive(state)
1002 self._set_color(state, 'outgoing_msg_colorbutton', 'outmsgtxtcolor')
1004 def on_auto_away_checkbutton_toggled(self, widget):
1005 self.on_checkbutton_toggled(widget, 'autoaway',
1006 [self.auto_away_time_spinbutton, self.auto_away_message_entry])
1008 def on_auto_away_time_spinbutton_value_changed(self, widget):
1009 aat = widget.get_value_as_int()
1010 gajim.config.set('autoawaytime', aat)
1011 gajim.interface.sleeper = common.sleepy.Sleepy(
1012 gajim.config.get('autoawaytime') * 60,
1013 gajim.config.get('autoxatime') * 60)
1014 gajim.interface.save_config()
1016 def on_auto_away_message_entry_changed(self, widget):
1017 gajim.config.set('autoaway_message', widget.get_text().decode('utf-8'))
1019 def on_auto_xa_checkbutton_toggled(self, widget):
1020 self.on_checkbutton_toggled(widget, 'autoxa',
1021 [self.auto_xa_time_spinbutton, self.auto_xa_message_entry])
1023 def on_auto_xa_time_spinbutton_value_changed(self, widget):
1024 axt = widget.get_value_as_int()
1025 gajim.config.set('autoxatime', axt)
1026 gajim.interface.sleeper = common.sleepy.Sleepy(
1027 gajim.config.get('autoawaytime') * 60,
1028 gajim.config.get('autoxatime') * 60)
1029 gajim.interface.save_config()
1031 def on_auto_xa_message_entry_changed(self, widget):
1032 gajim.config.set('autoxa_message', widget.get_text().decode('utf-8'))
1034 def on_prompt_online_status_message_checkbutton_toggled(self, widget):
1035 self.on_checkbutton_toggled(widget, 'ask_online_status')
1037 def on_prompt_offline_status_message_checkbutton_toggled(self, widget):
1038 self.on_checkbutton_toggled(widget, 'ask_offline_status')
1040 def fill_default_msg_treeview(self):
1041 model = self.default_msg_tree.get_model()
1042 model.clear()
1043 status = []
1044 for status_ in gajim.config.get_per('defaultstatusmsg'):
1045 status.append(status_)
1046 status.sort()
1047 for status_ in status:
1048 msg = gajim.config.get_per('defaultstatusmsg', status_, 'message')
1049 msg = helpers.from_one_line(msg)
1050 enabled = gajim.config.get_per('defaultstatusmsg', status_, 'enabled')
1051 iter_ = model.append()
1052 uf_show = helpers.get_uf_show(status_)
1053 model.set(iter_, 0, status_, 1, uf_show, 2, msg, 3, enabled)
1055 def on_default_msg_cell_edited(self, cell, row, new_text):
1056 model = self.default_msg_tree.get_model()
1057 iter_ = model.get_iter_from_string(row)
1058 model.set_value(iter_, 2, new_text)
1060 def default_msg_toggled_cb(self, cell, path):
1061 model = self.default_msg_tree.get_model()
1062 model[path][3] = not model[path][3]
1064 def on_default_msg_treemodel_row_changed(self, model, path, iter_):
1065 status = model[iter_][0]
1066 message = model[iter_][2].decode('utf-8')
1067 message = helpers.to_one_line(message)
1068 gajim.config.set_per('defaultstatusmsg', status, 'enabled',
1069 model[iter_][3])
1070 gajim.config.set_per('defaultstatusmsg', status, 'message', message)
1072 def on_default_status_expander_activate(self, expander):
1073 eventbox = self.xml.get_object('default_status_eventbox')
1074 vbox = self.xml.get_object('status_vbox')
1075 vbox.set_child_packing(eventbox, not expander.get_expanded(), True, 0,
1076 gtk.PACK_START)
1078 def save_status_messages(self, model):
1079 for msg in gajim.config.get_per('statusmsg'):
1080 gajim.config.del_per('statusmsg', msg)
1081 iter_ = model.get_iter_first()
1082 while iter_:
1083 val = model[iter_][0].decode('utf-8')
1084 if model[iter_][1]: # we have a preset message
1085 if not val: # no title, use message text for title
1086 val = model[iter_][1]
1087 gajim.config.add_per('statusmsg', val)
1088 msg = helpers.to_one_line(model[iter_][1].decode('utf-8'))
1089 gajim.config.set_per('statusmsg', val, 'message', msg)
1090 i = 2
1091 # store mood / activity
1092 for subname in ('activity', 'subactivity', 'activity_text',
1093 'mood', 'mood_text'):
1094 gajim.config.set_per('statusmsg', val, subname,
1095 model[iter_][i].decode('utf-8'))
1096 i += 1
1097 iter_ = model.iter_next(iter_)
1098 gajim.interface.save_config()
1100 def on_msg_treemodel_row_changed(self, model, path, iter_):
1101 self.save_status_messages(model)
1103 def on_msg_treemodel_row_deleted(self, model, path):
1104 self.save_status_messages(model)
1106 def on_av_combobox_changed(self, combobox, config_name):
1107 model = combobox.get_model()
1108 active = combobox.get_active()
1109 device = model[active][1].decode('utf-8')
1110 gajim.config.set(config_name, device)
1112 def on_audio_input_combobox_changed(self, widget):
1113 self.on_av_combobox_changed(widget, 'audio_input_device')
1115 def on_audio_output_combobox_changed(self, widget):
1116 self.on_av_combobox_changed(widget, 'audio_output_device')
1118 def on_video_input_combobox_changed(self, widget):
1119 self.on_av_combobox_changed(widget, 'video_input_device')
1121 def on_video_output_combobox_changed(self, widget):
1122 self.on_av_combobox_changed(widget, 'video_output_device')
1124 def on_video_framerate_combobox_changed(self, widget):
1125 self.on_av_combobox_changed(widget, 'video_framerate')
1127 def on_video_size_combobox_changed(self, widget):
1128 self.on_av_combobox_changed(widget, 'video_size')
1130 def on_stun_checkbutton_toggled(self, widget):
1131 self.on_checkbutton_toggled(widget, 'use_stun_server',
1132 [self.xml.get_object('stun_server_entry')])
1134 def stun_server_entry_changed(self, widget):
1135 gajim.config.set('stun_server', widget.get_text().decode('utf-8'))
1137 def on_applications_combobox_changed(self, widget):
1138 if widget.get_active() == 0:
1139 gajim.config.set('autodetect_browser_mailer', True)
1140 self.xml.get_object('custom_apps_frame').hide()
1141 elif widget.get_active() == 1:
1142 gajim.config.set('autodetect_browser_mailer', False)
1143 self.xml.get_object('custom_apps_frame').show()
1144 gajim.interface.save_config()
1146 def on_custom_browser_entry_changed(self, widget):
1147 gajim.config.set('custombrowser', widget.get_text().decode('utf-8'))
1148 gajim.interface.save_config()
1150 def on_custom_mail_client_entry_changed(self, widget):
1151 gajim.config.set('custommailapp', widget.get_text().decode('utf-8'))
1152 gajim.interface.save_config()
1154 def on_custom_file_manager_entry_changed(self, widget):
1155 gajim.config.set('custom_file_manager', widget.get_text().decode('utf-8'))
1156 gajim.interface.save_config()
1158 def on_log_show_changes_checkbutton_toggled(self, widget):
1159 self.on_checkbutton_toggled(widget, 'log_contact_status_changes')
1161 def on_log_encrypted_chats_checkbutton_toggled(self, widget):
1162 widget.set_inconsistent(False)
1163 self.on_per_account_checkbutton_toggled(widget, 'log_encrypted_sessions')
1165 def on_send_os_info_checkbutton_toggled(self, widget):
1166 widget.set_inconsistent(False)
1167 self.on_per_account_checkbutton_toggled(widget, 'send_os_info')
1169 def on_send_idle_time_checkbutton_toggled(self, widget):
1170 widget.set_inconsistent(False)
1171 self.on_per_account_checkbutton_toggled(widget, 'send_idle_time')
1173 def on_check_default_client_checkbutton_toggled(self, widget):
1174 self.on_checkbutton_toggled(widget, 'check_if_gajim_is_default')
1176 def on_notify_gmail_checkbutton_toggled(self, widget):
1177 self.on_checkbutton_toggled(widget, 'notify_on_new_gmail_email')
1179 def on_notify_gmail_extra_checkbutton_toggled(self, widget):
1180 self.on_checkbutton_toggled(widget, 'notify_on_new_gmail_email_extra')
1182 def fill_msg_treeview(self):
1183 self.xml.get_object('delete_msg_button').set_sensitive(False)
1184 model = self.msg_tree.get_model()
1185 model.clear()
1186 preset_status = []
1187 for msg_name in gajim.config.get_per('statusmsg'):
1188 if msg_name.startswith('_last_'):
1189 continue
1190 preset_status.append(msg_name)
1191 preset_status.sort()
1192 for msg_name in preset_status:
1193 msg_text = gajim.config.get_per('statusmsg', msg_name, 'message')
1194 msg_text = helpers.from_one_line(msg_text)
1195 activity = gajim.config.get_per('statusmsg', msg_name, 'activity')
1196 subactivity = gajim.config.get_per('statusmsg', msg_name,
1197 'subactivity')
1198 activity_text = gajim.config.get_per('statusmsg', msg_name,
1199 'activity_text')
1200 mood = gajim.config.get_per('statusmsg', msg_name, 'mood')
1201 mood_text = gajim.config.get_per('statusmsg', msg_name, 'mood_text')
1202 iter_ = model.append()
1203 model.set(iter_, 0, msg_name, 1, msg_text, 2, activity, 3,
1204 subactivity, 4, activity_text, 5, mood, 6, mood_text)
1206 def on_msg_cell_edited(self, cell, row, new_text):
1207 model = self.msg_tree.get_model()
1208 iter_ = model.get_iter_from_string(row)
1209 model.set_value(iter_, 0, new_text)
1211 def on_msg_treeview_cursor_changed(self, widget, data = None):
1212 (model, iter_) = self.msg_tree.get_selection().get_selected()
1213 if not iter_:
1214 return
1215 self.xml.get_object('delete_msg_button').set_sensitive(True)
1216 buf = self.xml.get_object('msg_textview').get_buffer()
1217 msg = model[iter_][1]
1218 buf.set_text(msg)
1220 def on_new_msg_button_clicked(self, widget, data = None):
1221 model = self.msg_tree.get_model()
1222 iter_ = model.append()
1223 model.set(iter_, 0, _('status message title'), 1, _('status message text'))
1224 self.msg_tree.set_cursor(model.get_path(iter_))
1226 def on_delete_msg_button_clicked(self, widget, data = None):
1227 (model, iter_) = self.msg_tree.get_selection().get_selected()
1228 if not iter_:
1229 return
1230 buf = self.xml.get_object('msg_textview').get_buffer()
1231 model.remove(iter_)
1232 buf.set_text('')
1233 self.xml.get_object('delete_msg_button').set_sensitive(False)
1235 def on_msg_textview_changed(self, widget, data = None):
1236 (model, iter_) = self.msg_tree.get_selection().get_selected()
1237 if not iter_:
1238 return
1239 buf = self.xml.get_object('msg_textview').get_buffer()
1240 first_iter, end_iter = buf.get_bounds()
1241 model.set_value(iter_, 1, buf.get_text(first_iter, end_iter))
1243 def on_msg_treeview_key_press_event(self, widget, event):
1244 if event.keyval == gtk.keysyms.Delete:
1245 self.on_delete_msg_button_clicked(widget)
1247 def on_open_advanced_editor_button_clicked(self, widget, data = None):
1248 if 'advanced_config' in gajim.interface.instances:
1249 gajim.interface.instances['advanced_config'].window.present()
1250 else:
1251 gajim.interface.instances['advanced_config'] = \
1252 dialogs.AdvancedConfigurationWindow()
1254 #---------- ManageProxiesWindow class -------------#
1255 class ManageProxiesWindow:
1256 def __init__(self):
1257 self.xml = gtkgui_helpers.get_gtk_builder('manage_proxies_window.ui')
1258 self.window = self.xml.get_object('manage_proxies_window')
1259 self.window.set_transient_for(gajim.interface.roster.window)
1260 self.proxies_treeview = self.xml.get_object('proxies_treeview')
1261 self.proxyname_entry = self.xml.get_object('proxyname_entry')
1262 self.proxytype_combobox = self.xml.get_object('proxytype_combobox')
1264 self.init_list()
1265 self.block_signal = False
1266 self.xml.connect_signals(self)
1267 self.window.show_all()
1268 # hide the BOSH fields by default
1269 self.show_bosh_fields()
1271 def show_bosh_fields(self, show=True):
1272 if show:
1273 self.xml.get_object('boshuri_entry').show()
1274 self.xml.get_object('boshuri_label').show()
1275 self.xml.get_object('boshuseproxy_checkbutton').show()
1276 else:
1277 cb = self.xml.get_object('boshuseproxy_checkbutton')
1278 cb.hide()
1279 cb.set_active(True)
1280 self.on_boshuseproxy_checkbutton_toggled(cb)
1281 self.xml.get_object('boshuri_entry').hide()
1282 self.xml.get_object('boshuri_label').hide()
1285 def fill_proxies_treeview(self):
1286 model = self.proxies_treeview.get_model()
1287 model.clear()
1288 iter_ = model.append()
1289 model.set(iter_, 0, _('None'))
1290 for p in gajim.config.get_per('proxies'):
1291 iter_ = model.append()
1292 model.set(iter_, 0, p)
1294 def init_list(self):
1295 self.xml.get_object('remove_proxy_button').set_sensitive(False)
1296 self.proxytype_combobox.set_sensitive(False)
1297 self.xml.get_object('proxy_table').set_sensitive(False)
1298 model = gtk.ListStore(str)
1299 self.proxies_treeview.set_model(model)
1300 col = gtk.TreeViewColumn('Proxies')
1301 self.proxies_treeview.append_column(col)
1302 renderer = gtk.CellRendererText()
1303 col.pack_start(renderer, True)
1304 col.set_attributes(renderer, text = 0)
1305 self.fill_proxies_treeview()
1306 self.xml.get_object('proxytype_combobox').set_active(0)
1308 def on_manage_proxies_window_destroy(self, widget):
1309 if 'accounts' in gajim.interface.instances:
1310 gajim.interface.instances['accounts'].\
1311 update_proxy_list()
1312 del gajim.interface.instances['manage_proxies']
1314 def on_add_proxy_button_clicked(self, widget):
1315 model = self.proxies_treeview.get_model()
1316 proxies = gajim.config.get_per('proxies')
1317 i = 1
1318 while ('proxy' + unicode(i)) in proxies:
1319 i += 1
1320 iter_ = model.append()
1321 model.set(iter_, 0, 'proxy' + unicode(i))
1322 gajim.config.add_per('proxies', 'proxy' + unicode(i))
1323 self.proxies_treeview.set_cursor(model.get_path(iter_))
1325 def on_remove_proxy_button_clicked(self, widget):
1326 (model, iter_) = self.proxies_treeview.get_selection().get_selected()
1327 if not iter_:
1328 return
1329 proxy = model[iter_][0].decode('utf-8')
1330 model.remove(iter_)
1331 gajim.config.del_per('proxies', proxy)
1332 self.xml.get_object('remove_proxy_button').set_sensitive(False)
1333 self.block_signal = True
1334 self.on_proxies_treeview_cursor_changed(self.proxies_treeview)
1335 self.block_signal = False
1337 def on_close_button_clicked(self, widget):
1338 self.window.destroy()
1340 def on_useauth_checkbutton_toggled(self, widget):
1341 if self.block_signal:
1342 return
1343 act = widget.get_active()
1344 proxy = self.proxyname_entry.get_text().decode('utf-8')
1345 gajim.config.set_per('proxies', proxy, 'useauth', act)
1346 self.xml.get_object('proxyuser_entry').set_sensitive(act)
1347 self.xml.get_object('proxypass_entry').set_sensitive(act)
1349 def on_boshuseproxy_checkbutton_toggled(self, widget):
1350 if self.block_signal:
1351 return
1352 act = widget.get_active()
1353 proxy = self.proxyname_entry.get_text().decode('utf-8')
1354 gajim.config.set_per('proxies', proxy, 'bosh_useproxy', act)
1355 self.xml.get_object('proxyhost_entry').set_sensitive(act)
1356 self.xml.get_object('proxyport_entry').set_sensitive(act)
1358 def on_proxies_treeview_cursor_changed(self, widget):
1359 #FIXME: check if off proxy settings are correct (see
1360 # http://trac.gajim.org/changeset/1921#file2 line 1221
1361 proxyhost_entry = self.xml.get_object('proxyhost_entry')
1362 proxyport_entry = self.xml.get_object('proxyport_entry')
1363 proxyuser_entry = self.xml.get_object('proxyuser_entry')
1364 proxypass_entry = self.xml.get_object('proxypass_entry')
1365 boshuri_entry = self.xml.get_object('boshuri_entry')
1366 useauth_checkbutton = self.xml.get_object('useauth_checkbutton')
1367 boshuseproxy_checkbutton = self.xml.get_object('boshuseproxy_checkbutton')
1368 self.block_signal = True
1369 proxyhost_entry.set_text('')
1370 proxyport_entry.set_text('')
1371 proxyuser_entry.set_text('')
1372 proxypass_entry.set_text('')
1373 boshuri_entry.set_text('')
1375 #boshuseproxy_checkbutton.set_active(False)
1376 #self.on_boshuseproxy_checkbutton_toggled(boshuseproxy_checkbutton)
1378 #useauth_checkbutton.set_active(False)
1379 #self.on_useauth_checkbutton_toggled(useauth_checkbutton)
1381 (model, iter_) = widget.get_selection().get_selected()
1382 if not iter_:
1383 self.xml.get_object('proxyname_entry').set_text('')
1384 self.xml.get_object('proxytype_combobox').set_sensitive(False)
1385 self.xml.get_object('proxy_table').set_sensitive(False)
1386 self.block_signal = False
1387 return
1389 proxy = model[iter_][0]
1390 self.xml.get_object('proxyname_entry').set_text(proxy)
1392 if proxy == _('None'): # special proxy None
1393 self.show_bosh_fields(False)
1394 self.proxyname_entry.set_editable(False)
1395 self.xml.get_object('remove_proxy_button').set_sensitive(False)
1396 self.xml.get_object('proxytype_combobox').set_sensitive(False)
1397 self.xml.get_object('proxy_table').set_sensitive(False)
1398 else:
1399 proxytype = gajim.config.get_per('proxies', proxy, 'type')
1401 self.show_bosh_fields(proxytype=='bosh')
1403 self.proxyname_entry.set_editable(True)
1404 self.xml.get_object('remove_proxy_button').set_sensitive(True)
1405 self.xml.get_object('proxytype_combobox').set_sensitive(True)
1406 self.xml.get_object('proxy_table').set_sensitive(True)
1407 proxyhost_entry.set_text(gajim.config.get_per('proxies', proxy,
1408 'host'))
1409 proxyport_entry.set_text(unicode(gajim.config.get_per('proxies',
1410 proxy, 'port')))
1411 proxyuser_entry.set_text(gajim.config.get_per('proxies', proxy,
1412 'user'))
1413 proxypass_entry.set_text(gajim.config.get_per('proxies', proxy,
1414 'pass'))
1415 boshuri_entry.set_text(gajim.config.get_per('proxies', proxy,
1416 'bosh_uri'))
1417 types = ['http', 'socks5', 'bosh']
1418 self.proxytype_combobox.set_active(types.index(proxytype))
1419 boshuseproxy_checkbutton.set_active(
1420 gajim.config.get_per('proxies', proxy, 'bosh_useproxy'))
1421 useauth_checkbutton.set_active(
1422 gajim.config.get_per('proxies', proxy, 'useauth'))
1423 self.block_signal = False
1425 def on_proxies_treeview_key_press_event(self, widget, event):
1426 if event.keyval == gtk.keysyms.Delete:
1427 self.on_remove_proxy_button_clicked(widget)
1429 def on_proxyname_entry_changed(self, widget):
1430 if self.block_signal:
1431 return
1432 (model, iter_) = self.proxies_treeview.get_selection().get_selected()
1433 if not iter_:
1434 return
1435 old_name = model.get_value(iter_, 0).decode('utf-8')
1436 new_name = widget.get_text().decode('utf-8')
1437 if new_name == '':
1438 return
1439 if new_name == old_name:
1440 return
1441 config = gajim.config.get_per('proxies', old_name)
1442 gajim.config.del_per('proxies', old_name)
1443 gajim.config.add_per('proxies', new_name)
1444 for option in config:
1445 gajim.config.set_per('proxies', new_name, option,
1446 config[option][common.config.OPT_VAL])
1447 model.set_value(iter_, 0, new_name)
1449 def on_proxytype_combobox_changed(self, widget):
1450 if self.block_signal:
1451 return
1452 types = ['http', 'socks5', 'bosh']
1453 type_ = self.proxytype_combobox.get_active()
1454 self.show_bosh_fields(types[type_]=='bosh')
1455 proxy = self.proxyname_entry.get_text().decode('utf-8')
1456 gajim.config.set_per('proxies', proxy, 'type', types[type_])
1458 def on_proxyhost_entry_changed(self, widget):
1459 if self.block_signal:
1460 return
1461 value = widget.get_text().decode('utf-8')
1462 proxy = self.proxyname_entry.get_text().decode('utf-8')
1463 gajim.config.set_per('proxies', proxy, 'host', value)
1465 def on_proxyport_entry_changed(self, widget):
1466 if self.block_signal:
1467 return
1468 value = widget.get_text().decode('utf-8')
1469 proxy = self.proxyname_entry.get_text().decode('utf-8')
1470 gajim.config.set_per('proxies', proxy, 'port', value)
1472 def on_proxyuser_entry_changed(self, widget):
1473 if self.block_signal:
1474 return
1475 value = widget.get_text().decode('utf-8')
1476 proxy = self.proxyname_entry.get_text().decode('utf-8')
1477 gajim.config.set_per('proxies', proxy, 'user', value)
1479 def on_boshuri_entry_changed(self, widget):
1480 if self.block_signal:
1481 return
1482 value = widget.get_text().decode('utf-8')
1483 proxy = self.proxyname_entry.get_text().decode('utf-8')
1484 gajim.config.set_per('proxies', proxy, 'bosh_uri', value)
1486 def on_proxypass_entry_changed(self, widget):
1487 if self.block_signal:
1488 return
1489 value = widget.get_text().decode('utf-8')
1490 proxy = self.proxyname_entry.get_text().decode('utf-8')
1491 gajim.config.set_per('proxies', proxy, 'pass', value)
1494 #---------- AccountsWindow class -------------#
1495 class AccountsWindow:
1497 Class for accounts window: list of accounts
1500 def on_accounts_window_destroy(self, widget):
1501 del gajim.interface.instances['accounts']
1503 def on_close_button_clicked(self, widget):
1504 self.check_resend_relog()
1505 self.window.destroy()
1507 def __init__(self):
1508 self.xml = gtkgui_helpers.get_gtk_builder('accounts_window.ui')
1509 self.window = self.xml.get_object('accounts_window')
1510 self.window.set_transient_for(gajim.interface.roster.window)
1511 self.accounts_treeview = self.xml.get_object('accounts_treeview')
1512 self.remove_button = self.xml.get_object('remove_button')
1513 self.rename_button = self.xml.get_object('rename_button')
1514 path_to_kbd_input_img = gtkgui_helpers.get_icon_path('gajim-kbd_input')
1515 img = self.xml.get_object('rename_image')
1516 img.set_from_file(path_to_kbd_input_img)
1517 self.notebook = self.xml.get_object('notebook')
1518 # Name
1519 model = gtk.ListStore(str)
1520 self.accounts_treeview.set_model(model)
1521 # column
1522 renderer = gtk.CellRendererText()
1523 self.accounts_treeview.insert_column_with_attributes(-1, _('Name'),
1524 renderer, text=0)
1526 self.current_account = None
1527 # When we fill info, we don't want to handle the changed signals
1528 self.ignore_events = False
1529 self.need_relogin = False
1530 self.resend_presence = False
1532 self.update_proxy_list()
1533 self.xml.connect_signals(self)
1534 self.init_accounts()
1535 self.window.show_all()
1537 # Merge accounts
1538 st = gajim.config.get('mergeaccounts')
1539 checkbutton = self.xml.get_object('merge_checkbutton')
1540 checkbutton.set_active(st)
1541 # prevent roster redraws by connecting the signal after button state is
1542 # set
1543 checkbutton.connect('toggled', self.on_merge_checkbutton_toggled)
1545 self.avahi_available = True
1546 try:
1547 import avahi
1548 except ImportError:
1549 self.avahi_available = False
1551 def on_accounts_window_key_press_event(self, widget, event):
1552 if event.keyval == gtk.keysyms.Escape:
1553 self.check_resend_relog()
1554 self.window.destroy()
1556 def select_account(self, account):
1557 model = self.accounts_treeview.get_model()
1558 iter_ = model.get_iter_root()
1559 while iter_:
1560 acct = model[iter_][0].decode('utf-8')
1561 if account == acct:
1562 self.accounts_treeview.set_cursor(model.get_path(iter_))
1563 return
1564 iter_ = model.iter_next(iter_)
1566 def init_accounts(self):
1568 Initialize listStore with existing accounts
1570 self.remove_button.set_sensitive(False)
1571 self.rename_button.set_sensitive(False)
1572 self.current_account = None
1573 model = self.accounts_treeview.get_model()
1574 model.clear()
1575 for account in gajim.config.get_per('accounts'):
1576 iter_ = model.append()
1577 model.set(iter_, 0, account)
1579 def resend(self, account):
1580 if not account in gajim.connections:
1581 return
1582 show = gajim.SHOW_LIST[gajim.connections[account].connected]
1583 status = gajim.connections[account].status
1584 gajim.connections[account].change_status(show, status)
1586 def check_resend_relog(self):
1587 if self.need_relogin and self.current_account == gajim.ZEROCONF_ACC_NAME:
1588 if gajim.ZEROCONF_ACC_NAME in gajim.connections:
1589 gajim.connections[gajim.ZEROCONF_ACC_NAME].update_details()
1590 return
1592 elif self.need_relogin and self.current_account and \
1593 gajim.connections[self.current_account].connected > 0:
1594 def login(account, show_before, status_before):
1596 Login with previous status
1598 # first make sure connection is really closed,
1599 # 0.5 may not be enough
1600 gajim.connections[account].disconnect(True)
1601 gajim.interface.roster.send_status(account, show_before,
1602 status_before)
1604 def relog(account):
1605 self.dialog.destroy()
1606 show_before = gajim.SHOW_LIST[gajim.connections[account].connected]
1607 status_before = gajim.connections[account].status
1608 gajim.interface.roster.send_status(account, 'offline',
1609 _('Be right back.'))
1610 gobject.timeout_add(500, login, account, show_before, status_before)
1612 def on_yes(checked, account):
1613 relog(account)
1614 def on_no(account):
1615 if self.resend_presence:
1616 self.resend(account)
1617 if self.current_account in gajim.connections:
1618 self.dialog = dialogs.YesNoDialog(_('Relogin now?'),
1619 _('If you want all the changes to apply instantly, '
1620 'you must relogin.'), on_response_yes=(on_yes,
1621 self.current_account), on_response_no=(on_no,
1622 self.current_account))
1623 elif self.resend_presence:
1624 self.resend(self.current_account)
1626 self.need_relogin = False
1627 self.resend_presence = False
1629 def on_accounts_treeview_cursor_changed(self, widget):
1631 Activate modify buttons when a row is selected, update accounts info
1633 sel = self.accounts_treeview.get_selection()
1634 (model, iter_) = sel.get_selected()
1635 if iter_:
1636 account = model[iter_][0].decode('utf-8')
1637 else:
1638 account = None
1639 if self.current_account and self.current_account == account:
1640 # We're comming back to our current account, no need to update widgets
1641 return
1642 # Save config for previous account if needed cause focus_out event is
1643 # called after the changed event
1644 if self.current_account and self.window.get_focus():
1645 focused_widget = self.window.get_focus()
1646 focused_widget_name = focused_widget.get_name()
1647 if focused_widget_name in ('jid_entry1', 'resource_entry1',
1648 'custom_port_entry', 'cert_entry1'):
1649 if focused_widget_name == 'jid_entry1':
1650 func = self.on_jid_entry1_focus_out_event
1651 elif focused_widget_name == 'resource_entry1':
1652 func = self.on_resource_entry1_focus_out_event
1653 elif focused_widget_name == 'custom_port_entry':
1654 func = self.on_custom_port_entry_focus_out_event
1655 elif focused_widget_name == 'cert_entry1':
1656 func = self.on_cert_entry1_focus_out_event
1657 if func(focused_widget, None):
1658 # Error detected in entry, don't change account, re-put cursor on
1659 # previous row
1660 self.select_account(self.current_account)
1661 return True
1662 self.window.set_focus(widget)
1664 self.check_resend_relog()
1666 if account:
1667 self.remove_button.set_sensitive(True)
1668 self.rename_button.set_sensitive(True)
1669 else:
1670 self.remove_button.set_sensitive(False)
1671 self.rename_button.set_sensitive(False)
1672 if iter_:
1673 self.current_account = account
1674 if account == gajim.ZEROCONF_ACC_NAME:
1675 self.remove_button.set_sensitive(False)
1676 self.init_account()
1677 self.update_proxy_list()
1679 def on_browse_for_client_cert_button_clicked(self, widget, data=None):
1680 def on_ok(widget, path_to_clientcert_file):
1681 self.dialog.destroy()
1682 if not path_to_clientcert_file:
1683 return
1684 self.xml.get_object('cert_entry1').set_text(path_to_clientcert_file)
1685 gajim.config.set_per('accounts', self.current_account,
1686 'client_cert', path_to_clientcert_file)
1688 def on_cancel(widget):
1689 self.dialog.destroy()
1691 path_to_clientcert_file = self.xml.get_object('cert_entry1').get_text()
1692 self.dialog = dialogs.ClientCertChooserDialog(path_to_clientcert_file,
1693 on_ok, on_cancel)
1695 def update_proxy_list(self):
1696 if self.current_account:
1697 our_proxy = gajim.config.get_per('accounts', self.current_account,
1698 'proxy')
1699 else:
1700 our_proxy = ''
1702 if not our_proxy:
1703 our_proxy = _('None')
1704 proxy_combobox = self.xml.get_object('proxies_combobox1')
1705 model = gtk.ListStore(str)
1706 proxy_combobox.set_model(model)
1707 l = gajim.config.get_per('proxies')
1708 l.insert(0, _('None'))
1709 for i in xrange(len(l)):
1710 model.append([l[i]])
1711 if our_proxy == l[i]:
1712 proxy_combobox.set_active(i)
1714 def init_account(self):
1715 if not self.current_account:
1716 self.notebook.set_current_page(0)
1717 return
1718 if gajim.config.get_per('accounts', self.current_account, 'is_zeroconf'):
1719 self.ignore_events = True
1720 self.init_zeroconf_account()
1721 self.ignore_events = False
1722 self.notebook.set_current_page(2)
1723 return
1724 self.ignore_events = True
1725 self.init_normal_account()
1726 self.ignore_events = False
1727 self.notebook.set_current_page(1)
1729 def init_zeroconf_account(self):
1730 active = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME,
1731 'active')
1732 self.xml.get_object('enable_zeroconf_checkbutton2').set_active(active)
1733 if not gajim.HAVE_ZEROCONF:
1734 self.xml.get_object('enable_zeroconf_checkbutton2').set_sensitive(
1735 False)
1736 self.xml.get_object('zeroconf_notebook').set_sensitive(active)
1737 # General tab
1738 st = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME,
1739 'autoconnect')
1740 self.xml.get_object('autoconnect_checkbutton2').set_active(st)
1742 list_no_log_for = gajim.config.get_per('accounts',
1743 gajim.ZEROCONF_ACC_NAME, 'no_log_for').split()
1744 if gajim.ZEROCONF_ACC_NAME in list_no_log_for:
1745 self.xml.get_object('log_history_checkbutton2').set_active(0)
1746 else:
1747 self.xml.get_object('log_history_checkbutton2').set_active(1)
1749 st = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME,
1750 'sync_with_global_status')
1751 self.xml.get_object('sync_with_global_status_checkbutton2').set_active(st)
1753 st = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME,
1754 'use_custom_host')
1755 self.xml.get_object('custom_port_checkbutton2').set_active(st)
1756 self.xml.get_object('custom_port_entry2').set_sensitive(st)
1758 st = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME,
1759 'custom_port')
1760 if not st:
1761 gajim.config.set_per('accounts', gajim.ZEROCONF_ACC_NAME,
1762 'custom_port', '5298')
1763 st = '5298'
1764 self.xml.get_object('custom_port_entry2').set_text(str(st))
1766 # Personal tab
1767 gpg_key_label = self.xml.get_object('gpg_key_label2')
1768 if gajim.ZEROCONF_ACC_NAME in gajim.connections and \
1769 gajim.connections[gajim.ZEROCONF_ACC_NAME].gpg:
1770 self.xml.get_object('gpg_choose_button2').set_sensitive(True)
1771 self.init_account_gpg()
1772 else:
1773 gpg_key_label.set_text(_('OpenPGP is not usable on this computer'))
1774 self.xml.get_object('gpg_choose_button2').set_sensitive(False)
1776 for opt in ('first_name', 'last_name', 'jabber_id', 'email'):
1777 st = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME,
1778 'zeroconf_' + opt)
1779 self.xml.get_object(opt + '_entry2').set_text(st)
1781 def init_account_gpg(self):
1782 account = self.current_account
1783 keyid = gajim.config.get_per('accounts', account, 'keyid')
1784 keyname = gajim.config.get_per('accounts', account, 'keyname')
1785 use_gpg_agent = gajim.config.get('use_gpg_agent')
1787 if account == gajim.ZEROCONF_ACC_NAME:
1788 widget_name_add = '2'
1789 else:
1790 widget_name_add = '1'
1792 gpg_key_label = self.xml.get_object('gpg_key_label' + widget_name_add)
1793 gpg_name_label = self.xml.get_object('gpg_name_label' + widget_name_add)
1794 use_gpg_agent_checkbutton = self.xml.get_object(
1795 'use_gpg_agent_checkbutton' + widget_name_add)
1797 if not keyid:
1798 use_gpg_agent_checkbutton.set_sensitive(False)
1799 gpg_key_label.set_text(_('No key selected'))
1800 gpg_name_label.set_text('')
1801 return
1803 gpg_key_label.set_text(keyid)
1804 gpg_name_label.set_text(keyname)
1805 use_gpg_agent_checkbutton.set_sensitive(True)
1806 use_gpg_agent_checkbutton.set_active(use_gpg_agent)
1808 def draw_normal_jid(self):
1809 account = self.current_account
1810 self.ignore_events = True
1811 active = gajim.config.get_per('accounts', account, 'active')
1812 self.xml.get_object('enable_checkbutton1').set_active(active)
1813 self.xml.get_object('normal_notebook1').set_sensitive(active)
1814 if gajim.config.get_per('accounts', account, 'anonymous_auth'):
1815 self.xml.get_object('anonymous_checkbutton1').set_active(True)
1816 self.xml.get_object('jid_label1').set_text(_('Server:'))
1817 save_password = self.xml.get_object('save_password_checkbutton1')
1818 save_password.set_active(False)
1819 save_password.set_sensitive(False)
1820 password_entry = self.xml.get_object('password_entry1')
1821 password_entry.set_text('')
1822 password_entry.set_sensitive(False)
1823 jid = gajim.config.get_per('accounts', account, 'hostname')
1824 else:
1825 self.xml.get_object('anonymous_checkbutton1').set_active(False)
1826 self.xml.get_object('jid_label1').set_text(_('Jabber ID:'))
1827 savepass = gajim.config.get_per('accounts', account, 'savepass')
1828 save_password = self.xml.get_object('save_password_checkbutton1')
1829 save_password.set_sensitive(True)
1830 save_password.set_active(savepass)
1831 password_entry = self.xml.get_object('password_entry1')
1832 if savepass:
1833 passstr = passwords.get_password(account) or ''
1834 password_entry.set_sensitive(True)
1835 else:
1836 passstr = ''
1837 password_entry.set_sensitive(False)
1838 password_entry.set_text(passstr)
1840 jid = gajim.config.get_per('accounts', account, 'name') \
1841 + '@' + gajim.config.get_per('accounts', account, 'hostname')
1842 self.xml.get_object('jid_entry1').set_text(jid)
1843 self.ignore_events = False
1845 def init_normal_account(self):
1846 account = self.current_account
1847 # Account tab
1848 self.draw_normal_jid()
1849 self.xml.get_object('resource_entry1').set_text(gajim.config.get_per(
1850 'accounts', account, 'resource'))
1852 client_cert = gajim.config.get_per('accounts', account, 'client_cert')
1853 self.xml.get_object('cert_entry1').set_text(client_cert)
1854 client_cert_encrypted = gajim.config.get_per('accounts', account,
1855 'client_cert_encrypted')
1856 self.xml.get_object('client_cert_encrypted_checkbutton1').\
1857 set_active(client_cert_encrypted)
1859 self.xml.get_object('adjust_priority_with_status_checkbutton1').\
1860 set_active(gajim.config.get_per('accounts', account,
1861 'adjust_priority_with_status'))
1862 spinbutton = self.xml.get_object('priority_spinbutton1')
1863 if gajim.config.get('enable_negative_priority'):
1864 spinbutton.set_range(-128, 127)
1865 else:
1866 spinbutton.set_range(0, 127)
1867 spinbutton.set_value(gajim.config.get_per('accounts', account,
1868 'priority'))
1870 # Connection tab
1871 use_env_http_proxy = gajim.config.get_per('accounts', account,
1872 'use_env_http_proxy')
1873 self.xml.get_object('use_env_http_proxy_checkbutton1').set_active(
1874 use_env_http_proxy)
1875 self.xml.get_object('proxy_hbox1').set_sensitive(not use_env_http_proxy)
1877 warn_when_insecure_ssl = gajim.config.get_per('accounts', account,
1878 'warn_when_insecure_ssl_connection')
1879 self.xml.get_object('warn_when_insecure_connection_checkbutton1').\
1880 set_active(warn_when_insecure_ssl)
1882 self.xml.get_object('send_keepalive_checkbutton1').set_active(
1883 gajim.config.get_per('accounts', account, 'keep_alives_enabled'))
1885 use_custom_host = gajim.config.get_per('accounts', account,
1886 'use_custom_host')
1887 self.xml.get_object('custom_host_port_checkbutton1').set_active(
1888 use_custom_host)
1889 custom_host = gajim.config.get_per('accounts', account, 'custom_host')
1890 if not custom_host:
1891 custom_host = gajim.config.get_per('accounts', account, 'hostname')
1892 gajim.config.set_per('accounts', account, 'custom_host', custom_host)
1893 self.xml.get_object('custom_host_entry1').set_text(custom_host)
1894 custom_port = gajim.config.get_per('accounts', account, 'custom_port')
1895 if not custom_port:
1896 custom_port = 5222
1897 gajim.config.set_per('accounts', account, 'custom_port', custom_port)
1898 self.xml.get_object('custom_port_entry1').set_text(unicode(custom_port))
1900 # Personal tab
1901 gpg_key_label = self.xml.get_object('gpg_key_label1')
1902 if gajim.HAVE_GPG:
1903 self.xml.get_object('gpg_choose_button1').set_sensitive(True)
1904 self.init_account_gpg()
1905 else:
1906 gpg_key_label.set_text(_('OpenPGP is not usable on this computer'))
1907 self.xml.get_object('gpg_choose_button1').set_sensitive(False)
1909 # General tab
1910 self.xml.get_object('autoconnect_checkbutton1').set_active(gajim.config.\
1911 get_per('accounts', account, 'autoconnect'))
1912 self.xml.get_object('autoreconnect_checkbutton1').set_active(gajim.
1913 config.get_per('accounts', account, 'autoreconnect'))
1915 list_no_log_for = gajim.config.get_per('accounts', account,
1916 'no_log_for').split()
1917 if account in list_no_log_for:
1918 self.xml.get_object('log_history_checkbutton1').set_active(False)
1919 else:
1920 self.xml.get_object('log_history_checkbutton1').set_active(True)
1922 self.xml.get_object('sync_with_global_status_checkbutton1').set_active(
1923 gajim.config.get_per('accounts', account, 'sync_with_global_status'))
1924 self.xml.get_object('use_ft_proxies_checkbutton1').set_active(
1925 gajim.config.get_per('accounts', account, 'use_ft_proxies'))
1927 def on_add_button_clicked(self, widget):
1929 When add button is clicked: open an account information window
1931 if 'account_creation_wizard' in gajim.interface.instances:
1932 gajim.interface.instances['account_creation_wizard'].window.present()
1933 else:
1934 gajim.interface.instances['account_creation_wizard'] = \
1935 AccountCreationWizardWindow()
1937 def on_remove_button_clicked(self, widget):
1939 When delete button is clicked: Remove an account from the listStore and
1940 from the config file
1942 if not self.current_account:
1943 return
1944 account = self.current_account
1945 if len(gajim.events.get_events(account)):
1946 dialogs.ErrorDialog(_('Unread events'),
1947 _('Read all pending events before removing this account.'))
1948 return
1950 if gajim.config.get_per('accounts', account, 'is_zeroconf'):
1951 # Should never happen as button is insensitive
1952 return
1954 win_opened = False
1955 if gajim.interface.msg_win_mgr.get_controls(acct=account):
1956 win_opened = True
1957 elif account in gajim.interface.instances:
1958 for key in gajim.interface.instances[account]:
1959 if gajim.interface.instances[account][key] and key != \
1960 'remove_account':
1961 win_opened = True
1962 break
1963 # Detect if we have opened windows for this account
1964 def remove(account):
1965 if account in gajim.interface.instances and \
1966 'remove_account' in gajim.interface.instances[account]:
1967 gajim.interface.instances[account]['remove_account'].window.\
1968 present()
1969 else:
1970 if not account in gajim.interface.instances:
1971 gajim.interface.instances[account] = {}
1972 gajim.interface.instances[account]['remove_account'] = \
1973 RemoveAccountWindow(account)
1974 if win_opened:
1975 dialogs.ConfirmationDialog(
1976 _('You have opened chat in account %s') % account,
1977 _('All chat and groupchat windows will be closed. Do you want to '
1978 'continue?'),
1979 on_response_ok = (remove, account))
1980 else:
1981 remove(account)
1983 def on_rename_button_clicked(self, widget):
1984 if not self.current_account:
1985 return
1986 active = gajim.config.get_per('accounts', self.current_account, 'active')
1987 if active and gajim.connections[self.current_account].connected != 0:
1988 dialogs.ErrorDialog(
1989 _('You are currently connected to the server'),
1990 _('To change the account name, you must be disconnected.'))
1991 return
1992 if len(gajim.events.get_events(self.current_account)):
1993 dialogs.ErrorDialog(_('Unread events'),
1994 _('To change the account name, you must read all pending '
1995 'events.'))
1996 return
1997 # Get the new name
1998 def on_renamed(new_name, old_name):
1999 if new_name in gajim.connections:
2000 dialogs.ErrorDialog(_('Account Name Already Used'),
2001 _('This name is already used by another of your accounts. '
2002 'Please choose another name.'))
2003 return
2004 if (new_name == ''):
2005 dialogs.ErrorDialog(_('Invalid account name'),
2006 _('Account name cannot be empty.'))
2007 return
2008 if new_name.find(' ') != -1:
2009 dialogs.ErrorDialog(_('Invalid account name'),
2010 _('Account name cannot contain spaces.'))
2011 return
2012 if active:
2013 # update variables
2014 gajim.interface.instances[new_name] = gajim.interface.instances[
2015 old_name]
2016 gajim.interface.minimized_controls[new_name] = \
2017 gajim.interface.minimized_controls[old_name]
2018 gajim.nicks[new_name] = gajim.nicks[old_name]
2019 gajim.block_signed_in_notifications[new_name] = \
2020 gajim.block_signed_in_notifications[old_name]
2021 gajim.groups[new_name] = gajim.groups[old_name]
2022 gajim.gc_connected[new_name] = gajim.gc_connected[old_name]
2023 gajim.automatic_rooms[new_name] = gajim.automatic_rooms[old_name]
2024 gajim.newly_added[new_name] = gajim.newly_added[old_name]
2025 gajim.to_be_removed[new_name] = gajim.to_be_removed[old_name]
2026 gajim.sleeper_state[new_name] = gajim.sleeper_state[old_name]
2027 gajim.encrypted_chats[new_name] = gajim.encrypted_chats[old_name]
2028 gajim.last_message_time[new_name] = \
2029 gajim.last_message_time[old_name]
2030 gajim.status_before_autoaway[new_name] = \
2031 gajim.status_before_autoaway[old_name]
2032 gajim.transport_avatar[new_name] = gajim.transport_avatar[old_name]
2033 gajim.gajim_optional_features[new_name] = \
2034 gajim.gajim_optional_features[old_name]
2035 gajim.caps_hash[new_name] = gajim.caps_hash[old_name]
2037 gajim.contacts.change_account_name(old_name, new_name)
2038 gajim.events.change_account_name(old_name, new_name)
2040 # change account variable for chat / gc controls
2041 gajim.interface.msg_win_mgr.change_account_name(old_name, new_name)
2042 # upgrade account variable in opened windows
2043 for kind in ('infos', 'disco', 'gc_config', 'search',
2044 'online_dialog', 'sub_request'):
2045 for j in gajim.interface.instances[new_name][kind]:
2046 gajim.interface.instances[new_name][kind][j].account = \
2047 new_name
2049 # ServiceCache object keep old property account
2050 if hasattr(gajim.connections[old_name], 'services_cache'):
2051 gajim.connections[old_name].services_cache.account = new_name
2052 del gajim.interface.instances[old_name]
2053 del gajim.interface.minimized_controls[old_name]
2054 del gajim.nicks[old_name]
2055 del gajim.block_signed_in_notifications[old_name]
2056 del gajim.groups[old_name]
2057 del gajim.gc_connected[old_name]
2058 del gajim.automatic_rooms[old_name]
2059 del gajim.newly_added[old_name]
2060 del gajim.to_be_removed[old_name]
2061 del gajim.sleeper_state[old_name]
2062 del gajim.encrypted_chats[old_name]
2063 del gajim.last_message_time[old_name]
2064 del gajim.status_before_autoaway[old_name]
2065 del gajim.transport_avatar[old_name]
2066 del gajim.gajim_optional_features[old_name]
2067 del gajim.caps_hash[old_name]
2068 gajim.connections[old_name].name = new_name
2069 gajim.connections[old_name].pep_change_account_name(new_name)
2070 gajim.connections[old_name].caps_change_account_name(new_name)
2071 gajim.connections[new_name] = gajim.connections[old_name]
2072 del gajim.connections[old_name]
2073 gajim.config.add_per('accounts', new_name)
2074 old_config = gajim.config.get_per('accounts', old_name)
2075 for opt in old_config:
2076 gajim.config.set_per('accounts', new_name, opt, old_config[opt][1])
2077 gajim.config.del_per('accounts', old_name)
2078 if self.current_account == old_name:
2079 self.current_account = new_name
2080 if old_name == gajim.ZEROCONF_ACC_NAME:
2081 gajim.ZEROCONF_ACC_NAME = new_name
2082 # refresh roster
2083 gajim.interface.roster.setup_and_draw_roster()
2084 self.init_accounts()
2085 self.select_account(new_name)
2087 title = _('Rename Account')
2088 message = _('Enter a new name for account %s') % self.current_account
2089 old_text = self.current_account
2090 dialogs.InputDialog(title, message, old_text, is_modal=False,
2091 ok_handler=(on_renamed, self.current_account))
2093 def option_changed(self, option, value):
2094 return gajim.config.get_per('accounts', self.current_account, option) != \
2095 value
2097 def on_jid_entry1_focus_out_event(self, widget, event):
2098 if self.ignore_events:
2099 return
2100 jid = widget.get_text()
2101 # check if jid is conform to RFC and stringprep it
2102 try:
2103 jid = helpers.parse_jid(jid)
2104 except helpers.InvalidFormat, s:
2105 if not widget.is_focus():
2106 pritext = _('Invalid Jabber ID')
2107 dialogs.ErrorDialog(pritext, str(s))
2108 gobject.idle_add(lambda: widget.grab_focus())
2109 return True
2111 jid_splited = jid.split('@', 1)
2112 if len(jid_splited) != 2 and not gajim.config.get_per('accounts',
2113 self.current_account, 'anonymous_auth'):
2114 if not widget.is_focus():
2115 pritext = _('Invalid Jabber ID')
2116 sectext = _('A Jabber ID must be in the form "user@servername".')
2117 dialogs.ErrorDialog(pritext, sectext)
2118 gobject.idle_add(lambda: widget.grab_focus())
2119 return True
2122 if gajim.config.get_per('accounts', self.current_account,
2123 'anonymous_auth'):
2124 gajim.config.set_per('accounts', self.current_account, 'hostname',
2125 jid_splited[0])
2126 if self.option_changed('hostname', jid_splited[0]):
2127 self.need_relogin = True
2128 else:
2129 if self.option_changed('name', jid_splited[0]) or \
2130 self.option_changed('hostname', jid_splited[1]):
2131 self.need_relogin = True
2133 gajim.config.set_per('accounts', self.current_account, 'name',
2134 jid_splited[0])
2135 gajim.config.set_per('accounts', self.current_account, 'hostname',
2136 jid_splited[1])
2138 def on_cert_entry1_focus_out_event(self, widget, event):
2139 if self.ignore_events:
2140 return
2141 client_cert = widget.get_text()
2142 if self.option_changed('client_cert', client_cert):
2143 self.need_relogin = True
2144 gajim.config.set_per('accounts', self.current_account, 'client_cert',
2145 client_cert)
2147 def on_anonymous_checkbutton1_toggled(self, widget):
2148 if self.ignore_events:
2149 return
2150 active = widget.get_active()
2151 gajim.config.set_per('accounts', self.current_account, 'anonymous_auth',
2152 active)
2153 self.draw_normal_jid()
2155 def on_password_entry1_changed(self, widget):
2156 if self.ignore_events:
2157 return
2158 passwords.save_password(self.current_account, widget.get_text().decode(
2159 'utf-8'))
2161 def on_save_password_checkbutton1_toggled(self, widget):
2162 if self.ignore_events:
2163 return
2164 active = widget.get_active()
2165 password_entry = self.xml.get_object('password_entry1')
2166 password_entry.set_sensitive(active)
2167 gajim.config.set_per('accounts', self.current_account, 'savepass', active)
2168 if active:
2169 password = password_entry.get_text()
2170 passwords.save_password(self.current_account, password)
2171 else:
2172 passwords.save_password(self.current_account, '')
2174 def on_resource_entry1_focus_out_event(self, widget, event):
2175 if self.ignore_events:
2176 return
2177 resource = self.xml.get_object('resource_entry1').get_text().decode(
2178 'utf-8')
2179 try:
2180 resource = helpers.parse_resource(resource)
2181 except helpers.InvalidFormat, s:
2182 if not widget.is_focus():
2183 pritext = _('Invalid Jabber ID')
2184 dialogs.ErrorDialog(pritext, str(s))
2185 gobject.idle_add(lambda: widget.grab_focus())
2186 return True
2188 if self.option_changed('resource', resource):
2189 self.need_relogin = True
2191 gajim.config.set_per('accounts', self.current_account, 'resource',
2192 resource)
2194 def on_adjust_priority_with_status_checkbutton1_toggled(self, widget):
2195 self.xml.get_object('priority_spinbutton1').set_sensitive(
2196 not widget.get_active())
2197 self.on_checkbutton_toggled(widget, 'adjust_priority_with_status',
2198 account = self.current_account)
2200 def on_priority_spinbutton1_value_changed(self, widget):
2201 prio = widget.get_value_as_int()
2203 if self.option_changed('priority', prio):
2204 self.resend_presence = True
2206 gajim.config.set_per('accounts', self.current_account, 'priority', prio)
2208 def on_synchronise_contacts_button1_clicked(self, widget):
2209 try:
2210 dialogs.SynchroniseSelectAccountDialog(self.current_account)
2211 except GajimGeneralException:
2212 # If we showed ErrorDialog, there will not be dialog instance
2213 return
2215 def on_change_password_button1_clicked(self, widget):
2216 def on_changed(new_password):
2217 if new_password is not None:
2218 gajim.connections[self.current_account].change_password(
2219 new_password)
2220 if self.xml.get_object('save_password_checkbutton1').get_active():
2221 self.xml.get_object('password_entry1').set_text(new_password)
2223 try:
2224 dialogs.ChangePasswordDialog(self.current_account, on_changed)
2225 except GajimGeneralException:
2226 # if we showed ErrorDialog, there will not be dialog instance
2227 return
2229 def on_client_cert_encrypted_checkbutton1_toggled(self, widget):
2230 if self.ignore_events:
2231 return
2232 self.on_checkbutton_toggled(widget, 'client_cert_encrypted',
2233 account=self.current_account)
2235 def on_autoconnect_checkbutton_toggled(self, widget):
2236 if self.ignore_events:
2237 return
2238 self.on_checkbutton_toggled(widget, 'autoconnect',
2239 account=self.current_account)
2241 def on_autoreconnect_checkbutton_toggled(self, widget):
2242 if self.ignore_events:
2243 return
2244 self.on_checkbutton_toggled(widget, 'autoreconnect',
2245 account=self.current_account)
2247 def on_log_history_checkbutton_toggled(self, widget):
2248 if self.ignore_events:
2249 return
2250 list_no_log_for = gajim.config.get_per('accounts', self.current_account,
2251 'no_log_for').split()
2252 if self.current_account in list_no_log_for:
2253 list_no_log_for.remove(self.current_account)
2255 if not widget.get_active():
2256 list_no_log_for.append(self.current_account)
2257 gajim.config.set_per('accounts', self.current_account, 'no_log_for',
2258 ' '.join(list_no_log_for))
2260 def on_sync_with_global_status_checkbutton_toggled(self, widget):
2261 if self.ignore_events:
2262 return
2263 self.on_checkbutton_toggled(widget, 'sync_with_global_status',
2264 account=self.current_account)
2265 gajim.interface.roster.update_status_combobox()
2267 def on_use_ft_proxies_checkbutton1_toggled(self, widget):
2268 if self.ignore_events:
2269 return
2270 self.on_checkbutton_toggled(widget, 'use_ft_proxies',
2271 account=self.current_account)
2273 def on_use_env_http_proxy_checkbutton1_toggled(self, widget):
2274 if self.ignore_events:
2275 return
2276 self.on_checkbutton_toggled(widget, 'use_env_http_proxy',
2277 account=self.current_account)
2278 hbox = self.xml.get_object('proxy_hbox1')
2279 hbox.set_sensitive(not widget.get_active())
2281 def on_proxies_combobox1_changed(self, widget):
2282 active = widget.get_active()
2283 proxy = widget.get_model()[active][0].decode('utf-8')
2284 if proxy == _('None'):
2285 proxy = ''
2287 if self.option_changed('proxy', proxy):
2288 self.need_relogin = True
2290 gajim.config.set_per('accounts', self.current_account, 'proxy', proxy)
2292 def on_manage_proxies_button1_clicked(self, widget):
2293 if 'manage_proxies' in gajim.interface.instances:
2294 gajim.interface.instances['manage_proxies'].window.present()
2295 else:
2296 gajim.interface.instances['manage_proxies'] = ManageProxiesWindow()
2298 def on_warn_when_insecure_connection_checkbutton1_toggled(self, widget):
2299 if self.ignore_events:
2300 return
2302 self.on_checkbutton_toggled(widget, 'warn_when_insecure_ssl_connection',
2303 account=self.current_account)
2305 def on_send_keepalive_checkbutton1_toggled(self, widget):
2306 if self.ignore_events:
2307 return
2308 self.on_checkbutton_toggled(widget, 'keep_alives_enabled',
2309 account=self.current_account)
2310 gajim.config.set_per('accounts', self.current_account,
2311 'ping_alives_enabled', widget.get_active())
2313 def on_custom_host_port_checkbutton1_toggled(self, widget):
2314 if self.option_changed('use_custom_host', widget.get_active()):
2315 self.need_relogin = True
2317 self.on_checkbutton_toggled(widget, 'use_custom_host',
2318 account=self.current_account)
2319 active = widget.get_active()
2320 self.xml.get_object('custom_host_port_hbox1').set_sensitive(active)
2322 def on_custom_host_entry1_changed(self, widget):
2323 if self.ignore_events:
2324 return
2325 host = widget.get_text().decode('utf-8')
2326 if self.option_changed('custom_host', host):
2327 self.need_relogin = True
2328 gajim.config.set_per('accounts', self.current_account, 'custom_host',
2329 host)
2331 def on_custom_port_entry_focus_out_event(self, widget, event):
2332 if self.ignore_events:
2333 return
2334 custom_port = widget.get_text()
2335 try:
2336 custom_port = int(custom_port)
2337 except Exception:
2338 if not widget.is_focus():
2339 dialogs.ErrorDialog(_('Invalid entry'),
2340 _('Custom port must be a port number.'))
2341 gobject.idle_add(lambda: widget.grab_focus())
2342 return True
2343 if self.option_changed('custom_port', custom_port):
2344 self.need_relogin = True
2345 gajim.config.set_per('accounts', self.current_account, 'custom_port',
2346 custom_port)
2348 def on_gpg_choose_button_clicked(self, widget, data = None):
2349 if self.current_account in gajim.connections and \
2350 gajim.connections[self.current_account].gpg:
2351 secret_keys = gajim.connections[self.current_account].\
2352 ask_gpg_secrete_keys()
2354 # self.current_account is None and/or gajim.connections is {}
2355 else:
2356 if gajim.HAVE_GPG:
2357 secret_keys = gpg.GnuPG().get_secret_keys()
2358 else:
2359 secret_keys = []
2360 if not secret_keys:
2361 dialogs.ErrorDialog(_('Failed to get secret keys'),
2362 _('There is no OpenPGP secret key available.'))
2363 secret_keys[_('None')] = _('None')
2365 def on_key_selected(keyID):
2366 if keyID is None:
2367 return
2368 if self.current_account == gajim.ZEROCONF_ACC_NAME:
2369 wiget_name_ext = '2'
2370 else:
2371 wiget_name_ext = '1'
2372 gpg_key_label = self.xml.get_object('gpg_key_label' + wiget_name_ext)
2373 gpg_name_label = self.xml.get_object('gpg_name_label' + wiget_name_ext)
2374 use_gpg_agent_checkbutton = self.xml.get_object(
2375 'use_gpg_agent_checkbutton' + wiget_name_ext)
2376 if keyID[0] == _('None'):
2377 gpg_key_label.set_text(_('No key selected'))
2378 gpg_name_label.set_text('')
2379 use_gpg_agent_checkbutton.set_sensitive(False)
2380 if self.option_changed('keyid', ''):
2381 self.need_relogin = True
2382 gajim.config.set_per('accounts', self.current_account, 'keyname',
2384 gajim.config.set_per('accounts', self.current_account, 'keyid', '')
2385 else:
2386 gpg_key_label.set_text(keyID[0])
2387 gpg_name_label.set_text(keyID[1])
2388 use_gpg_agent_checkbutton.set_sensitive(True)
2389 if self.option_changed('keyid', keyID[0]):
2390 self.need_relogin = True
2391 gajim.config.set_per('accounts', self.current_account, 'keyname',
2392 keyID[1])
2393 gajim.config.set_per('accounts', self.current_account, 'keyid',
2394 keyID[0])
2396 dialogs.ChooseGPGKeyDialog(_('OpenPGP Key Selection'),
2397 _('Choose your OpenPGP key'), secret_keys, on_key_selected)
2399 def on_use_gpg_agent_checkbutton_toggled(self, widget):
2400 self.on_checkbutton_toggled(widget, 'use_gpg_agent')
2402 def on_edit_details_button1_clicked(self, widget):
2403 if self.current_account not in gajim.interface.instances:
2404 dialogs.ErrorDialog(_('No such account available'),
2405 _('You must create your account before editing your personal '
2406 'information.'))
2407 return
2409 # show error dialog if account is newly created (not in gajim.connections)
2410 if self.current_account not in gajim.connections or \
2411 gajim.connections[self.current_account].connected < 2:
2412 dialogs.ErrorDialog(_('You are not connected to the server'),
2413 _('Without a connection, you can not edit your personal information.'))
2414 return
2416 if not gajim.connections[self.current_account].vcard_supported:
2417 dialogs.ErrorDialog(_("Your server doesn't support Vcard"),
2418 _("Your server can't save your personal information."))
2419 return
2421 gajim.interface.edit_own_details(self.current_account)
2423 def on_checkbutton_toggled(self, widget, config_name,
2424 change_sensitivity_widgets = None, account = None):
2425 if account:
2426 gajim.config.set_per('accounts', account, config_name,
2427 widget.get_active())
2428 else:
2429 gajim.config.set(config_name, widget.get_active())
2430 if change_sensitivity_widgets:
2431 for w in change_sensitivity_widgets:
2432 w.set_sensitive(widget.get_active())
2433 gajim.interface.save_config()
2435 def on_merge_checkbutton_toggled(self, widget):
2436 self.on_checkbutton_toggled(widget, 'mergeaccounts')
2437 if len(gajim.connections) >= 2: # Do not merge accounts if only one active
2438 gajim.interface.roster.regroup = gajim.config.get('mergeaccounts')
2439 else:
2440 gajim.interface.roster.regroup = False
2441 gajim.interface.roster.setup_and_draw_roster()
2443 def _disable_account(self, account):
2444 gajim.interface.roster.close_all(account)
2445 if account == gajim.ZEROCONF_ACC_NAME:
2446 gajim.connections[account].disable_account()
2447 del gajim.connections[account]
2448 gajim.interface.save_config()
2449 del gajim.interface.instances[account]
2450 del gajim.interface.minimized_controls[account]
2451 del gajim.nicks[account]
2452 del gajim.block_signed_in_notifications[account]
2453 del gajim.groups[account]
2454 gajim.contacts.remove_account(account)
2455 del gajim.gc_connected[account]
2456 del gajim.automatic_rooms[account]
2457 del gajim.to_be_removed[account]
2458 del gajim.newly_added[account]
2459 del gajim.sleeper_state[account]
2460 del gajim.encrypted_chats[account]
2461 del gajim.last_message_time[account]
2462 del gajim.status_before_autoaway[account]
2463 del gajim.transport_avatar[account]
2464 del gajim.gajim_optional_features[account]
2465 del gajim.caps_hash[account]
2466 if len(gajim.connections) >= 2:
2467 # Do not merge accounts if only one exists
2468 gajim.interface.roster.regroup = gajim.config.get('mergeaccounts')
2469 else:
2470 gajim.interface.roster.regroup = False
2471 gajim.interface.roster.setup_and_draw_roster()
2472 gajim.interface.roster.set_actions_menu_needs_rebuild()
2474 def _enable_account(self, account):
2475 if account == gajim.ZEROCONF_ACC_NAME:
2476 gajim.connections[account] = connection_zeroconf.ConnectionZeroconf(
2477 account)
2478 if gajim.connections[account].gpg:
2479 self.xml.get_object('gpg_choose_button2').set_sensitive(True)
2480 else:
2481 gajim.connections[account] = common.connection.Connection(account)
2482 if gajim.connections[account].gpg:
2483 self.xml.get_object('gpg_choose_button1').set_sensitive(True)
2484 self.init_account_gpg()
2485 # update variables
2486 gajim.interface.instances[account] = {'infos': {},
2487 'disco': {}, 'gc_config': {}, 'search': {}, 'online_dialog': {},
2488 'sub_request': {}}
2489 gajim.interface.minimized_controls[account] = {}
2490 gajim.connections[account].connected = 0
2491 gajim.groups[account] = {}
2492 gajim.contacts.add_account(account)
2493 gajim.gc_connected[account] = {}
2494 gajim.automatic_rooms[account] = {}
2495 gajim.newly_added[account] = []
2496 gajim.to_be_removed[account] = []
2497 if account == gajim.ZEROCONF_ACC_NAME:
2498 gajim.nicks[account] = gajim.ZEROCONF_ACC_NAME
2499 else:
2500 gajim.nicks[account] = gajim.config.get_per('accounts', account,
2501 'name')
2502 gajim.block_signed_in_notifications[account] = True
2503 gajim.sleeper_state[account] = 'off'
2504 gajim.encrypted_chats[account] = []
2505 gajim.last_message_time[account] = {}
2506 gajim.status_before_autoaway[account] = ''
2507 gajim.transport_avatar[account] = {}
2508 gajim.gajim_optional_features[account] = []
2509 gajim.caps_hash[account] = ''
2510 # refresh roster
2511 if len(gajim.connections) >= 2:
2512 # Do not merge accounts if only one exists
2513 gajim.interface.roster.regroup = gajim.config.get('mergeaccounts')
2514 else:
2515 gajim.interface.roster.regroup = False
2516 gajim.interface.roster.setup_and_draw_roster()
2517 gajim.interface.roster.set_actions_menu_needs_rebuild()
2518 gajim.interface.save_config()
2520 def on_enable_zeroconf_checkbutton2_toggled(self, widget):
2521 # don't do anything if there is an account with the local name but is a
2522 # normal account
2523 if self.ignore_events:
2524 return
2525 if self.current_account in gajim.connections and \
2526 gajim.connections[self.current_account].connected > 0:
2527 self.ignore_events = True
2528 self.xml.get_object('enable_zeroconf_checkbutton2').set_active(True)
2529 self.ignore_events = False
2530 dialogs.ErrorDialog(
2531 _('You are currently connected to the server'),
2532 _('To disable the account, you must be disconnected.'))
2533 return
2534 if gajim.ZEROCONF_ACC_NAME in gajim.connections and not \
2535 gajim.connections[gajim.ZEROCONF_ACC_NAME].is_zeroconf:
2536 gajim.connections[gajim.ZEROCONF_ACC_NAME].dispatch('ERROR',
2537 (_('Account Local already exists.'),
2538 _('Please rename or remove it before enabling link-local messaging'
2539 '.')))
2540 return
2542 if gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME, 'active') \
2543 and not widget.get_active():
2544 self.xml.get_object('zeroconf_notebook').set_sensitive(False)
2545 # disable
2546 self._disable_account(gajim.ZEROCONF_ACC_NAME)
2548 elif not gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME,
2549 'active') and widget.get_active():
2550 self.xml.get_object('zeroconf_notebook').set_sensitive(True)
2551 # enable (will create new account if not present)
2552 self._enable_account(gajim.ZEROCONF_ACC_NAME)
2554 self.on_checkbutton_toggled(widget, 'active',
2555 account=gajim.ZEROCONF_ACC_NAME)
2557 def on_enable_checkbutton1_toggled(self, widget):
2558 if self.ignore_events:
2559 return
2560 if self.current_account in gajim.connections and \
2561 gajim.connections[self.current_account].connected > 0:
2562 # connecting or connected
2563 self.ignore_events = True
2564 self.xml.get_object('enable_checkbutton1').set_active(True)
2565 self.ignore_events = False
2566 dialogs.ErrorDialog(
2567 _('You are currently connected to the server'),
2568 _('To disable the account, you must be disconnected.'))
2569 return
2570 # add/remove account in roster and all variables
2571 if widget.get_active():
2572 # enable
2573 self._enable_account(self.current_account)
2574 else:
2575 # disable
2576 self._disable_account(self.current_account)
2577 self.on_checkbutton_toggled(widget, 'active',
2578 account=self.current_account, change_sensitivity_widgets=[
2579 self.xml.get_object('normal_notebook1')])
2581 def on_custom_port_checkbutton2_toggled(self, widget):
2582 self.xml.get_object('custom_port_entry2').set_sensitive(
2583 widget.get_active())
2584 self.on_checkbutton_toggled(widget, 'use_custom_host',
2585 account = self.current_account)
2586 if not widget.get_active():
2587 self.xml.get_object('custom_port_entry2').set_text('5298')
2589 def on_first_name_entry2_changed(self, widget):
2590 if self.ignore_events:
2591 return
2592 name = widget.get_text().decode('utf-8')
2593 if self.option_changed('zeroconf_first_name', name):
2594 self.need_relogin = True
2595 gajim.config.set_per('accounts', self.current_account,
2596 'zeroconf_first_name', name)
2598 def on_last_name_entry2_changed(self, widget):
2599 if self.ignore_events:
2600 return
2601 name = widget.get_text().decode('utf-8')
2602 if self.option_changed('zeroconf_last_name', name):
2603 self.need_relogin = True
2604 gajim.config.set_per('accounts', self.current_account,
2605 'zeroconf_last_name', name)
2607 def on_jabber_id_entry2_changed(self, widget):
2608 if self.ignore_events:
2609 return
2610 id_ = widget.get_text().decode('utf-8')
2611 if self.option_changed('zeroconf_jabber_id', id_):
2612 self.need_relogin = True
2613 gajim.config.set_per('accounts', self.current_account,
2614 'zeroconf_jabber_id', id_)
2616 def on_email_entry2_changed(self, widget):
2617 if self.ignore_events:
2618 return
2619 email = widget.get_text().decode('utf-8')
2620 if self.option_changed('zeroconf_email', email):
2621 self.need_relogin = True
2622 gajim.config.set_per('accounts', self.current_account,
2623 'zeroconf_email', email)
2625 class FakeDataForm(gtk.Table, object):
2627 Class for forms that are in XML format <entry1>value1</entry1> infos in a
2628 table {entry1: value1}
2631 def __init__(self, infos):
2632 gtk.Table.__init__(self)
2633 self.infos = infos
2634 self.entries = {}
2635 self._draw_table()
2637 def _draw_table(self):
2639 Draw the table
2641 nbrow = 0
2642 if 'instructions' in self.infos:
2643 nbrow = 1
2644 self.resize(rows = nbrow, columns = 2)
2645 label = gtk.Label(self.infos['instructions'])
2646 self.attach(label, 0, 2, 0, 1, 0, 0, 0, 0)
2647 for name in self.infos.keys():
2648 if name in ('key', 'instructions', 'x', 'registered'):
2649 continue
2650 if not name:
2651 continue
2653 nbrow = nbrow + 1
2654 self.resize(rows = nbrow, columns = 2)
2655 label = gtk.Label(name.capitalize() + ':')
2656 self.attach(label, 0, 1, nbrow - 1, nbrow, 0, 0, 0, 0)
2657 entry = gtk.Entry()
2658 entry.set_activates_default(True)
2659 if self.infos[name]:
2660 entry.set_text(self.infos[name])
2661 if name == 'password':
2662 entry.set_visibility(False)
2663 self.attach(entry, 1, 2, nbrow - 1, nbrow, 0, 0, 0, 0)
2664 self.entries[name] = entry
2665 if nbrow == 1:
2666 entry.grab_focus()
2668 def get_infos(self):
2669 for name in self.entries.keys():
2670 self.infos[name] = self.entries[name].get_text().decode('utf-8')
2671 return self.infos
2673 class ServiceRegistrationWindow:
2675 Class for Service registration window. Window that appears when we want to
2676 subscribe to a service if is_form we use dataforms_widget else we use
2677 service_registarion_window
2679 def __init__(self, service, infos, account, is_form):
2680 self.service = service
2681 self.account = account
2682 self.is_form = is_form
2683 self.xml = gtkgui_helpers.get_gtk_builder('service_registration_window.ui')
2684 self.window = self.xml.get_object('service_registration_window')
2685 self.window.set_transient_for(gajim.interface.roster.window)
2686 if self.is_form:
2687 dataform = dataforms.ExtendForm(node = infos)
2688 self.data_form_widget = dataforms_widget.DataFormWidget(dataform)
2689 if self.data_form_widget.title:
2690 self.window.set_title('%s - Gajim' % self.data_form_widget.title)
2691 table = self.xml.get_object('table')
2692 table.attach(self.data_form_widget, 0, 2, 0, 1)
2693 else:
2694 if 'registered' in infos:
2695 self.window.set_title(_('Edit %s') % service)
2696 else:
2697 self.window.set_title(_('Register to %s') % service)
2698 self.data_form_widget = FakeDataForm(infos)
2699 table = self.xml.get_object('table')
2700 table.attach(self.data_form_widget, 0, 2, 0, 1)
2702 self.xml.connect_signals(self)
2703 self.window.show_all()
2705 def on_cancel_button_clicked(self, widget):
2706 self.window.destroy()
2708 def on_ok_button_clicked(self, widget):
2709 # send registration info to the core
2710 if self.is_form:
2711 form = self.data_form_widget.data_form
2712 gajim.connections[self.account].register_agent(self.service,
2713 form, True) # True is for is_form
2714 else:
2715 infos = self.data_form_widget.get_infos()
2716 if 'instructions' in infos:
2717 del infos['instructions']
2718 if 'registered' in infos:
2719 del infos['registered']
2720 gajim.connections[self.account].register_agent(self.service, infos)
2722 self.window.destroy()
2724 class GroupchatConfigWindow:
2726 def __init__(self, account, room_jid, form=None):
2727 self.account = account
2728 self.room_jid = room_jid
2729 self.form = form
2730 self.remove_button = {}
2731 self.affiliation_treeview = {}
2732 self.start_users_dict = {} # list at the beginning
2733 self.affiliation_labels = {'outcast': _('Ban List'),
2734 'member': _('Member List'), 'owner': _('Owner List'),
2735 'admin':_('Administrator List')}
2737 self.xml = gtkgui_helpers.get_gtk_builder('data_form_window.ui',
2738 'data_form_window')
2739 self.window = self.xml.get_object('data_form_window')
2740 self.window.set_transient_for(gajim.interface.roster.window)
2742 if self.form:
2743 config_vbox = self.xml.get_object('config_vbox')
2744 self.data_form_widget = dataforms_widget.DataFormWidget(self.form)
2745 # hide scrollbar of this data_form_widget, we already have in this
2746 # widget
2747 sw = self.data_form_widget.xml.get_object(
2748 'single_form_scrolledwindow')
2749 sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_NEVER)
2750 if self.form.title:
2751 self.xml.get_object('title_label').set_text(self.form.title)
2752 else:
2753 self.xml.get_object('title_hseparator').set_no_show_all(True)
2754 self.xml.get_object('title_hseparator').hide()
2756 self.data_form_widget.show()
2757 config_vbox.pack_start(self.data_form_widget)
2758 else:
2759 self.xml.get_object('title_label').set_no_show_all(True)
2760 self.xml.get_object('title_label').hide()
2761 self.xml.get_object('title_hseparator').set_no_show_all(True)
2762 self.xml.get_object('title_hseparator').hide()
2763 self.xml.get_object('config_hseparator').set_no_show_all(True)
2764 self.xml.get_object('config_hseparator').hide()
2766 # Draw the edit affiliation list things
2767 add_on_vbox = self.xml.get_object('add_on_vbox')
2769 for affiliation in self.affiliation_labels.keys():
2770 self.start_users_dict[affiliation] = {}
2771 hbox = gtk.HBox(spacing=5)
2772 add_on_vbox.pack_start(hbox, False)
2774 label = gtk.Label(self.affiliation_labels[affiliation])
2775 hbox.pack_start(label, False)
2777 bb = gtk.HButtonBox()
2778 bb.set_layout(gtk.BUTTONBOX_END)
2779 bb.set_spacing(5)
2780 hbox.pack_start(bb)
2781 add_button = gtk.Button(stock=gtk.STOCK_ADD)
2782 add_button.connect('clicked', self.on_add_button_clicked,
2783 affiliation)
2784 bb.pack_start(add_button)
2785 self.remove_button[affiliation] = gtk.Button(stock=gtk.STOCK_REMOVE)
2786 self.remove_button[affiliation].set_sensitive(False)
2787 self.remove_button[affiliation].connect('clicked',
2788 self.on_remove_button_clicked, affiliation)
2789 bb.pack_start(self.remove_button[affiliation])
2791 # jid, reason, nick, role
2792 liststore = gtk.ListStore(str, str, str, str)
2793 self.affiliation_treeview[affiliation] = gtk.TreeView(liststore)
2794 self.affiliation_treeview[affiliation].get_selection().set_mode(
2795 gtk.SELECTION_MULTIPLE)
2796 self.affiliation_treeview[affiliation].connect('cursor-changed',
2797 self.on_affiliation_treeview_cursor_changed, affiliation)
2798 renderer = gtk.CellRendererText()
2799 col = gtk.TreeViewColumn(_('JID'), renderer)
2800 col.add_attribute(renderer, 'text', 0)
2801 col.set_resizable(True)
2802 col.set_sort_column_id(0)
2803 self.affiliation_treeview[affiliation].append_column(col)
2805 if affiliation == 'outcast':
2806 renderer = gtk.CellRendererText()
2807 renderer.set_property('editable', True)
2808 renderer.connect('edited', self.on_cell_edited)
2809 col = gtk.TreeViewColumn(_('Reason'), renderer)
2810 col.add_attribute(renderer, 'text', 1)
2811 col.set_resizable(True)
2812 col.set_sort_column_id(1)
2813 self.affiliation_treeview[affiliation].append_column(col)
2814 elif affiliation == 'member':
2815 renderer = gtk.CellRendererText()
2816 col = gtk.TreeViewColumn(_('Nick'), renderer)
2817 col.add_attribute(renderer, 'text', 2)
2818 col.set_resizable(True)
2819 col.set_sort_column_id(2)
2820 self.affiliation_treeview[affiliation].append_column(col)
2821 renderer = gtk.CellRendererText()
2822 col = gtk.TreeViewColumn(_('Role'), renderer)
2823 col.add_attribute(renderer, 'text', 3)
2824 col.set_resizable(True)
2825 col.set_sort_column_id(3)
2826 self.affiliation_treeview[affiliation].append_column(col)
2828 sw = gtk.ScrolledWindow()
2829 sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_NEVER)
2830 sw.add(self.affiliation_treeview[affiliation])
2831 add_on_vbox.pack_start(sw)
2832 gajim.connections[self.account].get_affiliation_list(self.room_jid,
2833 affiliation)
2835 self.xml.connect_signals(self)
2836 self.window.show_all()
2838 def on_cancel_button_clicked(self, widget):
2839 self.window.destroy()
2841 def on_cell_edited(self, cell, path, new_text):
2842 model = self.affiliation_treeview['outcast'].get_model()
2843 new_text = new_text.decode('utf-8')
2844 iter_ = model.get_iter(path)
2845 model[iter_][1] = new_text
2847 def on_add_button_clicked(self, widget, affiliation):
2848 if affiliation == 'outcast':
2849 title = _('Banning...')
2850 #You can move '\n' before user@domain if that line is TOO BIG
2851 prompt = _('<b>Whom do you want to ban?</b>\n\n')
2852 elif affiliation == 'member':
2853 title = _('Adding Member...')
2854 prompt = _('<b>Whom do you want to make a member?</b>\n\n')
2855 elif affiliation == 'owner':
2856 title = _('Adding Owner...')
2857 prompt = _('<b>Whom do you want to make an owner?</b>\n\n')
2858 else:
2859 title = _('Adding Administrator...')
2860 prompt = _('<b>Whom do you want to make an administrator?</b>\n\n')
2861 prompt += _('Can be one of the following:\n'
2862 '1. user@domain/resource (only that resource matches).\n'
2863 '2. user@domain (any resource matches).\n'
2864 '3. domain/resource (only that resource matches).\n'
2865 '4. domain (the domain itself matches, as does any user@domain,\n'
2866 'domain/resource, or address containing a subdomain).')
2868 def on_ok(jid):
2869 if not jid:
2870 return
2871 model = self.affiliation_treeview[affiliation].get_model()
2872 model.append((jid, '', '', ''))
2873 dialogs.InputDialog(title, prompt, ok_handler=on_ok)
2875 def on_remove_button_clicked(self, widget, affiliation):
2876 selection = self.affiliation_treeview[affiliation].get_selection()
2877 model, paths = selection.get_selected_rows()
2878 row_refs = []
2879 for path in paths:
2880 row_refs.append(gtk.TreeRowReference(model, path))
2881 for row_ref in row_refs:
2882 path = row_ref.get_path()
2883 iter_ = model.get_iter(path)
2884 model.remove(iter_)
2885 self.remove_button[affiliation].set_sensitive(False)
2887 def on_affiliation_treeview_cursor_changed(self, widget, affiliation):
2888 self.remove_button[affiliation].set_sensitive(True)
2890 def affiliation_list_received(self, users_dict):
2892 Fill the affiliation treeview
2894 for jid in users_dict:
2895 affiliation = users_dict[jid]['affiliation']
2896 if affiliation not in self.affiliation_labels.keys():
2897 # Unknown affiliation or 'none' affiliation, do not show it
2898 continue
2899 self.start_users_dict[affiliation][jid] = users_dict[jid]
2900 tv = self.affiliation_treeview[affiliation]
2901 model = tv.get_model()
2902 reason = users_dict[jid].get('reason', '')
2903 nick = users_dict[jid].get('nick', '')
2904 role = users_dict[jid].get('role', '')
2905 model.append((jid, reason, nick, role))
2907 def on_data_form_window_destroy(self, widget):
2908 del gajim.interface.instances[self.account]['gc_config'][self.room_jid]
2910 def on_ok_button_clicked(self, widget):
2911 if self.form:
2912 form = self.data_form_widget.data_form
2913 gajim.connections[self.account].send_gc_config(self.room_jid, form)
2914 for affiliation in self.affiliation_labels.keys():
2915 users_dict = {}
2916 actual_jid_list = []
2917 model = self.affiliation_treeview[affiliation].get_model()
2918 iter_ = model.get_iter_first()
2919 # add new jid
2920 while iter_:
2921 jid = model[iter_][0].decode('utf-8')
2922 actual_jid_list.append(jid)
2923 if jid not in self.start_users_dict[affiliation] or \
2924 (affiliation == 'outcast' and 'reason' in self.start_users_dict[
2925 affiliation][jid] and self.start_users_dict[affiliation][jid]\
2926 ['reason'] != model[iter_][1].decode('utf-8')):
2927 users_dict[jid] = {'affiliation': affiliation}
2928 if affiliation == 'outcast':
2929 users_dict[jid]['reason'] = model[iter_][1].decode(
2930 'utf-8')
2931 iter_ = model.iter_next(iter_)
2932 # remove removed one
2933 for jid in self.start_users_dict[affiliation]:
2934 if jid not in actual_jid_list:
2935 users_dict[jid] = {'affiliation': 'none'}
2936 if users_dict:
2937 gajim.connections[self.account].send_gc_affiliation_list(
2938 self.room_jid, users_dict)
2939 self.window.destroy()
2941 #---------- RemoveAccountWindow class -------------#
2942 class RemoveAccountWindow:
2944 Ask for removing from gajim only or from gajim and server too and do
2945 removing of the account given
2948 def on_remove_account_window_destroy(self, widget):
2949 if self.account in gajim.interface.instances:
2950 del gajim.interface.instances[self.account]['remove_account']
2952 def on_cancel_button_clicked(self, widget):
2953 self.window.destroy()
2955 def __init__(self, account):
2956 self.account = account
2957 xml = gtkgui_helpers.get_gtk_builder('remove_account_window.ui')
2958 self.window = xml.get_object('remove_account_window')
2959 self.window.set_transient_for(gajim.interface.roster.window)
2960 self.remove_and_unregister_radiobutton = xml.get_object(
2961 'remove_and_unregister_radiobutton')
2962 self.window.set_title(_('Removing %s account') % self.account)
2963 xml.connect_signals(self)
2964 self.window.show_all()
2966 def on_remove_button_clicked(self, widget):
2967 def remove():
2968 if self.account in gajim.connections and \
2969 gajim.connections[self.account].connected and \
2970 not self.remove_and_unregister_radiobutton.get_active():
2971 # change status to offline only if we will not remove this JID from
2972 # server
2973 gajim.connections[self.account].change_status('offline', 'offline')
2974 if self.remove_and_unregister_radiobutton.get_active():
2975 if not self.account in gajim.connections:
2976 dialogs.ErrorDialog(
2977 _('Account is disabled'),
2978 _('To unregister from a server, account must be '
2979 'enabled.'))
2980 return
2981 if not gajim.connections[self.account].password:
2982 def on_ok(passphrase, checked):
2983 if passphrase == -1:
2984 # We don't remove account cause we canceled pw window
2985 return
2986 gajim.connections[self.account].password = passphrase
2987 gajim.connections[self.account].unregister_account(
2988 self._on_remove_success)
2990 dialogs.PassphraseDialog(
2991 _('Password Required'),
2992 _('Enter your password for account %s') % self.account,
2993 _('Save password'), ok_handler=on_ok)
2994 return
2995 gajim.connections[self.account].unregister_account(
2996 self._on_remove_success)
2997 else:
2998 self._on_remove_success(True)
3000 if self.account in gajim.connections and \
3001 gajim.connections[self.account].connected:
3002 dialogs.ConfirmationDialog(
3003 _('Account "%s" is connected to the server') % self.account,
3004 _('If you remove it, the connection will be lost.'),
3005 on_response_ok=remove)
3006 else:
3007 remove()
3009 def on_remove_responce_ok(self, is_checked):
3010 if is_checked[0]:
3011 self._on_remove_success(True)
3013 def _on_remove_success(self, res):
3014 # action of unregistration has failed, we don't remove the account
3015 # Error message is send by connect_and_auth()
3016 if not res:
3017 dialogs.ConfirmationDialogDoubleRadio(
3018 _('Connection to server %s failed') % self.account,
3019 _('What would you like to do?'),
3020 _('Remove only from Gajim'),
3021 _('Don\'t remove anything. I\'ll try again later'),
3022 on_response_ok=self.on_remove_responce_ok, is_modal=False)
3023 return
3024 # Close all opened windows
3025 gajim.interface.roster.close_all(self.account, force=True)
3026 if self.account in gajim.connections:
3027 gajim.connections[self.account].disconnect(on_purpose=True)
3028 gajim.connections[self.account].cleanup()
3029 del gajim.connections[self.account]
3030 gajim.logger.remove_roster(gajim.get_jid_from_account(self.account))
3031 gajim.config.del_per('accounts', self.account)
3032 gajim.interface.save_config()
3033 del gajim.interface.instances[self.account]
3034 if self.account in gajim.nicks:
3035 del gajim.interface.minimized_controls[self.account]
3036 del gajim.nicks[self.account]
3037 del gajim.block_signed_in_notifications[self.account]
3038 del gajim.groups[self.account]
3039 gajim.contacts.remove_account(self.account)
3040 del gajim.gc_connected[self.account]
3041 del gajim.automatic_rooms[self.account]
3042 del gajim.to_be_removed[self.account]
3043 del gajim.newly_added[self.account]
3044 del gajim.sleeper_state[self.account]
3045 del gajim.encrypted_chats[self.account]
3046 del gajim.last_message_time[self.account]
3047 del gajim.status_before_autoaway[self.account]
3048 del gajim.transport_avatar[self.account]
3049 del gajim.gajim_optional_features[self.account]
3050 del gajim.caps_hash[self.account]
3051 if len(gajim.connections) >= 2: # Do not merge accounts if only one exists
3052 gajim.interface.roster.regroup = gajim.config.get('mergeaccounts')
3053 else:
3054 gajim.interface.roster.regroup = False
3055 gajim.interface.roster.setup_and_draw_roster()
3056 gajim.interface.roster.set_actions_menu_needs_rebuild()
3057 if 'accounts' in gajim.interface.instances:
3058 gajim.interface.instances['accounts'].init_accounts()
3059 gajim.interface.instances['accounts'].init_account()
3060 self.window.destroy()
3062 #---------- ManageBookmarksWindow class -------------#
3063 class ManageBookmarksWindow:
3064 def __init__(self):
3065 self.xml = gtkgui_helpers.get_gtk_builder('manage_bookmarks_window.ui')
3066 self.window = self.xml.get_object('manage_bookmarks_window')
3067 self.window.set_transient_for(gajim.interface.roster.window)
3069 # Account-JID, RoomName, Room-JID, Autojoin, Minimize, Passowrd, Nick,
3070 # Show_Status
3071 self.treestore = gtk.TreeStore(str, str, str, bool, bool, str, str, str)
3072 self.treestore.set_sort_column_id(1, gtk.SORT_ASCENDING)
3074 # Store bookmarks in treeview.
3075 for account in gajim.connections:
3076 if gajim.connections[account].connected <= 1:
3077 continue
3078 if gajim.connections[account].is_zeroconf:
3079 continue
3080 if not gajim.connections[account].private_storage_supported:
3081 continue
3082 iter_ = self.treestore.append(None, [None, account, None, None,
3083 None, None, None, None])
3085 for bookmark in gajim.connections[account].bookmarks:
3086 if bookmark['name'] == '':
3087 # No name was given for this bookmark.
3088 # Use the first part of JID instead...
3089 name = bookmark['jid'].split("@")[0]
3090 bookmark['name'] = name
3092 # make '1', '0', 'true', 'false' (or other) to True/False
3093 autojoin = helpers.from_xs_boolean_to_python_boolean(
3094 bookmark['autojoin'])
3096 minimize = helpers.from_xs_boolean_to_python_boolean(
3097 bookmark['minimize'])
3099 print_status = bookmark.get('print_status', '')
3100 if print_status not in ('', 'all', 'in_and_out', 'none'):
3101 print_status = ''
3102 self.treestore.append(iter_, [
3103 account,
3104 bookmark['name'],
3105 bookmark['jid'],
3106 autojoin,
3107 minimize,
3108 bookmark['password'],
3109 bookmark['nick'],
3110 print_status ])
3112 self.print_status_combobox = self.xml.get_object('print_status_combobox')
3113 model = gtk.ListStore(str, str)
3115 self.option_list = {'': _('Default'), 'all': Q_('?print_status:All'),
3116 'in_and_out': _('Enter and leave only'),
3117 'none': Q_('?print_status:None')}
3118 opts = sorted(self.option_list.keys())
3119 for opt in opts:
3120 model.append([self.option_list[opt], opt])
3122 self.print_status_combobox.set_model(model)
3123 self.print_status_combobox.set_active(1)
3125 self.view = self.xml.get_object('bookmarks_treeview')
3126 self.view.set_model(self.treestore)
3127 self.view.expand_all()
3129 renderer = gtk.CellRendererText()
3130 column = gtk.TreeViewColumn('Bookmarks', renderer, text=1)
3131 self.view.append_column(column)
3133 self.selection = self.view.get_selection()
3134 self.selection.connect('changed', self.bookmark_selected)
3136 #Prepare input fields
3137 self.title_entry = self.xml.get_object('title_entry')
3138 self.title_entry.connect('changed', self.on_title_entry_changed)
3139 self.nick_entry = self.xml.get_object('nick_entry')
3140 self.nick_entry.connect('changed', self.on_nick_entry_changed)
3141 self.server_entry = self.xml.get_object('server_entry')
3142 self.server_entry.connect('changed', self.on_server_entry_changed)
3143 self.room_entry = self.xml.get_object('room_entry')
3144 self.room_entry.connect('changed', self.on_room_entry_changed)
3145 self.pass_entry = self.xml.get_object('pass_entry')
3146 self.pass_entry.connect('changed', self.on_pass_entry_changed)
3147 self.autojoin_checkbutton = self.xml.get_object('autojoin_checkbutton')
3148 self.minimize_checkbutton = self.xml.get_object('minimize_checkbutton')
3150 self.xml.connect_signals(self)
3151 self.window.show_all()
3152 # select root iter
3153 self.selection.select_iter(self.treestore.get_iter_root())
3155 def on_bookmarks_treeview_button_press_event(self, widget, event):
3156 (model, iter_) = self.selection.get_selected()
3157 if not iter_:
3158 # Removed a bookmark before
3159 return
3161 if model.iter_parent(iter_):
3162 # The currently selected node is a bookmark
3163 return not self.check_valid_bookmark()
3165 def on_manage_bookmarks_window_destroy(self, widget, event):
3166 del gajim.interface.instances['manage_bookmarks']
3168 def on_add_bookmark_button_clicked(self, widget):
3170 Add a new bookmark
3172 # Get the account that is currently used
3173 # (the parent of the currently selected item)
3174 (model, iter_) = self.selection.get_selected()
3175 if not iter_: # Nothing selected, do nothing
3176 return
3178 parent = model.iter_parent(iter_)
3180 if parent:
3181 # We got a bookmark selected, so we add_to the parent
3182 add_to = parent
3183 else:
3184 # No parent, so we got an account -> add to this.
3185 add_to = iter_
3187 account = model[add_to][1].decode('utf-8')
3188 nick = gajim.nicks[account]
3189 iter_ = self.treestore.append(add_to, [account, _('New Group Chat'),
3190 '@', False, False, '', nick, 'in_and_out'])
3192 self.view.expand_row(model.get_path(add_to), True)
3193 self.view.set_cursor(model.get_path(iter_))
3195 def on_remove_bookmark_button_clicked(self, widget):
3197 Remove selected bookmark
3199 (model, iter_) = self.selection.get_selected()
3200 if not iter_: # Nothing selected
3201 return
3203 if not model.iter_parent(iter_):
3204 # Don't remove account iters
3205 return
3207 model.remove(iter_)
3208 self.clear_fields()
3210 def check_valid_bookmark(self):
3212 Check if all neccessary fields are entered correctly
3214 (model, iter_) = self.selection.get_selected()
3216 if not model.iter_parent(iter_):
3217 #Account data can't be changed
3218 return
3220 if self.server_entry.get_text().decode('utf-8') == '' or \
3221 self.room_entry.get_text().decode('utf-8') == '':
3222 dialogs.ErrorDialog(_('This bookmark has invalid data'),
3223 _('Please be sure to fill out server and room fields or remove this'
3224 ' bookmark.'))
3225 return False
3227 return True
3229 def on_ok_button_clicked(self, widget):
3231 Parse the treestore data into our new bookmarks array, then send the new
3232 bookmarks to the server.
3234 (model, iter_) = self.selection.get_selected()
3235 if iter_ and model.iter_parent(iter_):
3236 #bookmark selected, check it
3237 if not self.check_valid_bookmark():
3238 return
3240 for account in self.treestore:
3241 account_unicode = account[1].decode('utf-8')
3242 gajim.connections[account_unicode].bookmarks = []
3244 for bm in account.iterchildren():
3245 # Convert True/False/None to '1' or '0'
3246 autojoin = unicode(int(bm[3]))
3247 minimize = unicode(int(bm[4]))
3248 name = bm[1]
3249 if name:
3250 name = name.decode('utf-8')
3251 jid = bm[2]
3252 if jid:
3253 jid = jid.decode('utf-8')
3254 pw = bm[5]
3255 if pw:
3256 pw = pw.decode('utf-8')
3257 nick = bm[6]
3258 if nick:
3259 nick = nick.decode('utf-8')
3261 # create the bookmark-dict
3262 bmdict = { 'name': name, 'jid': jid, 'autojoin': autojoin,
3263 'minimize': minimize, 'password': pw, 'nick': nick,
3264 'print_status': bm[7]}
3266 gajim.connections[account_unicode].bookmarks.append(bmdict)
3268 gajim.connections[account_unicode].store_bookmarks()
3269 gajim.interface.roster.set_actions_menu_needs_rebuild()
3270 self.window.destroy()
3272 def on_cancel_button_clicked(self, widget):
3273 self.window.destroy()
3275 def bookmark_selected(self, selection):
3277 Fill in the bookmark's data into the fields.
3279 (model, iter_) = selection.get_selected()
3281 if not iter_:
3282 # After removing the last bookmark for one account
3283 # this will be None, so we will just:
3284 return
3286 widgets = [ self.title_entry, self.nick_entry, self.room_entry,
3287 self.server_entry, self.pass_entry, self.autojoin_checkbutton,
3288 self.minimize_checkbutton, self.print_status_combobox]
3290 if model.iter_parent(iter_):
3291 # make the fields sensitive
3292 for field in widgets:
3293 field.set_sensitive(True)
3294 else:
3295 # Top-level has no data (it's the account fields)
3296 # clear fields & make them insensitive
3297 self.clear_fields()
3298 for field in widgets:
3299 field.set_sensitive(False)
3300 return
3302 # Fill in the data for childs
3303 self.title_entry.set_text(model[iter_][1])
3304 room_jid = model[iter_][2].decode('utf-8')
3305 (room, server) = room_jid.split('@')
3306 self.room_entry.set_text(room)
3307 self.server_entry.set_text(server)
3309 self.autojoin_checkbutton.set_active(model[iter_][3])
3310 self.minimize_checkbutton.set_active(model[iter_][4])
3311 # sensitive only if auto join is checked
3312 self.minimize_checkbutton.set_sensitive(model[iter_][3])
3314 if model[iter_][5] is not None:
3315 password = model[iter_][5].decode('utf-8')
3316 else:
3317 password = None
3319 if password:
3320 self.pass_entry.set_text(password)
3321 else:
3322 self.pass_entry.set_text('')
3323 nick = model[iter_][6]
3324 if nick:
3325 nick = nick.decode('utf-8')
3326 self.nick_entry.set_text(nick)
3327 else:
3328 self.nick_entry.set_text('')
3330 print_status = model[iter_][7]
3331 opts = sorted(self.option_list.keys())
3332 self.print_status_combobox.set_active(opts.index(print_status))
3334 def on_title_entry_changed(self, widget):
3335 (model, iter_) = self.selection.get_selected()
3336 if iter_: # After removing a bookmark, we got nothing selected
3337 if model.iter_parent(iter_):
3338 # Don't clear the title field for account nodes
3339 model[iter_][1] = self.title_entry.get_text()
3341 def on_nick_entry_changed(self, widget):
3342 (model, iter_) = self.selection.get_selected()
3343 if iter_:
3344 nick = self.nick_entry.get_text().decode('utf-8')
3345 try:
3346 nick = helpers.parse_resource(nick)
3347 except helpers.InvalidFormat, e:
3348 dialogs.ErrorDialog(_('Invalid nickname'),
3349 _('Character not allowed'))
3350 self.nick_entry.set_text(model[iter_][6])
3351 return True
3352 model[iter_][6] = nick
3354 def on_server_entry_changed(self, widget):
3355 (model, iter_) = self.selection.get_selected()
3356 if not iter_:
3357 return
3358 server = widget.get_text().decode('utf-8')
3359 if '@' in server:
3360 dialogs.ErrorDialog(_('Invalid server'), _('Character not allowed'))
3361 widget.set_text(server.replace('@', ''))
3363 room_jid = self.room_entry.get_text().decode('utf-8').strip() + '@' + \
3364 server.strip()
3365 try:
3366 room_jid = helpers.parse_resource(room_jid)
3367 except helpers.InvalidFormat, e:
3368 dialogs.ErrorDialog(_('Invalid server'),
3369 _('Character not allowed'))
3370 self.server_entry.set_text(model[iter_][2].split('@')[1])
3371 return True
3372 model[iter_][2] = room_jid
3374 def on_room_entry_changed(self, widget):
3375 (model, iter_) = self.selection.get_selected()
3376 if not iter_:
3377 return
3378 room = widget.get_text().decode('utf-8')
3379 if '@' in room:
3380 dialogs.ErrorDialog(_('Invalid server'), _('Character not allowed'))
3381 widget.set_text(room.replace('@', ''))
3382 room_jid = room.strip() + '@' + \
3383 self.server_entry.get_text().decode('utf-8').strip()
3384 try:
3385 room_jid = helpers.parse_resource(room_jid)
3386 except helpers.InvalidFormat, e:
3387 dialogs.ErrorDialog(_('Invalid room'),
3388 _('Character not allowed'))
3389 self.room_entry.set_text(model[iter_][2].split('@')[0])
3390 return True
3391 model[iter_][2] = room_jid
3393 def on_pass_entry_changed(self, widget):
3394 (model, iter_) = self.selection.get_selected()
3395 if iter_:
3396 model[iter_][5] = self.pass_entry.get_text()
3398 def on_autojoin_checkbutton_toggled(self, widget):
3399 (model, iter_) = self.selection.get_selected()
3400 if iter_:
3401 model[iter_][3] = self.autojoin_checkbutton.get_active()
3402 self.minimize_checkbutton.set_sensitive(model[iter_][3])
3404 def on_minimize_checkbutton_toggled(self, widget):
3405 (model, iter_) = self.selection.get_selected()
3406 if iter_:
3407 model[iter_][4] = self.minimize_checkbutton.get_active()
3409 def on_print_status_combobox_changed(self, widget):
3410 active = widget.get_active()
3411 model = widget.get_model()
3412 print_status = model[active][1]
3413 (model2, iter_) = self.selection.get_selected()
3414 if iter_:
3415 model2[iter_][7] = print_status
3417 def clear_fields(self):
3418 widgets = [ self.title_entry, self.nick_entry, self.room_entry,
3419 self.server_entry, self.pass_entry ]
3420 for field in widgets:
3421 field.set_text('')
3422 self.autojoin_checkbutton.set_active(False)
3423 self.minimize_checkbutton.set_active(False)
3424 self.print_status_combobox.set_active(1)
3426 class AccountCreationWizardWindow:
3427 def __init__(self):
3428 self.xml = gtkgui_helpers.get_gtk_builder(
3429 'account_creation_wizard_window.ui')
3430 self.window = self.xml.get_object('account_creation_wizard_window')
3431 self.window.set_transient_for(gajim.interface.roster.window)
3433 completion = gtk.EntryCompletion()
3434 completion1 = gtk.EntryCompletion()
3435 # Connect events from comboboxentry.child
3436 server_comboboxentry = self.xml.get_object('server_comboboxentry')
3437 entry = server_comboboxentry.child
3438 entry.connect('key_press_event',
3439 self.on_server_comboboxentry_key_press_event, server_comboboxentry)
3440 entry.set_completion(completion)
3441 # Do the same for the other server comboboxentry
3442 server_comboboxentry1 = self.xml.get_object('server_comboboxentry1')
3443 entry = server_comboboxentry1.child
3444 entry.set_completion(completion1)
3446 self.update_proxy_list()
3448 # parse servers.xml
3449 servers_xml = os.path.join(gajim.DATA_DIR, 'other', 'servers.xml')
3450 servers = gtkgui_helpers.parse_server_xml(servers_xml)
3451 servers_model = gtk.ListStore(str)
3452 for server in servers:
3453 servers_model.append((server,))
3455 completion.set_model(servers_model)
3456 completion.set_text_column(0)
3457 completion1.set_model(servers_model)
3458 completion1.set_text_column(0)
3460 # Put servers into comboboxentries
3461 server_comboboxentry.set_model(servers_model)
3462 server_comboboxentry.set_text_column(0)
3463 server_comboboxentry1.set_model(servers_model)
3464 server_comboboxentry1.set_text_column(0)
3466 # Generic widgets
3467 self.notebook = self.xml.get_object('notebook')
3468 self.cancel_button = self.xml.get_object('cancel_button')
3469 self.back_button = self.xml.get_object('back_button')
3470 self.forward_button = self.xml.get_object('forward_button')
3471 self.finish_button = self.xml.get_object('finish_button')
3472 self.advanced_button = self.xml.get_object('advanced_button')
3473 self.finish_label = self.xml.get_object('finish_label')
3474 self.go_online_checkbutton = self.xml.get_object(
3475 'go_online_checkbutton')
3476 self.show_vcard_checkbutton = self.xml.get_object(
3477 'show_vcard_checkbutton')
3478 self.progressbar = self.xml.get_object('progressbar')
3480 # some vars
3481 self.update_progressbar_timeout_id = None
3483 self.notebook.set_current_page(0)
3484 self.xml.connect_signals(self)
3485 self.window.show_all()
3486 gajim.ged.register_event_handler('new-account-connected', ged.GUI1,
3487 self._nec_new_acc_connected)
3488 gajim.ged.register_event_handler('new-account-not-connected', ged.GUI1,
3489 self._nec_new_acc_not_connected)
3490 gajim.ged.register_event_handler('account-created', ged.GUI1,
3491 self._nec_acc_is_ok)
3492 gajim.ged.register_event_handler('account-not-created', ged.GUI1,
3493 self._nec_acc_is_not_ok)
3495 def on_wizard_window_destroy(self, widget):
3496 page = self.notebook.get_current_page()
3497 if page in (4, 5) and self.account in gajim.connections:
3498 # connection instance is saved in gajim.connections and we canceled
3499 # the addition of the account
3500 del gajim.connections[self.account]
3501 if self.account in gajim.config.get_per('accounts'):
3502 gajim.config.del_per('accounts', self.account)
3503 gajim.ged.remove_event_handler('new-account-connected', ged.GUI1,
3504 self._nec_new_acc_connected)
3505 gajim.ged.remove_event_handler('new-account-not-connected', ged.GUI1,
3506 self._nec_new_acc_not_connected)
3507 gajim.ged.remove_event_handler('account-created', ged.GUI1,
3508 self._nec_acc_is_ok)
3509 gajim.ged.remove_event_handler('account-not-created', ged.GUI1,
3510 self._nec_acc_is_not_ok)
3511 del gajim.interface.instances['account_creation_wizard']
3513 def on_register_server_features_button_clicked(self, widget):
3514 helpers.launch_browser_mailer('url',
3515 'http://www.jabber.org/network/oldnetwork.shtml')
3517 def on_save_password_checkbutton_toggled(self, widget):
3518 self.xml.get_object('password_entry').grab_focus()
3520 def on_cancel_button_clicked(self, widget):
3521 self.window.destroy()
3523 def on_back_button_clicked(self, widget):
3524 cur_page = self.notebook.get_current_page()
3525 if cur_page in (1, 2):
3526 self.notebook.set_current_page(0)
3527 self.back_button.set_sensitive(False)
3528 elif cur_page == 3:
3529 self.xml.get_object('form_vbox').remove(self.data_form_widget)
3530 self.notebook.set_current_page(2) # show server page
3531 elif cur_page == 4:
3532 if self.account in gajim.connections:
3533 del gajim.connections[self.account]
3534 self.notebook.set_current_page(2)
3535 self.xml.get_object('form_vbox').remove(self.data_form_widget)
3536 elif cur_page == 6: # finish page
3537 self.forward_button.show()
3538 if self.modify:
3539 self.notebook.set_current_page(1) # Go to parameters page
3540 else:
3541 self.notebook.set_current_page(2) # Go to server page
3543 def on_anonymous_checkbutton1_toggled(self, widget):
3544 active = widget.get_active()
3545 self.xml.get_object('username_entry').set_sensitive(not active)
3546 self.xml.get_object('password_entry').set_sensitive(not active)
3547 self.xml.get_object('save_password_checkbutton').set_sensitive(
3548 not active)
3550 def show_finish_page(self):
3551 self.cancel_button.hide()
3552 self.back_button.hide()
3553 self.forward_button.hide()
3554 if self.modify:
3555 finish_text = '<big><b>%s</b></big>\n\n%s' % (
3556 _('Account has been added successfully'),
3557 _('You can set advanced account options by pressing the '
3558 'Advanced button, or later by choosing the Accounts menu item '
3559 'under the Edit menu from the main window.'))
3560 else:
3561 finish_text = '<big><b>%s</b></big>\n\n%s' % (
3562 _('Your new account has been created successfully'),
3563 _('You can set advanced account options by pressing the '
3564 'Advanced button, or later by choosing the Accounts menu item '
3565 'under the Edit menu from the main window.'))
3566 self.finish_label.set_markup(finish_text)
3567 self.finish_button.show()
3568 self.finish_button.set_property('has-default', True)
3569 self.advanced_button.show()
3570 self.go_online_checkbutton.show()
3571 img = self.xml.get_object('finish_image')
3572 if self.modify:
3573 img.set_from_stock(gtk.STOCK_APPLY, gtk.ICON_SIZE_DIALOG)
3574 else:
3575 path_to_file = gtkgui_helpers.get_icon_path('gajim', 48)
3576 img.set_from_file(path_to_file)
3577 self.show_vcard_checkbutton.set_active(not self.modify)
3578 self.notebook.set_current_page(6) # show finish page
3580 def on_forward_button_clicked(self, widget):
3581 cur_page = self.notebook.get_current_page()
3583 if cur_page == 0:
3584 widget = self.xml.get_object('use_existing_account_radiobutton')
3585 if widget.get_active():
3586 self.modify = True
3587 self.notebook.set_current_page(1)
3588 else:
3589 self.modify = False
3590 self.notebook.set_current_page(2)
3591 self.back_button.set_sensitive(True)
3592 return
3594 elif cur_page == 1:
3595 # We are adding an existing account
3596 anonymous = self.xml.get_object('anonymous_checkbutton1').\
3597 get_active()
3598 username = self.xml.get_object('username_entry').get_text().decode(
3599 'utf-8').strip()
3600 if not username and not anonymous:
3601 pritext = _('Invalid username')
3602 sectext = _(
3603 'You must provide a username to configure this account.')
3604 dialogs.ErrorDialog(pritext, sectext)
3605 return
3606 server = self.xml.get_object('server_comboboxentry').child.\
3607 get_text().decode('utf-8').strip()
3608 savepass = self.xml.get_object('save_password_checkbutton').\
3609 get_active()
3610 password = self.xml.get_object('password_entry').get_text().decode(
3611 'utf-8')
3613 jid = username + '@' + server
3614 # check if jid is conform to RFC and stringprep it
3615 try:
3616 jid = helpers.parse_jid(jid)
3617 except helpers.InvalidFormat, s:
3618 pritext = _('Invalid Jabber ID')
3619 dialogs.ErrorDialog(pritext, str(s))
3620 return
3622 self.account = server
3623 i = 1
3624 while self.account in gajim.connections:
3625 self.account = server + str(i)
3626 i += 1
3628 username, server = gajim.get_name_and_server_from_jid(jid)
3629 if self.xml.get_object('anonymous_checkbutton1').get_active():
3630 self.save_account('', server, False, '', anonymous=True)
3631 else:
3632 self.save_account(username, server, savepass, password)
3633 self.show_finish_page()
3634 elif cur_page == 2:
3635 # We are creating a new account
3636 server = self.xml.get_object('server_comboboxentry1').child.\
3637 get_text().decode('utf-8')
3639 if not server:
3640 dialogs.ErrorDialog(_('Invalid server'),
3641 _('Please provide a server on which you want to register.'))
3642 return
3643 self.account = server
3644 i = 1
3645 while self.account in gajim.connections:
3646 self.account = server + str(i)
3647 i += 1
3649 config = self.get_config('', server, '', '')
3650 # Get advanced options
3651 proxies_combobox = self.xml.get_object('proxies_combobox')
3652 active = proxies_combobox.get_active()
3653 proxy = proxies_combobox.get_model()[active][0].decode('utf-8')
3654 if proxy == _('None'):
3655 proxy = ''
3656 config['proxy'] = proxy
3658 config['use_custom_host'] = self.xml.get_object(
3659 'custom_host_port_checkbutton').get_active()
3660 custom_port = self.xml.get_object('custom_port_entry').get_text()
3661 try:
3662 custom_port = int(custom_port)
3663 except Exception:
3664 dialogs.ErrorDialog(_('Invalid entry'),
3665 _('Custom port must be a port number.'))
3666 return
3667 config['custom_port'] = custom_port
3668 config['custom_host'] = self.xml.get_object(
3669 'custom_host_entry').get_text().decode('utf-8')
3671 if self.xml.get_object('anonymous_checkbutton2').get_active():
3672 self.modify = True
3673 self.save_account('', server, False, '', anonymous=True)
3674 self.show_finish_page()
3675 else:
3676 self.notebook.set_current_page(5) # show creating page
3677 self.back_button.hide()
3678 self.forward_button.hide()
3679 self.update_progressbar_timeout_id = gobject.timeout_add(100,
3680 self.update_progressbar)
3681 # Get form from serveur
3682 con = connection.Connection(self.account)
3683 gajim.connections[self.account] = con
3684 con.new_account(self.account, config)
3685 elif cur_page == 3:
3686 checked = self.xml.get_object('ssl_checkbutton').get_active()
3687 if checked:
3688 hostname = gajim.connections[self.account].new_account_info[
3689 'hostname']
3690 # Check if cert is already in file
3691 certs = ''
3692 if os.path.isfile(gajim.MY_CACERTS):
3693 f = open(gajim.MY_CACERTS)
3694 certs = f.read()
3695 f.close()
3696 if self.ssl_cert in certs:
3697 dialogs.ErrorDialog(_('Certificate Already in File'),
3698 _('This certificate is already in file %s, so it\'s '
3699 'not added again.') % gajim.MY_CACERTS)
3700 else:
3701 f = open(gajim.MY_CACERTS, 'a')
3702 f.write(hostname + '\n')
3703 f.write(self.ssl_cert + '\n\n')
3704 f.close()
3705 gajim.connections[self.account].new_account_info[
3706 'ssl_fingerprint_sha1'] = self.ssl_fingerprint
3707 self.notebook.set_current_page(4) # show fom page
3708 elif cur_page == 4:
3709 if self.is_form:
3710 form = self.data_form_widget.data_form
3711 else:
3712 form = self.data_form_widget.get_infos()
3713 gajim.connections[self.account].send_new_account_infos(form,
3714 self.is_form)
3715 self.xml.get_object('form_vbox').remove(self.data_form_widget)
3716 self.xml.get_object('progressbar_label').set_markup(
3717 '<b>Account is being created</b>\n\nPlease wait...')
3718 self.notebook.set_current_page(5) # show creating page
3719 self.back_button.hide()
3720 self.forward_button.hide()
3721 self.update_progressbar_timeout_id = gobject.timeout_add(100,
3722 self.update_progressbar)
3724 def update_proxy_list(self):
3725 proxies_combobox = self.xml.get_object('proxies_combobox')
3726 model = gtk.ListStore(str)
3727 proxies_combobox.set_model(model)
3728 l = gajim.config.get_per('proxies')
3729 l.insert(0, _('None'))
3730 for i in xrange(len(l)):
3731 model.append([l[i]])
3732 proxies_combobox.set_active(0)
3734 def on_manage_proxies_button_clicked(self, widget):
3735 if 'manage_proxies' in gajim.interface.instances:
3736 gajim.interface.instances['manage_proxies'].window.present()
3737 else:
3738 gajim.interface.instances['manage_proxies'] = \
3739 ManageProxiesWindow()
3741 def on_custom_host_port_checkbutton_toggled(self, widget):
3742 self.xml.get_object('custom_host_hbox').set_sensitive(widget.\
3743 get_active())
3745 def update_progressbar(self):
3746 self.progressbar.pulse()
3747 return True # loop forever
3749 def _nec_new_acc_connected(self, obj):
3751 Connection to server succeded, present the form to the user
3753 # We receive events from all accounts from GED
3754 if obj.conn.name != self.account:
3755 return
3756 if self.update_progressbar_timeout_id is not None:
3757 gobject.source_remove(self.update_progressbar_timeout_id)
3758 self.back_button.show()
3759 self.forward_button.show()
3760 self.is_form = obj.is_form
3761 if obj.is_form:
3762 dataform = dataforms.ExtendForm(node=obj.config)
3763 self.data_form_widget = dataforms_widget.DataFormWidget(dataform)
3764 else:
3765 self.data_form_widget = FakeDataForm(obj.config)
3766 self.data_form_widget.show_all()
3767 self.xml.get_object('form_vbox').pack_start(self.data_form_widget)
3768 self.ssl_fingerprint = obj.ssl_fingerprint
3769 self.ssl_cert = obj.ssl_cert
3770 if obj.ssl_msg:
3771 # An SSL warning occured, show it
3772 hostname = gajim.connections[self.account].new_account_info[
3773 'hostname']
3774 self.xml.get_object('ssl_label').set_markup(_(
3775 '<b>Security Warning</b>'
3776 '\n\nThe authenticity of the %(hostname)s SSL certificate could'
3777 ' be invalid.\nSSL Error: %(error)s\n'
3778 'Do you still want to connect to this server?') % {
3779 'hostname': hostname, 'error': obj.ssl_msg})
3780 if obj.errnum in (18, 27):
3781 text = _('Add this certificate to the list of trusted '
3782 'certificates.\nSHA1 fingerprint of the certificate:\n%s') \
3783 % obj.ssl_fingerprint
3784 self.xml.get_object('ssl_checkbutton').set_label(text)
3785 else:
3786 self.xml.get_object('ssl_checkbutton').set_no_show_all(True)
3787 self.xml.get_object('ssl_checkbutton').hide()
3788 self.notebook.set_current_page(3) # show SSL page
3789 else:
3790 self.notebook.set_current_page(4) # show form page
3792 def _nec_new_acc_not_connected(self, obj):
3794 Account creation failed: connection to server failed
3796 # We receive events from all accounts from GED
3797 if obj.conn.name != self.account:
3798 return
3799 if self.account not in gajim.connections:
3800 return
3801 if self.update_progressbar_timeout_id is not None:
3802 gobject.source_remove(self.update_progressbar_timeout_id)
3803 del gajim.connections[self.account]
3804 if self.account in gajim.config.get_per('accounts'):
3805 gajim.config.del_per('accounts', self.account)
3806 self.back_button.show()
3807 self.cancel_button.show()
3808 self.go_online_checkbutton.hide()
3809 self.show_vcard_checkbutton.hide()
3810 img = self.xml.get_object('finish_image')
3811 img.set_from_stock(gtk.STOCK_DIALOG_ERROR, gtk.ICON_SIZE_DIALOG)
3812 finish_text = '<big><b>%s</b></big>\n\n%s' % (
3813 _('An error occurred during account creation'), obj.reason)
3814 self.finish_label.set_markup(finish_text)
3815 self.notebook.set_current_page(6) # show finish page
3817 def _nec_acc_is_ok(self, obj):
3819 Account creation succeeded
3821 # We receive events from all accounts from GED
3822 if obj.conn.name != self.account:
3823 return
3824 self.create_vars(obj.account_info)
3825 self.show_finish_page()
3827 if self.update_progressbar_timeout_id is not None:
3828 gobject.source_remove(self.update_progressbar_timeout_id)
3830 def _nec_acc_is_not_ok(self, obj):
3832 Account creation failed
3834 # We receive events from all accounts from GED
3835 if obj.conn.name != self.account:
3836 return
3837 self.back_button.show()
3838 self.cancel_button.show()
3839 self.go_online_checkbutton.hide()
3840 self.show_vcard_checkbutton.hide()
3841 del gajim.connections[self.account]
3842 if self.account in gajim.config.get_per('accounts'):
3843 gajim.config.del_per('accounts', self.account)
3844 img = self.xml.get_object('finish_image')
3845 img.set_from_stock(gtk.STOCK_DIALOG_ERROR, gtk.ICON_SIZE_DIALOG)
3846 finish_text = '<big><b>%s</b></big>\n\n%s' % (_(
3847 'An error occurred during account creation'), obj.reason)
3848 self.finish_label.set_markup(finish_text)
3849 self.notebook.set_current_page(6) # show finish page
3851 if self.update_progressbar_timeout_id is not None:
3852 gobject.source_remove(self.update_progressbar_timeout_id)
3854 def on_advanced_button_clicked(self, widget):
3855 if 'accounts' in gajim.interface.instances:
3856 gajim.interface.instances['accounts'].window.present()
3857 else:
3858 gajim.interface.instances['accounts'] = AccountsWindow()
3859 gajim.interface.instances['accounts'].select_account(self.account)
3860 self.window.destroy()
3862 def on_finish_button_clicked(self, widget):
3863 go_online = self.xml.get_object('go_online_checkbutton').get_active()
3864 show_vcard = self.xml.get_object('show_vcard_checkbutton').get_active()
3865 self.window.destroy()
3866 if show_vcard:
3867 gajim.interface.show_vcard_when_connect.append(self.account)
3868 if go_online:
3869 gajim.interface.roster.send_status(self.account, 'online', '')
3871 def on_username_entry_key_press_event(self, widget, event):
3872 # Check for pressed @ and jump to combobox if found
3873 if event.keyval == gtk.keysyms.at:
3874 combobox = self.xml.get_object('server_comboboxentry')
3875 combobox.grab_focus()
3876 combobox.child.set_position(-1)
3877 return True
3879 def on_server_comboboxentry_key_press_event(self, widget, event, combobox):
3880 # If backspace is pressed in empty field, return to the nick entry field
3881 backspace = event.keyval == gtk.keysyms.BackSpace
3882 empty = len(combobox.get_active_text()) == 0
3883 if backspace and empty and self.modify:
3884 username_entry = self.xml.get_object('username_entry')
3885 username_entry.grab_focus()
3886 username_entry.set_position(-1)
3887 return True
3889 def get_config(self, login, server, savepass, password, anonymous=False):
3890 config = {}
3891 config['name'] = login
3892 config['hostname'] = server
3893 config['savepass'] = savepass
3894 config['password'] = password
3895 config['resource'] = 'Gajim'
3896 config['anonymous_auth'] = anonymous
3897 config['priority'] = 5
3898 config['autoconnect'] = True
3899 config['no_log_for'] = ''
3900 config['sync_with_global_status'] = True
3901 config['proxy'] = ''
3902 config['usessl'] = False
3903 config['use_custom_host'] = False
3904 config['custom_port'] = 0
3905 config['custom_host'] = ''
3906 config['keyname'] = ''
3907 config['keyid'] = ''
3908 return config
3910 def save_account(self, login, server, savepass, password, anonymous=False):
3911 if self.account in gajim.connections:
3912 dialogs.ErrorDialog(_('Account name is in use'),
3913 _('You already have an account using this name.'))
3914 return
3915 con = connection.Connection(self.account)
3916 con.password = password
3918 config = self.get_config(login, server, savepass, password, anonymous)
3920 if not self.modify:
3921 con.new_account(self.account, config)
3922 return
3923 gajim.connections[self.account] = con
3924 self.create_vars(config)
3926 def create_vars(self, config):
3927 gajim.config.add_per('accounts', self.account)
3929 if not config['savepass']:
3930 config['password'] = ''
3932 for opt in config:
3933 gajim.config.set_per('accounts', self.account, opt, config[opt])
3935 # update variables
3936 gajim.interface.instances[self.account] = {'infos': {}, 'disco': {},
3937 'gc_config': {}, 'search': {}, 'online_dialog': {},
3938 'sub_request': {}}
3939 gajim.interface.minimized_controls[self.account] = {}
3940 gajim.connections[self.account].connected = 0
3941 gajim.connections[self.account].keepalives = gajim.config.get_per(
3942 'accounts', self.account, 'keep_alive_every_foo_secs')
3943 gajim.groups[self.account] = {}
3944 gajim.contacts.add_account(self.account)
3945 gajim.gc_connected[self.account] = {}
3946 gajim.automatic_rooms[self.account] = {}
3947 gajim.newly_added[self.account] = []
3948 gajim.to_be_removed[self.account] = []
3949 gajim.nicks[self.account] = config['name']
3950 gajim.block_signed_in_notifications[self.account] = True
3951 gajim.sleeper_state[self.account] = 'off'
3952 gajim.encrypted_chats[self.account] = []
3953 gajim.last_message_time[self.account] = {}
3954 gajim.status_before_autoaway[self.account] = ''
3955 gajim.transport_avatar[self.account] = {}
3956 gajim.gajim_optional_features[self.account] = []
3957 gajim.caps_hash[self.account] = ''
3958 # refresh accounts window
3959 if 'accounts' in gajim.interface.instances:
3960 gajim.interface.instances['accounts'].init_accounts()
3961 # refresh roster
3962 if len(gajim.connections) >= 2:
3963 # Do not merge accounts if only one exists
3964 gajim.interface.roster.regroup = gajim.config.get('mergeaccounts')
3965 else:
3966 gajim.interface.roster.regroup = False
3967 gajim.interface.roster.setup_and_draw_roster()
3968 gajim.interface.roster.set_actions_menu_needs_rebuild()
3969 gajim.interface.save_config()
3971 class ManagePEPServicesWindow:
3972 def __init__(self, account):
3973 self.xml = gtkgui_helpers.get_gtk_builder('manage_pep_services_window.ui')
3974 self.window = self.xml.get_object('manage_pep_services_window')
3975 self.window.set_transient_for(gajim.interface.roster.window)
3976 self.xml.get_object('configure_button').set_sensitive(False)
3977 self.xml.get_object('delete_button').set_sensitive(False)
3978 self.xml.connect_signals(self)
3979 self.account = account
3981 self.init_services()
3982 self.xml.get_object('services_treeview').get_selection().connect(
3983 'changed', self.on_services_selection_changed)
3985 gajim.ged.register_event_handler('pep-config-received', ged.GUI1,
3986 self._nec_pep_config_received)
3987 gajim.ged.register_event_handler('agent-items-received', ged.GUI1,
3988 self._nec_agent_items_received)
3990 self.window.show_all()
3992 def on_manage_pep_services_window_destroy(self, widget):
3993 '''close window'''
3994 del gajim.interface.instances[self.account]['pep_services']
3995 gajim.ged.remove_event_handler('pep-config-received', ged.GUI1,
3996 self._nec_pep_config_received)
3997 gajim.ged.remove_event_handler('agent-items-received', ged.GUI1,
3998 self._nec_agent_items_received)
4000 def on_close_button_clicked(self, widget):
4001 self.window.destroy()
4003 def on_services_selection_changed(self, sel):
4004 self.xml.get_object('configure_button').set_sensitive(True)
4005 self.xml.get_object('delete_button').set_sensitive(True)
4007 def init_services(self):
4008 self.treeview = self.xml.get_object('services_treeview')
4009 # service, access_model, group
4010 self.treestore = gtk.ListStore(str)
4011 self.treeview.set_model(self.treestore)
4013 col = gtk.TreeViewColumn('Service')
4014 self.treeview.append_column(col)
4016 cellrenderer_text = gtk.CellRendererText()
4017 col.pack_start(cellrenderer_text)
4018 col.add_attribute(cellrenderer_text, 'text', 0)
4020 our_jid = gajim.get_jid_from_account(self.account)
4021 gajim.connections[self.account].discoverItems(our_jid)
4023 def _nec_agent_items_received(self, obj):
4024 our_jid = gajim.get_jid_from_account(self.account)
4025 for item in obj.items:
4026 if 'jid' in item and item['jid'] == our_jid and 'node' in item:
4027 self.treestore.append([item['node']])
4029 def node_removed(self, jid, node):
4030 if jid != gajim.get_jid_from_account(self.account):
4031 return
4032 model = self.treeview.get_model()
4033 iter_ = model.get_iter_root()
4034 while iter_:
4035 if model[iter_][0] == node:
4036 model.remove(iter_)
4037 break
4038 iter_ = model.iter_next(iter_)
4040 def node_not_removed(self, jid, node, msg):
4041 if jid != gajim.get_jid_from_account(self.account):
4042 return
4043 dialogs.WarningDialog(_('PEP node was not removed'),
4044 _('PEP node %(node)s was not removed: %(message)s') % {'node': node,
4045 'message': msg})
4047 def on_delete_button_clicked(self, widget):
4048 selection = self.treeview.get_selection()
4049 if not selection:
4050 return
4051 model, iter_ = selection.get_selected()
4052 node = model[iter_][0]
4053 our_jid = gajim.get_jid_from_account(self.account)
4054 gajim.connections[self.account].send_pb_delete(our_jid, node,
4055 on_ok=self.node_removed, on_fail=self.node_not_removed)
4057 def on_configure_button_clicked(self, widget):
4058 selection = self.treeview.get_selection()
4059 if not selection:
4060 return
4061 model, iter_ = selection.get_selected()
4062 node = model[iter_][0]
4063 our_jid = gajim.get_jid_from_account(self.account)
4064 gajim.connections[self.account].request_pb_configuration(our_jid, node)
4066 def _nec_pep_config_received(self, obj):
4067 def on_ok(form, node):
4068 form.type = 'submit'
4069 our_jid = gajim.get_jid_from_account(self.account)
4070 gajim.connections[self.account].send_pb_configure(our_jid, node, form)
4071 window = dialogs.DataFormWindow(obj.form, (on_ok, obj.node))
4072 title = _('Configure %s') % obj.node
4073 window.set_title(title)
4074 window.show_all()
4076 class ManageSoundsWindow:
4077 def __init__(self):
4078 self.xml = gtkgui_helpers.get_gtk_builder('manage_sounds_window.ui')
4079 self.window = self.xml.get_object('manage_sounds_window')
4081 # sounds treeview
4082 self.sound_tree = self.xml.get_object('sounds_treeview')
4084 # active, event ui name, path to sound file, event_config_name
4085 model = gtk.ListStore(bool, str, str, str)
4086 self.sound_tree.set_model(model)
4088 col = gtk.TreeViewColumn(_('Active'))
4089 self.sound_tree.append_column(col)
4090 renderer = gtk.CellRendererToggle()
4091 renderer.set_property('activatable', True)
4092 renderer.connect('toggled', self.sound_toggled_cb)
4093 col.pack_start(renderer)
4094 col.set_attributes(renderer, active = 0)
4096 col = gtk.TreeViewColumn(_('Event'))
4097 self.sound_tree.append_column(col)
4098 renderer = gtk.CellRendererText()
4099 col.pack_start(renderer)
4100 col.set_attributes(renderer, text = 1)
4102 self.fill_sound_treeview()
4104 self.xml.connect_signals(self)
4106 self.sound_tree.get_model().connect('row-changed',
4107 self.on_sounds_treemodel_row_changed)
4109 self.window.show_all()
4111 def on_sounds_treemodel_row_changed(self, model, path, iter_):
4112 sound_event = model[iter_][3].decode('utf-8')
4113 gajim.config.set_per('soundevents', sound_event, 'enabled',
4114 bool(model[path][0]))
4115 gajim.config.set_per('soundevents', sound_event, 'path',
4116 model[iter_][2].decode('utf-8'))
4117 gajim.interface.save_config()
4119 def sound_toggled_cb(self, cell, path):
4120 model = self.sound_tree.get_model()
4121 model[path][0] = not model[path][0]
4123 def fill_sound_treeview(self):
4124 model = self.sound_tree.get_model()
4125 model.clear()
4126 model.set_sort_column_id(1, gtk.SORT_ASCENDING)
4128 # NOTE: sounds_ui_names MUST have all items of
4129 # sounds = gajim.config.get_per('soundevents') as keys
4130 sounds_dict = {
4131 'first_message_received': _('First Message Received'),
4132 'next_message_received_focused': _('Next Message Received Focused'),
4133 'next_message_received_unfocused':
4134 _('Next Message Received Unfocused'),
4135 'contact_connected': _('Contact Connected'),
4136 'contact_disconnected': _('Contact Disconnected'),
4137 'message_sent': _('Message Sent'),
4138 'muc_message_highlight': _('Group Chat Message Highlight'),
4139 'muc_message_received': _('Group Chat Message Received'),
4140 'gmail_received': _('GMail Email Received')
4143 for sound_event_config_name, sound_ui_name in sounds_dict.items():
4144 enabled = gajim.config.get_per('soundevents',
4145 sound_event_config_name, 'enabled')
4146 path = gajim.config.get_per('soundevents',
4147 sound_event_config_name, 'path')
4148 model.append((enabled, sound_ui_name, path, sound_event_config_name))
4150 def on_treeview_sounds_cursor_changed(self, widget, data = None):
4151 (model, iter_) = self.sound_tree.get_selection().get_selected()
4152 sounds_entry = self.xml.get_object('sounds_entry')
4153 if not iter_:
4154 sounds_entry.set_text('')
4155 return
4156 path_to_snd_file = model[iter_][2]
4157 sounds_entry.set_text(path_to_snd_file)
4159 def on_browse_for_sounds_button_clicked(self, widget, data = None):
4160 (model, iter_) = self.sound_tree.get_selection().get_selected()
4161 if not iter_:
4162 return
4163 def on_ok(widget, path_to_snd_file):
4164 self.dialog.destroy()
4165 model, iter_ = self.sound_tree.get_selection().get_selected()
4166 if not path_to_snd_file:
4167 model[iter_][2] = ''
4168 self.xml.get_object('sounds_entry').set_text('')
4169 model[iter_][0] = False
4170 return
4171 directory = os.path.dirname(path_to_snd_file)
4172 gajim.config.set('last_sounds_dir', directory)
4173 path_to_snd_file = helpers.strip_soundfile_path(path_to_snd_file)
4174 self.xml.get_object('sounds_entry').set_text(path_to_snd_file)
4176 model[iter_][2] = path_to_snd_file # set new path to sounds_model
4177 model[iter_][0] = True # set the sound to enabled
4179 def on_cancel(widget):
4180 self.dialog.destroy()
4182 path_to_snd_file = model[iter_][2].decode('utf-8')
4183 self.dialog = dialogs.SoundChooserDialog(path_to_snd_file, on_ok,
4184 on_cancel)
4186 def on_sounds_entry_changed(self, widget):
4187 path_to_snd_file = widget.get_text()
4188 model, iter_ = self.sound_tree.get_selection().get_selected()
4189 model[iter_][2] = path_to_snd_file # set new path to sounds_model
4191 def on_play_button_clicked(self, widget):
4192 model, iter_ = self.sound_tree.get_selection().get_selected()
4193 if not iter_:
4194 return
4195 snd_event_config_name = model[iter_][3]
4196 helpers.play_sound(snd_event_config_name)
4198 def on_close_button_clicked(self, widget):
4199 self.window.hide()
4201 def on_manage_sounds_window_delete_event(self, widget, event):
4202 self.window.hide()
4203 return True # do NOT destroy the window