gajim

view src/config.py @ 10773:1076fc9700f5

merge elghinn's branch (roster versioning) to trunk. Fixes #4661, #3190
author Yann Leboulanger <asterix@lagaule.org>
date Fri, 10 Jul 2009 15:05:01 +0200
parents bf4f20dac149 6771b91032cd
children 91e0be3dedf6
line source
1 # -*- coding:utf-8 -*-
2 ## src/config.py
3 ##
4 ## Copyright (C) 2003-2005 Vincent Hanquez <tab AT snarc.org>
5 ## Copyright (C) 2003-2008 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>
18 ##
19 ## This file is part of Gajim.
20 ##
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.
24 ##
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.
29 ##
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/>.
32 ##
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 GnuPG
62 from common.exceptions import GajimGeneralException
64 #---------- PreferencesWindow class -------------#
65 class PreferencesWindow:
66 '''Class for Preferences window'''
68 def on_preferences_window_destroy(self, widget):
69 '''close window'''
70 del gajim.interface.instances['preferences']
72 def on_close_button_clicked(self, widget):
73 self.window.destroy()
75 def __init__(self):
76 '''Initialize Preferences window'''
77 self.xml = gtkgui_helpers.get_glade('preferences_window.glade')
78 self.window = self.xml.get_widget('preferences_window')
79 self.window.set_transient_for(gajim.interface.roster.window)
80 self.notebook = self.xml.get_widget('preferences_notebook')
81 self.one_window_type_combobox =\
82 self.xml.get_widget('one_window_type_combobox')
83 self.iconset_combobox = self.xml.get_widget('iconset_combobox')
84 self.notify_on_signin_checkbutton = self.xml.get_widget(
85 'notify_on_signin_checkbutton')
86 self.notify_on_signout_checkbutton = self.xml.get_widget(
87 'notify_on_signout_checkbutton')
88 self.auto_popup_away_checkbutton = self.xml.get_widget(
89 'auto_popup_away_checkbutton')
90 self.sound_dnd_checkbutton = self.xml.get_widget('sound_dnd_checkbutton')
91 self.auto_away_checkbutton = self.xml.get_widget('auto_away_checkbutton')
92 self.auto_away_time_spinbutton = self.xml.get_widget(
93 'auto_away_time_spinbutton')
94 self.auto_away_message_entry = self.xml.get_widget(
95 'auto_away_message_entry')
96 self.auto_xa_checkbutton = self.xml.get_widget('auto_xa_checkbutton')
97 self.auto_xa_time_spinbutton = self.xml.get_widget(
98 'auto_xa_time_spinbutton')
99 self.auto_xa_message_entry = self.xml.get_widget('auto_xa_message_entry')
101 ### General tab ###
102 # Display avatars in roster
103 st = gajim.config.get('show_avatars_in_roster')
104 self.xml.get_widget('show_avatars_in_roster_checkbutton'). \
105 set_active(st)
107 # Display status msg under contact name in roster
108 st = gajim.config.get('show_status_msgs_in_roster')
109 self.xml.get_widget('show_status_msgs_in_roster_checkbutton'). \
110 set_active( st)
112 # Display mood in roster
113 st = gajim.config.get('show_mood_in_roster')
114 self.xml.get_widget('show_mood_in_roster_checkbutton'). \
115 set_active(st)
117 # Display activity in roster
118 st = gajim.config.get('show_activity_in_roster')
119 self.xml.get_widget('show_activity_in_roster_checkbutton'). \
120 set_active(st)
122 # Display tunes in roster
123 st = gajim.config.get('show_tunes_in_roster')
124 self.xml.get_widget('show_tunes_in_roster_checkbutton'). \
125 set_active(st)
127 # Sort contacts by show
128 st = gajim.config.get('sort_by_show_in_roster')
129 self.xml.get_widget('sort_by_show_in_roster_checkbutton').set_active(st)
130 st = gajim.config.get('sort_by_show_in_muc')
131 self.xml.get_widget('sort_by_show_in_muc_checkbutton').set_active(st)
133 # emoticons
134 emoticons_combobox = self.xml.get_widget('emoticons_combobox')
135 emoticons_list = os.listdir(os.path.join(gajim.DATA_DIR, 'emoticons'))
136 # user themes
137 if os.path.isdir(gajim.MY_EMOTS_PATH):
138 emoticons_list += os.listdir(gajim.MY_EMOTS_PATH)
139 renderer_text = gtk.CellRendererText()
140 emoticons_combobox.pack_start(renderer_text, True)
141 emoticons_combobox.add_attribute(renderer_text, 'text', 0)
142 model = gtk.ListStore(str)
143 emoticons_combobox.set_model(model)
144 l = []
145 for dir_ in emoticons_list:
146 if not os.path.isdir(os.path.join(gajim.DATA_DIR, 'emoticons', dir_)) \
147 and not os.path.isdir(os.path.join(gajim.MY_EMOTS_PATH, dir_)) :
148 continue
149 if dir_ != '.svn':
150 l.append(dir_)
151 l.append(_('Disabled'))
152 for i in xrange(len(l)):
153 model.append([l[i]])
154 if gajim.config.get('emoticons_theme') == l[i]:
155 emoticons_combobox.set_active(i)
156 if not gajim.config.get('emoticons_theme'):
157 emoticons_combobox.set_active(len(l)-1)
159 # Set default for single window type
160 choices = common.config.opt_one_window_types
161 type_ = gajim.config.get('one_message_window')
162 if type_ in choices:
163 self.one_window_type_combobox.set_active(choices.index(type_))
164 else:
165 self.one_window_type_combobox.set_active(0)
167 # Compact View
168 st = gajim.config.get('compact_view')
169 self.xml.get_widget('compact_view_checkbutton').set_active(st)
171 # Ignore XHTML
172 st = gajim.config.get('ignore_incoming_xhtml')
173 self.xml.get_widget('xhtml_checkbutton').set_active(st)
175 # use speller
176 if HAS_GTK_SPELL:
177 st = gajim.config.get('use_speller')
178 self.xml.get_widget('speller_checkbutton').set_active(st)
179 else:
180 self.xml.get_widget('speller_checkbutton').set_sensitive(False)
182 ### Style tab ###
183 # Themes
184 theme_combobox = self.xml.get_widget('theme_combobox')
185 cell = gtk.CellRendererText()
186 theme_combobox.pack_start(cell, True)
187 theme_combobox.add_attribute(cell, 'text', 0)
188 self.update_theme_list()
190 # iconset
191 iconsets_list = os.listdir(os.path.join(gajim.DATA_DIR, 'iconsets'))
192 if os.path.isdir(gajim.MY_ICONSETS_PATH):
193 iconsets_list += os.listdir(gajim.MY_ICONSETS_PATH)
194 # new model, image in 0, string in 1
195 model = gtk.ListStore(gtk.Image, str)
196 renderer_image = cell_renderer_image.CellRendererImage(0, 0)
197 renderer_text = gtk.CellRendererText()
198 renderer_text.set_property('xpad', 5)
199 self.iconset_combobox.pack_start(renderer_image, expand = False)
200 self.iconset_combobox.pack_start(renderer_text, expand = True)
201 self.iconset_combobox.set_attributes(renderer_text, text = 1)
202 self.iconset_combobox.add_attribute(renderer_image, 'image', 0)
203 self.iconset_combobox.set_model(model)
204 l = []
205 for dir in iconsets_list:
206 if not os.path.isdir(os.path.join(gajim.DATA_DIR, 'iconsets', dir)) \
207 and not os.path.isdir(os.path.join(gajim.MY_ICONSETS_PATH, dir)):
208 continue
209 if dir != '.svn' and dir != 'transports':
210 l.append(dir)
211 if l.count == 0:
212 l.append(' ')
213 for i in xrange(len(l)):
214 preview = gtk.Image()
215 files = []
216 files.append(os.path.join(helpers.get_iconset_path(l[i]), '16x16',
217 'online.png'))
218 files.append(os.path.join(helpers.get_iconset_path(l[i]), '16x16',
219 'online.gif'))
220 for file_ in files:
221 if os.path.exists(file_):
222 preview.set_from_file(file_)
223 model.append([preview, l[i]])
224 if gajim.config.get('iconset') == l[i]:
225 self.iconset_combobox.set_active(i)
227 # Use transports iconsets
228 st = gajim.config.get('use_transports_iconsets')
229 self.xml.get_widget('transports_iconsets_checkbutton').set_active(st)
231 # Color for incoming messages
232 colSt = gajim.config.get('inmsgcolor')
233 self.xml.get_widget('incoming_msg_colorbutton').set_color(
234 gtk.gdk.color_parse(colSt))
236 # Color for outgoing messages
237 colSt = gajim.config.get('outmsgcolor')
238 self.xml.get_widget('outgoing_msg_colorbutton').set_color(
239 gtk.gdk.color_parse(colSt))
241 # Color for status messages
242 colSt = gajim.config.get('statusmsgcolor')
243 self.xml.get_widget('status_msg_colorbutton').set_color(
244 gtk.gdk.color_parse(colSt))
246 # Color for hyperlinks
247 colSt = gajim.config.get('urlmsgcolor')
248 self.xml.get_widget('url_msg_colorbutton').set_color(
249 gtk.gdk.color_parse(colSt))
251 # Font for messages
252 font = gajim.config.get('conversation_font')
253 # try to set default font for the current desktop env
254 fontbutton = self.xml.get_widget('conversation_fontbutton')
255 if font == '':
256 fontbutton.set_sensitive(False)
257 self.xml.get_widget('default_chat_font').set_active(True)
258 else:
259 fontbutton.set_font_name(font)
261 ### Personal Events tab ###
262 # outgoing send chat state notifications
263 st = gajim.config.get('outgoing_chat_state_notifications')
264 combo = self.xml.get_widget('outgoing_chat_states_combobox')
265 if st == 'all':
266 combo.set_active(0)
267 elif st == 'composing_only':
268 combo.set_active(1)
269 else: # disabled
270 combo.set_active(2)
272 # displayed send chat state notifications
273 st = gajim.config.get('displayed_chat_state_notifications')
274 combo = self.xml.get_widget('displayed_chat_states_combobox')
275 if st == 'all':
276 combo.set_active(0)
277 elif st == 'composing_only':
278 combo.set_active(1)
279 else: # disabled
280 combo.set_active(2)
283 ### Notifications tab ###
284 # On new event
285 on_event_combobox = self.xml.get_widget('on_event_combobox')
286 if gajim.config.get('autopopup'):
287 on_event_combobox.set_active(0)
288 elif gajim.config.get('notify_on_new_message'):
289 on_event_combobox.set_active(1)
290 else:
291 on_event_combobox.set_active(2)
293 # notify on online statuses
294 st = gajim.config.get('notify_on_signin')
295 self.notify_on_signin_checkbutton.set_active(st)
297 # notify on offline statuses
298 st = gajim.config.get('notify_on_signout')
299 self.notify_on_signout_checkbutton.set_active(st)
301 # autopopupaway
302 st = gajim.config.get('autopopupaway')
303 self.auto_popup_away_checkbutton.set_active(st)
305 # sounddnd
306 st = gajim.config.get('sounddnd')
307 self.sound_dnd_checkbutton.set_active(st)
309 # Systray
310 systray_combobox = self.xml.get_widget('systray_combobox')
311 if gajim.config.get('trayicon') == 'never':
312 systray_combobox.set_active(0)
313 elif gajim.config.get('trayicon') == 'on_event':
314 systray_combobox.set_active(1)
315 else:
316 systray_combobox.set_active(2)
318 # sounds
319 if gajim.config.get('sounds_on'):
320 self.xml.get_widget('play_sounds_checkbutton').set_active(True)
321 else:
322 self.xml.get_widget('manage_sounds_button').set_sensitive(False)
324 # Notify user of new gmail e-mail messages,
325 # make checkbox sensitive if user has a gtalk account
326 frame_gmail = self.xml.get_widget('frame_gmail')
327 notify_gmail_checkbutton = self.xml.get_widget('notify_gmail_checkbutton')
328 notify_gmail_extra_checkbutton = self.xml.get_widget(
329 'notify_gmail_extra_checkbutton')
331 for account in gajim.config.get_per('accounts'):
332 jid = gajim.get_jid_from_account(account)
333 if gajim.get_server_from_jid(jid) in gajim.gmail_domains:
334 frame_gmail.set_sensitive(True)
335 st = gajim.config.get('notify_on_new_gmail_email')
336 notify_gmail_checkbutton.set_active(st)
337 st = gajim.config.get('notify_on_new_gmail_email_extra')
338 notify_gmail_extra_checkbutton.set_active(st)
339 break
341 #### Status tab ###
342 # Autoaway
343 st = gajim.config.get('autoaway')
344 self.auto_away_checkbutton.set_active(st)
346 # Autoawaytime
347 st = gajim.config.get('autoawaytime')
348 self.auto_away_time_spinbutton.set_value(st)
349 self.auto_away_time_spinbutton.set_sensitive(gajim.config.get('autoaway'))
351 # autoaway message
352 st = gajim.config.get('autoaway_message')
353 self.auto_away_message_entry.set_text(st)
354 self.auto_away_message_entry.set_sensitive(gajim.config.get('autoaway'))
356 # Autoxa
357 st = gajim.config.get('autoxa')
358 self.auto_xa_checkbutton.set_active(st)
360 # Autoxatime
361 st = gajim.config.get('autoxatime')
362 self.auto_xa_time_spinbutton.set_value(st)
363 self.auto_xa_time_spinbutton.set_sensitive(gajim.config.get('autoxa'))
365 # autoxa message
366 st = gajim.config.get('autoxa_message')
367 self.auto_xa_message_entry.set_text(st)
368 self.auto_xa_message_entry.set_sensitive(gajim.config.get('autoxa'))
370 from common import sleepy
371 if not sleepy.SUPPORTED:
372 self.xml.get_widget('autoaway_table').set_sensitive(False)
374 # ask_status when online / offline
375 st = gajim.config.get('ask_online_status')
376 self.xml.get_widget('prompt_online_status_message_checkbutton').\
377 set_active(st)
378 st = gajim.config.get('ask_offline_status')
379 self.xml.get_widget('prompt_offline_status_message_checkbutton').\
380 set_active(st)
382 # Default Status messages
383 self.default_msg_tree = self.xml.get_widget('default_msg_treeview')
384 col2 = self.default_msg_tree.rc_get_style().bg[gtk.STATE_ACTIVE].to_string()
385 # (status, translated_status, message, enabled)
386 model = gtk.ListStore(str, str, str, bool)
387 self.default_msg_tree.set_model(model)
388 col = gtk.TreeViewColumn(_('Status'))
389 col.set_resizable(True)
390 self.default_msg_tree.append_column(col)
391 renderer = gtk.CellRendererText()
392 col.pack_start(renderer, False)
393 col.set_attributes(renderer, text = 1)
394 col = gtk.TreeViewColumn(_('Default Message'))
395 col.set_resizable(True)
396 self.default_msg_tree.append_column(col)
397 renderer = gtk.CellRendererText()
398 col.pack_start(renderer, True)
399 col.set_attributes(renderer, text = 2)
400 renderer.connect('edited', self.on_default_msg_cell_edited)
401 renderer.set_property('editable', True)
402 renderer.set_property('cell-background', col2)
403 col = gtk.TreeViewColumn(_('Enabled'))
404 col.set_resizable(True)
405 self.default_msg_tree.append_column(col)
406 renderer = gtk.CellRendererToggle()
407 col.pack_start(renderer, False)
408 col.set_attributes(renderer, active = 3)
409 renderer.set_property('activatable', True)
410 renderer.connect('toggled', self.default_msg_toggled_cb)
411 self.fill_default_msg_treeview()
413 # Status messages
414 self.msg_tree = self.xml.get_widget('msg_treeview')
415 model = gtk.ListStore(str, str)
416 self.msg_tree.set_model(model)
417 col = gtk.TreeViewColumn('name')
418 self.msg_tree.append_column(col)
419 renderer = gtk.CellRendererText()
420 col.pack_start(renderer, True)
421 col.set_attributes(renderer, text = 0)
422 renderer.connect('edited', self.on_msg_cell_edited)
423 renderer.set_property('editable', True)
424 self.fill_msg_treeview()
425 buf = self.xml.get_widget('msg_textview').get_buffer()
426 buf.connect('changed', self.on_msg_textview_changed)
428 ### Advanced tab ###
429 # open links with
430 if os.name == 'nt':
431 applications_frame = self.xml.get_widget('applications_frame')
432 applications_frame.set_no_show_all(True)
433 applications_frame.hide()
434 else:
435 self.applications_combobox = self.xml.get_widget(
436 'applications_combobox')
437 self.xml.get_widget('custom_apps_frame').hide()
438 self.xml.get_widget('custom_apps_frame').set_no_show_all(True)
440 if gajim.config.get('autodetect_browser_mailer'):
441 self.applications_combobox.set_active(0)
442 # else autodetect_browser_mailer is False.
443 # so user has 'Always Use GNOME/KDE/Xfce' or Custom
444 elif gajim.config.get('openwith') == 'gnome-open':
445 self.applications_combobox.set_active(1)
446 elif gajim.config.get('openwith') == 'kfmclient exec':
447 self.applications_combobox.set_active(2)
448 elif gajim.config.get('openwith') == 'exo-open':
449 self.applications_combobox.set_active(3)
450 elif gajim.config.get('openwith') == 'custom':
451 self.applications_combobox.set_active(4)
452 self.xml.get_widget('custom_apps_frame').show()
454 self.xml.get_widget('custom_browser_entry').set_text(
455 gajim.config.get('custombrowser'))
456 self.xml.get_widget('custom_mail_client_entry').set_text(
457 gajim.config.get('custommailapp'))
458 self.xml.get_widget('custom_file_manager_entry').set_text(
459 gajim.config.get('custom_file_manager'))
461 # log status changes of contacts
462 st = gajim.config.get('log_contact_status_changes')
463 self.xml.get_widget('log_show_changes_checkbutton').set_active(st)
465 # log encrypted chat sessions
466 w = self.xml.get_widget('log_encrypted_chats_checkbutton')
467 st = self.get_per_account_option('log_encrypted_sessions')
468 if st == 'mixed':
469 w.set_inconsistent(True)
470 else:
471 w.set_active(st)
473 # send os info
474 w = self.xml.get_widget('send_os_info_checkbutton')
475 st = self.get_per_account_option('send_os_info')
476 if st == 'mixed':
477 w.set_inconsistent(True)
478 else:
479 w.set_active(st)
481 # check if gajm is default
482 st = gajim.config.get('check_if_gajim_is_default')
483 self.xml.get_widget('check_default_client_checkbutton').set_active(st)
485 # Ignore messages from unknown contacts
486 w = self.xml.get_widget('ignore_events_from_unknown_contacts_checkbutton')
487 st = self.get_per_account_option('ignore_unknown_contacts')
488 if st == 'mixed':
489 w.set_inconsistent(True)
490 else:
491 w.set_active(st)
493 self.xml.signal_autoconnect(self)
495 self.msg_tree.get_model().connect('row-changed',
496 self.on_msg_treemodel_row_changed)
497 self.msg_tree.get_model().connect('row-deleted',
498 self.on_msg_treemodel_row_deleted)
499 self.default_msg_tree.get_model().connect('row-changed',
500 self.on_default_msg_treemodel_row_changed)
502 self.theme_preferences = None
503 self.sounds_preferences = None
505 self.notebook.set_current_page(0)
507 self.window.show_all()
508 gtkgui_helpers.possibly_move_window_in_current_desktop(self.window)
510 def on_preferences_window_key_press_event(self, widget, event):
511 if event.keyval == gtk.keysyms.Escape:
512 self.window.hide()
514 def get_per_account_option(self, opt):
515 '''Return the value of the option opt if it's the same in all accounts
516 else returns "mixed"'''
517 if len(gajim.connections) == 0:
518 # a non existant key return default value
519 return gajim.config.get_per('accounts', '__default__', opt)
520 val = None
521 for account in gajim.connections:
522 v = gajim.config.get_per('accounts', account, opt)
523 if val is None:
524 val = v
525 elif val != v:
526 return 'mixed'
527 return val
529 def on_checkbutton_toggled(self, widget, config_name,
530 change_sensitivity_widgets=None):
531 gajim.config.set(config_name, widget.get_active())
532 if change_sensitivity_widgets:
533 for w in change_sensitivity_widgets:
534 w.set_sensitive(widget.get_active())
535 gajim.interface.save_config()
537 def on_per_account_checkbutton_toggled(self, widget, config_name,
538 change_sensitivity_widgets=None):
539 for account in gajim.connections:
540 gajim.config.set_per('accounts', account, config_name,
541 widget.get_active())
542 if change_sensitivity_widgets:
543 for w in change_sensitivity_widgets:
544 w.set_sensitive(widget.get_active())
545 gajim.interface.save_config()
547 def on_sort_by_show_in_roster_checkbutton_toggled(self, widget):
548 self.on_checkbutton_toggled(widget, 'sort_by_show_in_roster')
549 gajim.interface.roster.setup_and_draw_roster()
551 def on_sort_by_show_in_muc_checkbutton_toggled(self, widget):
552 self.on_checkbutton_toggled(widget, 'sort_by_show_in_muc')
553 # Redraw connected groupchats
554 for account in gajim.connections:
555 if gajim.connections[account].connected:
556 for gc_control in gajim.interface.msg_win_mgr.get_controls(
557 message_control.TYPE_GC) + \
558 gajim.interface.minimized_controls[account].values():
559 gc_control.draw_roster()
561 def on_show_avatars_in_roster_checkbutton_toggled(self, widget):
562 self.on_checkbutton_toggled(widget, 'show_avatars_in_roster')
563 gajim.interface.roster.setup_and_draw_roster()
564 # Redraw connected groupchats (in an ugly way)
565 for account in gajim.connections:
566 if gajim.connections[account].connected:
567 for gc_control in gajim.interface.msg_win_mgr.get_controls(
568 message_control.TYPE_GC) + \
569 gajim.interface.minimized_controls[account].values():
570 gc_control.draw_roster()
572 def on_show_status_msgs_in_roster_checkbutton_toggled(self, widget):
573 self.on_checkbutton_toggled(widget, 'show_status_msgs_in_roster')
574 gajim.interface.roster.setup_and_draw_roster()
575 for ctl in gajim.interface.msg_win_mgr.controls():
576 if ctl.type_id == message_control.TYPE_GC:
577 ctl.update_ui()
579 def on_show_mood_in_roster_checkbutton_toggled(self, widget):
580 self.on_checkbutton_toggled(widget, 'show_mood_in_roster')
581 gajim.interface.roster.setup_and_draw_roster()
583 def on_show_activity_in_roster_checkbutton_toggled(self, widget):
584 self.on_checkbutton_toggled(widget, 'show_activity_in_roster')
585 gajim.interface.roster.setup_and_draw_roster()
587 def on_show_tunes_in_roster_checkbutton_toggled(self, widget):
588 self.on_checkbutton_toggled(widget, 'show_tunes_in_roster')
589 gajim.interface.roster.setup_and_draw_roster()
591 def on_emoticons_combobox_changed(self, widget):
592 active = widget.get_active()
593 model = widget.get_model()
594 emot_theme = model[active][0].decode('utf-8')
595 if emot_theme == _('Disabled'):
596 gajim.config.set('emoticons_theme', '')
597 else:
598 gajim.config.set('emoticons_theme', emot_theme)
600 gajim.interface.init_emoticons(need_reload = True)
601 gajim.interface.make_regexps()
602 self.toggle_emoticons()
604 def toggle_emoticons(self):
605 '''Update emoticons state in Opened Chat Windows'''
606 for win in gajim.interface.msg_win_mgr.windows():
607 win.toggle_emoticons()
609 def on_one_window_type_combo_changed(self, widget):
610 active = widget.get_active()
611 config_type = common.config.opt_one_window_types[active]
612 gajim.config.set('one_message_window', config_type)
613 gajim.interface.save_config()
614 gajim.interface.msg_win_mgr.reconfig()
616 def on_compact_view_checkbutton_toggled(self, widget):
617 active = widget.get_active()
618 for ctl in gajim.interface.msg_win_mgr.controls():
619 ctl.chat_buttons_set_visible(active)
620 gajim.config.set('compact_view', active)
621 gajim.interface.save_config()
623 def on_xhtml_checkbutton_toggled(self, widget):
624 self.on_checkbutton_toggled(widget, 'ignore_incoming_xhtml')
625 helpers.update_optional_features()
627 def apply_speller(self):
628 for ctrl in gajim.interface.msg_win_mgr.controls():
629 if isinstance(ctrl, chat_control.ChatControlBase):
630 try:
631 spell_obj = gtkspell.get_from_text_view(ctrl.msg_textview)
632 except (TypeError, RuntimeError, OSError):
633 spell_obj = None
635 if not spell_obj:
636 ctrl.set_speller()
638 def remove_speller(self):
639 for ctrl in gajim.interface.msg_win_mgr.controls():
640 if isinstance(ctrl, chat_control.ChatControlBase):
641 try:
642 spell_obj = gtkspell.get_from_text_view(ctrl.msg_textview)
643 except (TypeError, RuntimeError):
644 spell_obj = None
645 if spell_obj:
646 spell_obj.detach()
648 def on_speller_checkbutton_toggled(self, widget):
649 active = widget.get_active()
650 gajim.config.set('use_speller', active)
651 gajim.interface.save_config()
652 if active:
653 lang = gajim.config.get('speller_language')
654 if not lang:
655 lang = gajim.LANG
656 tv = gtk.TextView()
657 try:
658 gtkspell.Spell(tv, lang)
659 except (TypeError, RuntimeError, OSError):
660 dialogs.ErrorDialog(
661 _('Dictionary for lang %s not available') % lang,
662 _('You have to install %s dictionary to use spellchecking, or '
663 'choose another language by setting the speller_language option.'
664 ) % lang)
665 gajim.config.set('use_speller', False)
666 widget.set_active(False)
667 else:
668 gajim.config.set('speller_language', lang)
669 self.apply_speller()
670 else:
671 self.remove_speller()
673 def on_theme_combobox_changed(self, widget):
674 model = widget.get_model()
675 active = widget.get_active()
676 config_theme = model[active][0].decode('utf-8').replace(' ', '_')
678 gajim.config.set('roster_theme', config_theme)
680 # begin repainting themed widgets throughout
681 gajim.interface.roster.repaint_themed_widgets()
682 gajim.interface.roster.change_roster_style(None)
683 gajim.interface.save_config()
685 def update_theme_list(self):
686 theme_combobox = self.xml.get_widget('theme_combobox')
687 model = gtk.ListStore(str)
688 theme_combobox.set_model(model)
689 i = 0
690 for config_theme in gajim.config.get_per('themes'):
691 theme = config_theme.replace('_', ' ')
692 model.append([theme])
693 if gajim.config.get('roster_theme') == config_theme:
694 theme_combobox.set_active(i)
695 i += 1
697 def on_manage_theme_button_clicked(self, widget):
698 if self.theme_preferences is None:
699 self.theme_preferences = dialogs.GajimThemesWindow()
700 else:
701 self.theme_preferences.window.present()
702 self.theme_preferences.select_active_theme()
704 def on_iconset_combobox_changed(self, widget):
705 model = widget.get_model()
706 active = widget.get_active()
707 icon_string = model[active][1].decode('utf-8')
708 gajim.config.set('iconset', icon_string)
709 gtkgui_helpers.reload_jabber_state_images()
710 gajim.interface.save_config()
712 def on_transports_iconsets_checkbutton_toggled(self, widget):
713 self.on_checkbutton_toggled(widget, 'use_transports_iconsets')
714 gtkgui_helpers.reload_jabber_state_images()
716 def on_outgoing_chat_states_combobox_changed(self, widget):
717 active = widget.get_active()
718 old_value = gajim.config.get('outgoing_chat_state_notifications')
719 if active == 0: # all
720 gajim.config.set('outgoing_chat_state_notifications', 'all')
721 elif active == 1: # only composing
722 gajim.config.set('outgoing_chat_state_notifications', 'composing_only')
723 else: # disabled
724 gajim.config.set('outgoing_chat_state_notifications', 'disabled')
725 new_value = gajim.config.get('outgoing_chat_state_notifications')
726 if 'disabled' in (old_value, new_value):
727 # we changed from disabled to sth else or vice versa
728 helpers.update_optional_features()
730 def on_displayed_chat_states_combobox_changed(self, widget):
731 active = widget.get_active()
732 if active == 0: # all
733 gajim.config.set('displayed_chat_state_notifications', 'all')
734 elif active == 1: # only composing
735 gajim.config.set('displayed_chat_state_notifications',
736 'composing_only')
737 else: # disabled
738 gajim.config.set('displayed_chat_state_notifications', 'disabled')
740 def on_ignore_events_from_unknown_contacts_checkbutton_toggled(self, widget):
741 widget.set_inconsistent(False)
742 self.on_per_account_checkbutton_toggled(widget, 'ignore_unknown_contacts')
744 def on_on_event_combobox_changed(self, widget):
745 active = widget.get_active()
746 if active == 0:
747 gajim.config.set('autopopup', True)
748 gajim.config.set('notify_on_new_message', False)
749 elif active == 1:
750 gajim.config.set('autopopup', False)
751 gajim.config.set('notify_on_new_message', True)
752 else:
753 gajim.config.set('autopopup', False)
754 gajim.config.set('notify_on_new_message', False)
756 def on_notify_on_signin_checkbutton_toggled(self, widget):
757 self.on_checkbutton_toggled(widget, 'notify_on_signin')
759 def on_notify_on_signout_checkbutton_toggled(self, widget):
760 self.on_checkbutton_toggled(widget, 'notify_on_signout')
762 def on_auto_popup_away_checkbutton_toggled(self, widget):
763 self.on_checkbutton_toggled(widget, 'autopopupaway')
765 def on_sound_dnd_checkbutton_toggled(self, widget):
766 self.on_checkbutton_toggled(widget, 'sounddnd')
768 def on_systray_combobox_changed(self, widget):
769 active = widget.get_active()
770 if active == 0:
771 gajim.config.set('trayicon', 'never')
772 gajim.interface.systray_enabled = False
773 gajim.interface.systray.hide_icon()
774 elif active == 1:
775 gajim.config.set('trayicon', 'on_event')
776 gajim.interface.systray_enabled = True
777 gajim.interface.systray.show_icon()
778 gajim.interface.systray.set_img()
779 else:
780 gajim.config.set('trayicon', 'always')
781 gajim.interface.systray_enabled = True
782 gajim.interface.systray.show_icon()
783 gajim.interface.systray.set_img()
785 def on_advanced_notifications_button_clicked(self, widget):
786 dialogs.AdvancedNotificationsWindow()
788 def on_play_sounds_checkbutton_toggled(self, widget):
789 self.on_checkbutton_toggled(widget, 'sounds_on',
790 [self.xml.get_widget('manage_sounds_button')])
792 def on_manage_sounds_button_clicked(self, widget):
793 if self.sounds_preferences is None:
794 self.sounds_preferences = ManageSoundsWindow()
795 else:
796 self.sounds_preferences.window.present()
798 def update_text_tags(self):
799 '''Update color tags in Opened Chat Windows'''
800 for win in gajim.interface.msg_win_mgr.windows():
801 win.update_tags()
803 def on_preference_widget_color_set(self, widget, text):
804 color = widget.get_color()
805 color_string = gtkgui_helpers.make_color_string(color)
806 gajim.config.set(text, color_string)
807 self.update_text_tags()
808 gajim.interface.save_config()
810 def on_preference_widget_font_set(self, widget, text):
811 if widget:
812 font = widget.get_font_name()
813 else:
814 font = ''
815 gajim.config.set(text, font)
816 self.update_text_font()
817 gajim.interface.save_config()
819 def update_text_font(self):
820 '''Update text font in Opened Chat Windows'''
821 for win in gajim.interface.msg_win_mgr.windows():
822 win.update_font()
824 def on_incoming_msg_colorbutton_color_set(self, widget):
825 self.on_preference_widget_color_set(widget, 'inmsgcolor')
827 def on_outgoing_msg_colorbutton_color_set(self, widget):
828 self.on_preference_widget_color_set(widget, 'outmsgcolor')
830 def on_url_msg_colorbutton_color_set(self, widget):
831 self.on_preference_widget_color_set(widget, 'urlmsgcolor')
833 def on_status_msg_colorbutton_color_set(self, widget):
834 self.on_preference_widget_color_set(widget, 'statusmsgcolor')
836 def on_conversation_fontbutton_font_set(self, widget):
837 self.on_preference_widget_font_set(widget, 'conversation_font')
839 def on_default_chat_font_toggled(self, widget):
840 font_widget = self.xml.get_widget('conversation_fontbutton')
841 if widget.get_active():
842 font_widget.set_sensitive(False)
843 font_widget = None
844 else:
845 font_widget.set_sensitive(True)
846 self.on_preference_widget_font_set(font_widget, 'conversation_font')
848 def on_reset_colors_button_clicked(self, widget):
849 for i in ('inmsgcolor', 'outmsgcolor', 'statusmsgcolor', 'urlmsgcolor'):
850 gajim.config.set(i, gajim.interface.default_colors[i])
852 self.xml.get_widget('incoming_msg_colorbutton').set_color(\
853 gtk.gdk.color_parse(gajim.config.get('inmsgcolor')))
854 self.xml.get_widget('outgoing_msg_colorbutton').set_color(\
855 gtk.gdk.color_parse(gajim.config.get('outmsgcolor')))
856 self.xml.get_widget('status_msg_colorbutton').set_color(\
857 gtk.gdk.color_parse(gajim.config.get('statusmsgcolor')))
858 self.xml.get_widget('url_msg_colorbutton').set_color(\
859 gtk.gdk.color_parse(gajim.config.get('urlmsgcolor')))
860 self.update_text_tags()
861 gajim.interface.save_config()
863 def on_auto_away_checkbutton_toggled(self, widget):
864 self.on_checkbutton_toggled(widget, 'autoaway',
865 [self.auto_away_time_spinbutton, self.auto_away_message_entry])
867 def on_auto_away_time_spinbutton_value_changed(self, widget):
868 aat = widget.get_value_as_int()
869 gajim.config.set('autoawaytime', aat)
870 gajim.interface.sleeper = common.sleepy.Sleepy(
871 gajim.config.get('autoawaytime') * 60,
872 gajim.config.get('autoxatime') * 60)
873 gajim.interface.save_config()
875 def on_auto_away_message_entry_changed(self, widget):
876 gajim.config.set('autoaway_message', widget.get_text().decode('utf-8'))
878 def on_auto_xa_checkbutton_toggled(self, widget):
879 self.on_checkbutton_toggled(widget, 'autoxa',
880 [self.auto_xa_time_spinbutton, self.auto_xa_message_entry])
882 def on_auto_xa_time_spinbutton_value_changed(self, widget):
883 axt = widget.get_value_as_int()
884 gajim.config.set('autoxatime', axt)
885 gajim.interface.sleeper = common.sleepy.Sleepy(
886 gajim.config.get('autoawaytime') * 60,
887 gajim.config.get('autoxatime') * 60)
888 gajim.interface.save_config()
890 def on_auto_xa_message_entry_changed(self, widget):
891 gajim.config.set('autoxa_message', widget.get_text().decode('utf-8'))
893 def on_prompt_online_status_message_checkbutton_toggled(self, widget):
894 self.on_checkbutton_toggled(widget, 'ask_online_status')
896 def on_prompt_offline_status_message_checkbutton_toggled(self, widget):
897 self.on_checkbutton_toggled(widget, 'ask_offline_status')
899 def fill_default_msg_treeview(self):
900 model = self.default_msg_tree.get_model()
901 model.clear()
902 status = []
903 for status_ in gajim.config.get_per('defaultstatusmsg'):
904 status.append(status_)
905 status.sort()
906 for status_ in status:
907 msg = gajim.config.get_per('defaultstatusmsg', status_, 'message')
908 enabled = gajim.config.get_per('defaultstatusmsg', status_, 'enabled')
909 iter_ = model.append()
910 uf_show = helpers.get_uf_show(status_)
911 model.set(iter_, 0, status_, 1, uf_show, 2, msg, 3, enabled)
913 def on_default_msg_cell_edited(self, cell, row, new_text):
914 model = self.default_msg_tree.get_model()
915 iter_ = model.get_iter_from_string(row)
916 model.set_value(iter_, 2, new_text)
918 def default_msg_toggled_cb(self, cell, path):
919 model = self.default_msg_tree.get_model()
920 model[path][3] = not model[path][3]
922 def on_default_msg_treemodel_row_changed(self, model, path, iter_):
923 status = model[iter_][0]
924 message = model[iter_][2].decode('utf-8')
925 gajim.config.set_per('defaultstatusmsg', status, 'enabled',
926 model[iter_][3])
927 gajim.config.set_per('defaultstatusmsg', status, 'message', message)
929 def on_default_status_expander_activate(self, expander):
930 eventbox = self.xml.get_widget('default_status_eventbox')
931 vbox = self.xml.get_widget('status_vbox')
932 vbox.set_child_packing(eventbox, not expander.get_expanded(), True, 0,
933 gtk.PACK_START)
935 def save_status_messages(self, model):
936 for msg in gajim.config.get_per('statusmsg'):
937 gajim.config.del_per('statusmsg', msg)
938 iter_ = model.get_iter_first()
939 while iter_:
940 val = model[iter_][0].decode('utf-8')
941 if model[iter_][1]: # we have a preset message
942 if not val: # no title, use message text for title
943 val = model[iter_][1]
944 gajim.config.add_per('statusmsg', val)
945 msg = helpers.to_one_line(model[iter_][1].decode('utf-8'))
946 gajim.config.set_per('statusmsg', val, 'message', msg)
947 iter_ = model.iter_next(iter_)
948 gajim.interface.save_config()
950 def on_msg_treemodel_row_changed(self, model, path, iter_):
951 self.save_status_messages(model)
953 def on_msg_treemodel_row_deleted(self, model, path):
954 self.save_status_messages(model)
956 def on_applications_combobox_changed(self, widget):
957 gajim.config.set('autodetect_browser_mailer', False)
958 if widget.get_active() == 4:
959 self.xml.get_widget('custom_apps_frame').show()
960 gajim.config.set('openwith', 'custom')
961 else:
962 if widget.get_active() == 0:
963 gajim.config.set('autodetect_browser_mailer', True)
964 elif widget.get_active() == 1:
965 gajim.config.set('openwith', 'gnome-open')
966 elif widget.get_active() == 2:
967 gajim.config.set('openwith', 'kfmclient exec')
968 elif widget.get_active() == 3:
969 gajim.config.set('openwith', 'exo-open')
970 self.xml.get_widget('custom_apps_frame').hide()
971 gajim.interface.save_config()
973 def on_custom_browser_entry_changed(self, widget):
974 gajim.config.set('custombrowser', widget.get_text().decode('utf-8'))
975 gajim.interface.save_config()
977 def on_custom_mail_client_entry_changed(self, widget):
978 gajim.config.set('custommailapp', widget.get_text().decode('utf-8'))
979 gajim.interface.save_config()
981 def on_custom_file_manager_entry_changed(self, widget):
982 gajim.config.set('custom_file_manager', widget.get_text().decode('utf-8'))
983 gajim.interface.save_config()
985 def on_log_show_changes_checkbutton_toggled(self, widget):
986 self.on_checkbutton_toggled(widget, 'log_contact_status_changes')
988 def on_log_encrypted_chats_checkbutton_toggled(self, widget):
989 widget.set_inconsistent(False)
990 self.on_per_account_checkbutton_toggled(widget, 'log_encrypted_sessions')
992 def on_send_os_info_checkbutton_toggled(self, widget):
993 widget.set_inconsistent(False)
994 self.on_per_account_checkbutton_toggled(widget, 'send_os_info')
996 def on_check_default_client_checkbutton_toggled(self, widget):
997 self.on_checkbutton_toggled(widget, 'check_if_gajim_is_default')
999 def on_notify_gmail_checkbutton_toggled(self, widget):
1000 self.on_checkbutton_toggled(widget, 'notify_on_new_gmail_email')
1002 def on_notify_gmail_extra_checkbutton_toggled(self, widget):
1003 self.on_checkbutton_toggled(widget, 'notify_on_new_gmail_email_extra')
1005 def fill_msg_treeview(self):
1006 self.xml.get_widget('delete_msg_button').set_sensitive(False)
1007 model = self.msg_tree.get_model()
1008 model.clear()
1009 preset_status = []
1010 for msg_name in gajim.config.get_per('statusmsg'):
1011 if msg_name.startswith('_last_'):
1012 continue
1013 preset_status.append(msg_name)
1014 preset_status.sort()
1015 for msg_name in preset_status:
1016 msg_text = gajim.config.get_per('statusmsg', msg_name, 'message')
1017 msg_text = helpers.from_one_line(msg_text)
1018 iter_ = model.append()
1019 model.set(iter_, 0, msg_name, 1, msg_text)
1021 def on_msg_cell_edited(self, cell, row, new_text):
1022 model = self.msg_tree.get_model()
1023 iter_ = model.get_iter_from_string(row)
1024 model.set_value(iter_, 0, new_text)
1026 def on_msg_treeview_cursor_changed(self, widget, data = None):
1027 (model, iter_) = self.msg_tree.get_selection().get_selected()
1028 if not iter_:
1029 return
1030 self.xml.get_widget('delete_msg_button').set_sensitive(True)
1031 buf = self.xml.get_widget('msg_textview').get_buffer()
1032 msg = model[iter_][1]
1033 buf.set_text(msg)
1035 def on_new_msg_button_clicked(self, widget, data = None):
1036 model = self.msg_tree.get_model()
1037 iter_ = model.append()
1038 model.set(iter_, 0, _('status message title'), 1, _('status message text'))
1039 self.msg_tree.set_cursor(model.get_path(iter_))
1041 def on_delete_msg_button_clicked(self, widget, data = None):
1042 (model, iter_) = self.msg_tree.get_selection().get_selected()
1043 if not iter_:
1044 return
1045 buf = self.xml.get_widget('msg_textview').get_buffer()
1046 model.remove(iter_)
1047 buf.set_text('')
1048 self.xml.get_widget('delete_msg_button').set_sensitive(False)
1050 def on_msg_textview_changed(self, widget, data = None):
1051 (model, iter_) = self.msg_tree.get_selection().get_selected()
1052 if not iter_:
1053 return
1054 buf = self.xml.get_widget('msg_textview').get_buffer()
1055 first_iter, end_iter = buf.get_bounds()
1056 model.set_value(iter_, 1, buf.get_text(first_iter, end_iter))
1058 def on_msg_treeview_key_press_event(self, widget, event):
1059 if event.keyval == gtk.keysyms.Delete:
1060 self.on_delete_msg_button_clicked(widget)
1062 def on_open_advanced_editor_button_clicked(self, widget, data = None):
1063 if 'advanced_config' in gajim.interface.instances:
1064 gajim.interface.instances['advanced_config'].window.present()
1065 else:
1066 gajim.interface.instances['advanced_config'] = \
1067 dialogs.AdvancedConfigurationWindow()
1069 #---------- ManageProxiesWindow class -------------#
1070 class ManageProxiesWindow:
1071 def __init__(self):
1072 self.xml = gtkgui_helpers.get_glade('manage_proxies_window.glade')
1073 self.window = self.xml.get_widget('manage_proxies_window')
1074 self.window.set_transient_for(gajim.interface.roster.window)
1075 self.proxies_treeview = self.xml.get_widget('proxies_treeview')
1076 self.proxyname_entry = self.xml.get_widget('proxyname_entry')
1077 self.proxytype_combobox = self.xml.get_widget('proxytype_combobox')
1079 self.init_list()
1080 self.xml.signal_autoconnect(self)
1081 self.window.show_all()
1082 # hide the BOSH fields by default
1083 self.show_bosh_fields()
1085 def show_bosh_fields(self, show=True):
1086 if show:
1087 self.xml.get_widget('boshuri_entry').show()
1088 self.xml.get_widget('boshport_entry').show()
1089 self.xml.get_widget('boshuri_label').show()
1090 self.xml.get_widget('boshport_label').show()
1091 self.xml.get_widget('boshuseproxy_checkbutton').show()
1092 else:
1093 cb = self.xml.get_widget('boshuseproxy_checkbutton')
1094 cb.hide()
1095 cb.set_active(True)
1096 self.on_boshuseproxy_checkbutton_toggled(cb)
1097 self.xml.get_widget('boshuri_entry').hide()
1098 self.xml.get_widget('boshport_entry').hide()
1099 self.xml.get_widget('boshuri_label').hide()
1100 self.xml.get_widget('boshport_label').hide()
1103 def fill_proxies_treeview(self):
1104 model = self.proxies_treeview.get_model()
1105 model.clear()
1106 iter_ = model.append()
1107 model.set(iter_, 0, _('None'))
1108 for p in gajim.config.get_per('proxies'):
1109 iter_ = model.append()
1110 model.set(iter_, 0, p)
1112 def init_list(self):
1113 self.xml.get_widget('remove_proxy_button').set_sensitive(False)
1114 self.proxytype_combobox.set_sensitive(False)
1115 self.xml.get_widget('proxy_table').set_sensitive(False)
1116 model = gtk.ListStore(str)
1117 self.proxies_treeview.set_model(model)
1118 col = gtk.TreeViewColumn('Proxies')
1119 self.proxies_treeview.append_column(col)
1120 renderer = gtk.CellRendererText()
1121 col.pack_start(renderer, True)
1122 col.set_attributes(renderer, text = 0)
1123 self.fill_proxies_treeview()
1124 self.xml.get_widget('proxytype_combobox').set_active(0)
1126 def on_manage_proxies_window_destroy(self, widget):
1127 if 'accounts' in gajim.interface.instances:
1128 gajim.interface.instances['accounts'].\
1129 update_proxy_list()
1130 del gajim.interface.instances['manage_proxies']
1132 def on_add_proxy_button_clicked(self, widget):
1133 model = self.proxies_treeview.get_model()
1134 proxies = gajim.config.get_per('proxies')
1135 i = 1
1136 while ('proxy' + unicode(i)) in proxies:
1137 i += 1
1138 iter_ = model.append()
1139 model.set(iter_, 0, 'proxy' + unicode(i))
1140 gajim.config.add_per('proxies', 'proxy' + unicode(i))
1142 def on_remove_proxy_button_clicked(self, widget):
1143 (model, iter_) = self.proxies_treeview.get_selection().get_selected()
1144 if not iter_:
1145 return
1146 proxy = model[iter_][0].decode('utf-8')
1147 model.remove(iter_)
1148 gajim.config.del_per('proxies', proxy)
1149 self.xml.get_widget('remove_proxy_button').set_sensitive(False)
1151 def on_close_button_clicked(self, widget):
1152 self.window.destroy()
1154 def on_useauth_checkbutton_toggled(self, widget):
1155 act = widget.get_active()
1156 proxy = self.proxyname_entry.get_text().decode('utf-8')
1157 gajim.config.set_per('proxies', proxy, 'useauth', act)
1158 self.xml.get_widget('proxyuser_entry').set_sensitive(act)
1159 self.xml.get_widget('proxypass_entry').set_sensitive(act)
1161 def on_boshuseproxy_checkbutton_toggled(self, widget):
1162 act = widget.get_active()
1163 proxy = self.proxyname_entry.get_text().decode('utf-8')
1164 gajim.config.set_per('proxies', proxy, 'bosh_useproxy', act)
1165 self.xml.get_widget('proxyhost_entry').set_sensitive(act)
1166 self.xml.get_widget('proxyport_entry').set_sensitive(act)
1168 def on_proxies_treeview_cursor_changed(self, widget):
1169 #FIXME: check if off proxy settings are correct (see
1170 # http://trac.gajim.org/changeset/1921#file2 line 1221
1171 (model, iter_) = widget.get_selection().get_selected()
1172 if not iter_:
1173 return
1174 proxy = model[iter_][0]
1175 self.xml.get_widget('proxyname_entry').set_text(proxy)
1176 proxyhost_entry = self.xml.get_widget('proxyhost_entry')
1177 proxyport_entry = self.xml.get_widget('proxyport_entry')
1178 proxyuser_entry = self.xml.get_widget('proxyuser_entry')
1179 proxypass_entry = self.xml.get_widget('proxypass_entry')
1180 boshuri_entry = self.xml.get_widget('boshuri_entry')
1181 boshport_entry = self.xml.get_widget('boshport_entry')
1182 useauth_checkbutton = self.xml.get_widget('useauth_checkbutton')
1183 boshuseproxy_checkbutton = self.xml.get_widget('boshuseproxy_checkbutton')
1184 proxyhost_entry.set_text('')
1185 proxyport_entry.set_text('')
1186 proxyuser_entry.set_text('')
1187 proxypass_entry.set_text('')
1188 boshuri_entry.set_text('')
1190 #boshuseproxy_checkbutton.set_active(False)
1191 #self.on_boshuseproxy_checkbutton_toggled(boshuseproxy_checkbutton)
1193 #useauth_checkbutton.set_active(False)
1194 #self.on_useauth_checkbutton_toggled(useauth_checkbutton)
1196 if proxy == _('None'): # special proxy None
1197 self.show_bosh_fields(False)
1198 self.proxyname_entry.set_editable(False)
1199 self.xml.get_widget('remove_proxy_button').set_sensitive(False)
1200 self.xml.get_widget('proxytype_combobox').set_sensitive(False)
1201 self.xml.get_widget('proxy_table').set_sensitive(False)
1202 else:
1203 proxytype = gajim.config.get_per('proxies', proxy, 'type')
1205 self.show_bosh_fields(proxytype=='bosh')
1207 self.proxyname_entry.set_editable(True)
1208 self.xml.get_widget('remove_proxy_button').set_sensitive(True)
1209 self.xml.get_widget('proxytype_combobox').set_sensitive(True)
1210 self.xml.get_widget('proxy_table').set_sensitive(True)
1211 proxyhost_entry.set_text(gajim.config.get_per('proxies', proxy,
1212 'host'))
1213 proxyport_entry.set_text(unicode(gajim.config.get_per('proxies',
1214 proxy, 'port')))
1215 proxyuser_entry.set_text(gajim.config.get_per('proxies', proxy,
1216 'user'))
1217 proxypass_entry.set_text(gajim.config.get_per('proxies', proxy,
1218 'pass'))
1219 boshuri_entry.set_text(gajim.config.get_per('proxies', proxy,
1220 'bosh_uri'))
1221 boshport_entry.set_text(unicode(gajim.config.get_per('proxies', proxy,
1222 'bosh_port')))
1223 types = ['http', 'socks5', 'bosh']
1224 self.proxytype_combobox.set_active(types.index(proxytype))
1225 boshuseproxy_checkbutton.set_active(
1226 gajim.config.get_per('proxies', proxy, 'bosh_useproxy'))
1227 useauth_checkbutton.set_active(
1228 gajim.config.get_per('proxies', proxy, 'useauth'))
1230 def on_proxies_treeview_key_press_event(self, widget, event):
1231 if event.keyval == gtk.keysyms.Delete:
1232 self.on_remove_proxy_button_clicked(widget)
1234 def on_proxyname_entry_changed(self, widget):
1235 (model, iter_) = self.proxies_treeview.get_selection().get_selected()
1236 if not iter_:
1237 return
1238 old_name = model.get_value(iter_, 0).decode('utf-8')
1239 new_name = widget.get_text().decode('utf-8')
1240 if new_name == '':
1241 return
1242 if new_name == old_name:
1243 return
1244 config = gajim.config.get_per('proxies', old_name)
1245 gajim.config.del_per('proxies', old_name)
1246 gajim.config.add_per('proxies', new_name)
1247 for option in config:
1248 gajim.config.set_per('proxies', new_name, option,
1249 config[option][common.config.OPT_VAL])
1250 model.set_value(iter_, 0, new_name)
1252 def on_proxytype_combobox_changed(self, widget):
1253 types = ['http', 'socks5', 'bosh']
1254 type_ = self.proxytype_combobox.get_active()
1255 self.show_bosh_fields(types[type_]=='bosh')
1256 proxy = self.proxyname_entry.get_text().decode('utf-8')
1257 gajim.config.set_per('proxies', proxy, 'type', types[type_])
1259 def on_proxyhost_entry_changed(self, widget):
1260 value = widget.get_text().decode('utf-8')
1261 proxy = self.proxyname_entry.get_text().decode('utf-8')
1262 gajim.config.set_per('proxies', proxy, 'host', value)
1264 def on_proxyport_entry_changed(self, widget):
1265 value = widget.get_text().decode('utf-8')
1266 proxy = self.proxyname_entry.get_text().decode('utf-8')
1267 gajim.config.set_per('proxies', proxy, 'port', value)
1269 def on_proxyuser_entry_changed(self, widget):
1270 value = widget.get_text().decode('utf-8')
1271 proxy = self.proxyname_entry.get_text().decode('utf-8')
1272 gajim.config.set_per('proxies', proxy, 'user', value)
1274 def on_boshuri_entry_changed(self, widget):
1275 value = widget.get_text().decode('utf-8')
1276 proxy = self.proxyname_entry.get_text().decode('utf-8')
1277 gajim.config.set_per('proxies', proxy, 'bosh_uri', value)
1279 def on_boshport_entry_changed(self, widget):
1280 value = widget.get_text().decode('utf-8')
1281 proxy = self.proxyname_entry.get_text().decode('utf-8')
1282 gajim.config.set_per('proxies', proxy, 'bosh_port', value)
1284 def on_proxypass_entry_changed(self, widget):
1285 value = widget.get_text().decode('utf-8')
1286 proxy = self.proxyname_entry.get_text().decode('utf-8')
1287 gajim.config.set_per('proxies', proxy, 'pass', value)
1290 #---------- AccountsWindow class -------------#
1291 class AccountsWindow:
1292 '''Class for accounts window: list of accounts'''
1293 def on_accounts_window_destroy(self, widget):
1294 del gajim.interface.instances['accounts']
1296 def on_close_button_clicked(self, widget):
1297 self.check_resend_relog()
1298 self.window.destroy()
1300 def __init__(self):
1301 self.xml = gtkgui_helpers.get_glade('accounts_window.glade')
1302 self.window = self.xml.get_widget('accounts_window')
1303 self.window.set_transient_for(gajim.interface.roster.window)
1304 self.accounts_treeview = self.xml.get_widget('accounts_treeview')
1305 self.remove_button = self.xml.get_widget('remove_button')
1306 self.rename_button = self.xml.get_widget('rename_button')
1307 path_to_kbd_input_img = os.path.join(gajim.DATA_DIR, 'pixmaps',
1308 'kbd_input.png')
1309 img = self.xml.get_widget('rename_image')
1310 img.set_from_file(path_to_kbd_input_img)
1311 self.notebook = self.xml.get_widget('notebook')
1312 # Name
1313 model = gtk.ListStore(str)
1314 self.accounts_treeview.set_model(model)
1315 # column
1316 renderer = gtk.CellRendererText()
1317 self.accounts_treeview.insert_column_with_attributes(-1,
1318 _('Name'), renderer, text = 0)
1320 self.current_account = None
1321 # When we fill info, we don't want to handle the changed signals
1322 self.ignore_events = False
1323 self.need_relogin = False
1324 self.resend_presence = False
1326 self.update_proxy_list()
1327 self.xml.signal_autoconnect(self)
1328 self.init_accounts()
1329 self.window.show_all()
1331 # Merge accounts
1332 st = gajim.config.get('mergeaccounts')
1333 checkbutton = self.xml.get_widget('merge_checkbutton')
1334 checkbutton.set_active(st)
1335 # prevent roster redraws by connecting the signal after button state is set
1336 checkbutton.connect('toggled', self.on_merge_checkbutton_toggled)
1338 self.avahi_available = True
1339 try:
1340 import avahi
1341 except ImportError:
1342 self.avahi_available = False
1344 def on_accounts_window_key_press_event(self, widget, event):
1345 if event.keyval == gtk.keysyms.Escape:
1346 self.check_resend_relog()
1347 self.window.destroy()
1349 def select_account(self, account):
1350 model = self.accounts_treeview.get_model()
1351 iter_ = model.get_iter_root()
1352 while iter_:
1353 acct = model[iter_][0].decode('utf-8')
1354 if account == acct:
1355 self.accounts_treeview.set_cursor(model.get_path(iter_))
1356 return
1357 iter_ = model.iter_next(iter_)
1359 def init_accounts(self):
1360 '''initialize listStore with existing accounts'''
1361 self.remove_button.set_sensitive(False)
1362 self.rename_button.set_sensitive(False)
1363 self.current_account = None
1364 model = self.accounts_treeview.get_model()
1365 model.clear()
1366 for account in gajim.config.get_per('accounts'):
1367 iter_ = model.append()
1368 model.set(iter_, 0, account)
1370 def resend(self, account):
1371 show = gajim.SHOW_LIST[gajim.connections[account].connected]
1372 status = gajim.connections[account].status
1373 gajim.connections[account].change_status(show, status)
1375 def check_resend_relog(self):
1376 if self.need_relogin and self.current_account == gajim.ZEROCONF_ACC_NAME:
1377 if gajim.ZEROCONF_ACC_NAME in gajim.connections:
1378 gajim.connections[gajim.ZEROCONF_ACC_NAME].update_details()
1379 return
1381 elif self.need_relogin and self.current_account and \
1382 gajim.connections[self.current_account].connected > 0:
1383 def login(account, show_before, status_before):
1384 ''' login with previous status'''
1385 # first make sure connection is really closed,
1386 # 0.5 may not be enough
1387 gajim.connections[account].disconnect(True)
1388 gajim.interface.roster.send_status(account, show_before,
1389 status_before)
1391 def relog(account):
1392 self.dialog.destroy()
1393 show_before = gajim.SHOW_LIST[gajim.connections[account].connected]
1394 status_before = gajim.connections[account].status
1395 gajim.interface.roster.send_status(account, 'offline',
1396 _('Be right back.'))
1397 gobject.timeout_add(500, login, account, show_before, status_before)
1399 def on_yes(checked, account):
1400 relog(account)
1401 def on_no(account):
1402 if self.resend_presence:
1403 self.resend(account)
1404 self.dialog = dialogs.YesNoDialog(_('Relogin now?'),
1405 _('If you want all the changes to apply instantly, '
1406 'you must relogin.'), on_response_yes=(on_yes,
1407 self.current_account), on_response_no=(on_no, self.current_account))
1408 elif self.resend_presence:
1409 self.resend(self.current_account)
1411 self.need_relogin = False
1412 self.resend_presence = False
1414 def on_accounts_treeview_cursor_changed(self, widget):
1415 '''Activate modify buttons when a row is selected, update accounts info'''
1416 sel = self.accounts_treeview.get_selection()
1417 (model, iter_) = sel.get_selected()
1418 if iter_:
1419 account = model[iter_][0].decode('utf-8')
1420 else:
1421 account = None
1422 if self.current_account and self.current_account == account:
1423 # We're comming back to our current account, no need to update widgets
1424 return
1425 # Save config for previous account if needed cause focus_out event is
1426 # called after the changed event
1427 if self.current_account and self.window.get_focus():
1428 focused_widget = self.window.get_focus()
1429 focused_widget_name = focused_widget.get_name()
1430 if focused_widget_name in ('jid_entry1', 'resource_entry1',
1431 'custom_port_entry'):
1432 if focused_widget_name == 'jid_entry1':
1433 func = self.on_jid_entry1_focus_out_event
1434 elif focused_widget_name == 'resource_entry1':
1435 func = self.on_resource_entry1_focus_out_event
1436 elif focused_widget_name == 'custom_port_entry':
1437 func = self.on_custom_port_entry_focus_out_event
1438 if func(focused_widget, None):
1439 # Error detected in entry, don't change account, re-put cursor on
1440 # previous row
1441 self.select_account(self.current_account)
1442 return True
1443 self.window.set_focus(widget)
1445 self.check_resend_relog()
1447 self.remove_button.set_sensitive(True)
1448 self.rename_button.set_sensitive(True)
1449 if iter_:
1450 self.current_account = account
1451 if account == gajim.ZEROCONF_ACC_NAME:
1452 self.remove_button.set_sensitive(False)
1453 self.init_account()
1454 self.update_proxy_list()
1456 def update_proxy_list(self):
1457 if self.current_account:
1458 our_proxy = gajim.config.get_per('accounts', self.current_account,
1459 'proxy')
1460 else:
1461 our_proxy = ''
1463 if not our_proxy:
1464 our_proxy = _('None')
1465 proxy_combobox = self.xml.get_widget('proxies_combobox1')
1466 model = gtk.ListStore(str)
1467 proxy_combobox.set_model(model)
1468 l = gajim.config.get_per('proxies')
1469 l.insert(0, _('None'))
1470 for i in xrange(len(l)):
1471 model.append([l[i]])
1472 if our_proxy == l[i]:
1473 proxy_combobox.set_active(i)
1475 def init_account(self):
1476 if not self.current_account:
1477 self.notebook.set_current_page(0)
1478 return
1479 if gajim.config.get_per('accounts', self.current_account, 'is_zeroconf'):
1480 self.ignore_events = True
1481 self.init_zeroconf_account()
1482 self.ignore_events = False
1483 self.notebook.set_current_page(2)
1484 return
1485 self.ignore_events = True
1486 self.init_normal_account()
1487 self.ignore_events = False
1488 self.notebook.set_current_page(1)
1490 def init_zeroconf_account(self):
1491 enable = gajim.config.get('enable_zeroconf') and gajim.HAVE_ZEROCONF
1492 self.xml.get_widget('enable_zeroconf_checkbutton2').set_active(enable)
1493 if not gajim.HAVE_ZEROCONF:
1494 self.xml.get_widget('enable_zeroconf_checkbutton2').set_sensitive(
1495 False)
1496 self.xml.get_widget('zeroconf_notebook').set_sensitive(enable)
1497 # General tab
1498 st = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME,
1499 'autoconnect')
1500 self.xml.get_widget('autoconnect_checkbutton2').set_active(st)
1502 list_no_log_for = gajim.config.get_per('accounts',
1503 gajim.ZEROCONF_ACC_NAME, 'no_log_for').split()
1504 if gajim.ZEROCONF_ACC_NAME in list_no_log_for:
1505 self.xml.get_widget('log_history_checkbutton2').set_active(0)
1506 else:
1507 self.xml.get_widget('log_history_checkbutton2').set_active(1)
1509 st = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME,
1510 'sync_with_global_status')
1511 self.xml.get_widget('sync_with_global_status_checkbutton2').set_active(st)
1513 st = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME,
1514 'use_custom_host')
1515 self.xml.get_widget('custom_port_checkbutton2').set_active(st)
1516 self.xml.get_widget('custom_port_entry2').set_sensitive(st)
1518 st = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME,
1519 'custom_port')
1520 if not st:
1521 gajim.config.set_per('accounts', gajim.ZEROCONF_ACC_NAME,
1522 'custom_port', '5298')
1523 st = '5298'
1524 self.xml.get_widget('custom_port_entry2').set_text(str(st))
1526 # Personal tab
1527 gpg_key_label = self.xml.get_widget('gpg_key_label2')
1528 if gajim.ZEROCONF_ACC_NAME in gajim.connections and \
1529 gajim.connections[gajim.ZEROCONF_ACC_NAME].gpg:
1530 self.xml.get_widget('gpg_choose_button2').set_sensitive(True)
1531 self.init_account_gpg()
1532 else:
1533 gpg_key_label.set_text(_('OpenPGP is not usable on this computer'))
1534 self.xml.get_widget('gpg_choose_button2').set_sensitive(False)
1536 for opt in ('first_name', 'last_name', 'jabber_id', 'email'):
1537 st = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME,
1538 'zeroconf_' + opt)
1539 self.xml.get_widget(opt + '_entry2').set_text(st)
1541 def init_account_gpg(self):
1542 account = self.current_account
1543 keyid = gajim.config.get_per('accounts', account, 'keyid')
1544 keyname = gajim.config.get_per('accounts', account, 'keyname')
1545 use_gpg_agent = gajim.config.get('use_gpg_agent')
1547 if account == gajim.ZEROCONF_ACC_NAME:
1548 widget_name_add = '2'
1549 else:
1550 widget_name_add = '1'
1552 gpg_key_label = self.xml.get_widget('gpg_key_label' + widget_name_add)
1553 gpg_name_label = self.xml.get_widget('gpg_name_label' + widget_name_add)
1554 use_gpg_agent_checkbutton = self.xml.get_widget(
1555 'use_gpg_agent_checkbutton' + widget_name_add)
1557 if not keyid or not gajim.connections[account].gpg:
1558 use_gpg_agent_checkbutton.set_sensitive(False)
1559 gpg_key_label.set_text(_('No key selected'))
1560 gpg_name_label.set_text('')
1561 return
1563 gpg_key_label.set_text(keyid)
1564 gpg_name_label.set_text(keyname)
1565 use_gpg_agent_checkbutton.set_sensitive(True)
1566 use_gpg_agent_checkbutton.set_active(use_gpg_agent)
1568 def init_normal_account(self):
1569 account = self.current_account
1570 # Account tab
1571 jid = gajim.config.get_per('accounts', account, 'name') \
1572 + '@' + gajim.config.get_per('accounts', account, 'hostname')
1573 self.xml.get_widget('jid_entry1').set_text(jid)
1574 savepass = gajim.config.get_per('accounts', account, 'savepass')
1575 self.xml.get_widget('save_password_checkbutton1').set_active(savepass)
1576 password_entry = self.xml.get_widget('password_entry1')
1577 if savepass:
1578 passstr = passwords.get_password(account) or ''
1579 password_entry.set_sensitive(True)
1580 else:
1581 passstr = ''
1582 password_entry.set_sensitive(False)
1583 password_entry.set_text(passstr)
1585 self.xml.get_widget('resource_entry1').set_text(gajim.config.get_per(
1586 'accounts', account, 'resource'))
1587 self.xml.get_widget('adjust_priority_with_status_checkbutton1').\
1588 set_active(gajim.config.get_per('accounts', account,
1589 'adjust_priority_with_status'))
1590 spinbutton = self.xml.get_widget('priority_spinbutton1')
1591 if gajim.config.get('enable_negative_priority'):
1592 spinbutton.set_range(-128, 127)
1593 else:
1594 spinbutton.set_range(0, 127)
1595 spinbutton.set_value(gajim.config.get_per('accounts', account,
1596 'priority'))
1598 # Connection tab
1599 use_env_http_proxy = gajim.config.get_per('accounts', account,
1600 'use_env_http_proxy')
1601 self.xml.get_widget('use_env_http_proxy_checkbutton1').set_active(
1602 use_env_http_proxy)
1603 self.xml.get_widget('proxy_hbox1').set_sensitive(not use_env_http_proxy)
1605 warn_when_insecure_ssl = gajim.config.get_per('accounts', account,
1606 'warn_when_insecure_ssl_connection')
1607 self.xml.get_widget('warn_when_insecure_connection_checkbutton1').\
1608 set_active(warn_when_insecure_ssl)
1610 self.xml.get_widget('send_keepalive_checkbutton1').set_active(
1611 gajim.config.get_per('accounts', account, 'keep_alives_enabled'))
1613 use_custom_host = gajim.config.get_per('accounts', account,
1614 'use_custom_host')
1615 self.xml.get_widget('custom_host_port_checkbutton1').set_active(
1616 use_custom_host)
1617 custom_host = gajim.config.get_per('accounts', account, 'custom_host')
1618 if not custom_host:
1619 custom_host = gajim.config.get_per('accounts', account, 'hostname')
1620 gajim.config.set_per('accounts', account, 'custom_host', custom_host)
1621 self.xml.get_widget('custom_host_entry1').set_text(custom_host)
1622 custom_port = gajim.config.get_per('accounts', account, 'custom_port')
1623 if not custom_port:
1624 custom_port = 5222
1625 gajim.config.set_per('accounts', account, 'custom_port', custom_port)
1626 self.xml.get_widget('custom_port_entry1').set_text(unicode(custom_port))
1628 # Personal tab
1629 gpg_key_label = self.xml.get_widget('gpg_key_label1')
1630 if gajim.connections[account].gpg:
1631 self.xml.get_widget('gpg_choose_button1').set_sensitive(True)
1632 self.init_account_gpg()
1633 else:
1634 gpg_key_label.set_text(_('OpenPGP is not usable on this computer'))
1635 self.xml.get_widget('gpg_choose_button1').set_sensitive(False)
1637 # General tab
1638 self.xml.get_widget('autoconnect_checkbutton1').set_active(gajim.config.\
1639 get_per('accounts', account, 'autoconnect'))
1640 self.xml.get_widget('autoreconnect_checkbutton1').set_active(gajim.
1641 config.get_per('accounts', account, 'autoreconnect'))
1643 list_no_log_for = gajim.config.get_per('accounts', account,
1644 'no_log_for').split()
1645 if account in list_no_log_for:
1646 self.xml.get_widget('log_history_checkbutton1').set_active(False)
1647 else:
1648 self.xml.get_widget('log_history_checkbutton1').set_active(True)
1650 self.xml.get_widget('sync_with_global_status_checkbutton1').set_active(
1651 gajim.config.get_per('accounts', account, 'sync_with_global_status'))
1652 self.xml.get_widget('use_ft_proxies_checkbutton1').set_active(
1653 gajim.config.get_per('accounts', account, 'use_ft_proxies'))
1655 def on_add_button_clicked(self, widget):
1656 '''When add button is clicked: open an account information window'''
1657 if 'account_creation_wizard' in gajim.interface.instances:
1658 gajim.interface.instances['account_creation_wizard'].window.present()
1659 else:
1660 gajim.interface.instances['account_creation_wizard'] = \
1661 AccountCreationWizardWindow()
1663 def on_remove_button_clicked(self, widget):
1664 '''When delete button is clicked:
1665 Remove an account from the listStore and from the config file'''
1666 if not self.current_account:
1667 return
1668 account = self.current_account
1669 if len(gajim.events.get_events(account)):
1670 dialogs.ErrorDialog(_('Unread events'),
1671 _('Read all pending events before removing this account.'))
1672 return
1674 if gajim.config.get_per('accounts', account, 'is_zeroconf'):
1675 # Should never happen as button is insensitive
1676 return
1678 win_opened = False
1679 if gajim.interface.msg_win_mgr.get_controls(acct = account):
1680 win_opened = True
1681 else:
1682 for key in gajim.interface.instances[account]:
1683 if gajim.interface.instances[account][key] and key != \
1684 'remove_account':
1685 win_opened = True
1686 break
1687 # Detect if we have opened windows for this account
1688 def remove(account):
1689 if 'remove_account' in gajim.interface.instances[account]:
1690 gajim.interface.instances[account]['remove_account'].window.\
1691 present()
1692 else:
1693 gajim.interface.instances[account]['remove_account'] = \
1694 RemoveAccountWindow(account)
1695 if win_opened:
1696 dialogs.ConfirmationDialog(
1697 _('You have opened chat in account %s') % account,
1698 _('All chat and groupchat windows will be closed. Do you want to '
1699 'continue?'),
1700 on_response_ok = (remove, account))
1701 else:
1702 remove(account)
1704 def on_rename_button_clicked(self, widget):
1705 if not self.current_account:
1706 return
1707 enable = gajim.config.get('enable_zeroconf')
1708 if (self.current_account != gajim.ZEROCONF_ACC_NAME or enable) and \
1709 gajim.connections[self.current_account].connected != 0:
1710 dialogs.ErrorDialog(
1711 _('You are currently connected to the server'),
1712 _('To change the account name, you must be disconnected.'))
1713 return
1714 if len(gajim.events.get_events(self.current_account)):
1715 dialogs.ErrorDialog(_('Unread events'),
1716 _('To change the account name, you must read all pending '
1717 'events.'))
1718 return
1719 # Get the new name
1720 def on_renamed(new_name, old_name):
1721 if new_name in gajim.connections:
1722 dialogs.ErrorDialog(_('Account Name Already Used'),
1723 _('This name is already used by another of your accounts. '
1724 'Please choose another name.'))
1725 return
1726 if (new_name == ''):
1727 dialogs.ErrorDialog(_('Invalid account name'),
1728 _('Account name cannot be empty.'))
1729 return
1730 if new_name.find(' ') != -1:
1731 dialogs.ErrorDialog(_('Invalid account name'),
1732 _('Account name cannot contain spaces.'))
1733 return
1734 if self.current_account != gajim.ZEROCONF_ACC_NAME or enable:
1735 # update variables
1736 gajim.interface.instances[new_name] = gajim.interface.instances[
1737 old_name]
1738 gajim.interface.minimized_controls[new_name] = \
1739 gajim.interface.minimized_controls[old_name]
1740 gajim.nicks[new_name] = gajim.nicks[old_name]
1741 gajim.block_signed_in_notifications[new_name] = \
1742 gajim.block_signed_in_notifications[old_name]
1743 gajim.groups[new_name] = gajim.groups[old_name]
1744 gajim.gc_connected[new_name] = gajim.gc_connected[old_name]
1745 gajim.automatic_rooms[new_name] = gajim.automatic_rooms[old_name]
1746 gajim.newly_added[new_name] = gajim.newly_added[old_name]
1747 gajim.to_be_removed[new_name] = gajim.to_be_removed[old_name]
1748 gajim.sleeper_state[new_name] = gajim.sleeper_state[old_name]
1749 gajim.encrypted_chats[new_name] = gajim.encrypted_chats[old_name]
1750 gajim.last_message_time[new_name] = \
1751 gajim.last_message_time[old_name]
1752 gajim.status_before_autoaway[new_name] = \
1753 gajim.status_before_autoaway[old_name]
1754 gajim.transport_avatar[new_name] = gajim.transport_avatar[old_name]
1755 gajim.gajim_optional_features[new_name] = \
1756 gajim.gajim_optional_features[old_name]
1757 gajim.caps_hash[new_name] = gajim.caps_hash[old_name]
1759 gajim.contacts.change_account_name(old_name, new_name)
1760 gajim.events.change_account_name(old_name, new_name)
1762 # change account variable for chat / gc controls
1763 gajim.interface.msg_win_mgr.change_account_name(old_name, new_name)
1764 # upgrade account variable in opened windows
1765 for kind in ('infos', 'disco', 'gc_config', 'search',
1766 'online_dialog'):
1767 for j in gajim.interface.instances[new_name][kind]:
1768 gajim.interface.instances[new_name][kind][j].account = \
1769 new_name
1771 # ServiceCache object keep old property account
1772 if hasattr(gajim.connections[old_name], 'services_cache'):
1773 gajim.connections[old_name].services_cache.account = new_name
1774 del gajim.interface.instances[old_name]
1775 del gajim.interface.minimized_controls[old_name]
1776 del gajim.nicks[old_name]
1777 del gajim.block_signed_in_notifications[old_name]
1778 del gajim.groups[old_name]
1779 del gajim.gc_connected[old_name]
1780 del gajim.automatic_rooms[old_name]
1781 del gajim.newly_added[old_name]
1782 del gajim.to_be_removed[old_name]
1783 del gajim.sleeper_state[old_name]
1784 del gajim.encrypted_chats[old_name]
1785 del gajim.last_message_time[old_name]
1786 del gajim.status_before_autoaway[old_name]
1787 del gajim.transport_avatar[old_name]
1788 del gajim.gajim_optional_features[old_name]
1789 del gajim.caps_hash[old_name]
1790 gajim.connections[old_name].name = new_name
1791 gajim.connections[new_name] = gajim.connections[old_name]
1792 del gajim.connections[old_name]
1793 gajim.config.add_per('accounts', new_name)
1794 old_config = gajim.config.get_per('accounts', old_name)
1795 for opt in old_config:
1796 gajim.config.set_per('accounts', new_name, opt, old_config[opt][1])
1797 gajim.config.del_per('accounts', old_name)
1798 if self.current_account == old_name:
1799 self.current_account = new_name
1800 if old_name == gajim.ZEROCONF_ACC_NAME:
1801 gajim.ZEROCONF_ACC_NAME = new_name
1802 # refresh roster
1803 gajim.interface.roster.setup_and_draw_roster()
1804 self.init_accounts()
1805 self.select_account(new_name)
1807 title = _('Rename Account')
1808 message = _('Enter a new name for account %s') % self.current_account
1809 old_text = self.current_account
1810 dialogs.InputDialog(title, message, old_text, is_modal=False,
1811 ok_handler=(on_renamed, self.current_account))
1813 def option_changed(self, option, value):
1814 return gajim.config.get_per('accounts', self.current_account, option) != \
1815 value
1817 def on_jid_entry1_focus_out_event(self, widget, event):
1818 if self.ignore_events:
1819 return
1820 jid = widget.get_text()
1821 # check if jid is conform to RFC and stringprep it
1822 try:
1823 jid = helpers.parse_jid(jid)
1824 except helpers.InvalidFormat, s:
1825 if not widget.is_focus():
1826 pritext = _('Invalid Jabber ID')
1827 dialogs.ErrorDialog(pritext, str(s))
1828 gobject.idle_add(lambda: widget.grab_focus())
1829 return True
1831 jid_splited = jid.split('@', 1)
1832 if len(jid_splited) != 2:
1833 if not widget.is_focus():
1834 pritext = _('Invalid Jabber ID')
1835 sectext = _('A Jabber ID must be in the form "user@servername".')
1836 dialogs.ErrorDialog(pritext, sectext)
1837 gobject.idle_add(lambda: widget.grab_focus())
1838 return True
1840 if self.option_changed('name', jid_splited[0]) or \
1841 self.option_changed('hostname', jid_splited[1]):
1842 self.need_relogin = True
1844 gajim.config.set_per('accounts', self.current_account, 'name',
1845 jid_splited[0])
1846 gajim.config.set_per('accounts', self.current_account, 'hostname',
1847 jid_splited[1])
1849 def on_password_entry1_changed(self, widget):
1850 if self.ignore_events:
1851 return
1852 passwords.save_password(self.current_account, widget.get_text().decode(
1853 'utf-8'))
1855 def on_save_password_checkbutton1_toggled(self, widget):
1856 if self.ignore_events:
1857 return
1858 active = widget.get_active()
1859 password_entry = self.xml.get_widget('password_entry1')
1860 password_entry.set_sensitive(active)
1861 gajim.config.set_per('accounts', self.current_account, 'savepass', active)
1862 if active:
1863 password = password_entry.get_text()
1864 passwords.save_password(self.current_account, password)
1865 else:
1866 passwords.save_password(self.current_account, '')
1868 def on_resource_entry1_focus_out_event(self, widget, event):
1869 if self.ignore_events:
1870 return
1871 resource = self.xml.get_widget('resource_entry1').get_text().decode(
1872 'utf-8')
1873 try:
1874 resource = helpers.parse_resource(resource)
1875 except helpers.InvalidFormat, s:
1876 if not widget.is_focus():
1877 pritext = _('Invalid Jabber ID')
1878 dialogs.ErrorDialog(pritext, str(s))
1879 gobject.idle_add(lambda: widget.grab_focus())
1880 return True
1882 if self.option_changed('resource', resource):
1883 self.need_relogin = True
1885 gajim.config.set_per('accounts', self.current_account, 'resource',
1886 resource)
1888 def on_adjust_priority_with_status_checkbutton1_toggled(self, widget):
1889 self.xml.get_widget('priority_spinbutton1').set_sensitive(
1890 not widget.get_active())
1891 self.on_checkbutton_toggled(widget, 'adjust_priority_with_status',
1892 account = self.current_account)
1894 def on_priority_spinbutton1_value_changed(self, widget):
1895 prio = widget.get_value_as_int()
1897 if self.option_changed('priority', prio):
1898 self.resend_presence = True
1900 gajim.config.set_per('accounts', self.current_account, 'priority', prio)
1902 def on_synchronise_contacts_button1_clicked(self, widget):
1903 try:
1904 dialogs.SynchroniseSelectAccountDialog(self.current_account)
1905 except GajimGeneralException:
1906 # If we showed ErrorDialog, there will not be dialog instance
1907 return
1909 def on_change_password_button1_clicked(self, widget):
1910 def on_changed(new_password):
1911 if new_password is not None:
1912 gajim.connections[self.current_account].change_password(
1913 new_password)
1914 if self.xml.get_widget('save_password_checkbutton1').get_active():
1915 self.xml.get_widget('password_entry1').set_text(new_password)
1917 try:
1918 dialogs.ChangePasswordDialog(self.current_account, on_changed)
1919 except GajimGeneralException:
1920 # if we showed ErrorDialog, there will not be dialog instance
1921 return
1923 def on_autoconnect_checkbutton_toggled(self, widget):
1924 if self.ignore_events:
1925 return
1926 self.on_checkbutton_toggled(widget, 'autoconnect',
1927 account=self.current_account)
1929 def on_autoreconnect_checkbutton_toggled(self, widget):
1930 if self.ignore_events:
1931 return
1932 self.on_checkbutton_toggled(widget, 'autoreconnect',
1933 account=self.current_account)
1935 def on_log_history_checkbutton_toggled(self, widget):
1936 if self.ignore_events:
1937 return
1938 list_no_log_for = gajim.config.get_per('accounts', self.current_account,
1939 'no_log_for').split()
1940 if self.current_account in list_no_log_for:
1941 list_no_log_for.remove(self.current_account)
1943 if not widget.get_active():
1944 list_no_log_for.append(self.current_account)
1945 gajim.config.set_per('accounts', self.current_account, 'no_log_for',
1946 ' '.join(list_no_log_for))
1948 def on_sync_with_global_status_checkbutton_toggled(self, widget):
1949 if self.ignore_events:
1950 return
1951 self.on_checkbutton_toggled(widget, 'sync_with_global_status',
1952 account=self.current_account)
1953 gajim.interface.roster.update_status_combobox()
1955 def on_use_ft_proxies_checkbutton1_toggled(self, widget):
1956 if self.ignore_events:
1957 return
1958 self.on_checkbutton_toggled(widget, 'use_ft_proxies',
1959 account=self.current_account)
1961 def on_use_env_http_proxy_checkbutton1_toggled(self, widget):
1962 if self.ignore_events:
1963 return
1964 self.on_checkbutton_toggled(widget, 'use_env_http_proxy',
1965 account=self.current_account)
1966 hbox = self.xml.get_widget('proxy_hbox1')
1967 hbox.set_sensitive(not widget.get_active())
1969 def on_proxies_combobox1_changed(self, widget):
1970 active = widget.get_active()
1971 proxy = widget.get_model()[active][0].decode('utf-8')
1972 if proxy == _('None'):
1973 proxy = ''
1975 if self.option_changed('proxy', proxy):
1976 self.need_relogin = True
1978 gajim.config.set_per('accounts', self.current_account, 'proxy', proxy)
1980 def on_manage_proxies_button1_clicked(self, widget):
1981 if 'manage_proxies' in gajim.interface.instances:
1982 gajim.interface.instances['manage_proxies'].window.present()
1983 else:
1984 gajim.interface.instances['manage_proxies'] = ManageProxiesWindow()
1986 def on_warn_when_insecure_connection_checkbutton1_toggled(self, widget):
1987 if self.ignore_events:
1988 return
1990 self.on_checkbutton_toggled(widget, 'warn_when_insecure_ssl_connection',
1991 account=self.current_account)
1993 def on_send_keepalive_checkbutton1_toggled(self, widget):
1994 if self.ignore_events:
1995 return
1996 self.on_checkbutton_toggled(widget, 'keep_alives_enabled',
1997 account=self.current_account)
1998 gajim.config.set_per('accounts', self.current_account,
1999 'ping_alives_enabled', widget.get_active())
2001 def on_custom_host_port_checkbutton1_toggled(self, widget):
2002 if self.option_changed('use_custom_host', widget.get_active()):
2003 self.need_relogin = True
2005 self.on_checkbutton_toggled(widget, 'use_custom_host',
2006 account=self.current_account)
2007 active = widget.get_active()
2008 self.xml.get_widget('custom_host_port_hbox1').set_sensitive(active)
2010 def on_custom_host_entry1_changed(self, widget):
2011 if self.ignore_events:
2012 return
2013 host = widget.get_text().decode('utf-8')
2014 if self.option_changed('custom_host', host):
2015 self.need_relogin = True
2016 gajim.config.set_per('accounts', self.current_account, 'custom_host',
2017 host)
2019 def on_custom_port_entry_focus_out_event(self, widget, event):
2020 if self.ignore_events:
2021 return
2022 custom_port = widget.get_text()
2023 try:
2024 custom_port = int(custom_port)
2025 except Exception:
2026 if not widget.is_focus():
2027 dialogs.ErrorDialog(_('Invalid entry'),
2028 _('Custom port must be a port number.'))
2029 gobject.idle_add(lambda: widget.grab_focus())
2030 return True
2031 if self.option_changed('custom_port', custom_port):
2032 self.need_relogin = True
2033 gajim.config.set_per('accounts', self.current_account, 'custom_port',
2034 custom_port)
2036 def on_gpg_choose_button_clicked(self, widget, data = None):
2037 if self.current_account in gajim.connections and \
2038 gajim.connections[self.current_account].gpg:
2039 secret_keys = gajim.connections[self.current_account].\
2040 ask_gpg_secrete_keys()
2042 # self.current_account is None and/or gajim.connections is {}
2043 else:
2044 if gajim.HAVE_GPG:
2045 secret_keys = GnuPG.GnuPG().get_secret_keys()
2046 else:
2047 secret_keys = []
2048 if not secret_keys:
2049 dialogs.ErrorDialog(_('Failed to get secret keys'),
2050 _('There was a problem retrieving your OpenPGP secret keys.'))
2051 return
2052 secret_keys[_('None')] = _('None')
2054 def on_key_selected(keyID):
2055 if keyID is None:
2056 return
2057 if self.current_account == gajim.ZEROCONF_ACC_NAME:
2058 wiget_name_ext = '2'
2059 else:
2060 wiget_name_ext = '1'
2061 gpg_key_label = self.xml.get_widget('gpg_key_label' + wiget_name_ext)
2062 gpg_name_label = self.xml.get_widget('gpg_name_label' + wiget_name_ext)
2063 use_gpg_agent_checkbutton = self.xml.get_widget(
2064 'use_gpg_agent_checkbutton' + wiget_name_ext)
2065 if keyID[0] == _('None'):
2066 gpg_key_label.set_text(_('No key selected'))
2067 gpg_name_label.set_text('')
2068 use_gpg_agent_checkbutton.set_sensitive(False)
2069 if self.option_changed('keyid', ''):
2070 self.need_relogin = True
2071 gajim.config.set_per('accounts', self.current_account, 'keyname',
2072 '')
2073 gajim.config.set_per('accounts', self.current_account, 'keyid', '')
2074 else:
2075 gpg_key_label.set_text(keyID[0])
2076 gpg_name_label.set_text(keyID[1])
2077 use_gpg_agent_checkbutton.set_sensitive(True)
2078 if self.option_changed('keyid', keyID[0]):
2079 self.need_relogin = True
2080 gajim.config.set_per('accounts', self.current_account, 'keyname',
2081 keyID[1])
2082 gajim.config.set_per('accounts', self.current_account, 'keyid',
2083 keyID[0])
2085 dialogs.ChooseGPGKeyDialog(_('OpenPGP Key Selection'),
2086 _('Choose your OpenPGP key'), secret_keys, on_key_selected)
2088 def on_use_gpg_agent_checkbutton_toggled(self, widget):
2089 self.on_checkbutton_toggled(widget, 'use_gpg_agent')
2091 def on_edit_details_button1_clicked(self, widget):
2092 if self.current_account not in gajim.interface.instances:
2093 dialogs.ErrorDialog(_('No such account available'),
2094 _('You must create your account before editing your personal '
2095 'information.'))
2096 return
2098 # show error dialog if account is newly created (not in gajim.connections)
2099 if self.current_account not in gajim.connections or \
2100 gajim.connections[self.current_account].connected < 2:
2101 dialogs.ErrorDialog(_('You are not connected to the server'),
2102 _('Without a connection, you can not edit your personal information.'))
2103 return
2105 if not gajim.connections[self.current_account].vcard_supported:
2106 dialogs.ErrorDialog(_("Your server doesn't support Vcard"),
2107 _("Your server can't save your personal information."))
2108 return
2110 gajim.interface.edit_own_details(self.current_account)
2112 def on_checkbutton_toggled(self, widget, config_name,
2113 change_sensitivity_widgets = None, account = None):
2114 if account:
2115 gajim.config.set_per('accounts', account, config_name,
2116 widget.get_active())
2117 else:
2118 gajim.config.set(config_name, widget.get_active())
2119 if change_sensitivity_widgets:
2120 for w in change_sensitivity_widgets:
2121 w.set_sensitive(widget.get_active())
2122 gajim.interface.save_config()
2124 def on_merge_checkbutton_toggled(self, widget):
2125 self.on_checkbutton_toggled(widget, 'mergeaccounts')
2126 if len(gajim.connections) >= 2: # Do not merge accounts if only one exists
2127 gajim.interface.roster.regroup = gajim.config.get('mergeaccounts')
2128 else:
2129 gajim.interface.roster.regroup = False
2130 gajim.interface.roster.setup_and_draw_roster()
2132 def on_enable_zeroconf_checkbutton2_toggled(self, widget):
2133 # don't do anything if there is an account with the local name but is a
2134 # normal account
2135 if gajim.ZEROCONF_ACC_NAME in gajim.connections and not \
2136 gajim.connections[gajim.ZEROCONF_ACC_NAME].is_zeroconf:
2137 gajim.connections[gajim.ZEROCONF_ACC_NAME].dispatch('ERROR',
2138 (_('Account Local already exists.'),
2139 _('Please rename or remove it before enabling link-local messaging'
2140 '.')))
2141 return
2143 if gajim.config.get('enable_zeroconf') and not widget.get_active():
2144 self.xml.get_widget('zeroconf_notebook').set_sensitive(False)
2145 # disable
2146 gajim.interface.roster.close_all(gajim.ZEROCONF_ACC_NAME)
2147 gajim.connections[gajim.ZEROCONF_ACC_NAME].disable_account()
2148 del gajim.connections[gajim.ZEROCONF_ACC_NAME]
2149 gajim.interface.save_config()
2150 del gajim.interface.instances[gajim.ZEROCONF_ACC_NAME]
2151 del gajim.interface.minimized_controls[gajim.ZEROCONF_ACC_NAME]
2152 del gajim.nicks[gajim.ZEROCONF_ACC_NAME]
2153 del gajim.block_signed_in_notifications[gajim.ZEROCONF_ACC_NAME]
2154 del gajim.groups[gajim.ZEROCONF_ACC_NAME]
2155 gajim.contacts.remove_account(gajim.ZEROCONF_ACC_NAME)
2156 del gajim.gc_connected[gajim.ZEROCONF_ACC_NAME]
2157 del gajim.automatic_rooms[gajim.ZEROCONF_ACC_NAME]
2158 del gajim.to_be_removed[gajim.ZEROCONF_ACC_NAME]
2159 del gajim.newly_added[gajim.ZEROCONF_ACC_NAME]
2160 del gajim.sleeper_state[gajim.ZEROCONF_ACC_NAME]
2161 del gajim.encrypted_chats[gajim.ZEROCONF_ACC_NAME]
2162 del gajim.last_message_time[gajim.ZEROCONF_ACC_NAME]
2163 del gajim.status_before_autoaway[gajim.ZEROCONF_ACC_NAME]
2164 del gajim.transport_avatar[gajim.ZEROCONF_ACC_NAME]
2165 del gajim.gajim_optional_features[gajim.ZEROCONF_ACC_NAME]
2166 del gajim.caps_hash[gajim.ZEROCONF_ACC_NAME]
2167 if len(gajim.connections) >= 2:
2168 # Do not merge accounts if only one exists
2169 gajim.interface.roster.regroup = gajim.config.get('mergeaccounts')
2170 else:
2171 gajim.interface.roster.regroup = False
2172 gajim.interface.roster.setup_and_draw_roster()
2173 gajim.interface.roster.set_actions_menu_needs_rebuild()
2175 elif not gajim.config.get('enable_zeroconf') and widget.get_active():
2176 self.xml.get_widget('zeroconf_notebook').set_sensitive(True)
2177 # enable (will create new account if not present)
2178 gajim.connections[gajim.ZEROCONF_ACC_NAME] = connection_zeroconf.\
2179 ConnectionZeroconf(gajim.ZEROCONF_ACC_NAME)
2180 if gajim.connections[gajim.ZEROCONF_ACC_NAME].gpg:
2181 self.xml.get_widget('gpg_choose_button2').set_sensitive(True)
2182 self.init_account_gpg()
2183 # update variables
2184 gajim.interface.instances[gajim.ZEROCONF_ACC_NAME] = {'infos': {},
2185 'disco': {}, 'gc_config': {}, 'search': {}, 'online_dialog': {}}
2186 gajim.interface.minimized_controls[gajim.ZEROCONF_ACC_NAME] = {}
2187 gajim.connections[gajim.ZEROCONF_ACC_NAME].connected = 0
2188 gajim.groups[gajim.ZEROCONF_ACC_NAME] = {}
2189 gajim.contacts.add_account(gajim.ZEROCONF_ACC_NAME)
2190 gajim.gc_connected[gajim.ZEROCONF_ACC_NAME] = {}
2191 gajim.automatic_rooms[gajim.ZEROCONF_ACC_NAME] = {}
2192 gajim.newly_added[gajim.ZEROCONF_ACC_NAME] = []
2193 gajim.to_be_removed[gajim.ZEROCONF_ACC_NAME] = []
2194 gajim.nicks[gajim.ZEROCONF_ACC_NAME] = gajim.ZEROCONF_ACC_NAME
2195 gajim.block_signed_in_notifications[gajim.ZEROCONF_ACC_NAME] = True
2196 gajim.sleeper_state[gajim.ZEROCONF_ACC_NAME] = 'off'
2197 gajim.encrypted_chats[gajim.ZEROCONF_ACC_NAME] = []
2198 gajim.last_message_time[gajim.ZEROCONF_ACC_NAME] = {}
2199 gajim.status_before_autoaway[gajim.ZEROCONF_ACC_NAME] = ''
2200 gajim.transport_avatar[gajim.ZEROCONF_ACC_NAME] = {}
2201 gajim.gajim_optional_features[gajim.ZEROCONF_ACC_NAME] = []
2202 gajim.caps_hash[gajim.ZEROCONF_ACC_NAME] = ''
2203 # refresh roster
2204 if len(gajim.connections) >= 2:
2205 # Do not merge accounts if only one exists
2206 gajim.interface.roster.regroup = gajim.config.get('mergeaccounts')
2207 else:
2208 gajim.interface.roster.regroup = False
2209 gajim.interface.roster.setup_and_draw_roster()
2210 gajim.interface.roster.set_actions_menu_needs_rebuild()
2211 gajim.interface.save_config()
2213 self.on_checkbutton_toggled(widget, 'enable_zeroconf')
2215 def on_custom_port_checkbutton2_toggled(self, widget):
2216 self.xml.get_widget('custom_port_entry2').set_sensitive(
2217 widget.get_active())
2218 self.on_checkbutton_toggled(widget, 'use_custom_host',
2219 account = self.current_account)
2220 if not widget.get_active():
2221 self.xml.get_widget('custom_port_entry2').set_text('5298')
2223 def on_first_name_entry2_changed(self, widget):
2224 if self.ignore_events:
2225 return
2226 name = widget.get_text().decode('utf-8')
2227 if self.option_changed('zeroconf_first_name', name):
2228 self.need_relogin = True
2229 gajim.config.set_per('accounts', self.current_account,
2230 'zeroconf_first_name', name)
2232 def on_last_name_entry2_changed(self, widget):
2233 if self.ignore_events:
2234 return
2235 name = widget.get_text().decode('utf-8')
2236 if self.option_changed('zeroconf_last_name', name):
2237 self.need_relogin = True
2238 gajim.config.set_per('accounts', self.current_account,
2239 'zeroconf_last_name', name)
2241 def on_jabber_id_entry2_changed(self, widget):
2242 if self.ignore_events:
2243 return
2244 id_ = widget.get_text().decode('utf-8')
2245 if self.option_changed('zeroconf_jabber_id', id_):
2246 self.need_relogin = True
2247 gajim.config.set_per('accounts', self.current_account,
2248 'zeroconf_jabber_id', id_)
2250 def on_email_entry2_changed(self, widget):
2251 if self.ignore_events:
2252 return
2253 email = widget.get_text().decode('utf-8')
2254 if self.option_changed('zeroconf_email', email):
2255 self.need_relogin = True
2256 gajim.config.set_per('accounts', self.current_account,
2257 'zeroconf_email', email)
2259 class FakeDataForm(gtk.Table, object):
2260 '''Class for forms that are in XML format <entry1>value1</entry1>
2261 infos in a table {entry1: value1, }'''
2262 def __init__(self, infos):
2263 gtk.Table.__init__(self)
2264 self.infos = infos
2265 self.entries = {}
2266 self._draw_table()
2268 def _draw_table(self):
2269 '''Draw the table'''
2270 nbrow = 0
2271 if 'instructions' in self.infos:
2272 nbrow = 1
2273 self.resize(rows = nbrow, columns = 2)
2274 label = gtk.Label(self.infos['instructions'])
2275 self.attach(label, 0, 2, 0, 1, 0, 0, 0, 0)
2276 for name in self.infos.keys():
2277 if name in ('key', 'instructions', 'x', 'registered'):
2278 continue
2279 if not name:
2280 continue
2282 nbrow = nbrow + 1
2283 self.resize(rows = nbrow, columns = 2)
2284 label = gtk.Label(name.capitalize() + ':')
2285 self.attach(label, 0, 1, nbrow - 1, nbrow, 0, 0, 0, 0)
2286 entry = gtk.Entry()
2287 entry.set_activates_default(True)
2288 if self.infos[name]:
2289 entry.set_text(self.infos[name])
2290 if name == 'password':
2291 entry.set_visibility(False)
2292 self.attach(entry, 1, 2, nbrow - 1, nbrow, 0, 0, 0, 0)
2293 self.entries[name] = entry
2294 if nbrow == 1:
2295 entry.grab_focus()
2297 def get_infos(self):
2298 for name in self.entries.keys():
2299 self.infos[name] = self.entries[name].get_text().decode('utf-8')
2300 return self.infos
2302 class ServiceRegistrationWindow:
2303 '''Class for Service registration window:
2304 Window that appears when we want to subscribe to a service
2305 if is_form we use dataforms_widget else we use service_registarion_window'''
2306 def __init__(self, service, infos, account, is_form):
2307 self.service = service
2308 self.account = account
2309 self.is_form = is_form
2310 self.xml = gtkgui_helpers.get_glade('service_registration_window.glade')
2311 self.window = self.xml.get_widget('service_registration_window')
2312 self.window.set_transient_for(gajim.interface.roster.window)
2313 if self.is_form:
2314 dataform = dataforms.ExtendForm(node = infos)
2315 self.data_form_widget = dataforms_widget.DataFormWidget(dataform)
2316 if self.data_form_widget.title:
2317 self.window.set_title('%s - Gajim' % self.data_form_widget.title)
2318 table = self.xml.get_widget('table')
2319 table.attach(self.data_form_widget, 0, 2, 0, 1)
2320 else:
2321 if 'registered' in infos:
2322 self.window.set_title(_('Edit %s') % service)
2323 else:
2324 self.window.set_title(_('Register to %s') % service)
2325 self.data_form_widget = FakeDataForm(infos)
2326 table = self.xml.get_widget('table')
2327 table.attach(self.data_form_widget, 0, 2, 0, 1)
2329 self.xml.signal_autoconnect(self)
2330 self.window.show_all()
2332 def on_cancel_button_clicked(self, widget):
2333 self.window.destroy()
2335 def on_ok_button_clicked(self, widget):
2336 # send registration info to the core
2337 if self.is_form:
2338 form = self.data_form_widget.data_form
2339 gajim.connections[self.account].register_agent(self.service,
2340 form, True) # True is for is_form
2341 else:
2342 infos = self.data_form_widget.get_infos()
2343 if 'instructions' in infos:
2344 del infos['instructions']
2345 if 'registered' in infos:
2346 del infos['registered']
2347 gajim.connections[self.account].register_agent(self.service, infos)
2349 self.window.destroy()
2351 class GroupchatConfigWindow:
2352 '''GroupchatConfigWindow class'''
2353 def __init__(self, account, room_jid, form = None):
2354 self.account = account
2355 self.room_jid = room_jid
2356 self.form = form
2357 self.remove_button = {}
2358 self.affiliation_treeview = {}
2359 self.start_users_dict = {} # list at the beginning
2360 self.affiliation_labels = {'outcast': _('Ban List'),
2361 'member': _('Member List'),
2362 'owner': _('Owner List'),
2363 'admin':_('Administrator List')}
2365 self.xml = gtkgui_helpers.get_glade('data_form_window.glade', 'data_form_window')
2366 self.window = self.xml.get_widget('data_form_window')
2367 self.window.set_transient_for(gajim.interface.roster.window)
2369 if self.form:
2370 config_vbox = self.xml.get_widget('config_vbox')
2371 dataform = dataforms.ExtendForm(node = self.form)
2372 self.data_form_widget = dataforms_widget.DataFormWidget(dataform)
2373 # hide scrollbar of this data_form_widget, we already have in this
2374 # widget
2375 sw = self.data_form_widget.xml.get_widget('single_form_scrolledwindow')
2376 sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_NEVER)
2378 self.data_form_widget.show()
2379 config_vbox.pack_start(self.data_form_widget)
2381 # Draw the edit affiliation list things
2382 add_on_vbox = self.xml.get_widget('add_on_vbox')
2384 for affiliation in self.affiliation_labels.keys():
2385 self.start_users_dict[affiliation] = {}
2386 hbox = gtk.HBox(spacing = 5)
2387 add_on_vbox.pack_start(hbox, False)
2389 label = gtk.Label(self.affiliation_labels[affiliation])
2390 hbox.pack_start(label, False)
2392 bb = gtk.HButtonBox()
2393 bb.set_layout(gtk.BUTTONBOX_END)
2394 bb.set_spacing(5)
2395 hbox.pack_start(bb)
2396 add_button = gtk.Button(stock = gtk.STOCK_ADD)
2397 add_button.connect('clicked', self.on_add_button_clicked, affiliation)
2398 bb.pack_start(add_button)
2399 self.remove_button[affiliation] = gtk.Button(stock = gtk.STOCK_REMOVE)
2400 self.remove_button[affiliation].set_sensitive(False)
2401 self.remove_button[affiliation].connect('clicked',
2402 self.on_remove_button_clicked, affiliation)
2403 bb.pack_start(self.remove_button[affiliation])
2405 liststore = gtk.ListStore(str, str, str, str) # Jid, reason, nick, role
2406 self.affiliation_treeview[affiliation] = gtk.TreeView(liststore)
2407 self.affiliation_treeview[affiliation].get_selection().set_mode(
2408 gtk.SELECTION_MULTIPLE)
2409 self.affiliation_treeview[affiliation].connect('cursor-changed',
2410 self.on_affiliation_treeview_cursor_changed, affiliation)
2411 renderer = gtk.CellRendererText()
2412 col = gtk.TreeViewColumn(_('JID'), renderer)
2413 col.add_attribute(renderer, 'text', 0)
2414 col.set_resizable(True)
2415 col.set_sort_column_id(0)
2416 self.affiliation_treeview[affiliation].append_column(col)
2418 if affiliation == 'outcast':
2419 renderer = gtk.CellRendererText()
2420 renderer.set_property('editable', True)
2421 renderer.connect('edited', self.on_cell_edited)
2422 col = gtk.TreeViewColumn(_('Reason'), renderer)
2423 col.add_attribute(renderer, 'text', 1)
2424 col.set_resizable(True)
2425 col.set_sort_column_id(1)
2426 self.affiliation_treeview[affiliation].append_column(col)
2427 elif affiliation == 'member':
2428 renderer = gtk.CellRendererText()
2429 col = gtk.TreeViewColumn(_('Nick'), renderer)
2430 col.add_attribute(renderer, 'text', 2)
2431 col.set_resizable(True)
2432 col.set_sort_column_id(2)
2433 self.affiliation_treeview[affiliation].append_column(col)
2434 renderer = gtk.CellRendererText()
2435 col = gtk.TreeViewColumn(_('Role'), renderer)
2436 col.add_attribute(renderer, 'text', 3)
2437 col.set_resizable(True)
2438 col.set_sort_column_id(3)
2439 self.affiliation_treeview[affiliation].append_column(col)
2441 sw = gtk.ScrolledWindow()
2442 sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_NEVER)
2443 sw.add(self.affiliation_treeview[affiliation])
2444 add_on_vbox.pack_start(sw)
2445 gajim.connections[self.account].get_affiliation_list(self.room_jid,
2446 affiliation)
2448 self.xml.signal_autoconnect(self)
2449 self.window.show_all()
2451 def on_cancel_button_clicked(self, widget):
2452 self.window.destroy()
2454 def on_cell_edited(self, cell, path, new_text):
2455 model = self.affiliation_treeview['outcast'].get_model()
2456 new_text = new_text.decode('utf-8')
2457 iter_ = model.get_iter(path)
2458 model[iter_][1] = new_text
2460 def on_add_button_clicked(self, widget, affiliation):
2461 if affiliation == 'outcast':
2462 title = _('Banning...')
2463 #You can move '\n' before user@domain if that line is TOO BIG
2464 prompt = _('<b>Whom do you want to ban?</b>\n\n')
2465 elif affiliation == 'member':
2466 title = _('Adding Member...')
2467 prompt = _('<b>Whom do you want to make a member?</b>\n\n')
2468 elif affiliation == 'owner':
2469 title = _('Adding Owner...')
2470 prompt = _('<b>Whom do you want to make an owner?</b>\n\n')
2471 else:
2472 title = _('Adding Administrator...')
2473 prompt = _('<b>Whom do you want to make an administrator?</b>\n\n')
2474 prompt += _('Can be one of the following:\n'
2475 '1. user@domain/resource (only that resource matches).\n'
2476 '2. user@domain (any resource matches).\n'
2477 '3. domain/resource (only that resource matches).\n'
2478 '4. domain (the domain itself matches, as does any user@domain,\n'
2479 'domain/resource, or address containing a subdomain).')
2481 def on_ok(jid):
2482 if not jid:
2483 return
2484 model = self.affiliation_treeview[affiliation].get_model()
2485 model.append((jid,'', '', ''))
2486 dialogs.InputDialog(title, prompt, ok_handler=on_ok)
2488 def on_remove_button_clicked(self, widget, affiliation):
2489 selection = self.affiliation_treeview[affiliation].get_selection()
2490 model, paths = selection.get_selected_rows()
2491 row_refs = []
2492 for path in paths:
2493 row_refs.append(gtk.TreeRowReference(model, path))
2494 for row_ref in row_refs:
2495 path = row_ref.get_path()
2496 iter_ = model.get_iter(path)
2497 jid = model[iter_][0]
2498 model.remove(iter_)
2499 self.remove_button[affiliation].set_sensitive(False)
2501 def on_affiliation_treeview_cursor_changed(self, widget, affiliation):
2502 self.remove_button[affiliation].set_sensitive(True)
2504 def affiliation_list_received(self, users_dict):
2505 '''Fill the affiliation treeview'''
2506 for jid in users_dict:
2507 affiliation = users_dict[jid]['affiliation']
2508 if affiliation not in self.affiliation_labels.keys():
2509 # Unknown affiliation or 'none' affiliation, do not show it
2510 continue
2511 self.start_users_dict[affiliation][jid] = users_dict[jid]
2512 tv = self.affiliation_treeview[affiliation]
2513 model = tv.get_model()
2514 reason = users_dict[jid].get('reason', '')
2515 nick = users_dict[jid].get('nick', '')
2516 role = users_dict[jid].get('role', '')
2517 model.append((jid, reason, nick, role))
2519 def on_data_form_window_destroy(self, widget):
2520 del gajim.interface.instances[self.account]['gc_config'][self.room_jid]
2522 def on_ok_button_clicked(self, widget):
2523 if self.form:
2524 form = self.data_form_widget.data_form
2525 gajim.connections[self.account].send_gc_config(self.room_jid, form)
2526 for affiliation in self.affiliation_labels.keys():
2527 users_dict = {}
2528 actual_jid_list = []
2529 model = self.affiliation_treeview[affiliation].get_model()
2530 iter_ = model.get_iter_first()
2531 # add new jid
2532 while iter_:
2533 jid = model[iter_][0].decode('utf-8')
2534 actual_jid_list.append(jid)
2535 if jid not in self.start_users_dict[affiliation] or \
2536 (affiliation == 'outcast' and 'reason' in self.start_users_dict[affiliation]\
2537 [jid] and self.start_users_dict[affiliation][jid]\
2538 ['reason'] != model[iter_][1].decode('utf-8')):
2539 users_dict[jid] = {'affiliation': affiliation}
2540 if affiliation == 'outcast':
2541 users_dict[jid]['reason'] = model[iter_][1].decode('utf-8')
2542 iter_ = model.iter_next(iter_)
2543 # remove removed one
2544 for jid in self.start_users_dict[affiliation]:
2545 if jid not in actual_jid_list:
2546 users_dict[jid] = {'affiliation': 'none'}
2547 if users_dict:
2548 gajim.connections[self.account].send_gc_affiliation_list(
2549 self.room_jid, users_dict)
2550 self.window.destroy()
2552 #---------- RemoveAccountWindow class -------------#
2553 class RemoveAccountWindow:
2554 '''ask for removing from gajim only or from gajim and server too
2555 and do removing of the account given'''
2557 def on_remove_account_window_destroy(self, widget):
2558 if self.account in gajim.interface.instances:
2559 del gajim.interface.instances[self.account]['remove_account']
2561 def on_cancel_button_clicked(self, widget):
2562 self.window.destroy()
2564 def __init__(self, account):
2565 self.account = account
2566 xml = gtkgui_helpers.get_glade('remove_account_window.glade')
2567 self.window = xml.get_widget('remove_account_window')
2568 self.window.set_transient_for(gajim.interface.roster.window)
2569 self.remove_and_unregister_radiobutton = xml.get_widget(
2570 'remove_and_unregister_radiobutton')
2571 self.window.set_title(_('Removing %s account') % self.account)
2572 xml.signal_autoconnect(self)
2573 self.window.show_all()
2575 def on_remove_button_clicked(self, widget):
2576 def remove():
2577 if gajim.connections[self.account].connected and \
2578 not self.remove_and_unregister_radiobutton.get_active():
2579 # change status to offline only if we will not remove this JID from
2580 # server
2581 gajim.connections[self.account].change_status('offline', 'offline')
2582 if self.remove_and_unregister_radiobutton.get_active():
2583 if not gajim.connections[self.account].password:
2584 def on_ok(passphrase, checked):
2585 if passphrase == -1:
2586 # We don't remove account cause we canceled pw window
2587 return
2588 gajim.connections[self.account].password = passphrase
2589 gajim.connections[self.account].unregister_account(
2590 self._on_remove_success)
2592 dialogs.PassphraseDialog(
2593 _('Password Required'),
2594 _('Enter your password for account %s') % self.account,
2595 _('Save password'), ok_handler=on_ok)
2596 return
2597 gajim.connections[self.account].unregister_account(
2598 self._on_remove_success)
2599 else:
2600 self._on_remove_success(True)
2602 if gajim.connections[self.account].connected:
2603 dialogs.ConfirmationDialog(
2604 _('Account "%s" is connected to the server') % self.account,
2605 _('If you remove it, the connection will be lost.'),
2606 on_response_ok=remove)
2607 else:
2608 remove()
2610 def _on_remove_success(self, res):
2611 # action of unregistration has failed, we don't remove the account
2612 # Error message is send by connect_and_auth()
2613 if not res:
2614 return
2615 # Close all opened windows
2616 gajim.interface.roster.close_all(self.account, force = True)
2617 gajim.connections[self.account].disconnect(on_purpose = True)
2618 del gajim.connections[self.account]
2619 gajim.logger.remove_roster(gajim.get_jid_from_account(self.account))
2620 gajim.config.del_per('accounts', self.account)
2621 gajim.interface.save_config()
2622 del gajim.interface.instances[self.account]
2623 del gajim.interface.minimized_controls[self.account]
2624 del gajim.nicks[self.account]
2625 del gajim.block_signed_in_notifications[self.account]
2626 del gajim.groups[self.account]
2627 gajim.contacts.remove_account(self.account)
2628 del gajim.gc_connected[self.account]
2629 del gajim.automatic_rooms[self.account]
2630 del gajim.to_be_removed[self.account]
2631 del gajim.newly_added[self.account]
2632 del gajim.sleeper_state[self.account]
2633 del gajim.encrypted_chats[self.account]
2634 del gajim.last_message_time[self.account]
2635 del gajim.status_before_autoaway[self.account]
2636 del gajim.transport_avatar[self.account]
2637 del gajim.gajim_optional_features[self.account]
2638 del gajim.caps_hash[self.account]
2639 if len(gajim.connections) >= 2: # Do not merge accounts if only one exists
2640 gajim.interface.roster.regroup = gajim.config.get('mergeaccounts')
2641 else:
2642 gajim.interface.roster.regroup = False
2643 gajim.interface.roster.setup_and_draw_roster()
2644 gajim.interface.roster.set_actions_menu_needs_rebuild()
2645 if 'accounts' in gajim.interface.instances:
2646 gajim.interface.instances['accounts'].init_accounts()
2647 self.window.destroy()
2649 #---------- ManageBookmarksWindow class -------------#
2650 class ManageBookmarksWindow:
2651 def __init__(self):
2652 self.xml = gtkgui_helpers.get_glade('manage_bookmarks_window.glade')
2653 self.window = self.xml.get_widget('manage_bookmarks_window')
2654 self.window.set_transient_for(gajim.interface.roster.window)
2656 # Account-JID, RoomName, Room-JID, Autojoin, Minimize, Passowrd, Nick,
2657 # Show_Status
2658 self.treestore = gtk.TreeStore(str, str, str, bool, bool, str, str, str)
2659 self.treestore.set_sort_column_id(1, gtk.SORT_ASCENDING)
2661 # Store bookmarks in treeview.
2662 for account in gajim.connections:
2663 if gajim.connections[account].connected <= 1:
2664 continue
2665 if gajim.connections[account].is_zeroconf:
2666 continue
2667 if not gajim.connections[account].private_storage_supported:
2668 continue
2669 iter_ = self.treestore.append(None, [None, account, None, None,
2670 None, None, None, None])
2672 for bookmark in gajim.connections[account].bookmarks:
2673 if bookmark['name'] == '':
2674 # No name was given for this bookmark.
2675 # Use the first part of JID instead...
2676 name = bookmark['jid'].split("@")[0]
2677 bookmark['name'] = name
2679 # make '1', '0', 'true', 'false' (or other) to True/False
2680 autojoin = helpers.from_xs_boolean_to_python_boolean(
2681 bookmark['autojoin'])
2683 minimize = helpers.from_xs_boolean_to_python_boolean(
2684 bookmark['minimize'])
2686 print_status = bookmark.get('print_status', '')
2687 if print_status not in ('', 'all', 'in_and_out', 'none'):
2688 print_status = ''
2689 self.treestore.append(iter_, [
2690 account,
2691 bookmark['name'],
2692 bookmark['jid'],
2693 autojoin,
2694 minimize,
2695 bookmark['password'],
2696 bookmark['nick'],
2697 print_status ])
2699 self.print_status_combobox = self.xml.get_widget('print_status_combobox')
2700 model = gtk.ListStore(str, str)
2702 self.option_list = {'': _('Default'), 'all': Q_('?print_status:All'),
2703 'in_and_out': _('Enter and leave only'),
2704 'none': Q_('?print_status:None')}
2705 opts = sorted(self.option_list.keys())
2706 for opt in opts:
2707 model.append([self.option_list[opt], opt])
2709 self.print_status_combobox.set_model(model)
2710 self.print_status_combobox.set_active(1)
2712 self.view = self.xml.get_widget('bookmarks_treeview')
2713 self.view.set_model(self.treestore)
2714 self.view.expand_all()
2716 renderer = gtk.CellRendererText()
2717 column = gtk.TreeViewColumn('Bookmarks', renderer, text=1)
2718 self.view.append_column(column)
2720 self.selection = self.view.get_selection()
2721 self.selection.connect('changed', self.bookmark_selected)
2723 #Prepare input fields
2724 self.title_entry = self.xml.get_widget('title_entry')
2725 self.title_entry.connect('changed', self.on_title_entry_changed)
2726 self.nick_entry = self.xml.get_widget('nick_entry')
2727 self.nick_entry.connect('changed', self.on_nick_entry_changed)
2728 self.server_entry = self.xml.get_widget('server_entry')
2729 self.server_entry.connect('changed', self.on_server_entry_changed)
2730 self.room_entry = self.xml.get_widget('room_entry')
2731 self.room_entry.connect('changed', self.on_room_entry_changed)
2732 self.pass_entry = self.xml.get_widget('pass_entry')
2733 self.pass_entry.connect('changed', self.on_pass_entry_changed)
2734 self.autojoin_checkbutton = self.xml.get_widget('autojoin_checkbutton')
2735 self.minimize_checkbutton = self.xml.get_widget('minimize_checkbutton')
2737 self.xml.signal_autoconnect(self)
2738 self.window.show_all()
2740 def on_bookmarks_treeview_button_press_event(self, widget, event):
2741 (model, iter_) = self.selection.get_selected()
2742 if not iter_:
2743 # Removed a bookmark before
2744 return
2746 if model.iter_parent(iter_):
2747 # The currently selected node is a bookmark
2748 return not self.check_valid_bookmark()
2750 def on_manage_bookmarks_window_destroy(self, widget, event):
2751 del gajim.interface.instances['manage_bookmarks']
2753 def on_add_bookmark_button_clicked(self, widget):
2754 '''Add a new bookmark.'''
2755 # Get the account that is currently used
2756 # (the parent of the currently selected item)
2757 (model, iter_) = self.selection.get_selected()
2758 if not iter_: # Nothing selected, do nothing
2759 return
2761 parent = model.iter_parent(iter_)
2763 if parent:
2764 # We got a bookmark selected, so we add_to the parent
2765 add_to = parent
2766 else:
2767 # No parent, so we got an account -> add to this.
2768 add_to = iter_
2770 account = model[add_to][1].decode('utf-8')
2771 nick = gajim.nicks[account]
2772 iter_ = self.treestore.append(add_to, [account, _('New Group Chat'), '',
2773 False, False, '', nick, 'in_and_out'])
2775 self.view.expand_row(model.get_path(add_to), True)
2776 self.view.set_cursor(model.get_path(iter_))
2778 def on_remove_bookmark_button_clicked(self, widget):
2779 '''
2780 Remove selected bookmark.
2781 '''
2782 (model, iter_) = self.selection.get_selected()
2783 if not iter_: # Nothing selected
2784 return
2786 if not model.iter_parent(iter_):
2787 # Don't remove account iters
2788 return
2790 model.remove(iter_)
2791 self.clear_fields()
2793 def check_valid_bookmark(self):
2794 '''
2795 Check if all neccessary fields are entered correctly.
2796 '''
2797 (model, iter_) = self.selection.get_selected()
2799 if not model.iter_parent(iter_):
2800 #Account data can't be changed
2801 return
2803 if self.server_entry.get_text().decode('utf-8') == '' or \
2804 self.room_entry.get_text().decode('utf-8') == '':
2805 dialogs.ErrorDialog(_('This bookmark has invalid data'),
2806 _('Please be sure to fill out server and room fields or remove this'
2807 ' bookmark.'))
2808 return False
2810 return True
2812 def on_ok_button_clicked(self, widget):
2813 '''
2814 Parse the treestore data into our new bookmarks array,
2815 then send the new bookmarks to the server.
2816 '''
2817 (model, iter_) = self.selection.get_selected()
2818 if iter_ and model.iter_parent(iter_):
2819 #bookmark selected, check it
2820 if not self.check_valid_bookmark():
2821 return
2823 for account in self.treestore:
2824 account_unicode = account[1].decode('utf-8')
2825 gajim.connections[account_unicode].bookmarks = []
2827 for bm in account.iterchildren():
2828 #Convert True/False/None to '1' or '0'
2829 autojoin = unicode(int(bm[3]))
2830 minimize = unicode(int(bm[4]))
2832 #create the bookmark-dict
2833 bmdict = { 'name': bm[1], 'jid': bm[2], 'autojoin': autojoin,
2834 'minimize': minimize, 'password': bm[5], 'nick': bm[6],
2835 'print_status': bm[7]}
2837 gajim.connections[account_unicode].bookmarks.append(bmdict)
2839 gajim.connections[account_unicode].store_bookmarks()
2840 gajim.interface.roster.set_actions_menu_needs_rebuild()
2841 self.window.destroy()
2843 def on_cancel_button_clicked(self, widget):
2844 self.window.destroy()
2846 def bookmark_selected(self, selection):
2847 '''
2848 Fill in the bookmark's data into the fields.
2849 '''
2850 (model, iter_) = selection.get_selected()
2852 if not iter_:
2853 # After removing the last bookmark for one account
2854 # this will be None, so we will just:
2855 return
2857 widgets = [ self.title_entry, self.nick_entry, self.room_entry,
2858 self.server_entry, self.pass_entry, self.autojoin_checkbutton,
2859 self.minimize_checkbutton, self.print_status_combobox]
2861 if model.iter_parent(iter_):
2862 # make the fields sensitive
2863 for field in widgets:
2864 field.set_sensitive(True)
2865 else:
2866 # Top-level has no data (it's the account fields)
2867 # clear fields & make them insensitive
2868 self.clear_fields()
2869 for field in widgets:
2870 field.set_sensitive(False)
2871 return
2873 # Fill in the data for childs
2874 self.title_entry.set_text(model[iter_][1])
2875 room_jid = model[iter_][2].decode('utf-8')
2876 try:
2877 (room, server) = room_jid.split('@')
2878 except ValueError:
2879 # We just added this one
2880 room = ''
2881 server = ''
2882 self.room_entry.set_text(room)
2883 self.server_entry.set_text(server)
2885 self.autojoin_checkbutton.set_active(model[iter_][3])
2886 self.minimize_checkbutton.set_active(model[iter_][4])
2887 # sensitive only if auto join is checked
2888 self.minimize_checkbutton.set_sensitive(model[iter_][3])
2890 if model[iter_][5] is not None:
2891 password = model[iter_][5].decode('utf-8')
2892 else:
2893 password = None
2895 if password:
2896 self.pass_entry.set_text(password)
2897 else:
2898 self.pass_entry.set_text('')
2899 nick = model[iter_][6]
2900 if nick:
2901 nick = nick.decode('utf-8')
2902 self.nick_entry.set_text(nick)
2903 else:
2904 self.nick_entry.set_text('')
2906 print_status = model[iter_][7]
2907 opts = sorted(self.option_list.keys())
2908 self.print_status_combobox.set_active(opts.index(print_status))
2910 def on_title_entry_changed(self, widget):
2911 (model, iter_) = self.selection.get_selected()
2912 if iter_: # After removing a bookmark, we got nothing selected
2913 if model.iter_parent(iter_):
2914 # Don't clear the title field for account nodes
2915 model[iter_][1] = self.title_entry.get_text()
2917 def on_nick_entry_changed(self, widget):
2918 (model, iter_) = self.selection.get_selected()
2919 if iter_:
2920 model[iter_][6] = self.nick_entry.get_text()
2922 def on_server_entry_changed(self, widget):
2923 (model, iter_) = self.selection.get_selected()
2924 if iter_:
2925 room_jid = self.room_entry.get_text().decode('utf-8').strip() + '@' + \
2926 self.server_entry.get_text().decode('utf-8').strip()
2927 model[iter_][2] = room_jid.replace(' ', '')
2929 def on_room_entry_changed(self, widget):
2930 (model, iter_) = self.selection.get_selected()
2931 if iter_:
2932 room_jid = self.room_entry.get_text().decode('utf-8') + '@' + \
2933 self.server_entry.get_text().decode('utf-8')
2934 model[iter_][2] = room_jid
2936 def on_pass_entry_changed(self, widget):
2937 (model, iter_) = self.selection.get_selected()
2938 if iter_:
2939 model[iter_][5] = self.pass_entry.get_text()
2941 def on_autojoin_checkbutton_toggled(self, widget):
2942 (model, iter_) = self.selection.get_selected()
2943 if iter_:
2944 model[iter_][3] = self.autojoin_checkbutton.get_active()
2945 self.minimize_checkbutton.set_sensitive(model[iter_][3])
2947 def on_minimize_checkbutton_toggled(self, widget):
2948 (model, iter_) = self.selection.get_selected()
2949 if iter_:
2950 model[iter_][4] = self.minimize_checkbutton.get_active()
2952 def on_print_status_combobox_changed(self, widget):
2953 active = widget.get_active()
2954 model = widget.get_model()
2955 print_status = model[active][1]
2956 (model2, iter_) = self.selection.get_selected()
2957 if iter_:
2958 model2[iter_][7] = print_status
2960 def clear_fields(self):
2961 widgets = [ self.title_entry, self.nick_entry, self.room_entry,
2962 self.server_entry, self.pass_entry ]
2963 for field in widgets:
2964 field.set_text('')
2965 self.autojoin_checkbutton.set_active(False)
2966 self.minimize_checkbutton.set_active(False)
2967 self.print_status_combobox.set_active(1)
2969 class AccountCreationWizardWindow:
2970 def __init__(self):
2971 self.xml = gtkgui_helpers.get_glade(
2972 'account_creation_wizard_window.glade')
2973 self.window = self.xml.get_widget('account_creation_wizard_window')
2975 completion = gtk.EntryCompletion()
2976 # Connect events from comboboxentry.child
2977 server_comboboxentry = self.xml.get_widget('server_comboboxentry')
2978 entry = server_comboboxentry.child
2979 entry.connect('key_press_event',
2980 self.on_server_comboboxentry_key_press_event, server_comboboxentry)
2981 entry.set_completion(completion)
2982 # Do the same for the other server comboboxentry
2983 server_comboboxentry1 = self.xml.get_widget('server_comboboxentry1')
2984 entry = server_comboboxentry1.child
2985 entry.connect('key_press_event',
2986 self.on_server_comboboxentry_key_press_event, server_comboboxentry1)
2987 entry.set_completion(completion)
2989 self.update_proxy_list()
2991 # parse servers.xml
2992 servers_xml = os.path.join(gajim.DATA_DIR, 'other', 'servers.xml')
2993 servers = gtkgui_helpers.parse_server_xml(servers_xml)
2994 servers_model = gtk.ListStore(str, int)
2995 for server in servers:
2996 if not server[2]['hidden']:
2997 servers_model.append((str(server[0]), int(server[1])))
2999 completion.set_model(servers_model)
3000 completion.set_text_column(0)
3002 # Put servers into comboboxentries
3003 server_comboboxentry.set_model(servers_model)
3004 server_comboboxentry.set_text_column(0)
3005 server_comboboxentry1.set_model(servers_model)
3006 server_comboboxentry1.set_text_column(0)
3008 # Generic widgets
3009 self.notebook = self.xml.get_widget('notebook')
3010 self.cancel_button = self.xml.get_widget('cancel_button')
3011 self.back_button = self.xml.get_widget('back_button')
3012 self.forward_button = self.xml.get_widget('forward_button')
3013 self.finish_button = self.xml.get_widget('finish_button')
3014 self.advanced_button = self.xml.get_widget('advanced_button')
3015 self.finish_label = self.xml.get_widget('finish_label')
3016 self.go_online_checkbutton = self.xml.get_widget(
3017 'go_online_checkbutton')
3018 self.show_vcard_checkbutton = self.xml.get_widget(
3019 'show_vcard_checkbutton')
3020 self.progressbar = self.xml.get_widget('progressbar')
3022 # some vars
3023 self.update_progressbar_timeout_id = None
3025 self.notebook.set_current_page(0)
3026 self.xml.signal_autoconnect(self)
3027 self.window.show_all()
3029 def on_wizard_window_destroy(self, widget):
3030 page = self.notebook.get_current_page()
3031 if page in (4, 5) and self.account in gajim.connections:
3032 # connection instance is saved in gajim.connections and we canceled the
3033 # addition of the account
3034 del gajim.connections[self.account]
3035 if self.account in gajim.config.get_per('accounts'):
3036 gajim.config.del_per('accounts', self.account)
3037 del gajim.interface.instances['account_creation_wizard']
3039 def on_register_server_features_button_clicked(self, widget):
3040 helpers.launch_browser_mailer('url',
3041 'http://www.jabber.org/network/oldnetwork.shtml')
3043 def on_save_password_checkbutton_toggled(self, widget):
3044 self.xml.get_widget('password_entry').grab_focus()
3046 def on_cancel_button_clicked(self, widget):
3047 self.window.destroy()
3049 def on_back_button_clicked(self, widget):
3050 cur_page = self.notebook.get_current_page()
3051 if cur_page in (1, 2):
3052 self.notebook.set_current_page(0)
3053 self.back_button.set_sensitive(False)
3054 elif cur_page == 3:
3055 self.xml.get_widget('form_vbox').remove(self.data_form_widget)
3056 self.notebook.set_current_page(2) # show server page
3057 elif cur_page == 4:
3058 if self.account in gajim.connections:
3059 del gajim.connections[self.account]
3060 self.notebook.set_current_page(2)
3061 self.xml.get_widget('form_vbox').remove(self.data_form_widget)
3062 elif cur_page == 6: # finish page
3063 self.forward_button.show()
3064 if self.modify:
3065 self.notebook.set_current_page(1) # Go to parameters page
3066 else:
3067 self.notebook.set_current_page(2) # Go to server page
3069 def on_forward_button_clicked(self, widget):
3070 cur_page = self.notebook.get_current_page()
3072 if cur_page == 0:
3073 widget = self.xml.get_widget('use_existing_account_radiobutton')
3074 if widget.get_active():
3075 self.modify = True
3076 self.notebook.set_current_page(1)
3077 else:
3078 self.modify = False
3079 self.notebook.set_current_page(2)
3080 self.back_button.set_sensitive(True)
3081 return
3083 elif cur_page == 1:
3084 # We are adding an existing account
3085 username = self.xml.get_widget('username_entry').get_text().decode(
3086 'utf-8').strip()
3087 if not username:
3088 pritext = _('Invalid username')
3089 sectext = _(
3090 'You must provide a username to configure this account.')
3091 dialogs.ErrorDialog(pritext, sectext)
3092 return
3093 server = self.xml.get_widget('server_comboboxentry').child.get_text().\
3094 decode('utf-8').strip()
3095 savepass = self.xml.get_widget('save_password_checkbutton').\
3096 get_active()
3097 password = self.xml.get_widget('password_entry').get_text().decode(
3098 'utf-8')
3100 jid = username + '@' + server
3101 # check if jid is conform to RFC and stringprep it
3102 try:
3103 jid = helpers.parse_jid(jid)
3104 except helpers.InvalidFormat, s:
3105 pritext = _('Invalid Jabber ID')
3106 dialogs.ErrorDialog(pritext, str(s))
3107 return
3109 self.account = server
3110 i = 1
3111 while self.account in gajim.connections:
3112 self.account = server + str(i)
3113 i += 1
3115 username, server = gajim.get_name_and_server_from_jid(jid)
3116 self.save_account(username, server, savepass, password)
3117 self.cancel_button.hide()
3118 self.back_button.hide()
3119 self.forward_button.hide()
3120 if self.modify:
3121 finish_text = '<big><b>%s</b></big>\n\n%s' % (
3122 _('Account has been added successfully'),
3123 _('You can set advanced account options by pressing the '
3124 'Advanced button, or later by choosing the Accounts menuitem '
3125 'under the Edit menu from the main window.'))
3126 self.finish_label.set_markup(finish_text)
3127 self.finish_button.show()
3128 self.finish_button.set_property('has-default', True)
3129 self.advanced_button.show()
3130 self.go_online_checkbutton.show()
3131 img = self.xml.get_widget('finish_image')
3132 img.set_from_stock(gtk.STOCK_APPLY, gtk.ICON_SIZE_DIALOG)
3133 self.notebook.set_current_page(6) # show finish page
3134 self.show_vcard_checkbutton.set_active(False)
3135 elif cur_page == 2:
3136 # We are creating a new account
3137 server = self.xml.get_widget('server_comboboxentry1').child.get_text()\
3138 .decode('utf-8')
3140 if not server:
3141 dialogs.ErrorDialog(_('Invalid server'),
3142 _('Please provide a server on which you want to register.'))
3143 return
3144 self.account = server
3145 i = 1
3146 while self.account in gajim.connections:
3147 self.account = server + str(i)
3148 i += 1
3150 config = self.get_config('', server, '', '')
3151 # Get advanced options
3152 proxies_combobox = self.xml.get_widget('proxies_combobox')
3153 active = proxies_combobox.get_active()
3154 proxy = proxies_combobox.get_model()[active][0].decode('utf-8')
3155 if proxy == _('None'):
3156 proxy = ''
3157 config['proxy'] = proxy
3159 config['use_custom_host'] = self.xml.get_widget(
3160 'custom_host_port_checkbutton').get_active()
3161 custom_port = self.xml.get_widget('custom_port_entry').get_text()
3162 try:
3163 custom_port = int(custom_port)
3164 except Exception:
3165 dialogs.ErrorDialog(_('Invalid entry'),
3166 _('Custom port must be a port number.'))
3167 return
3168 config['custom_port'] = custom_port
3169 config['custom_host'] = self.xml.get_widget(
3170 'custom_host_entry').get_text().decode('utf-8')
3172 self.notebook.set_current_page(5) # show creating page
3173 self.back_button.hide()
3174 self.forward_button.hide()
3175 self.update_progressbar_timeout_id = gobject.timeout_add(100,
3176 self.update_progressbar)
3177 # Get form from serveur
3178 con = connection.Connection(self.account)
3179 gajim.connections[self.account] = con
3180 con.new_account(self.account, config)
3181 elif cur_page == 3:
3182 checked = self.xml.get_widget('ssl_checkbutton').get_active()
3183 if checked:
3184 hostname = gajim.connections[self.account].new_account_info[
3185 'hostname']
3186 # Check if cert is already in file
3187 certs = ''
3188 if os.path.isfile(gajim.MY_CACERTS):
3189 f = open(gajim.MY_CACERTS)
3190 certs = f.read()
3191 f.close()
3192 if self.ssl_cert in certs:
3193 dialogs.ErrorDialog(_('Certificate Already in File'),
3194 _('This certificate is already in file %s, so it\'s not added again.') % gajim.MY_CACERTS)
3195 else:
3196 f = open(gajim.MY_CACERTS, 'a')
3197 f.write(hostname + '\n')
3198 f.write(self.ssl_cert + '\n\n')
3199 f.close()
3200 gajim.connections[self.account].new_account_info[
3201 'ssl_fingerprint_sha1'] = self.ssl_fingerprint
3202 self.notebook.set_current_page(4) # show fom page
3203 elif cur_page == 4:
3204 if self.is_form:
3205 form = self.data_form_widget.data_form
3206 else:
3207 form = self.data_form_widget.get_infos()
3208 gajim.connections[self.account].send_new_account_infos(form,
3209 self.is_form)
3210 self.xml.get_widget('form_vbox').remove(self.data_form_widget)
3211 self.xml.get_widget('progressbar_label').set_markup('<b>Account is being created</b>\n\nPlease wait...')
3212 self.notebook.set_current_page(5) # show creating page
3213 self.back_button.hide()
3214 self.forward_button.hide()
3215 self.update_progressbar_timeout_id = gobject.timeout_add(100,
3216 self.update_progressbar)
3218 def update_proxy_list(self):
3219 proxies_combobox = self.xml.get_widget('proxies_combobox')
3220 model = gtk.ListStore(str)
3221 proxies_combobox.set_model(model)
3222 l = gajim.config.get_per('proxies')
3223 l.insert(0, _('None'))
3224 for i in xrange(len(l)):
3225 model.append([l[i]])
3226 proxies_combobox.set_active(0)
3228 def on_manage_proxies_button_clicked(self, widget):
3229 if 'manage_proxies' in gajim.interface.instances:
3230 gajim.interface.instances['manage_proxies'].window.present()
3231 else:
3232 gajim.interface.instances['manage_proxies'] = \
3233 ManageProxiesWindow()
3235 def on_custom_host_port_checkbutton_toggled(self, widget):
3236 self.xml.get_widget('custom_host_hbox').set_sensitive(widget.get_active())
3238 def update_progressbar(self):
3239 self.progressbar.pulse()
3240 return True # loop forever
3242 def new_acc_connected(self, form, is_form, ssl_msg, ssl_err, ssl_cert,
3243 ssl_fingerprint):
3244 '''connection to server succeded, present the form to the user.'''
3245 if self.update_progressbar_timeout_id is not None:
3246 gobject.source_remove(self.update_progressbar_timeout_id)
3247 self.back_button.show()
3248 self.forward_button.show()
3249 self.is_form = is_form
3250 if is_form:
3251 dataform = dataforms.ExtendForm(node = form)
3252 self.data_form_widget = dataforms_widget.DataFormWidget(dataform)
3253 else:
3254 self.data_form_widget = FakeDataForm(form)
3255 self.data_form_widget.show_all()
3256 self.xml.get_widget('form_vbox').pack_start(self.data_form_widget)
3257 self.ssl_fingerprint = ssl_fingerprint
3258 self.ssl_cert = ssl_cert
3259 if ssl_msg:
3260 # An SSL warning occured, show it
3261 hostname = gajim.connections[self.account].new_account_info['hostname']
3262 self.xml.get_widget('ssl_label').set_markup(_('<b>Security Warning</b>'
3263 '\n\nThe authenticity of the %(hostname)s SSL certificate could be '
3264 'invalid.\nSSL Error: %(error)s\n'
3265 'Do you still want to connect to this server?') % {
3266 'hostname': hostname, 'error': ssl_msg})
3267 if ssl_err in (18, 27):
3268 text = _('Add this certificate to the list of trusted certificates.\nSHA1 fingerprint of the certificate:\n%s') % ssl_fingerprint
3269 self.xml.get_widget('ssl_checkbutton').set_label(text)
3270 else:
3271 self.xml.get_widget('ssl_checkbutton').set_no_show_all(True)
3272 self.xml.get_widget('ssl_checkbutton').hide()
3273 self.notebook.set_current_page(3) # show SSL page
3274 else:
3275 self.notebook.set_current_page(4) # show form page
3277 def new_acc_not_connected(self, reason):
3278 '''Account creation failed: connection to server failed'''
3279 if self.account not in gajim.connections:
3280 return
3281 if self.update_progressbar_timeout_id is not None:
3282 gobject.source_remove(self.update_progressbar_timeout_id)
3283 del gajim.connections[self.account]
3284 if self.account in gajim.config.get_per('accounts'):
3285 gajim.config.del_per('accounts', self.account)
3286 self.back_button.show()
3287 self.cancel_button.show()
3288 self.go_online_checkbutton.hide()
3289 self.show_vcard_checkbutton.hide()
3290 img = self.xml.get_widget('finish_image')
3291 img.set_from_stock(gtk.STOCK_DIALOG_ERROR, gtk.ICON_SIZE_DIALOG)
3292 finish_text = '<big><b>%s</b></big>\n\n%s' % (
3293 _('An error occurred during account creation') , reason)
3294 self.finish_label.set_markup(finish_text)
3295 self.notebook.set_current_page(6) # show finish page
3297 def acc_is_ok(self, config):
3298 '''Account creation succeeded'''
3299 self.create_vars(config)
3300 self.cancel_button.hide()
3301 self.back_button.hide()
3302 self.forward_button.hide()
3303 self.finish_button.show()
3304 self.finish_button.set_property('has-default', True)
3305 self.advanced_button.show()
3306 self.go_online_checkbutton.show()
3307 self.show_vcard_checkbutton.show()
3308 img = self.xml.get_widget('finish_image')
3309 path_to_file = os.path.join(gajim.DATA_DIR, 'pixmaps', 'gajim.png')
3310 img.set_from_file(path_to_file)
3312 finish_text = '<big><b>%s</b></big>\n\n%s' % (
3313 _('Your new account has been created successfully'),
3314 _('You can set advanced account options by pressing the Advanced '
3315 'button, or later by choosing the Accounts menuitem under the Edit '
3316 'menu from the main window.'))
3317 self.finish_label.set_markup(finish_text)
3318 self.notebook.set_current_page(6) # show finish page
3320 if self.update_progressbar_timeout_id is not None:
3321 gobject.source_remove(self.update_progressbar_timeout_id)
3323 def acc_is_not_ok(self, reason):
3324 '''Account creation failed'''
3325 self.back_button.show()
3326 self.cancel_button.show()
3327 self.go_online_checkbutton.hide()
3328 self.show_vcard_checkbutton.hide()
3329 del gajim.connections[self.account]
3330 if self.account in gajim.config.get_per('accounts'):
3331 gajim.config.del_per('accounts', self.account)
3332 img = self.xml.get_widget('finish_image')
3333 img.set_from_stock(gtk.STOCK_DIALOG_ERROR, gtk.ICON_SIZE_DIALOG)
3334 finish_text = '<big><b>%s</b></big>\n\n%s' % (_('An error occurred during '
3335 'account creation') , reason)
3336 self.finish_label.set_markup(finish_text)
3337 self.notebook.set_current_page(6) # show finish page
3339 if self.update_progressbar_timeout_id is not None:
3340 gobject.source_remove(self.update_progressbar_timeout_id)
3342 def on_advanced_button_clicked(self, widget):
3343 if 'accounts' in gajim.interface.instances:
3344 gajim.interface.instances['accounts'].window.present()
3345 else:
3346 gajim.interface.instances['accounts'] = AccountsWindow()
3347 gajim.interface.instances['accounts'].select_account(
3348 self.account)
3349 self.window.destroy()
3351 def on_finish_button_clicked(self, widget):
3352 go_online = self.xml.get_widget('go_online_checkbutton').get_active()
3353 show_vcard = self.xml.get_widget('show_vcard_checkbutton').get_active()
3354 self.window.destroy()
3355 if show_vcard:
3356 gajim.interface.show_vcard_when_connect.append(self.account)
3357 if go_online:
3358 gajim.interface.roster.send_status(self.account, 'online', '')
3360 def on_username_entry_key_press_event(self, widget, event):
3361 # Check for pressed @ and jump to combobox if found
3362 if event.keyval == gtk.keysyms.at:
3363 combobox = self.xml.get_widget('server_comboboxentry')
3364 combobox.grab_focus()
3365 combobox.child.set_position(-1)
3366 return True
3368 def on_server_comboboxentry_key_press_event(self, widget, event, combobox):
3369 # If backspace is pressed in empty field, return to the nick entry field
3370 backspace = event.keyval == gtk.keysyms.BackSpace
3371 empty = len(combobox.get_active_text()) == 0
3372 if backspace and empty and self.modify:
3373 username_entry = self.xml.get_widget('username_entry')
3374 username_entry.grab_focus()
3375 username_entry.set_position(-1)
3376 return True
3378 def get_config(self, login, server, savepass, password):
3379 config = {}
3380 config['name'] = login
3381 config['hostname'] = server
3382 config['savepass'] = savepass
3383 config['password'] = password
3384 config['resource'] = 'Gajim'
3385 config['priority'] = 5
3386 config['autoconnect'] = True
3387 config['no_log_for'] = ''
3388 config['sync_with_global_status'] = True
3389 config['proxy'] = ''
3390 config['usessl'] = False
3391 config['use_custom_host'] = False
3392 config['custom_port'] = 0
3393 config['custom_host'] = ''
3394 config['keyname'] = ''
3395 config['keyid'] = ''
3396 return config
3398 def save_account(self, login, server, savepass, password):
3399 if self.account in gajim.connections:
3400 dialogs.ErrorDialog(_('Account name is in use'),
3401 _('You already have an account using this name.'))
3402 return
3403 con = connection.Connection(self.account)
3404 con.password = password
3406 config = self.get_config(login, server, savepass, password)
3408 if not self.modify:
3409 con.new_account(self.account, config)
3410 return
3411 gajim.connections[self.account] = con
3412 self.create_vars(config)
3414 def create_vars(self, config):
3415 gajim.config.add_per('accounts', self.account)
3417 if not config['savepass']:
3418 config['password'] = ''
3420 for opt in config:
3421 gajim.config.set_per('accounts', self.account, opt, config[opt])
3423 # update variables
3424 gajim.interface.instances[self.account] = {'infos': {}, 'disco': {},
3425 'gc_config': {}, 'search': {}, 'online_dialog': {}}
3426 gajim.interface.minimized_controls[self.account] = {}
3427 gajim.connections[self.account].connected = 0
3428 gajim.connections[self.account].keepalives = gajim.config.get_per(
3429 'accounts', self.account, 'keep_alive_every_foo_secs')
3430 gajim.groups[self.account] = {}
3431 gajim.contacts.add_account(self.account)
3432 gajim.gc_connected[self.account] = {}
3433 gajim.automatic_rooms[self.account] = {}
3434 gajim.newly_added[self.account] = []
3435 gajim.to_be_removed[self.account] = []
3436 gajim.nicks[self.account] = config['name']
3437 gajim.block_signed_in_notifications[self.account] = True
3438 gajim.sleeper_state[self.account] = 'off'
3439 gajim.encrypted_chats[self.account] = []
3440 gajim.last_message_time[self.account] = {}
3441 gajim.status_before_autoaway[self.account] = ''
3442 gajim.transport_avatar[self.account] = {}
3443 gajim.gajim_optional_features[self.account] = []
3444 gajim.caps_hash[self.account] = ''
3445 # refresh accounts window
3446 if 'accounts' in gajim.interface.instances:
3447 gajim.interface.instances['accounts'].init_accounts()
3448 # refresh roster
3449 if len(gajim.connections) >= 2: # Do not merge accounts if only one exists
3450 gajim.interface.roster.regroup = gajim.config.get('mergeaccounts')
3451 else:
3452 gajim.interface.roster.regroup = False
3453 gajim.interface.roster.setup_and_draw_roster()
3454 gajim.interface.roster.set_actions_menu_needs_rebuild()
3455 gajim.interface.save_config()
3457 class ManagePEPServicesWindow:
3458 def __init__(self, account):
3459 self.xml = gtkgui_helpers.get_glade('manage_pep_services_window.glade')
3460 self.window = self.xml.get_widget('manage_pep_services_window')
3461 self.window.set_transient_for(gajim.interface.roster.window)
3462 self.xml.get_widget('configure_button').set_sensitive(False)
3463 self.xml.get_widget('delete_button').set_sensitive(False)
3464 self.xml.signal_autoconnect(self)
3465 self.account = account
3467 self.init_services()
3468 self.xml.get_widget('services_treeview').get_selection().connect(
3469 'changed', self.on_services_selection_changed)
3470 self.window.show_all()
3472 def on_manage_pep_services_window_destroy(self, widget):
3473 '''close window'''
3474 del gajim.interface.instances[self.account]['pep_services']
3476 def on_close_button_clicked(self, widget):
3477 self.window.destroy()
3479 def on_services_selection_changed(self, sel):
3480 self.xml.get_widget('configure_button').set_sensitive(True)
3481 self.xml.get_widget('delete_button').set_sensitive(True)
3483 def init_services(self):
3484 self.treeview = self.xml.get_widget('services_treeview')
3485 # service, access_model, group
3486 self.treestore = gtk.ListStore(str)
3487 self.treeview.set_model(self.treestore)
3489 col = gtk.TreeViewColumn('Service')
3490 self.treeview.append_column(col)
3492 cellrenderer_text = gtk.CellRendererText()
3493 col.pack_start(cellrenderer_text)
3494 col.add_attribute(cellrenderer_text, 'text', 0)
3496 our_jid = gajim.get_jid_from_account(self.account)
3497 gajim.connections[self.account].discoverItems(our_jid)
3499 def items_received(self, items):
3500 our_jid = gajim.get_jid_from_account(self.account)
3501 for item in items:
3502 if 'jid' in item and item['jid'] == our_jid and 'node' in item:
3503 self.treestore.append([item['node']])
3505 def node_removed(self, node):
3506 model = self.treeview.get_model()
3507 iter_ = model.get_iter_root()
3508 while iter_:
3509 if model[iter_][0] == node:
3510 model.remove(iter_)
3511 break
3512 iter_ = model.get_iter_next(iter_)
3514 def on_delete_button_clicked(self, widget):
3515 selection = self.treeview.get_selection()
3516 if not selection:
3517 return
3518 model, iter_ = selection.get_selected()
3519 node = model[iter_][0]
3520 our_jid = gajim.get_jid_from_account(self.account)
3521 gajim.connections[self.account].send_pb_delete(our_jid, node)
3523 def on_configure_button_clicked(self, widget):
3524 selection = self.treeview.get_selection()
3525 if not selection:
3526 return
3527 model, iter_ = selection.get_selected()
3528 node = model[iter_][0]
3529 our_jid = gajim.get_jid_from_account(self.account)
3530 gajim.connections[self.account].request_pb_configuration(our_jid, node)
3532 def config(self, node, form):
3533 def on_ok(form, node):
3534 form.type = 'submit'
3535 our_jid = gajim.get_jid_from_account(self.account)
3536 gajim.connections[self.account].send_pb_configure(our_jid, node, form)
3537 window = dialogs.DataFormWindow(form, (on_ok, node))
3538 title = "Configure %s" % node
3539 window.set_title(title)
3540 window.show_all()
3542 class ManageSoundsWindow:
3543 def __init__(self):
3544 self.xml = gtkgui_helpers.get_glade('manage_sounds_window.glade')
3545 self.window = self.xml.get_widget('manage_sounds_window')
3547 # sounds treeview
3548 self.sound_tree = self.xml.get_widget('sounds_treeview')
3550 # active, event ui name, path to sound file, event_config_name
3551 model = gtk.ListStore(bool, str, str, str)
3552 self.sound_tree.set_model(model)
3554 col = gtk.TreeViewColumn(_('Active'))
3555 self.sound_tree.append_column(col)
3556 renderer = gtk.CellRendererToggle()
3557 renderer.set_property('activatable', True)
3558 renderer.connect('toggled', self.sound_toggled_cb)
3559 col.pack_start(renderer)
3560 col.set_attributes(renderer, active = 0)
3562 col = gtk.TreeViewColumn(_('Event'))
3563 self.sound_tree.append_column(col)
3564 renderer = gtk.CellRendererText()
3565 col.pack_start(renderer)
3566 col.set_attributes(renderer, text = 1)
3568 self.fill_sound_treeview()
3570 self.xml.signal_autoconnect(self)
3572 self.sound_tree.get_model().connect('row-changed',
3573 self.on_sounds_treemodel_row_changed)
3575 self.window.show_all()
3577 def on_sounds_treemodel_row_changed(self, model, path, iter_):
3578 sound_event = model[iter_][3].decode('utf-8')
3579 gajim.config.set_per('soundevents', sound_event, 'enabled',
3580 bool(model[path][0]))
3581 gajim.config.set_per('soundevents', sound_event, 'path',
3582 model[iter_][2].decode('utf-8'))
3583 gajim.interface.save_config()
3585 def sound_toggled_cb(self, cell, path):
3586 model = self.sound_tree.get_model()
3587 model[path][0] = not model[path][0]
3589 def fill_sound_treeview(self):
3590 model = self.sound_tree.get_model()
3591 model.clear()
3592 model.set_sort_column_id(1, gtk.SORT_ASCENDING)
3594 # NOTE: sounds_ui_names MUST have all items of
3595 # sounds = gajim.config.get_per('soundevents') as keys
3596 sounds_dict = {
3597 'first_message_received': _('First Message Received'),
3598 'next_message_received_focused': _('Next Message Received Focused'),
3599 'next_message_received_unfocused':
3600 _('Next Message Received Unfocused'),
3601 'contact_connected': _('Contact Connected'),
3602 'contact_disconnected': _('Contact Disconnected'),
3603 'message_sent': _('Message Sent'),
3604 'muc_message_highlight': _('Group Chat Message Highlight'),
3605 'muc_message_received': _('Group Chat Message Received'),
3606 'gmail_received': _('GMail Email Received')
3609 for sound_event_config_name, sound_ui_name in sounds_dict.items():
3610 enabled = gajim.config.get_per('soundevents',
3611 sound_event_config_name, 'enabled')
3612 path = gajim.config.get_per('soundevents',
3613 sound_event_config_name, 'path')
3614 model.append((enabled, sound_ui_name, path, sound_event_config_name))
3616 def on_treeview_sounds_cursor_changed(self, widget, data = None):
3617 (model, iter_) = self.sound_tree.get_selection().get_selected()
3618 sounds_entry = self.xml.get_widget('sounds_entry')
3619 if not iter_:
3620 sounds_entry.set_text('')
3621 return
3622 path_to_snd_file = model[iter_][2]
3623 sounds_entry.set_text(path_to_snd_file)
3625 def on_browse_for_sounds_button_clicked(self, widget, data = None):
3626 (model, iter_) = self.sound_tree.get_selection().get_selected()
3627 if not iter_:
3628 return
3629 def on_ok(widget, path_to_snd_file):
3630 self.dialog.destroy()
3631 model, iter_ = self.sound_tree.get_selection().get_selected()
3632 if not path_to_snd_file:
3633 model[iter_][2] = ''
3634 self.xml.get_widget('sounds_entry').set_text('')
3635 model[iter_][0] = False
3636 return
3637 directory = os.path.dirname(path_to_snd_file)
3638 gajim.config.set('last_sounds_dir', directory)
3639 path_to_snd_file = helpers.strip_soundfile_path(path_to_snd_file)
3640 self.xml.get_widget('sounds_entry').set_text(path_to_snd_file)
3642 model[iter_][2] = path_to_snd_file # set new path to sounds_model
3643 model[iter_][0] = True # set the sound to enabled
3645 def on_cancel(widget):
3646 self.dialog.destroy()
3648 path_to_snd_file = model[iter_][2].decode('utf-8')
3649 self.dialog = dialogs.SoundChooserDialog(path_to_snd_file, on_ok,
3650 on_cancel)
3652 def on_sounds_entry_changed(self, widget):
3653 path_to_snd_file = widget.get_text()
3654 model, iter_ = self.sound_tree.get_selection().get_selected()
3655 model[iter_][2] = path_to_snd_file # set new path to sounds_model
3657 def on_play_button_clicked(self, widget):
3658 model, iter_ = self.sound_tree.get_selection().get_selected()
3659 if not iter_:
3660 return
3661 snd_event_config_name = model[iter_][3]
3662 helpers.play_sound(snd_event_config_name)
3664 def on_close_button_clicked(self, widget):
3665 self.window.hide()
3667 def on_manage_sounds_window_delete_event(self, widget, event):
3668 self.window.hide()
3669 return True # do NOT destroy the window
3670 # vim: se ts=3: