1# Copyright (C) 2018 Philipp Hörist <philipp AT hoerist.com> 2# 3# This file is part of Gajim. 4# 5# Gajim is free software; you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published 7# by the Free Software Foundation; version 3 only. 8# 9# Gajim is distributed in the hope that it will be useful, 10# but WITHOUT ANY WARRANTY; without even the implied warranty of 11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12# GNU General Public License for more details. 13# 14# You should have received a copy of the GNU General Public License 15# along with Gajim. If not, see <http://www.gnu.org/licenses/>. 16 17from gi.repository import Gtk 18from gi.repository import GLib 19from gi.repository import Gdk 20from gi.repository import Pango 21 22from gajim.common import app 23from gajim.common import passwords 24from gajim.common.i18n import _ 25from gajim.common.i18n import Q_ 26 27from gajim import gtkgui_helpers 28 29from .util import get_image_button 30from .util import MaxWidthComboBoxText 31from .util import open_window 32from .const import SettingKind 33from .const import SettingType 34 35 36class SettingsDialog(Gtk.ApplicationWindow): 37 def __init__(self, parent, title, flags, settings, account, 38 extend=None): 39 Gtk.ApplicationWindow.__init__(self) 40 self.set_application(app.app) 41 self.set_show_menubar(False) 42 self.set_title(title) 43 self.set_transient_for(parent) 44 self.set_resizable(False) 45 self.set_default_size(250, -1) 46 self.set_type_hint(Gdk.WindowTypeHint.DIALOG) 47 self.get_style_context().add_class('settings-dialog') 48 self.account = account 49 if flags == Gtk.DialogFlags.MODAL: 50 self.set_modal(True) 51 elif flags == Gtk.DialogFlags.DESTROY_WITH_PARENT: 52 self.set_destroy_with_parent(True) 53 54 self.listbox = SettingsBox(account, extend=extend) 55 self.listbox.set_hexpand(True) 56 self.listbox.set_selection_mode(Gtk.SelectionMode.NONE) 57 58 for setting in settings: 59 self.listbox.add_setting(setting) 60 self.listbox.update_states() 61 62 self.add(self.listbox) 63 64 self.show_all() 65 self.connect_after('key-press-event', self.on_key_press) 66 67 def on_key_press(self, _widget, event): 68 if event.keyval == Gdk.KEY_Escape: 69 self.destroy() 70 71 def get_setting(self, name): 72 return self.listbox.get_setting(name) 73 74 75class SettingsBox(Gtk.ListBox): 76 def __init__(self, account=None, jid=None, extend=None): 77 Gtk.ListBox.__init__(self) 78 self.get_style_context().add_class('settings-box') 79 self.account = account 80 self.jid = jid 81 self.named_settings = {} 82 83 self.map = { 84 SettingKind.SWITCH: SwitchSetting, 85 SettingKind.SPIN: SpinSetting, 86 SettingKind.DIALOG: DialogSetting, 87 SettingKind.ENTRY: EntrySetting, 88 SettingKind.COLOR: ColorSetting, 89 SettingKind.ACTION: ActionSetting, 90 SettingKind.LOGIN: LoginSetting, 91 SettingKind.FILECHOOSER: FileChooserSetting, 92 SettingKind.CALLBACK: CallbackSetting, 93 SettingKind.PRIORITY: PrioritySetting, 94 SettingKind.HOSTNAME: CutstomHostnameSetting, 95 SettingKind.CHANGEPASSWORD: ChangePasswordSetting, 96 SettingKind.COMBO: ComboSetting, 97 SettingKind.POPOVER: PopoverSetting, 98 SettingKind.AUTO_AWAY: CutstomAutoAwaySetting, 99 SettingKind.AUTO_EXTENDED_AWAY: CutstomAutoExtendedAwaySetting, 100 SettingKind.USE_STUN_SERVER: CustomStunServerSetting, 101 SettingKind.NOTIFICATIONS: NotificationsSetting, 102 } 103 104 if extend is not None: 105 for setting, callback in extend: 106 self.map[setting] = callback 107 108 self.connect('row-activated', self.on_row_activated) 109 110 @staticmethod 111 def on_row_activated(_listbox, row): 112 row.on_row_activated() 113 114 def add_setting(self, setting): 115 if not isinstance(setting, Gtk.ListBoxRow): 116 if setting.props is not None: 117 listitem = self.map[setting.kind](self.account, 118 self.jid, 119 *setting[1:-1], 120 **setting.props) 121 else: 122 listitem = self.map[setting.kind](self.account, 123 self.jid, 124 *setting[1:-1]) 125 126 if setting.name is not None: 127 self.named_settings[setting.name] = listitem 128 self.add(listitem) 129 130 def get_setting(self, name): 131 return self.named_settings[name] 132 133 def update_states(self): 134 for row in self.get_children(): 135 row.update_activatable() 136 137 138class GenericSetting(Gtk.ListBoxRow): 139 def __init__(self, 140 account, 141 jid, 142 label, 143 type_, 144 value, 145 name, 146 callback, 147 data, 148 desc, 149 bind, 150 inverted, 151 enabled_func): 152 153 Gtk.ListBoxRow.__init__(self) 154 self._grid = Gtk.Grid() 155 self._grid.set_size_request(-1, 30) 156 self._grid.set_column_spacing(12) 157 158 self.callback = callback 159 self.type_ = type_ 160 self.value = value 161 self.data = data 162 self.label = label 163 self.account = account 164 self.jid = jid 165 self.name = name 166 self.bind = bind 167 self.inverted = inverted 168 self.enabled_func = enabled_func 169 self.setting_value = self.get_value() 170 171 description_box = Gtk.Box( 172 orientation=Gtk.Orientation.VERTICAL, spacing=0) 173 description_box.set_valign(Gtk.Align.CENTER) 174 175 settingtext = Gtk.Label(label=label) 176 settingtext.set_hexpand(True) 177 settingtext.set_halign(Gtk.Align.START) 178 settingtext.set_valign(Gtk.Align.CENTER) 179 settingtext.set_vexpand(True) 180 description_box.add(settingtext) 181 182 if desc is not None: 183 description = Gtk.Label(label=desc) 184 description.set_name('SubDescription') 185 description.set_hexpand(True) 186 description.set_halign(Gtk.Align.START) 187 description.set_valign(Gtk.Align.CENTER) 188 description.set_xalign(0) 189 description.set_line_wrap(True) 190 description.set_line_wrap_mode(Pango.WrapMode.WORD) 191 description.set_max_width_chars(50) 192 description_box.add(description) 193 194 self._grid.add(description_box) 195 196 self.setting_box = Gtk.Box(spacing=12) 197 self.setting_box.set_size_request(200, -1) 198 self.setting_box.set_valign(Gtk.Align.CENTER) 199 self.setting_box.set_name('GenericSettingBox') 200 self._grid.add(self.setting_box) 201 self.add(self._grid) 202 203 self._bind_sensitive_state() 204 205 def _bind_sensitive_state(self): 206 if self.bind is None: 207 return 208 209 bind_setting_type, setting, account, jid = self._parse_bind() 210 211 app.settings.bind_signal(setting, 212 self, 213 'set_sensitive', 214 account=account, 215 jid=jid, 216 inverted=self.inverted) 217 218 if bind_setting_type == SettingType.CONTACT: 219 value = app.settings.get_contact_setting(account, jid, setting) 220 221 elif bind_setting_type == SettingType.GROUP_CHAT: 222 value = app.settings.get_group_chat_setting(account, jid, setting) 223 224 elif bind_setting_type == SettingType.ACCOUNT_CONFIG: 225 value = app.settings.get_account_setting(account, setting) 226 227 else: 228 value = app.settings.get(setting) 229 230 if self.inverted: 231 value = not value 232 self.set_sensitive(value) 233 234 def _parse_bind(self): 235 if '::' not in self.bind: 236 return SettingType.CONFIG, self.bind, None, None 237 238 bind_setting_type, setting = self.bind.split('::') 239 if bind_setting_type == 'account': 240 return SettingType.ACCOUNT_CONFIG, setting, self.account, None 241 242 if bind_setting_type == 'contact': 243 return SettingType.CONTACT, setting, self.account, self.jid 244 245 if bind_setting_type == 'group_chat': 246 return SettingType.GROUP_CHAT, setting, self.account, self.jid 247 raise ValueError(f'Invalid bind argument: {self.bind}') 248 249 def get_value(self): 250 return self.__get_value(self.type_, 251 self.value, 252 self.account, 253 self.jid) 254 255 @staticmethod 256 def __get_value(type_, value, account, jid): 257 if value is None: 258 return None 259 if type_ == SettingType.VALUE: 260 return value 261 262 if type_ == SettingType.CONTACT: 263 return app.settings.get_contact_setting(account, jid, value) 264 265 if type_ == SettingType.GROUP_CHAT: 266 return app.settings.get_group_chat_setting( 267 account, jid, value) 268 269 if type_ == SettingType.CONFIG: 270 return app.settings.get(value) 271 272 if type_ == SettingType.ACCOUNT_CONFIG: 273 if value == 'password': 274 return passwords.get_password(account) 275 if value == 'no_log_for': 276 no_log = app.settings.get_account_setting( 277 account, 'no_log_for').split() 278 return account not in no_log 279 return app.settings.get_account_setting(account, value) 280 281 if type_ == SettingType.ACTION: 282 if value.startswith('-'): 283 return account + value 284 return value 285 286 raise ValueError('Wrong SettingType?') 287 288 def set_value(self, state): 289 if self.type_ == SettingType.CONFIG: 290 app.settings.set(self.value, state) 291 292 elif self.type_ == SettingType.ACCOUNT_CONFIG: 293 if self.value == 'password': 294 passwords.save_password(self.account, state) 295 if self.value == 'no_log_for': 296 self.set_no_log_for(self.account, state) 297 else: 298 app.settings.set_account_setting(self.account, 299 self.value, 300 state) 301 302 elif self.type_ == SettingType.CONTACT: 303 app.settings.set_contact_setting( 304 self.account, self.jid, self.value, state) 305 306 elif self.type_ == SettingType.GROUP_CHAT: 307 app.settings.set_group_chat_setting( 308 self.account, self.jid, self.value, state) 309 310 if self.callback is not None: 311 self.callback(state, self.data) 312 313 @staticmethod 314 def set_no_log_for(account, state): 315 no_log = app.settings.get_account_setting(account, 'no_log_for').split() 316 if state and account in no_log: 317 no_log.remove(account) 318 elif not state and account not in no_log: 319 no_log.append(account) 320 app.settings.set_account_setting(account, 321 'no_log_for', 322 ' '.join(no_log)) 323 324 def on_row_activated(self): 325 raise NotImplementedError 326 327 def update_activatable(self): 328 if self.enabled_func is None: 329 return 330 331 enabled_func_value = self.enabled_func() 332 self.set_activatable(enabled_func_value) 333 self.set_sensitive(enabled_func_value) 334 335 def _add_action_button(self, kwargs): 336 icon_name = kwargs.get('button-icon-name') 337 button_text = kwargs.get('button-text') 338 tooltip_text = kwargs.get('button-tooltip') or '' 339 style = kwargs.get('button-style') 340 341 if icon_name is not None: 342 button = Gtk.Button.new_from_icon_name(icon_name, Gtk.IconSize.MENU) 343 344 elif button_text is not None: 345 button = Gtk.Button(label=button_text) 346 347 else: 348 return 349 350 if style is not None: 351 for css_class in style.split(' '): 352 button.get_style_context().add_class(css_class) 353 354 button.connect('clicked', kwargs['button-callback']) 355 button.set_tooltip_text(tooltip_text) 356 self.setting_box.add(button) 357 358 359class SwitchSetting(GenericSetting): 360 def __init__(self, *args, **kwargs): 361 GenericSetting.__init__(self, *args) 362 363 self.switch = Gtk.Switch() 364 if self.type_ == SettingType.ACTION: 365 self.switch.set_action_name('app.%s' % self.setting_value) 366 state = app.app.get_action_state(self.setting_value) 367 self.switch.set_active(state.get_boolean()) 368 else: 369 self.switch.set_active(self.setting_value) 370 self.switch.connect('notify::active', self.on_switch) 371 self.switch.set_hexpand(True) 372 self.switch.set_halign(Gtk.Align.END) 373 self.switch.set_valign(Gtk.Align.CENTER) 374 375 self._switch_state_label = Gtk.Label() 376 self._switch_state_label.set_xalign(1) 377 self._switch_state_label.set_valign(Gtk.Align.CENTER) 378 self._set_label(self.setting_value) 379 380 box = Gtk.Box(spacing=12) 381 box.set_halign(Gtk.Align.END) 382 box.add(self._switch_state_label) 383 box.add(self.switch) 384 self.setting_box.add(box) 385 386 self._add_action_button(kwargs) 387 388 self.show_all() 389 390 def on_row_activated(self): 391 state = self.switch.get_active() 392 self.switch.set_active(not state) 393 394 def on_switch(self, switch, *args): 395 value = switch.get_active() 396 self.set_value(value) 397 self._set_label(value) 398 399 def _set_label(self, active): 400 text = Q_('?switch:On') if active else Q_('?switch:Off') 401 self._switch_state_label.set_text(text) 402 403 404class EntrySetting(GenericSetting): 405 def __init__(self, *args): 406 GenericSetting.__init__(self, *args) 407 408 self.entry = Gtk.Entry() 409 self.entry.set_text(str(self.setting_value)) 410 self.entry.connect('notify::text', self.on_text_change) 411 self.entry.set_valign(Gtk.Align.CENTER) 412 self.entry.set_alignment(1) 413 414 if self.value == 'password': 415 self.entry.set_invisible_char('*') 416 self.entry.set_visibility(False) 417 418 self.setting_box.pack_end(self.entry, True, True, 0) 419 420 self.show_all() 421 422 def on_text_change(self, *args): 423 text = self.entry.get_text() 424 self.set_value(text) 425 426 def on_row_activated(self): 427 self.entry.grab_focus() 428 429 430class ColorSetting(GenericSetting): 431 def __init__(self, *args): 432 GenericSetting.__init__(self, *args) 433 434 rgba = Gdk.RGBA() 435 rgba.parse(self.setting_value) 436 self.color_button = Gtk.ColorButton() 437 self.color_button.set_rgba(rgba) 438 self.color_button.connect('color-set', self.on_color_set) 439 self.color_button.set_valign(Gtk.Align.CENTER) 440 self.color_button.set_halign(Gtk.Align.END) 441 442 self.setting_box.pack_end(self.color_button, True, True, 0) 443 444 self.show_all() 445 446 def on_color_set(self, button): 447 rgba = button.get_rgba() 448 self.set_value(rgba.to_string()) 449 app.css_config.refresh() 450 451 def on_row_activated(self): 452 self.color_button.grab_focus() 453 454 455class DialogSetting(GenericSetting): 456 def __init__(self, *args, dialog): 457 GenericSetting.__init__(self, *args) 458 self.dialog = dialog 459 460 self.setting_value = Gtk.Label() 461 self.setting_value.set_text(self.get_setting_value()) 462 self.setting_value.set_halign(Gtk.Align.END) 463 self.setting_box.pack_start(self.setting_value, True, True, 0) 464 465 self.show_all() 466 467 def show_dialog(self, parent): 468 if self.dialog: 469 dialog = self.dialog(self.account, parent) 470 dialog.connect('destroy', self.on_destroy) 471 472 def on_destroy(self, *args): 473 self.setting_value.set_text(self.get_setting_value()) 474 475 def get_setting_value(self): 476 self.setting_value.hide() 477 return '' 478 479 def on_row_activated(self): 480 self.show_dialog(self.get_toplevel()) 481 482 483class SpinSetting(GenericSetting): 484 def __init__(self, *args, range_): 485 GenericSetting.__init__(self, *args) 486 487 lower, upper = range_ 488 adjustment = Gtk.Adjustment(value=0, 489 lower=lower, 490 upper=upper, 491 step_increment=1, 492 page_increment=10, 493 page_size=0) 494 495 self.spin = Gtk.SpinButton() 496 self.spin.set_adjustment(adjustment) 497 self.spin.set_numeric(True) 498 self.spin.set_update_policy(Gtk.SpinButtonUpdatePolicy.IF_VALID) 499 self.spin.set_value(self.setting_value) 500 self.spin.set_halign(Gtk.Align.FILL) 501 self.spin.set_valign(Gtk.Align.CENTER) 502 self.spin.connect('notify::value', self.on_value_change) 503 504 self.setting_box.pack_start(self.spin, True, True, 0) 505 506 self.show_all() 507 508 def on_row_activated(self): 509 self.spin.grab_focus() 510 511 def on_value_change(self, spin, *args): 512 value = spin.get_value_as_int() 513 self.set_value(value) 514 515 516class FileChooserSetting(GenericSetting): 517 def __init__(self, *args, filefilter): 518 GenericSetting.__init__(self, *args) 519 520 button = Gtk.FileChooserButton(title=self.label, 521 action=Gtk.FileChooserAction.OPEN) 522 button.set_halign(Gtk.Align.END) 523 524 # GTK Bug: The FileChooserButton expands without limit 525 # get the label and use set_max_wide_chars() 526 label = button.get_children()[0].get_children()[0].get_children()[1] 527 label.set_max_width_chars(20) 528 529 if filefilter: 530 name, pattern = filefilter 531 filter_ = Gtk.FileFilter() 532 filter_.set_name(name) 533 filter_.add_pattern(pattern) 534 button.add_filter(filter_) 535 button.set_filter(filter_) 536 537 filter_ = Gtk.FileFilter() 538 filter_.set_name(_('All files')) 539 filter_.add_pattern('*') 540 button.add_filter(filter_) 541 542 if self.setting_value: 543 button.set_filename(self.setting_value) 544 button.connect('selection-changed', self.on_select) 545 546 clear_button = get_image_button( 547 'edit-clear-all-symbolic', _('Clear File')) 548 clear_button.connect('clicked', lambda *args: button.unselect_all()) 549 self.setting_box.pack_start(button, True, True, 0) 550 self.setting_box.pack_start(clear_button, False, False, 0) 551 552 self.show_all() 553 554 def on_select(self, filechooser): 555 self.set_value(filechooser.get_filename() or '') 556 557 def on_row_activated(self): 558 pass 559 560 561class CallbackSetting(GenericSetting): 562 def __init__(self, *args, callback): 563 GenericSetting.__init__(self, *args) 564 self.callback = callback 565 self.show_all() 566 567 def on_row_activated(self): 568 self.callback() 569 570 571class ActionSetting(GenericSetting): 572 def __init__(self, *args, account): 573 GenericSetting.__init__(self, *args) 574 action_name = '%s%s' % (account, self.value) 575 self.action = gtkgui_helpers.get_action(action_name) 576 self.variant = GLib.Variant.new_string(account) 577 self.on_enable() 578 579 self.show_all() 580 self.action.connect('notify::enabled', self.on_enable) 581 582 def on_enable(self, *args): 583 self.set_sensitive(self.action.get_enabled()) 584 585 def on_row_activated(self): 586 self.action.activate(self.variant) 587 588 589class LoginSetting(DialogSetting): 590 def __init__(self, *args, **kwargs): 591 DialogSetting.__init__(self, *args, **kwargs) 592 self.setting_value.set_selectable(True) 593 594 def get_setting_value(self): 595 jid = app.get_jid_from_account(self.account) 596 return jid 597 598 599class PopoverSetting(GenericSetting): 600 def __init__(self, *args, entries, **kwargs): 601 GenericSetting.__init__(self, *args) 602 603 self._entries = self._convert_to_dict(entries) 604 605 box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, 606 spacing=12) 607 box.set_halign(Gtk.Align.END) 608 box.set_hexpand(True) 609 610 self._default_text = kwargs.get('default-text') 611 612 self._current_label = Gtk.Label() 613 self._current_label.set_valign(Gtk.Align.CENTER) 614 image = Gtk.Image.new_from_icon_name('pan-down-symbolic', 615 Gtk.IconSize.MENU) 616 image.set_valign(Gtk.Align.CENTER) 617 618 box.add(self._current_label) 619 box.add(image) 620 621 self._menu_listbox = Gtk.ListBox() 622 self._menu_listbox.set_selection_mode(Gtk.SelectionMode.NONE) 623 self._add_menu_entries() 624 self._menu_listbox.connect('row-activated', 625 self._on_menu_row_activated) 626 627 scrolled_window = Gtk.ScrolledWindow() 628 scrolled_window.set_propagate_natural_height(True) 629 scrolled_window.set_propagate_natural_width(True) 630 scrolled_window.set_max_content_height(400) 631 scrolled_window.set_policy(Gtk.PolicyType.NEVER, 632 Gtk.PolicyType.AUTOMATIC) 633 scrolled_window.add(self._menu_listbox) 634 scrolled_window.show_all() 635 636 self._popover = Gtk.Popover() 637 self._popover.get_style_context().add_class('combo') 638 self._popover.set_relative_to(image) 639 self._popover.set_position(Gtk.PositionType.BOTTOM) 640 self._popover.add(scrolled_window) 641 642 self.setting_box.add(box) 643 644 self._add_action_button(kwargs) 645 646 text = self._entries.get(self.setting_value, self._default_text or '') 647 self._current_label.set_text(text) 648 649 app.settings.connect_signal(self.value, 650 self._on_setting_changed, 651 account=self.account, 652 jid=self.jid) 653 654 self.connect('destroy', self._on_destroy) 655 656 self.show_all() 657 658 @staticmethod 659 def _convert_to_dict(entries): 660 if isinstance(entries, list): 661 entries = {key: key for key in entries} 662 return entries 663 664 def _on_setting_changed(self, value, *args): 665 text = self._entries.get(value) 666 if text is None: 667 text = self._default_text or '' 668 669 self._current_label.set_text(text) 670 671 def _add_menu_entries(self): 672 if self._default_text is not None: 673 self._menu_listbox.add(PopoverRow(self._default_text, '')) 674 675 for value, label in self._entries.items(): 676 self._menu_listbox.add(PopoverRow(label, value)) 677 678 self._menu_listbox.show_all() 679 680 def _on_menu_row_activated(self, listbox, row): 681 listbox.unselect_all() 682 self._popover.popdown() 683 684 self.set_value(row.value) 685 686 def on_row_activated(self): 687 self._popover.popup() 688 689 def update_entries(self, entries): 690 self._entries = self._convert_to_dict(entries) 691 self._menu_listbox.foreach(self._menu_listbox.remove) 692 self._add_menu_entries() 693 694 def _on_destroy(self, *args): 695 app.settings.disconnect_signals(self) 696 697 698class PopoverRow(Gtk.ListBoxRow): 699 def __init__(self, label, value): 700 Gtk.ListBoxRow.__init__(self) 701 self.label = label 702 self.value = value 703 704 label = Gtk.Label(label=label) 705 label.set_xalign(0) 706 self.add(label) 707 708 709class ComboSetting(GenericSetting): 710 def __init__(self, *args, combo_items): 711 GenericSetting.__init__(self, *args) 712 713 self.combo = MaxWidthComboBoxText() 714 self.combo.set_valign(Gtk.Align.CENTER) 715 716 for index, value in enumerate(combo_items): 717 if isinstance(value, tuple): 718 value, label = value 719 self.combo.append(value, _(label)) 720 else: 721 self.combo.append(value, value) 722 if value == self.setting_value or index == 0: 723 self.combo.set_active(index) 724 725 self.combo.connect('changed', self.on_value_change) 726 727 self.setting_box.pack_start(self.combo, True, True, 0) 728 self.show_all() 729 730 def on_value_change(self, combo): 731 self.set_value(combo.get_active_id()) 732 733 def on_row_activated(self): 734 pass 735 736 737class PrioritySetting(DialogSetting): 738 def __init__(self, *args, **kwargs): 739 DialogSetting.__init__(self, *args, **kwargs) 740 741 def get_setting_value(self): 742 adjust = app.settings.get_account_setting( 743 self.account, 'adjust_priority_with_status') 744 if adjust: 745 return _('Adjust to Status') 746 747 priority = app.settings.get_account_setting(self.account, 'priority') 748 return str(priority) 749 750 751class CutstomHostnameSetting(DialogSetting): 752 def __init__(self, *args, **kwargs): 753 DialogSetting.__init__(self, *args, **kwargs) 754 755 def get_setting_value(self): 756 custom = app.settings.get_account_setting(self.account, 757 'use_custom_host') 758 return Q_('?switch:On') if custom else Q_('?switch:Off') 759 760 761class ChangePasswordSetting(DialogSetting): 762 def __init__(self, *args, **kwargs): 763 DialogSetting.__init__(self, *args, **kwargs) 764 765 def show_dialog(self, parent): 766 parent.destroy() 767 open_window('ChangePassword', account=self.account) 768 769 def update_activatable(self): 770 activatable = False 771 if self.account in app.connections: 772 con = app.connections[self.account] 773 activatable = (con.state.is_available and 774 con.get_module('Register').supported) 775 self.set_activatable(activatable) 776 777 778class CutstomAutoAwaySetting(DialogSetting): 779 def __init__(self, *args, **kwargs): 780 DialogSetting.__init__(self, *args, **kwargs) 781 782 def get_setting_value(self): 783 value = app.settings.get('autoaway') 784 return Q_('?switch:On') if value else Q_('?switch:Off') 785 786 787class CutstomAutoExtendedAwaySetting(DialogSetting): 788 def __init__(self, *args, **kwargs): 789 DialogSetting.__init__(self, *args, **kwargs) 790 791 def get_setting_value(self): 792 value = app.settings.get('autoxa') 793 return Q_('?switch:On') if value else Q_('?switch:Off') 794 795 796class CustomStunServerSetting(DialogSetting): 797 def __init__(self, *args, **kwargs): 798 DialogSetting.__init__(self, *args, **kwargs) 799 800 def get_setting_value(self): 801 value = app.settings.get('use_stun_server') 802 return Q_('?switch:On') if value else Q_('?switch:Off') 803 804 805class NotificationsSetting(DialogSetting): 806 def __init__(self, *args, **kwargs): 807 DialogSetting.__init__(self, *args, **kwargs) 808 809 def get_setting_value(self): 810 value = app.settings.get('show_notifications') 811 return Q_('?switch:On') if value else Q_('?switch:Off') 812