# 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 logging import sys from gi.repository import Gtk from gi.repository import Gdk from gajim.common import app from gajim.common import configpaths from gajim.common import helpers from gajim.common.const import THRESHOLD_OPTIONS from gajim.common.nec import NetworkEvent from gajim.common.i18n import _ from gajim.common.helpers import open_file from gajim.common.multimedia_helpers import AudioInputManager from gajim.common.multimedia_helpers import AudioOutputManager from gajim.common.multimedia_helpers import VideoInputManager from gajim.chat_control_base import ChatControlBase from .const import Setting from .const import SettingKind from .const import SettingType from .const import ControlType from .emoji_chooser import emoji_chooser from .settings import SettingsBox from .settings import SettingsDialog from .sidebar_switcher import SideBarSwitcher from .video_preview import VideoPreview from .util import get_available_iconsets from .util import open_window from .util import get_app_window from .util import get_builder if app.is_installed('GSPELL'): from gi.repository import Gspell # pylint: disable=ungrouped-imports log = logging.getLogger('gajim.gui.preferences') 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_name('PreferencesWindow') self.set_default_size(900, 650) self.set_resizable(True) self.set_title(_('Preferences')) self._ui = get_builder('preferences.ui') self._video_preview = None self._prefs = {} side_bar_switcher = SideBarSwitcher() side_bar_switcher.set_stack(self._ui.stack) self._ui.grid.attach(side_bar_switcher, 0, 0, 1, 1) self.add(self._ui.grid) self._check_emoji_theme() prefs = [ ('window_behaviour', WindowBehaviour), ('contact_list', ContactList), ('chats', Chats), ('group_chats', GroupChats), ('visual_notifications', VisualNotifications), ('sounds', Sounds), ('status_message', StatusMessage), ('automatic_status', AutomaticStatus), ('themes', Themes), ('emoji', Emoji), ('status_icon', StatusIcon), ('server', Server), ('audio', Audio), ('video', Video), ('miscellaneous', Miscellaneous), ('advanced', Advanced), ] self._add_prefs(prefs) self._add_video_preview() self._ui.audio_video_info_bar.set_revealed(not app.is_installed('AV')) self.connect('key-press-event', self._on_key_press) self._ui.connect_signals(self) self.show_all() if sys.platform not in ('win32', 'darwin'): self._ui.emoji.hide() def get_ui(self): return self._ui def _add_prefs(self, prefs): for ui_name, klass in prefs: pref_box = getattr(self._ui, ui_name) if ui_name == 'video' and sys.platform == 'win32': continue pref = klass(self) pref_box.add(pref) self._prefs[ui_name] = pref def _add_video_preview(self): if sys.platform == 'win32': return self._video_preview = VideoPreview() self._ui.video.add(self._video_preview.widget) def _on_key_press(self, _widget, event): if event.keyval == Gdk.KEY_Escape: self.destroy() def get_video_preview(self): return self._video_preview @staticmethod def _on_features_clicked(_widget, _response): open_window('Features') def update_theme_list(self): self._prefs['themes'].update_theme_list() def update_proxy_list(self): self._prefs['miscellaneous'].update_proxy_list() @staticmethod def get_all_controls(): 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 @staticmethod def get_all_muc_controls(): for ctrl in app.interface.msg_win_mgr.get_controls( ControlType.GROUPCHAT): yield ctrl for account in app.connections: for ctrl in app.interface.minimized_controls[account].values(): yield ctrl @staticmethod def _check_emoji_theme(): # Ensure selected emoji theme is valid emoji_themes = helpers.get_available_emoticon_themes() settings_theme = app.settings.get('emoticons_theme') if settings_theme not in emoji_themes: app.settings.set('emoticons_theme', 'font') class PreferenceBox(SettingsBox): def __init__(self, settings): SettingsBox.__init__(self, None) self.get_style_context().add_class('settings-border') self.set_selection_mode(Gtk.SelectionMode.NONE) self.set_vexpand(False) self.set_valign(Gtk.Align.END) for setting in settings: self.add_setting(setting) self.update_states() class WindowBehaviour(PreferenceBox): def __init__(self, *args): win_layout_items = { 'never': _('Detached contact list with detached chats'), 'always': _('Detached contact list with single chat'), 'always_with_roster': _('Single window for everything'), 'peracct': _('Detached contact list with chats grouped by account'), 'pertype': _('Detached contact list with chats grouped by type'), } roster_on_startup_items = { 'always': _('Always'), 'never': _('Never'), 'last_state': _('Restore last state'), } tab_position_items = { 'top': _('Top'), 'bottom': _('Bottom'), 'left': _('Left'), 'Right': _('Right'), } settings = [ Setting(SettingKind.POPOVER, _('Window Layout'), SettingType.CONFIG, 'one_message_window', props={'entries': win_layout_items}, callback=self._on_win_layout_changed), Setting(SettingKind.POPOVER, _('Contact List on Startup'), SettingType.CONFIG, 'show_roster_on_startup', props={'entries': roster_on_startup_items}, desc=_('Show contact list when starting Gajim')), Setting(SettingKind.SWITCH, _('Quit on Close'), SettingType.CONFIG, 'quit_on_roster_x_button', desc=_('Quit when closing contact list')), Setting(SettingKind.POPOVER, _('Tab Position'), SettingType.CONFIG, 'tabs_position', props={'entries': tab_position_items}, desc=_('Placement of chat window tabs'), callback=self._on_win_layout_changed), ] PreferenceBox.__init__(self, settings) @staticmethod def _on_win_layout_changed(*args): app.interface.msg_win_mgr.reconfig() class ContactList(PreferenceBox): def __init__(self, *args): settings = [ Setting(SettingKind.SWITCH, _('Merge Accounts'), SettingType.CONFIG, 'mergeaccounts', callback=self._on_merge_accounts), Setting(SettingKind.SWITCH, _('Enable Metacontacts'), SettingType.CONFIG, 'metacontacts_enabled'), Setting(SettingKind.SWITCH, _('Show Avatars'), SettingType.CONFIG, 'show_avatars_in_roster', callback=self._on_show_avatar_in_roster_changed), Setting(SettingKind.SWITCH, _('Show Status Message'), SettingType.CONFIG, 'show_status_msgs_in_roster', callback=self._on_show_status_in_roster), Setting(SettingKind.SWITCH, _('Sort Contacts by Status'), SettingType.CONFIG, 'sort_by_show_in_roster', callback=self._on_sort_by_show_in_roster), Setting(SettingKind.SWITCH, _('Show Mood'), SettingType.CONFIG, 'show_mood_in_roster'), Setting(SettingKind.SWITCH, _('Show Activity'), SettingType.CONFIG, 'show_activity_in_roster'), Setting(SettingKind.SWITCH, _('Show Tune'), SettingType.CONFIG, 'show_tunes_in_roster'), Setting(SettingKind.SWITCH, _('Show Location'), SettingType.CONFIG, 'show_location_in_roster'), ] PreferenceBox.__init__(self, settings) @staticmethod def _on_merge_accounts(*args): app.app.activate_action('merge') @staticmethod def _on_show_avatar_in_roster_changed(*args): app.interface.roster.setup_and_draw_roster() @staticmethod def _on_show_status_in_roster(*args): app.interface.roster.setup_and_draw_roster() controls = get_app_window('Preferences').get_all_muc_controls() for ctrl in controls: ctrl.roster.draw_contacts() @staticmethod def _on_sort_by_show_in_roster(*args): app.interface.roster.setup_and_draw_roster() class Chats(PreferenceBox): def __init__(self, *args): speller_desc = None if not app.is_installed('GSPELL'): speller_desc = _('Needs gspell to be installed') settings = [ Setting(SettingKind.SWITCH, _('Spell Checking'), SettingType.CONFIG, 'use_speller', desc=speller_desc, enabled_func=self._speller_available, callback=self._on_use_speller), Setting(SettingKind.SWITCH, _('Message Receipts (✔)'), SettingType.CONFIG, 'positive_184_ack', desc=_('Add a checkmark to received messages')), Setting(SettingKind.SWITCH, _('XHTML Formatting'), SettingType.CONFIG, 'show_xhtml', desc=_('Render XHTML styles (colors, etc.) of incoming ' 'messages')), Setting(SettingKind.SWITCH, _('Show Send Message Button'), SettingType.CONFIG, 'show_send_message_button'), Setting(SettingKind.SWITCH, _('Show Status Message'), SettingType.CONFIG, 'print_status_in_chats'), Setting(SettingKind.SWITCH, _('Show Chat State In Tabs'), SettingType.CONFIG, 'show_chatstate_in_tabs', desc=_('Show the contact’s chat state (e.g. typing) in ' 'the chat’s tab')), Setting(SettingKind.SWITCH, _('Show Chat State In Banner'), SettingType.CONFIG, 'show_chatstate_in_banner', desc=_('Show the contact’s chat state (e.g. typing) in ' 'the chats tab’s banner')), Setting(SettingKind.SWITCH, _('Display Chat State In Contact List'), SettingType.CONFIG, 'show_chatstate_in_roster', desc=_('Show the contact’s chat state (e.g. typing) in ' 'the contact list')), ] PreferenceBox.__init__(self, settings) @staticmethod def _speller_available(): return app.is_installed('GSPELL') @staticmethod def _on_use_speller(value, *args): if not value: return lang = app.settings.get('speller_language') gspell_lang = Gspell.language_lookup(lang) if gspell_lang is None: gspell_lang = Gspell.language_get_default() app.settings.set('speller_language', gspell_lang.get_code()) for ctrl in get_app_window('Preferences').get_all_controls(): if isinstance(ctrl, ChatControlBase): ctrl.set_speller() class GroupChats(PreferenceBox): def __init__(self, *args): settings = [ Setting(SettingKind.SWITCH, _('Show Subject'), SettingType.CONFIG, 'show_subject_on_join'), Setting(SettingKind.SWITCH, _('Sort Contacts by Status'), SettingType.CONFIG, 'sort_by_show_in_muc', callback=self._on_sort_by_show_in_muc), Setting(SettingKind.POPOVER, _('Default Sync Threshold'), SettingType.CONFIG, 'gc_sync_threshold_public_default', desc=_('Default for new public group chats'), props={'entries': THRESHOLD_OPTIONS}), Setting(SettingKind.SWITCH, _('Direct Messages'), SettingType.CONFIG, 'muc_prefer_direct_msg', desc=_('Prefer direct messages in private group chats ')), Setting(SettingKind.SWITCH, _('Show Joined / Left'), SettingType.CONFIG, 'gc_print_join_left_default', desc=_('Default for new group chats'), props={'button-text':_('Reset'), 'button-tooltip': _('Reset all group chats to the ' 'current default value'), 'button-style': 'destructive-action', 'button-callback': self._reset_join_left}), Setting(SettingKind.SWITCH, _('Show Status Changes'), SettingType.CONFIG, 'gc_print_status_default', desc=_('Default for new group chats'), props={'button-text':_('Reset'), 'button-tooltip': _('Reset all group chats to the ' 'current default value'), 'button-style': 'destructive-action', 'button-callback': self._reset_print_status}), ] PreferenceBox.__init__(self, settings) @staticmethod def _on_sort_by_show_in_muc(*args): for ctrl in get_app_window('Preferences').get_all_muc_controls(): ctrl.roster.invalidate_sort() @staticmethod def _reset_join_left(button): button.set_sensitive(False) app.settings.set_group_chat_settings('print_join_left', None) @staticmethod def _reset_print_status(button): button.set_sensitive(False) app.settings.set_group_chat_settings('print_status', None) class VisualNotifications(PreferenceBox): def __init__(self, *args): trayicon_items = { 'never': _('Hide icon'), 'on_event': _('Only show for pending events'), 'always': _('Always show icon'), } settings = [ Setting(SettingKind.POPOVER, _('Notification Area Icon'), SettingType.CONFIG, 'trayicon', props={'entries': trayicon_items}, callback=self._on_trayicon), Setting(SettingKind.SWITCH, _('Open Events'), SettingType.CONFIG, 'autopopup', desc=_('Open events instead of showing a notification ' 'in the contact list')), Setting(SettingKind.NOTIFICATIONS, _('Show Notifications'), SettingType.DIALOG, props={'dialog': NotificationsDialog}), ] PreferenceBox.__init__(self, settings) @staticmethod def _on_trayicon(value, *args): if value == 'never': app.interface.hide_systray() elif value == 'on_event': app.interface.show_systray() else: app.interface.show_systray() class NotificationsDialog(SettingsDialog): def __init__(self, account, parent): settings = [ Setting(SettingKind.SWITCH, _('Show Notifications'), SettingType.CONFIG, 'show_notifications'), Setting(SettingKind.SWITCH, _('Notifications When Away'), SettingType.CONFIG, 'autopopupaway', desc=_('Show notifications even if you are Away, ' 'Busy, etc.'), bind='show_notifications'), ] SettingsDialog.__init__(self, parent, _('Notifications'), Gtk.DialogFlags.MODAL, settings, account) class Sounds(PreferenceBox): def __init__(self, *args): settings = [ Setting(SettingKind.SWITCH, _('Play Sounds'), SettingType.CONFIG, 'sounds_on', desc=_('Play sounds to notify about events'), props={'button-icon-name': 'preferences-system-symbolic', 'button-callback': self._on_manage_sounds}), Setting(SettingKind.SWITCH, _('Sounds When Away'), SettingType.CONFIG, 'sounddnd', desc=_('Play sounds even when you are Away, Busy, etc.'), bind='sounds_on'), ] PreferenceBox.__init__(self, settings) def _on_manage_sounds(self, *args): open_window('ManageSounds', transient_for=self.get_toplevel()) class StatusMessage(PreferenceBox): def __init__(self, *args): settings = [ Setting(SettingKind.SWITCH, _('Sign In'), SettingType.CONFIG, 'ask_online_status'), Setting(SettingKind.SWITCH, _('Sign Out'), SettingType.CONFIG, 'ask_offline_status'), Setting(SettingKind.SWITCH, _('Status Change'), SettingType.CONFIG, 'always_ask_for_status_message'), ] PreferenceBox.__init__(self, settings) class AutomaticStatus(PreferenceBox): def __init__(self, *args): settings = [ Setting(SettingKind.AUTO_AWAY, _('Auto Away'), SettingType.DIALOG, desc=_('Change your status to \'Away\' after a certain ' 'amount of time'), props={'dialog': AutoAwayDialog}), Setting(SettingKind.AUTO_EXTENDED_AWAY, _('Auto Not Available'), SettingType.DIALOG, desc=_('Change your status to \'Not Available\' after a ' 'certain amount of time'), props={'dialog': AutoExtendedAwayDialog}), ] PreferenceBox.__init__(self, settings) @staticmethod def _get_auto_away(): return app.settings.get('autoaway') @staticmethod def _get_auto_xa(): return app.settings.get('autoxa') class AutoAwayDialog(SettingsDialog): def __init__(self, account, parent): settings = [ Setting(SettingKind.SWITCH, _('Auto Away'), SettingType.CONFIG, 'autoaway'), Setting(SettingKind.SPIN, _('Time Until Away'), SettingType.CONFIG, 'autoawaytime', desc=_('Minutes until your status gets changed'), props={'range_': (1, 720)}, bind='autoaway'), Setting(SettingKind.ENTRY, _('Status Message'), SettingType.CONFIG, 'autoaway_message', bind='autoaway'), ] SettingsDialog.__init__(self, parent, _('Auto Away Settings'), Gtk.DialogFlags.MODAL, settings, account) class AutoExtendedAwayDialog(SettingsDialog): def __init__(self, account, parent): settings = [ Setting(SettingKind.SWITCH, _('Auto Not Available'), SettingType.CONFIG, 'autoxa'), Setting(SettingKind.SPIN, _('Time Until Not Available'), SettingType.CONFIG, 'autoxatime', desc=_('Minutes until your status gets changed'), props={'range_': (1, 720)}, bind='autoxa'), Setting(SettingKind.ENTRY, _('Status Message'), SettingType.CONFIG, 'autoxa_message', bind='autoxa'), ] SettingsDialog.__init__(self, parent, _('Auto Extended Away Settings'), Gtk.DialogFlags.MODAL, settings, account) class Themes(PreferenceBox): def __init__(self, *args): theme_items = self._get_theme_items() dark_theme_items = { 0: _('Disabled'), 1: _('Enabled'), 2: _('System'), } settings = [ Setting(SettingKind.POPOVER, _('Dark Theme'), SettingType.CONFIG, 'dark_theme', props={'entries': dark_theme_items}, callback=self._on_dark_theme), Setting(SettingKind.POPOVER, _('Theme'), SettingType.CONFIG, 'roster_theme', name='roster_theme', props={'entries': theme_items, 'button-icon-name': 'preferences-system-symbolic', 'button-callback': self._on_edit_themes}, callback=self._on_theme_changed), ] PreferenceBox.__init__(self, settings) @staticmethod def _get_theme_items(): theme_items = ['default'] for settings_theme in app.css_config.themes: theme_items.append(settings_theme) return theme_items def update_theme_list(self): self.get_setting('roster_theme').update_entries(self._get_theme_items()) def _on_edit_themes(self, *args): open_window('Themes', transient=self.get_toplevel()) @staticmethod def _on_theme_changed(value, *args): app.css_config.change_theme(value) app.nec.push_incoming_event(NetworkEvent('theme-update')) app.nec.push_incoming_event(NetworkEvent('style-changed')) app.interface.roster.repaint_themed_widgets() app.interface.roster.change_roster_style(None) @staticmethod def _on_dark_theme(value, *args): app.css_config.set_dark_theme(int(value)) app.nec.push_incoming_event(NetworkEvent('style-changed')) class Emoji(PreferenceBox): def __init__(self, *args): if sys.platform not in ('win32', 'darwin'): PreferenceBox.__init__(self, []) return emoji_themes_items = [] for theme in helpers.get_available_emoticon_themes(): emoji_themes_items.append(theme) settings = [ Setting(SettingKind.POPOVER, _('Emoji Theme'), SettingType.CONFIG, 'emoticons_theme', desc=_('Choose from various emoji styles'), props={'entries': emoji_themes_items}, callback=self._on_emoticons_theme) ] PreferenceBox.__init__(self, settings) def _on_emoticons_theme(self, *args): emoji_chooser.load() self._toggle_emoticons() @staticmethod def _toggle_emoticons(): controls = get_app_window('Preferences').get_all_controls() for ctrl in controls: ctrl.toggle_emoticons() class StatusIcon(PreferenceBox): def __init__(self, *args): iconset_items = [] for _index, iconset_name in enumerate(get_available_iconsets()): iconset_items.append(iconset_name) settings = [ Setting(SettingKind.POPOVER, _('Status Icon Set'), SettingType.CONFIG, 'iconset', props={'entries': iconset_items}, callback=self._on_iconset_changed), Setting(SettingKind.SWITCH, _('Use Transport Icons'), SettingType.CONFIG, 'use_transports_iconsets', desc=_('Display protocol-specific status icons ' '(ICQ, ..)')), ] PreferenceBox.__init__(self, settings) @staticmethod def _on_iconset_changed(*args): app.interface.roster.update_icons() class Server(PreferenceBox): def __init__(self, *args): settings = [ Setting(SettingKind.USE_STUN_SERVER, _('Use STUN Server'), SettingType.DIALOG, desc=_('Helps to establish calls through firewalls'), props={'dialog': StunServerDialog}), ] PreferenceBox.__init__(self, settings) self.set_sensitive(app.is_installed('AV')) class StunServerDialog(SettingsDialog): def __init__(self, account, parent): settings = [ Setting(SettingKind.SWITCH, _('Use STUN Server'), SettingType.CONFIG, 'use_stun_server'), Setting(SettingKind.ENTRY, _('STUN Server'), SettingType.CONFIG, 'stun_server', bind='use_stun_server') ] SettingsDialog.__init__(self, parent, _('STUN Server Settings'), Gtk.DialogFlags.MODAL, settings, account) class Audio(PreferenceBox): def __init__(self, *args): deps_installed = app.is_installed('AV') audio_input_devices = {} audio_output_devices = {} if deps_installed: audio_input_devices = AudioInputManager().get_devices() audio_output_devices = AudioOutputManager().get_devices() audio_input_items = self._create_av_combo_items(audio_input_devices) audio_output_items = self._create_av_combo_items(audio_output_devices) settings = [ Setting(SettingKind.POPOVER, _('Audio Input Device'), SettingType.CONFIG, 'audio_input_device', desc=_('Select your audio input (e.g. microphone)'), props={'entries': audio_input_items}), Setting(SettingKind.POPOVER, _('Audio Output Device'), SettingType.CONFIG, 'audio_output_device', desc=_('Select an audio output (e.g. speakers, ' 'headphones)'), props={'entries': audio_output_items}), ] PreferenceBox.__init__(self, settings) self.set_sensitive(deps_installed) @staticmethod def _create_av_combo_items(items_dict): items = enumerate(sorted( items_dict.items(), key=lambda x: '' if x[1].startswith('auto') else x[0].lower())) combo_items = {} for _index, (name, value) in items: combo_items[value] = name return combo_items class Video(PreferenceBox): def __init__(self, *args): deps_installed = app.is_installed('AV') video_input_devices = {} if deps_installed: video_input_devices = VideoInputManager().get_devices() video_input_items = self._create_av_combo_items(video_input_devices) video_framerates = { '': _('Default'), '15/1': '15 fps', '10/1': '10 fps', '5/1': '5 fps', '5/2': '2.5 fps', } video_sizes = { '': _('Default'), '800x600': '800x600', '640x480': '640x480', '320x240': '320x240', } settings = [ Setting(SettingKind.POPOVER, _('Video Input Device'), SettingType.CONFIG, 'video_input_device', props={'entries': video_input_items}, desc=_('Select your video input device (e.g. webcam, ' 'screen capture)'), callback=self._on_video_input_changed), Setting(SettingKind.POPOVER, _('Video Framerate'), SettingType.CONFIG, 'video_framerate', props={'entries': video_framerates}), Setting(SettingKind.POPOVER, _('Video Resolution'), SettingType.CONFIG, 'video_size', props={'entries': video_sizes}), Setting(SettingKind.SWITCH, _('Show My Video Stream'), SettingType.CONFIG, 'video_see_self', desc=_('Show your own video stream in calls')), Setting(SettingKind.SWITCH, _('Live Preview'), SettingType.VALUE, desc=_('Show a live preview to test your video source'), callback=self._toggle_live_preview), ] PreferenceBox.__init__(self, settings) self.set_sensitive(deps_installed) @staticmethod def _on_video_input_changed(value, *args): preview = get_app_window('Preferences').get_video_preview() if preview is None or not preview.is_active: # changed signal gets triggered when we fill the combobox return preview.refresh() @staticmethod def _toggle_live_preview(value, *args): preview = get_app_window('Preferences').get_video_preview() preview.toggle_preview(value) @staticmethod def _create_av_combo_items(items_dict): items = enumerate(sorted( items_dict.items(), key=lambda x: '' if x[1].startswith('auto') else x[0].lower())) combo_items = {} for _index, (name, value) in items: combo_items[value] = name return combo_items class Miscellaneous(PreferenceBox): def __init__(self, pref_window): self._hints_list = [ 'start_chat', ] settings = [ Setting(SettingKind.POPOVER, _('Global Proxy'), SettingType.CONFIG, 'global_proxy', name='global_proxy', props={'entries': self._get_proxies(), 'default-text': _('System'), 'button-icon-name': 'preferences-system-symbolic', 'button-callback': self._on_proxy_edit}), Setting(SettingKind.SWITCH, _('Use System Keyring'), SettingType.CONFIG, 'use_keyring', desc=_('Use your system’s keyring to store passwords')), ] if sys.platform in ('win32', 'darwin'): settings.append( Setting(SettingKind.SWITCH, _('Check For Updates'), SettingType.CONFIG, 'check_for_update', desc=_('Check for Gajim updates periodically'))) PreferenceBox.__init__(self, settings) reset_button = pref_window.get_ui().reset_button reset_button.connect('clicked', self._on_reset_hints) reset_button.set_sensitive(self._check_hints_reset) @staticmethod def _get_proxies(): return {proxy: proxy for proxy in app.settings.get_proxies()} @staticmethod def _on_proxy_edit(*args): open_window('ManageProxies') def update_proxy_list(self): self.get_setting('global_proxy').update_entries(self._get_proxies()) def _check_hints_reset(self): for hint in self._hints_list: if app.settings.get('show_help_%s' % hint) is False: return True return False def _on_reset_hints(self, button): for hint in self._hints_list: app.settings.set('show_help_%s' % hint, True) button.set_sensitive(False) class Advanced(PreferenceBox): def __init__(self, pref_window): settings = [ Setting(SettingKind.SWITCH, _('Debug Logging'), SettingType.VALUE, app.get_debug_mode(), props={'button-icon-name': 'folder-symbolic', 'button-callback': self._on_open_debug_logs}, callback=self._on_debug_logging), ] PreferenceBox.__init__(self, settings) pref_window.get_ui().ace_button.connect( 'clicked', self._on_advanced_config_editor) @staticmethod def _on_debug_logging(value, *args): app.set_debug_mode(value) @staticmethod def _on_open_debug_logs(*args): open_file(configpaths.get('DEBUG')) @staticmethod def _on_advanced_config_editor(*args): open_window('AdvancedConfig')