# This file is part of Gajim. # # Gajim is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published # by the Free Software Foundation; version 3 only. # # Gajim is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Gajim. If not, see . import os import sys from gi.repository import Gtk from gi.repository import Gdk from gi.repository import Pango from gajim.common import app from gajim.common import helpers from gajim.common import config as c_config from gajim.common import idle from gajim.common.i18n import _ from gajim.common.i18n import ngettext from gajim import message_control from gajim.chat_control_base import ChatControlBase from gajim.gtk.util import get_builder from gajim.gtk.util import get_icon_name from gajim.gtk.util import get_available_iconsets from gajim.gtk.dialogs import AspellDictError from gajim.gtk.themes import Themes from gajim.gtk.advanced_config import AdvancedConfig from gajim.gtk.proxies import ManageProxies from gajim.gtk.sounds import ManageSounds try: from gajim.common.multimedia_helpers import AudioInputManager, AudioOutputManager from gajim.common.multimedia_helpers import VideoInputManager, VideoOutputManager HAS_GST = True except (ImportError, ValueError): HAS_GST = False if app.is_installed('GSPELL'): from gi.repository import Gspell class Preferences(Gtk.ApplicationWindow): def __init__(self): Gtk.ApplicationWindow.__init__(self) self.set_application(app.app) self.set_position(Gtk.WindowPosition.CENTER) self.set_show_menubar(False) self.set_title(_('Preferences')) self._ui = get_builder('preferences_window.ui') self.add(self._ui.preferences_window) ### General tab ### ## Behavior of Windows and Tabs # Set default for single window type choices = c_config.opt_one_window_types type_ = app.config.get('one_message_window') if type_ in choices: self._ui.one_window_type_combobox.set_active(choices.index(type_)) else: self._ui.one_window_type_combobox.set_active(0) # Show roster on startup choices = c_config.opt_show_roster_on_startup type_ = app.config.get('show_roster_on_startup') if type_ in choices: self._ui.show_roster_on_startup.set_active(choices.index(type_)) else: self._ui.show_roster_on_startup.set_active(0) # Quit on roster x st = app.config.get('quit_on_roster_x_button') self._ui.quit_on_roster_x_checkbutton.set_active(st) # Tab placement st = app.config.get('tabs_position') if st == 'top': self._ui.tabs_placement.set_active(0) elif st == 'bottom': self._ui.tabs_placement.set_active(1) elif st == 'left': self._ui.tabs_placement.set_active(2) else: # right self._ui.tabs_placement.set_active(3) # Show avatar in tabs st = app.config.get('show_avatar_in_tabs') self._ui.show_avatar_in_tabs_checkbutton.set_active(st) ## Roster Appearance # Display avatars in roster st = app.config.get('show_avatars_in_roster') self._ui.show_avatars_in_roster_checkbutton.set_active(st) # Display status msg under contact name in roster st = app.config.get('show_status_msgs_in_roster') self._ui.show_status_msgs_in_roster_checkbutton.set_active(st) # Display PEP in roster st1 = app.config.get('show_mood_in_roster') st2 = app.config.get('show_activity_in_roster') st3 = app.config.get('show_tunes_in_roster') st4 = app.config.get('show_location_in_roster') if st1 == st2 == st3 == st4: self._ui.show_pep_in_roster_checkbutton.set_active(st1) else: self._ui.show_pep_in_roster_checkbutton.set_inconsistent(True) # Sort contacts by show st = app.config.get('sort_by_show_in_roster') self._ui.sort_by_show_in_roster_checkbutton.set_active(st) st = app.config.get('sort_by_show_in_muc') self._ui.sort_by_show_in_muc_checkbutton.set_active(st) ### Chat tab ### ## Chat Settings # Use speller if app.is_installed('GSPELL'): st = app.config.get('use_speller') self._ui.speller_checkbutton.set_active(st) else: self._ui.speller_checkbutton.set_sensitive(False) # XEP-0184 positive ack st = app.config.get('positive_184_ack') self._ui.positive_184_ack_checkbutton.set_active(st) # Ignore XHTML st = app.config.get('ignore_incoming_xhtml') self._ui.xhtml_checkbutton.set_active(st) # Print status messages in single chats st = app.config.get('print_status_in_chats') self._ui.print_status_in_chats_checkbutton.set_active(st) # Show subject on join st = app.config.get('show_subject_on_join') self._ui.subject_on_join_checkbutton.set_active(st) # Group chat settings threshold_model = self._ui.sync_threshold_combobox.get_model() for day in app.config.get_options('threshold_options'): if day == '0': label = _('No threshold') else: label = ngettext('%s day' % day, '%s days' % day, int(day)) threshold_model.append([day, label]) public_threshold = app.config.get('public_room_sync_threshold') self._ui.sync_threshold_combobox.set_id_column(0) self._ui.sync_threshold_combobox.set_active_id(str(public_threshold)) st = app.config.get('print_join_left_default') self._ui.join_leave_checkbutton.set_active(st) st = app.config.get('print_status_muc_default') self._ui.status_change_checkbutton.set_active(st) # Displayed chat state notifications st = app.config.get('show_chatstate_in_tabs') self._ui.show_chatstate_in_tabs.set_active(st) st = app.config.get('show_chatstate_in_roster') self._ui.show_chatstate_in_roster.set_active(st) st = app.config.get('show_chatstate_in_banner') self._ui.show_chatstate_in_banner.set_active(st) ### Notifications tab ### ## Visual Notifications # Systray icon if app.config.get('trayicon') == 'never': self._ui.systray_combobox.set_active(0) elif app.config.get('trayicon') == 'on_event': self._ui.systray_combobox.set_active(1) else: # always self._ui.systray_combobox.set_active(2) # Notify on new event if app.config.get('autopopup'): self._ui.on_event_received_combobox.set_active(0) elif app.config.get('notify_on_new_message'): self._ui.on_event_received_combobox.set_active(1) else: # only show in roster self._ui.on_event_received_combobox.set_active(2) # Notify on online statuses st = app.config.get('notify_on_signin') self._ui.notify_on_signin_checkbutton.set_active(st) # Notify on offline statuses st = app.config.get('notify_on_signout') self._ui.notify_on_signout_checkbutton.set_active(st) # Auto popup when away st = app.config.get('autopopupaway') self._ui.auto_popup_away_checkbutton.set_active(st) # Auto popup when chat already open st = app.config.get('autopopup_chat_opened') self._ui.auto_popup_chat_opened_checkbutton.set_active(st) ## Sounds # Sounds if app.config.get('sounds_on'): self._ui.play_sounds_checkbutton.set_active(True) else: self._ui.manage_sounds_button.set_sensitive(False) # Allow sounds when dnd st = app.config.get('sounddnd') self._ui.sound_dnd_checkbutton.set_active(st) #### Status tab ### # Auto away st = app.config.get('autoaway') self._ui.auto_away_checkbutton.set_active(st) # Auto away time st = app.config.get('autoawaytime') self._ui.auto_away_time_spinbutton.set_value(st) self._ui.auto_away_time_spinbutton.set_sensitive(app.config.get('autoaway')) # Auto away message st = app.config.get('autoaway_message') self._ui.auto_away_message_entry.set_text(st) self._ui.auto_away_message_entry.set_sensitive(app.config.get('autoaway')) # Auto xa st = app.config.get('autoxa') self._ui.auto_xa_checkbutton.set_active(st) # Auto xa time st = app.config.get('autoxatime') self._ui.auto_xa_time_spinbutton.set_value(st) self._ui.auto_xa_time_spinbutton.set_sensitive(app.config.get('autoxa')) # Auto xa message st = app.config.get('autoxa_message') self._ui.auto_xa_message_entry.set_text(st) self._ui.auto_xa_message_entry.set_sensitive(app.config.get('autoxa')) if not idle.Monitor.is_available(): self._ui.autoaway_table.set_sensitive(False) # Restore last status st = self.get_per_account_option('restore_last_status') if st == 'mixed': self._ui.restore_last_status_checkbutton.set_inconsistent(True) else: self._ui.restore_last_status_checkbutton.set_active(st) # Ask for status when online/offline st = app.config.get('ask_online_status') self._ui.prompt_online_status_message_checkbutton.set_active(st) st = app.config.get('ask_offline_status') self._ui.prompt_offline_status_message_checkbutton.set_active(st) # Default status messages self.fill_default_msg_treeview() # Status messages renderer = Gtk.CellRendererText() renderer.connect('edited', self.on_msg_cell_edited) renderer.set_property('editable', True) col = Gtk.TreeViewColumn('name', renderer, text=0) self._ui.msg_treeview.append_column(col) self.fill_msg_treeview() buf = self._ui.msg_textview.get_buffer() buf.connect('end-user-action', self.on_msg_textview_changed) ### Privacy tab ### # Send idle time st = self.get_per_account_option('send_idle_time') if st == 'mixed': self._ui.send_idle_time_checkbutton.set_inconsistent(True) else: self._ui.send_idle_time_checkbutton.set_active(st) # Send absolute time info st = self.get_per_account_option('send_time_info') if st == 'mixed': self._ui.send_time_info_checkbutton.set_inconsistent(True) else: self._ui.send_time_info_checkbutton.set_active(st) # Send OS info st = self.get_per_account_option('send_os_info') if st == 'mixed': self._ui.send_os_info_checkbutton.set_inconsistent(True) else: self._ui.send_os_info_checkbutton.set_active(st) # Ignore messages from unknown contacts st = self.get_per_account_option('ignore_unknown_contacts') if st == 'mixed': self._ui.ignore_events_from_unknown_contacts_checkbutton.set_inconsistent(True) else: self._ui.ignore_events_from_unknown_contacts_checkbutton.set_active(st) # Outgoing chat state notifications st = app.config.get('outgoing_chat_state_notifications') if st == 'all': self._ui.outgoing_chat_states_combobox.set_active(0) elif st == 'composing_only': self._ui.outgoing_chat_states_combobox.set_active(1) else: # disabled self._ui.outgoing_chat_states_combobox.set_active(2) ### Style tab ### # Themes self.changed_id = self._ui.theme_combobox.connect( 'changed', self.on_theme_combobox_changed) self.update_theme_list() # Dark theme self._ui.dark_theme_combobox.set_active_id(str(app.config.get('dark_theme'))) # Emoticons emoticon_themes = helpers.get_available_emoticon_themes() for theme in emoticon_themes: self._ui.emoticons_combobox.append_text(theme) config_theme = app.config.get('emoticons_theme') if config_theme not in emoticon_themes: config_theme = 'font' self._ui.emoticons_combobox.set_id_column(0) self._ui.emoticons_combobox.set_active_id(config_theme) self._ui.ascii_emoticons.set_active(app.config.get('ascii_emoticons')) # Iconset model = Gtk.ListStore(str, str) renderer_image = Gtk.CellRendererPixbuf() renderer_text = Gtk.CellRendererText() renderer_text.set_property('xpad', 5) self._ui.iconset_combobox.pack_start(renderer_image, False) self._ui.iconset_combobox.pack_start(renderer_text, True) self._ui.iconset_combobox.add_attribute(renderer_text, 'text', 1) self._ui.iconset_combobox.add_attribute(renderer_image, 'icon_name', 0) self._ui.iconset_combobox.set_model(model) for index, iconset_name in enumerate(get_available_iconsets()): icon_name = get_icon_name('online', iconset=iconset_name) model.append([icon_name, iconset_name]) if app.config.get('iconset') == iconset_name: self._ui.iconset_combobox.set_active(index) # Use transports iconsets st = app.config.get('use_transports_iconsets') self._ui.transports_iconsets_checkbutton.set_active(st) ### Audio/Video tab ### def create_av_combobox(opt_name, device_dict, config_name=None, key=None): combobox = self._ui.get_object(opt_name + '_combobox') cell = Gtk.CellRendererText() cell.set_property('ellipsize', Pango.EllipsizeMode.END) cell.set_property('ellipsize-set', True) combobox.pack_start(cell, True) combobox.add_attribute(cell, 'text', 0) model = Gtk.ListStore(str, str) combobox.set_model(model) if config_name: config = app.config.get(config_name) else: config = app.config.get(opt_name + '_device') for index, (name, value) in enumerate(sorted(device_dict.items(), key=key)): model.append((name, value)) if config == value: combobox.set_active(index) if HAS_GST and app.is_installed('FARSTREAM'): create_av_combobox('audio_input', AudioInputManager().get_devices()) create_av_combobox('audio_output', AudioOutputManager().get_devices( )) create_av_combobox('video_input', VideoInputManager().get_devices()) create_av_combobox('video_output', VideoOutputManager().get_devices( )) create_av_combobox('video_framerate', {_('Default'): '', '15fps': '15/1', '10fps': '10/1', '5fps': '5/1', '2.5fps': '5/2'}, 'video_framerate', key=lambda x: -1 if \ not x[1] else float(x[0][:-3])) create_av_combobox('video_size', {_('Default'): '', '800x600': '800x600', '640x480': '640x480', '320x240': '320x240'}, 'video_size', key=lambda x: -1 if \ not x[1] else int(x[0][:3])) st = app.config.get('video_see_self') self._ui.video_see_self_checkbutton.set_active(st) else: for opt_name in ('audio_input', 'audio_output', 'video_input', 'video_output', 'video_framerate', 'video_size'): combobox = self._ui.get_object(opt_name + '_combobox') combobox.set_sensitive(False) # STUN st = app.config.get('use_stun_server') self._ui.stun_checkbutton.set_active(st) self._ui.stun_server_entry.set_text(app.config.get('stun_server')) if not st: self._ui.stun_server_entry.set_sensitive(False) ### Advanced tab ### ## Applications (open links with) if os.name == 'nt': self._ui.custom_apps_frame.set_no_show_all(True) self._ui.custom_apps_frame.hide() else: self._ui.custom_apps_frame.hide() self._ui.custom_apps_frame.set_no_show_all(True) if app.config.get('autodetect_browser_mailer'): self._ui.applications_combobox.set_active(0) else: self._ui.applications_combobox.set_active(1) self._ui.custom_apps_frame.show() self._ui.custom_browser_entry.set_text( app.config.get('custombrowser')) self._ui.custom_mail_client_entry.set_text( app.config.get('custommailapp')) self._ui.custom_file_manager_entry.set_text( app.config.get('custom_file_manager')) ## Miscellaneous # Proxy self.update_proxy_list() # Log status changes of contacts st = app.config.get('log_contact_status_changes') self._ui.log_show_changes_checkbutton.set_active(st) # Enable debug logging if sys.platform == 'win32': self._ui.enable_logging.set_active(app.get_win_debug_mode()) self._ui.enable_logging.show() self._ui.connect_signals(self) self.connect('key-press-event', self._on_key_press) self._ui.msg_treeview.get_model().connect('row-changed', self.on_msg_treemodel_row_changed) self._ui.msg_treeview.get_model().connect('row-deleted', self.on_msg_treemodel_row_deleted) self._ui.default_msg_treeview.get_model().connect('row-changed', self.on_default_msg_treemodel_row_changed) self.sounds_preferences = None self.theme_preferences = None self.show_all() def _on_key_press(self, widget, event): if event.keyval == Gdk.KEY_Escape: self.destroy() def get_per_account_option(self, opt): """ Return the value of the option opt if it's the same in all accounts else returns "mixed" """ if not app.connections: # A non existent key return default value return app.config.get_per('accounts', '__default__', opt) val = None for account in app.connections: v = app.config.get_per('accounts', account, opt) if val is None: val = v elif val != v: return 'mixed' return val def on_checkbutton_toggled(self, widget, config_name, change_sensitivity_widgets=None): app.config.set(config_name, widget.get_active()) if change_sensitivity_widgets: for w in change_sensitivity_widgets: w.set_sensitive(widget.get_active()) def on_per_account_checkbutton_toggled(self, widget, config_name, change_sensitivity_widgets=None): for account in app.connections: app.config.set_per('accounts', account, config_name, widget.get_active()) if change_sensitivity_widgets: for w in change_sensitivity_widgets: w.set_sensitive(widget.get_active()) def _get_all_controls(self): for ctrl in app.interface.msg_win_mgr.get_controls(): yield ctrl for account in app.connections: for ctrl in app.interface.minimized_controls[account].values(): yield ctrl def _get_all_muc_controls(self): for ctrl in app.interface.msg_win_mgr.get_controls( message_control.TYPE_GC): yield ctrl for account in app.connections: for ctrl in app.interface.minimized_controls[account].values(): yield ctrl ### General tab ### def on_one_window_type_combo_changed(self, widget): active = widget.get_active() config_type = c_config.opt_one_window_types[active] app.config.set('one_message_window', config_type) app.interface.msg_win_mgr.reconfig() def on_show_roster_on_startup_changed(self, widget): active = widget.get_active() config_type = c_config.opt_show_roster_on_startup[active] app.config.set('show_roster_on_startup', config_type) def on_quit_on_roster_x_checkbutton_toggled(self, widget): self.on_checkbutton_toggled(widget, 'quit_on_roster_x_button') def on_tab_placement_changed(self, widget): active = widget.get_active() if active == 0: # top app.config.set('tabs_position', 'top') elif active == 1: # bottom app.config.set('tabs_position', 'bottom') elif active == 2: # left app.config.set('tabs_position', 'left') else: # right app.config.set('tabs_position', 'right') def on_show_avatar_in_tabs_checkbutton_toggled(self, widget): self.on_checkbutton_toggled(widget, 'show_avatar_in_tabs') def on_show_avatars_in_roster_checkbutton_toggled(self, widget): self.on_checkbutton_toggled(widget, 'show_avatars_in_roster') app.interface.roster.setup_and_draw_roster() # Redraw groupchats (in an ugly way) for ctrl in self._get_all_muc_controls(): ctrl.draw_roster() def on_show_status_msgs_in_roster_checkbutton_toggled(self, widget): self.on_checkbutton_toggled(widget, 'show_status_msgs_in_roster') app.interface.roster.setup_and_draw_roster() for ctrl in self._get_all_muc_controls(): ctrl.update_ui() def on_show_pep_in_roster_checkbutton_toggled(self, widget): self.on_checkbutton_toggled(widget, 'show_mood_in_roster') self.on_checkbutton_toggled(widget, 'show_activity_in_roster') self.on_checkbutton_toggled(widget, 'show_tunes_in_roster') self.on_checkbutton_toggled(widget, 'show_location_in_roster') app.interface.roster.setup_and_draw_roster() def on_sort_by_show_in_roster_checkbutton_toggled(self, widget): self.on_checkbutton_toggled(widget, 'sort_by_show_in_roster') app.interface.roster.setup_and_draw_roster() def on_sort_by_show_in_muc_checkbutton_toggled(self, widget): self.on_checkbutton_toggled(widget, 'sort_by_show_in_muc') # Redraw groupchats for ctrl in self._get_all_muc_controls(): ctrl.draw_roster() ### Chat tab ### def on_speller_checkbutton_toggled(self, widget): active = widget.get_active() app.config.set('use_speller', active) if not active: return lang = app.config.get('speller_language') gspell_lang = Gspell.language_lookup(lang) if gspell_lang is None: gspell_lang = Gspell.language_get_default() if gspell_lang is None: AspellDictError(lang) app.config.set('use_speller', False) widget.set_active(False) else: app.config.set('speller_language', gspell_lang.get_code()) self.apply_speller() def apply_speller(self): for ctrl in self._get_all_controls(): if isinstance(ctrl, ChatControlBase): ctrl.set_speller() def on_positive_184_ack_checkbutton_toggled(self, widget): self.on_checkbutton_toggled(widget, 'positive_184_ack') def on_xhtml_checkbutton_toggled(self, widget): self.on_checkbutton_toggled(widget, 'ignore_incoming_xhtml') helpers.update_optional_features() def on_print_status_in_chats_checkbutton_toggled(self, widget): self.on_checkbutton_toggled(widget, 'print_status_in_chats') def on_subject_on_join_checkbutton_toggled(self, widget): self.on_checkbutton_toggled(widget, 'show_subject_on_join') def _on_sync_threshold_changed(self, widget): active = widget.get_active_id() app.config.set('public_room_sync_threshold', int(active)) def _on_join_leave_toggled(self, widget): self.on_checkbutton_toggled(widget, 'print_join_left_default') for control in self._get_all_muc_controls(): control.update_actions() def _on_status_change_toggled(self, widget): self.on_checkbutton_toggled(widget, 'print_status_muc_default') for control in self._get_all_muc_controls(): control.update_actions() def on_show_chatstate_in_tabs_toggled(self, widget): self.on_checkbutton_toggled(widget, 'show_chatstate_in_tabs') def on_show_chatstate_in_roster_toggled(self, widget): self.on_checkbutton_toggled(widget, 'show_chatstate_in_roster') def on_show_chatstate_in_banner_toggled(self, widget): self.on_checkbutton_toggled(widget, 'show_chatstate_in_banner') ### Notifications tab ### def on_systray_combobox_changed(self, widget): active = widget.get_active() if active == 0: app.config.set('trayicon', 'never') app.interface.systray_enabled = False app.interface.systray.hide_icon() elif active == 1: app.config.set('trayicon', 'on_event') app.interface.systray_enabled = True app.interface.systray.show_icon() else: app.config.set('trayicon', 'always') app.interface.systray_enabled = True app.interface.systray.show_icon() def on_event_received_combobox_changed(self, widget): active = widget.get_active() if active == 0: app.config.set('autopopup', True) app.config.set('notify_on_new_message', False) elif active == 1: app.config.set('autopopup', False) app.config.set('notify_on_new_message', True) else: app.config.set('autopopup', False) app.config.set('notify_on_new_message', False) def on_notify_on_signin_checkbutton_toggled(self, widget): self.on_checkbutton_toggled(widget, 'notify_on_signin') def on_notify_on_signout_checkbutton_toggled(self, widget): self.on_checkbutton_toggled(widget, 'notify_on_signout') def on_auto_popup_away_checkbutton_toggled(self, widget): self.on_checkbutton_toggled(widget, 'autopopupaway') def on_auto_popup_chat_opened_checkbutton_toggled(self, widget): self.on_checkbutton_toggled(widget, 'autopopup_chat_opened') def on_play_sounds_checkbutton_toggled(self, widget): self.on_checkbutton_toggled(widget, 'sounds_on', [self._ui.manage_sounds_button]) def on_manage_sounds_button_clicked(self, widget): if self.sounds_preferences is None: self.sounds_preferences = ManageSounds() else: self.sounds_preferences.window.present() def on_sound_dnd_checkbutton_toggled(self, widget): self.on_checkbutton_toggled(widget, 'sounddnd') ### Status tab ### def on_auto_away_checkbutton_toggled(self, widget): self.on_checkbutton_toggled(widget, 'autoaway', [self._ui.auto_away_time_spinbutton, self._ui.auto_away_message_entry]) def on_auto_away_time_spinbutton_value_changed(self, widget): aat = widget.get_value_as_int() app.config.set('autoawaytime', aat) idle.Monitor.set_interval(app.config.get('autoawaytime') * 60, app.config.get('autoxatime') * 60) def on_auto_away_message_entry_changed(self, widget): app.config.set('autoaway_message', widget.get_text()) def on_auto_xa_checkbutton_toggled(self, widget): self.on_checkbutton_toggled(widget, 'autoxa', [self._ui.auto_xa_time_spinbutton, self._ui.auto_xa_message_entry]) def on_auto_xa_time_spinbutton_value_changed(self, widget): axt = widget.get_value_as_int() app.config.set('autoxatime', axt) idle.Monitor.set_interval(app.config.get('autoawaytime') * 60, app.config.get('autoxatime') * 60) def on_auto_xa_message_entry_changed(self, widget): app.config.set('autoxa_message', widget.get_text()) def on_restore_last_status_checkbutton_toggled(self, widget): widget.set_inconsistent(False) self.on_per_account_checkbutton_toggled(widget, 'restore_last_status') def on_prompt_online_status_message_checkbutton_toggled(self, widget): self.on_checkbutton_toggled(widget, 'ask_online_status') def on_prompt_offline_status_message_checkbutton_toggled(self, widget): self.on_checkbutton_toggled(widget, 'ask_offline_status') def fill_default_msg_treeview(self): model = self._ui.default_msg_treeview.get_model() model.clear() status = [] for status_ in app.config.get_per('defaultstatusmsg'): status.append(status_) status.sort() for status_ in status: msg = app.config.get_per('defaultstatusmsg', status_, 'message') msg = helpers.from_one_line(msg) enabled = app.config.get_per('defaultstatusmsg', status_, 'enabled') iter_ = model.append() uf_show = helpers.get_uf_show(status_) model.set(iter_, 0, status_, 1, uf_show, 2, msg, 3, enabled) def on_default_msg_cell_edited(self, cell, row, new_text): model = self._ui.default_msg_treeview.get_model() iter_ = model.get_iter_from_string(row) model.set_value(iter_, 2, new_text) def default_msg_toggled_cb(self, cell, path): model = self._ui.default_msg_treeview.get_model() model[path][3] = not model[path][3] def on_default_msg_treemodel_row_changed(self, model, path, iter_): status = model[iter_][0] message = model[iter_][2] message = helpers.to_one_line(message) app.config.set_per('defaultstatusmsg', status, 'enabled', model[iter_][3]) app.config.set_per('defaultstatusmsg', status, 'message', message) def save_status_messages(self, model): for msg in app.config.get_per('statusmsg'): app.config.del_per('statusmsg', msg) iter_ = model.get_iter_first() while iter_: val = model[iter_][0] if model[iter_][1]: # We have a preset message if not val: # No title, use message text for title val = model[iter_][1] app.config.add_per('statusmsg', val) msg = helpers.to_one_line(model[iter_][1]) app.config.set_per('statusmsg', val, 'message', msg) i = 2 # Store mood / activity for subname in ('activity', 'subactivity', 'activity_text', 'mood', 'mood_text'): val2 = model[iter_][i] if not val2: val2 = '' app.config.set_per('statusmsg', val, subname, val2) i += 1 iter_ = model.iter_next(iter_) def on_msg_treemodel_row_changed(self, model, path, iter_): self.save_status_messages(model) def on_msg_treemodel_row_deleted(self, model, path): self.save_status_messages(model) def fill_msg_treeview(self): self._ui.delete_msg_button.set_sensitive(False) model = self._ui.msg_treeview.get_model() model.clear() preset_status = [] for msg_name in app.config.get_per('statusmsg'): if msg_name.startswith('_last_'): continue preset_status.append(msg_name) preset_status.sort() for msg_name in preset_status: msg_text = app.config.get_per('statusmsg', msg_name, 'message') msg_text = helpers.from_one_line(msg_text) activity = app.config.get_per('statusmsg', msg_name, 'activity') subactivity = app.config.get_per('statusmsg', msg_name, 'subactivity') activity_text = app.config.get_per('statusmsg', msg_name, 'activity_text') mood = app.config.get_per('statusmsg', msg_name, 'mood') mood_text = app.config.get_per('statusmsg', msg_name, 'mood_text') iter_ = model.append() model.set(iter_, 0, msg_name, 1, msg_text, 2, activity, 3, subactivity, 4, activity_text, 5, mood, 6, mood_text) def on_msg_cell_edited(self, cell, row, new_text): model = self._ui.msg_treeview.get_model() iter_ = model.get_iter_from_string(row) model.set_value(iter_, 0, new_text) def on_msg_treeview_cursor_changed(self, widget, data=None): sel = self._ui.msg_treeview.get_selection() if not sel: return (model, iter_) = sel.get_selected() if not iter_: return self._ui.delete_msg_button.set_sensitive(True) buf = self._ui.msg_textview.get_buffer() msg = model[iter_][1] buf.set_text(msg) def on_new_msg_button_clicked(self, widget, data=None): model = self._ui.msg_treeview.get_model() iter_ = model.append() model.set( iter_, 0, _('status message title'), 1, _('status message text')) self._ui.msg_treeview.set_cursor(model.get_path(iter_)) def on_delete_msg_button_clicked(self, widget, data=None): sel = self._ui.msg_treeview.get_selection() if not sel: return (model, iter_) = sel.get_selected() if not iter_: return buf = self._ui.msg_textview.get_buffer() model.remove(iter_) buf.set_text('') self._ui.delete_msg_button.set_sensitive(False) def on_msg_textview_changed(self, widget, data=None): sel = self._ui.msg_treeview.get_selection() if not sel: return (model, iter_) = sel.get_selected() if not iter_: return buf = self._ui.msg_textview.get_buffer() first_iter, end_iter = buf.get_bounds() model.set_value(iter_, 1, buf.get_text(first_iter, end_iter, True)) def on_msg_treeview_key_press_event(self, widget, event): if event.keyval == Gdk.KEY_Delete: self.on_delete_msg_button_clicked(widget) ### Privacy tab ### def on_send_idle_time_checkbutton_toggled(self, widget): widget.set_inconsistent(False) self.on_per_account_checkbutton_toggled(widget, 'send_idle_time') def on_send_time_info_checkbutton_toggled(self, widget): widget.set_inconsistent(False) self.on_per_account_checkbutton_toggled(widget, 'send_time_info') def on_send_os_info_checkbutton_toggled(self, widget): widget.set_inconsistent(False) self.on_per_account_checkbutton_toggled(widget, 'send_os_info') def on_ignore_events_from_unknown_contacts_checkbutton_toggled(self, widget): widget.set_inconsistent(False) self.on_per_account_checkbutton_toggled(widget, 'ignore_unknown_contacts') def on_outgoing_chat_states_combobox_changed(self, widget): active = widget.get_active() old_value = app.config.get('outgoing_chat_state_notifications') if active == 0: # all app.config.set('outgoing_chat_state_notifications', 'all') elif active == 1: # only composing app.config.set('outgoing_chat_state_notifications', 'composing_only') else: # disabled app.config.set('outgoing_chat_state_notifications', 'disabled') new_value = app.config.get('outgoing_chat_state_notifications') if 'disabled' in (old_value, new_value): # We changed from disabled to sth else or vice versa helpers.update_optional_features() ### Style ### @staticmethod def on_theme_combobox_changed(combobox): theme = combobox.get_active_id() app.config.set('roster_theme', theme) app.css_config.change_theme(theme) # Begin repainting themed widgets throughout app.interface.roster.repaint_themed_widgets() app.interface.roster.change_roster_style(None) def update_theme_list(self): with self._ui.theme_combobox.handler_block(self.changed_id): self._ui.theme_combobox.remove_all() self._ui.theme_combobox.append('default', 'default') for config_theme in app.css_config.themes: self._ui.theme_combobox.append(config_theme, config_theme) self._ui.theme_combobox.set_active_id(app.config.get('roster_theme')) def on_manage_theme_button_clicked(self, widget): window = app.get_app_window(Themes) if window is None: Themes(self) else: window.present() def on_dark_theme_changed(self, widget): app.css_config.set_dark_theme(int(widget.get_active_id())) def on_emoticons_combobox_changed(self, widget): active = widget.get_active() model = widget.get_model() emot_theme = model[active][0] app.config.set('emoticons_theme', emot_theme) from gajim.gtk.emoji_chooser import emoji_chooser emoji_chooser.load() self.toggle_emoticons() def on_convert_ascii_toggle(self, widget): app.config.set('ascii_emoticons', widget.get_active()) app.interface.make_regexps() def toggle_emoticons(self): """ Update emoticons state in Opened Chat Windows """ for ctrl in self._get_all_controls(): ctrl.toggle_emoticons() def on_iconset_combobox_changed(self, widget): model = widget.get_model() active = widget.get_active() icon_string = model[active][1] app.config.set('iconset', icon_string) app.interface.roster.update_icons() def on_transports_iconsets_checkbutton_toggled(self, widget): self.on_checkbutton_toggled(widget, 'use_transports_iconsets') ### Audio/Video tab ### def on_av_combobox_changed(self, combobox, config_name): model = combobox.get_model() active = combobox.get_active() device = model[active][1] app.config.set(config_name, device) def on_audio_input_combobox_changed(self, widget): self.on_av_combobox_changed(widget, 'audio_input_device') def on_audio_output_combobox_changed(self, widget): self.on_av_combobox_changed(widget, 'audio_output_device') def on_video_input_combobox_changed(self, widget): self.on_av_combobox_changed(widget, 'video_input_device') def on_video_output_combobox_changed(self, widget): self.on_av_combobox_changed(widget, 'video_output_device') def on_video_framerate_combobox_changed(self, widget): self.on_av_combobox_changed(widget, 'video_framerate') def on_video_size_combobox_changed(self, widget): self.on_av_combobox_changed(widget, 'video_size') def on_video_see_self_checkbutton_toggled(self, widget): self.on_checkbutton_toggled(widget, 'video_see_self') def on_stun_checkbutton_toggled(self, widget): self.on_checkbutton_toggled(widget, 'use_stun_server', [ self._ui.stun_server_entry]) def stun_server_entry_changed(self, widget): app.config.set('stun_server', widget.get_text()) ### Advanced tab ### # Applications def on_applications_combobox_changed(self, widget): if widget.get_active() == 0: app.config.set('autodetect_browser_mailer', True) self._ui.custom_apps_frame.hide() elif widget.get_active() == 1: app.config.set('autodetect_browser_mailer', False) self._ui.custom_apps_frame.show() def on_custom_browser_entry_changed(self, widget): app.config.set('custombrowser', widget.get_text()) def on_custom_mail_client_entry_changed(self, widget): app.config.set('custommailapp', widget.get_text()) def on_custom_file_manager_entry_changed(self, widget): app.config.set('custom_file_manager', widget.get_text()) # Proxies def on_proxies_combobox_changed(self, widget): active = widget.get_active() if active == -1: return proxy = widget.get_model()[active][0] if proxy == _('No Proxy'): proxy = '' app.config.set('global_proxy', proxy) def on_manage_proxies_button_clicked(self, widget): if 'manage_proxies' in app.interface.instances: app.interface.instances['manage_proxies'].window.present() else: app.interface.instances['manage_proxies'] = ManageProxies() def update_proxy_list(self): our_proxy = app.config.get('global_proxy') if not our_proxy: our_proxy = _('No Proxy') model = self._ui.proxies_combobox.get_model() model.clear() proxies = app.config.get_per('proxies') proxies.insert(0, _('No Proxy')) for index, proxy in enumerate(proxies): model.append([proxy]) if our_proxy == proxy: self._ui.proxies_combobox.set_active(index) if not our_proxy in proxies: self._ui.proxies_combobox.set_active(0) # Log status changes of contacts def on_log_show_changes_checkbutton_toggled(self, widget): self.on_checkbutton_toggled(widget, 'log_contact_status_changes') # Enable debug logging def on_enable_logging_toggled(self, widget): app.set_win_debug_mode(widget.get_active()) # Advanced Config Editor (ACE) def on_open_advanced_editor_button_clicked(self, widget, data=None): if 'advanced_config' in app.interface.instances: app.interface.instances['advanced_config'].window.present() else: app.interface.instances['advanced_config'] = AdvancedConfig(self)