diff options
Diffstat (limited to '')
-rw-r--r-- | deluge/plugins/Notifications/deluge_notifications/gtkui.py | 741 |
1 files changed, 741 insertions, 0 deletions
diff --git a/deluge/plugins/Notifications/deluge_notifications/gtkui.py b/deluge/plugins/Notifications/deluge_notifications/gtkui.py new file mode 100644 index 0000000..4dc5ff8 --- /dev/null +++ b/deluge/plugins/Notifications/deluge_notifications/gtkui.py @@ -0,0 +1,741 @@ +# +# Copyright (C) 2009-2010 Pedro Algarvio <pedro@algarvio.me> +# +# Basic plugin template created by: +# Copyright (C) 2008 Martijn Voncken <mvoncken@gmail.com> +# Copyright (C) 2007-2009 Andrew Resch <andrewresch@gmail.com> +# Copyright (C) 2009 Damien Churchill <damoxc@gmail.com> +# +# This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with +# the additional special exception to link portions of this program with the OpenSSL library. +# See LICENSE for more details. +# + +import logging +from os.path import basename + +from gi import require_version +from gi.repository import Gtk +from twisted.internet import defer + +import deluge.common +import deluge.component as component +import deluge.configmanager +from deluge.plugins.pluginbase import Gtk3PluginBase +from deluge.ui.client import client + +from .common import CustomNotifications, get_resource + +# Relative imports + +log = logging.getLogger(__name__) + +try: + import pygame + + SOUND_AVAILABLE = True +except ImportError: + SOUND_AVAILABLE = False + +try: + require_version('Notify', '0.7') + from gi.repository import GLib, Notify +except (ValueError, ImportError): + POPUP_AVAILABLE = False +else: + POPUP_AVAILABLE = not deluge.common.windows_check() + + +DEFAULT_PREFS = { + # BLINK + 'blink_enabled': False, + # FLASH + 'flash_enabled': False, + # POPUP + 'popup_enabled': False, + # SOUND + 'sound_enabled': False, + 'sound_path': '', + 'custom_sounds': {}, + # Subscriptions + 'subscriptions': {'popup': [], 'blink': [], 'sound': []}, +} + +RECIPIENT_FIELD, RECIPIENT_EDIT = list(range(2)) +( + SUB_EVENT, + SUB_EVENT_DOC, + SUB_NOT_EMAIL, + SUB_NOT_POPUP, + SUB_NOT_BLINK, + SUB_NOT_SOUND, +) = list(range(6)) +SND_EVENT, SND_EVENT_DOC, SND_NAME, SND_PATH = list(range(4)) + + +class GtkUiNotifications(CustomNotifications): + def __init__(self, plugin_name=None): + CustomNotifications.__init__(self, plugin_name) + + def enable(self): + CustomNotifications.enable(self) + self.register_custom_blink_notification( + 'TorrentFinishedEvent', self._on_torrent_finished_event_blink + ) + self.register_custom_sound_notification( + 'TorrentFinishedEvent', self._on_torrent_finished_event_sound + ) + self.register_custom_popup_notification( + 'TorrentFinishedEvent', self._on_torrent_finished_event_popup + ) + + def disable(self): + self.deregister_custom_blink_notification('TorrentFinishedEvent') + self.deregister_custom_sound_notification('TorrentFinishedEvent') + self.deregister_custom_popup_notification('TorrentFinishedEvent') + CustomNotifications.disable(self) + + def register_custom_popup_notification(self, eventtype, handler): + """This is used to register popup notifications for custom event types. + + :param event: the event name + :param type: string + :param handler: function, to be called when `:param:event` is emitted + + Your handler should return a tuple of (popup_title, popup_contents). + """ + self._register_custom_provider('popup', eventtype, handler) + + def deregister_custom_popup_notification(self, eventtype): + self._deregister_custom_provider('popup', eventtype) + + def register_custom_blink_notification(self, eventtype, handler): + """This is used to register blink notifications for custom event types. + + :param event: str, the event name + :param handler: function, to be called when `:param:event` is emitted + + Your handler should return `True` or `False` to blink or not the + trayicon. + """ + self._register_custom_provider('blink', eventtype, handler) + + def deregister_custom_blink_notification(self, eventtype): + self._deregister_custom_provider('blink', eventtype) + + def register_custom_sound_notification(self, eventtype, handler): + """This is used to register sound notifications for custom event types. + + :param event: the event name + :type event: string + :param handler: function to be called when `:param:event` is emitted + + Your handler should return either '' to use the sound defined on the + notification preferences, the path to a sound file, which will then be + played or None, where no sound will be played at all. + """ + self._register_custom_provider('sound', eventtype, handler) + + def deregister_custom_sound_notification(self, eventtype): + self._deregister_custom_provider('sound', eventtype) + + def handle_custom_popup_notification(self, result, eventtype): + title, message = result + return defer.maybeDeferred(self.__popup, title, message) + + def handle_custom_blink_notification(self, result, eventtype): + if result: + return defer.maybeDeferred(self.__blink) + return defer.succeed( + 'Will not blink. The returned value from the custom ' + 'handler was: %s' % result + ) + + def handle_custom_sound_notification(self, result, eventtype): + if isinstance(result, ''.__class__): + if not result and eventtype in self.config['custom_sounds']: + return defer.maybeDeferred( + self.__play_sound, self.config['custom_sounds'][eventtype] + ) + return defer.maybeDeferred(self.__play_sound, result) + return defer.succeed( + 'Will not play sound. The returned value from the ' + 'custom handler was: %s' % result + ) + + def __blink(self): + self.systray.blink(True) + return defer.succeed(_('Notification Blink shown')) + + def __popup(self, title='', message=''): + if not self.config['popup_enabled']: + return defer.succeed(_('Popup notification is not enabled.')) + if not POPUP_AVAILABLE: + err_msg = _('libnotify is not installed') + log.warning(err_msg) + return defer.fail(ImportError(err_msg)) + + if Notify.init('Deluge'): + self.note = Notify.Notification.new(title, message, 'deluge-panel') + self.note.set_hint('desktop-entry', GLib.Variant.new_string('deluge')) + if not self.note.show(): + err_msg = _('Failed to popup notification') + log.warning(err_msg) + return defer.fail(Exception(err_msg)) + return defer.succeed(_('Notification popup shown')) + + def __play_sound(self, sound_path=''): + if not self.config['sound_enabled']: + return defer.succeed(_('Sound notification not enabled')) + if not SOUND_AVAILABLE: + err_msg = _('pygame is not installed') + log.warning(err_msg) + return defer.fail(ImportError(err_msg)) + + pygame.init() + try: + if not sound_path: + sound_path = self.config['sound_path'] + alert_sound = pygame.mixer.music + alert_sound.load(sound_path) + alert_sound.play() + except pygame.error as ex: + err_msg = _('Sound notification failed %s') % ex + log.warning(err_msg) + return defer.fail(ex) + else: + msg = _('Sound notification Success') + log.info(msg) + return defer.succeed(msg) + + def _on_torrent_finished_event_blink(self, torrent_id): + return True # Yes, Blink + + def _on_torrent_finished_event_sound(self, torrent_id): + # Since there's no custom sound hardcoded, just return '' + return '' + + def _on_torrent_finished_event_popup(self, torrent_id): + d = client.core.get_torrent_status(torrent_id, ['name', 'file_progress']) + d.addCallback(self._on_torrent_finished_event_got_torrent_status) + d.addErrback(self._on_torrent_finished_event_torrent_status_failure) + return d + + def _on_torrent_finished_event_torrent_status_failure(self, failure): + log.debug('Failed to get torrent status to be able to show the popup') + + def _on_torrent_finished_event_got_torrent_status(self, torrent_status): + log.debug( + 'Handler for TorrentFinishedEvent GTKUI called. ' 'Got Torrent Status' + ) + title = _('Finished Torrent') + torrent_status['num_files'] = torrent_status['file_progress'].count(1.0) + message = ( + _( + 'The torrent "%(name)s" including %(num_files)i file(s) ' + 'has finished downloading.' + ) + % torrent_status + ) + return title, message + + +class GtkUI(Gtk3PluginBase, GtkUiNotifications): + def __init__(self, plugin_name): + Gtk3PluginBase.__init__(self, plugin_name) + GtkUiNotifications.__init__(self) + + def enable(self): + self.config = deluge.configmanager.ConfigManager( + 'notifications-gtk.conf', DEFAULT_PREFS + ) + self.builder = Gtk.Builder() + self.builder.add_from_file(get_resource('config.ui')) + self.builder.get_object('smtp_port').set_value(25) + self.prefs = self.builder.get_object('prefs_box') + self.prefs.show_all() + + self.build_recipients_model_populate_treeview() + self.build_sounds_model_populate_treeview() + self.build_notifications_model_populate_treeview() + + client.notifications.get_handled_events().addCallback( + self.popuplate_what_needs_handled_events + ) + + self.builder.connect_signals( + { + 'on_add_button_clicked': ( + self.on_add_button_clicked, + self.recipients_treeview, + ), + 'on_delete_button_clicked': ( + self.on_delete_button_clicked, + self.recipients_treeview, + ), + 'on_enabled_toggled': self.on_enabled_toggled, + 'on_sound_enabled_toggled': self.on_sound_enabled_toggled, + 'on_sounds_edit_button_clicked': self.on_sounds_edit_button_clicked, + 'on_sounds_revert_button_clicked': self.on_sounds_revert_button_clicked, + 'on_sound_path_update_preview': self.on_sound_path_update_preview, + } + ) + + component.get('Preferences').add_page(_('Notifications'), self.prefs) + + component.get('PluginManager').register_hook( + 'on_apply_prefs', self.on_apply_prefs + ) + component.get('PluginManager').register_hook( + 'on_show_prefs', self.on_show_prefs + ) + + if not POPUP_AVAILABLE: + self.builder.get_object('popup_enabled').set_property('sensitive', False) + if not SOUND_AVAILABLE: + # for widget_name in ('sound_enabled', 'sound_path', 'sounds_page', 'sounds_page_label'): + # self.builder.get_object(widget_name).set_property('sensitive', False) + self.builder.get_object('sound_enabled').set_property('sensitive', False) + self.builder.get_object('sound_path').set_property('sensitive', False) + self.builder.get_object('sounds_page').set_property('sensitive', False) + self.builder.get_object('sounds_page_label').set_property( + 'sensitive', False + ) + + self.systray = component.get('SystemTray') + if not hasattr(self.systray, 'tray'): + # Tray is not beeing used + self.builder.get_object('blink_enabled').set_property('sensitive', False) + + GtkUiNotifications.enable(self) + + def disable(self): + GtkUiNotifications.disable(self) + component.get('Preferences').remove_page(_('Notifications')) + component.get('PluginManager').deregister_hook( + 'on_apply_prefs', self.on_apply_prefs + ) + component.get('PluginManager').deregister_hook( + 'on_show_prefs', self.on_show_prefs + ) + + def build_recipients_model_populate_treeview(self): + # SMTP Recipients treeview/model + self.recipients_treeview = self.builder.get_object('smtp_recipients') + treeview_selection = self.recipients_treeview.get_selection() + treeview_selection.connect( + 'changed', self.on_recipients_treeview_selection_changed + ) + self.recipients_model = Gtk.ListStore(str, bool) + + renderer = Gtk.CellRendererText() + renderer.connect('edited', self.on_cell_edited, self.recipients_model) + renderer.recipient = RECIPIENT_FIELD + column = Gtk.TreeViewColumn( + 'Recipients', renderer, text=RECIPIENT_FIELD, editable=RECIPIENT_EDIT + ) + column.set_expand(True) + self.recipients_treeview.append_column(column) + self.recipients_treeview.set_model(self.recipients_model) + + def build_sounds_model_populate_treeview(self): + # Sound customisation treeview/model + self.sounds_treeview = self.builder.get_object('sounds_treeview') + sounds_selection = self.sounds_treeview.get_selection() + sounds_selection.connect('changed', self.on_sounds_treeview_selection_changed) + + self.sounds_treeview.set_tooltip_column(SND_EVENT_DOC) + self.sounds_model = Gtk.ListStore(str, str, str, str) + + renderer = Gtk.CellRendererText() + renderer.event = SND_EVENT + column = Gtk.TreeViewColumn('Event', renderer, text=SND_EVENT) + column.set_expand(True) + self.sounds_treeview.append_column(column) + + renderer = Gtk.CellRendererText() + renderer.event_doc = SND_EVENT_DOC + column = Gtk.TreeViewColumn('Doc', renderer, text=SND_EVENT_DOC) + column.set_property('visible', False) + self.sounds_treeview.append_column(column) + + renderer = Gtk.CellRendererText() + renderer.sound_name = SND_NAME + column = Gtk.TreeViewColumn('Name', renderer, text=SND_NAME) + self.sounds_treeview.append_column(column) + + renderer = Gtk.CellRendererText() + renderer.sound_path = SND_PATH + column = Gtk.TreeViewColumn('Path', renderer, text=SND_PATH) + column.set_property('visible', False) + self.sounds_treeview.append_column(column) + + self.sounds_treeview.set_model(self.sounds_model) + + def build_notifications_model_populate_treeview(self): + # Notification Subscriptions treeview/model + self.subscriptions_treeview = self.builder.get_object('subscriptions_treeview') + subscriptions_selection = self.subscriptions_treeview.get_selection() + subscriptions_selection.connect( + 'changed', self.on_subscriptions_treeview_selection_changed + ) + self.subscriptions_treeview.set_tooltip_column(SUB_EVENT_DOC) + self.subscriptions_model = Gtk.ListStore(str, str, bool, bool, bool, bool) + + renderer = Gtk.CellRendererText() + setattr(renderer, 'event', SUB_EVENT) + column = Gtk.TreeViewColumn('Event', renderer, text=SUB_EVENT) + column.set_expand(True) + self.subscriptions_treeview.append_column(column) + + renderer = Gtk.CellRendererText() + setattr(renderer, 'event_doc', SUB_EVENT) + column = Gtk.TreeViewColumn('Doc', renderer, text=SUB_EVENT_DOC) + column.set_property('visible', False) + self.subscriptions_treeview.append_column(column) + + renderer = Gtk.CellRendererToggle() + renderer.set_property('activatable', True) + renderer.connect('toggled', self._on_email_col_toggled) + column = Gtk.TreeViewColumn('Email', renderer, active=SUB_NOT_EMAIL) + column.set_clickable(True) + self.subscriptions_treeview.append_column(column) + + renderer = Gtk.CellRendererToggle() + renderer.set_property('activatable', True) + renderer.connect('toggled', self._on_popup_col_toggled) + column = Gtk.TreeViewColumn('Popup', renderer, active=SUB_NOT_POPUP) + column.set_clickable(True) + self.subscriptions_treeview.append_column(column) + + renderer = Gtk.CellRendererToggle() + renderer.set_property('activatable', True) + renderer.connect('toggled', self._on_blink_col_toggled) + column = Gtk.TreeViewColumn('Blink', renderer, active=SUB_NOT_BLINK) + column.set_clickable(True) + self.subscriptions_treeview.append_column(column) + + renderer = Gtk.CellRendererToggle() + renderer.set_property('activatable', True) + renderer.connect('toggled', self._on_sound_col_toggled) + column = Gtk.TreeViewColumn('Sound', renderer, active=SUB_NOT_SOUND) + column.set_clickable(True) + self.subscriptions_treeview.append_column(column) + self.subscriptions_treeview.set_model(self.subscriptions_model) + + def popuplate_what_needs_handled_events( + self, handled_events, email_subscriptions=None + ): + if email_subscriptions is None: + email_subscriptions = [] + self.populate_subscriptions(handled_events, email_subscriptions) + self.populate_sounds(handled_events) + + def populate_sounds(self, handled_events): + self.sounds_model.clear() + for event_name, event_doc in handled_events: + if event_name in self.config['custom_sounds']: + snd_path = self.config['custom_sounds'][event_name] + else: + snd_path = self.config['sound_path'] + + if snd_path: + self.sounds_model.set( + self.sounds_model.append(), + SND_EVENT, + event_name, + SND_EVENT_DOC, + event_doc, + SND_NAME, + basename(snd_path), + SND_PATH, + snd_path, + ) + + def populate_subscriptions(self, handled_events, email_subscriptions=None): + if email_subscriptions is None: + email_subscriptions = [] + subscriptions_dict = self.config['subscriptions'] + self.subscriptions_model.clear() + # self.handled_events = handled_events + for event_name, event_doc in handled_events: + self.subscriptions_model.set( + self.subscriptions_model.append(), + SUB_EVENT, + event_name, + SUB_EVENT_DOC, + event_doc, + SUB_NOT_EMAIL, + event_name in email_subscriptions, + SUB_NOT_POPUP, + event_name in subscriptions_dict['popup'], + SUB_NOT_BLINK, + event_name in subscriptions_dict['blink'], + SUB_NOT_SOUND, + event_name in subscriptions_dict['sound'], + ) + + def on_apply_prefs(self): + log.debug('applying prefs for Notifications') + + current_popup_subscriptions = [] + current_blink_subscriptions = [] + current_sound_subscriptions = [] + current_email_subscriptions = [] + for event, doc, email, popup, blink, sound in self.subscriptions_model: + if email: + current_email_subscriptions.append(event) + if popup: + current_popup_subscriptions.append(event) + if blink: + current_blink_subscriptions.append(event) + if sound: + current_sound_subscriptions.append(event) + + old_sound_file = self.config['sound_path'] + new_sound_file = self.builder.get_object('sound_path').get_filename() + log.debug( + 'Old Default sound file: %s New one: %s', old_sound_file, new_sound_file + ) + custom_sounds = {} + for event_name, event_doc, filename, filepath in self.sounds_model: + log.debug('Custom sound for event "%s": %s', event_name, filename) + if filepath == old_sound_file: + continue + custom_sounds[event_name] = filepath + + self.config.config.update( + { + 'popup_enabled': self.builder.get_object('popup_enabled').get_active(), + 'blink_enabled': self.builder.get_object('blink_enabled').get_active(), + 'sound_enabled': self.builder.get_object('sound_enabled').get_active(), + 'sound_path': new_sound_file, + 'subscriptions': { + 'popup': current_popup_subscriptions, + 'blink': current_blink_subscriptions, + 'sound': current_sound_subscriptions, + }, + 'custom_sounds': custom_sounds, + } + ) + self.config.save() + + core_config = { + 'smtp_enabled': self.builder.get_object('smtp_enabled').get_active(), + 'smtp_host': self.builder.get_object('smtp_host').get_text(), + 'smtp_port': self.builder.get_object('smtp_port').get_value(), + 'smtp_user': self.builder.get_object('smtp_user').get_text(), + 'smtp_pass': self.builder.get_object('smtp_pass').get_text(), + 'smtp_from': self.builder.get_object('smtp_from').get_text(), + 'smtp_tls': self.builder.get_object('smtp_tls').get_active(), + 'smtp_recipients': [ + dest[0] for dest in self.recipients_model if dest[0] != 'USER@HOST' + ], + 'subscriptions': {'email': current_email_subscriptions}, + } + + client.notifications.set_config(core_config) + client.notifications.get_config().addCallback(self.cb_get_config) + + def on_show_prefs(self): + client.notifications.get_config().addCallback(self.cb_get_config) + + def cb_get_config(self, core_config): + """Callback for on show_prefs.""" + self.builder.get_object('smtp_host').set_text(core_config['smtp_host']) + self.builder.get_object('smtp_port').set_value(core_config['smtp_port']) + self.builder.get_object('smtp_user').set_text(core_config['smtp_user']) + self.builder.get_object('smtp_pass').set_text(core_config['smtp_pass']) + self.builder.get_object('smtp_from').set_text(core_config['smtp_from']) + self.builder.get_object('smtp_tls').set_active(core_config['smtp_tls']) + self.recipients_model.clear() + for recipient in core_config['smtp_recipients']: + self.recipients_model.set( + self.recipients_model.append(), + RECIPIENT_FIELD, + recipient, + RECIPIENT_EDIT, + False, + ) + self.builder.get_object('smtp_enabled').set_active(core_config['smtp_enabled']) + self.builder.get_object('sound_enabled').set_active( + self.config['sound_enabled'] + ) + self.builder.get_object('popup_enabled').set_active( + self.config['popup_enabled'] + ) + self.builder.get_object('blink_enabled').set_active( + self.config['blink_enabled'] + ) + if self.config['sound_path']: + sound_path = self.config['sound_path'] + else: + sound_path = deluge.common.get_default_download_dir() + self.builder.get_object('sound_path').set_filename(sound_path) + # Force toggle + self.on_enabled_toggled(self.builder.get_object('smtp_enabled')) + self.on_sound_enabled_toggled(self.builder.get_object('sound_enabled')) + + client.notifications.get_handled_events().addCallback( + self.popuplate_what_needs_handled_events, + core_config['subscriptions']['email'], + ) + + def on_sound_path_update_preview(self, filechooser): + client.notifications.get_handled_events().addCallback(self.populate_sounds) + + def on_add_button_clicked(self, widget, treeview): + model = treeview.get_model() + model.set(model.append(), RECIPIENT_FIELD, 'USER@HOST', RECIPIENT_EDIT, True) + + def on_delete_button_clicked(self, widget, treeview): + selection = treeview.get_selection() + model, selected_iter = selection.get_selected() + if selected_iter: + model.remove(selected_iter) + + def on_cell_edited(self, cell, path_string, new_text, model): + str_iter = model.get_iter_from_string(path_string) + model.set(str_iter, RECIPIENT_FIELD, new_text) + + def on_recipients_treeview_selection_changed(self, selection): + model, selected_connection_iter = selection.get_selected() + if selected_connection_iter: + self.builder.get_object('delete_button').set_property('sensitive', True) + else: + self.builder.get_object('delete_button').set_property('sensitive', False) + + def on_subscriptions_treeview_selection_changed(self, selection): + model, selected_connection_iter = selection.get_selected() + if selected_connection_iter: + self.builder.get_object('delete_button').set_property('sensitive', True) + else: + self.builder.get_object('delete_button').set_property('sensitive', False) + + def on_sounds_treeview_selection_changed(self, selection): + model, selected_iter = selection.get_selected() + if selected_iter: + self.builder.get_object('sounds_edit_button').set_property( + 'sensitive', True + ) + path = model.get(selected_iter, SND_PATH)[0] + log.debug('Sound selection changed: %s', path) + if path != self.config['sound_path']: + self.builder.get_object('sounds_revert_button').set_property( + 'sensitive', True + ) + else: + self.builder.get_object('sounds_revert_button').set_property( + 'sensitive', False + ) + else: + self.builder.get_object('sounds_edit_button').set_property( + 'sensitive', False + ) + self.builder.get_object('sounds_revert_button').set_property( + 'sensitive', False + ) + + def on_sounds_revert_button_clicked(self, widget): + log.debug('on_sounds_revert_button_clicked') + selection = self.sounds_treeview.get_selection() + model, selected_iter = selection.get_selected() + if selected_iter: + log.debug('on_sounds_revert_button_clicked: got iter') + model.set( + selected_iter, + SND_PATH, + self.config['sound_path'], + SND_NAME, + basename(self.config['sound_path']), + ) + + def on_sounds_edit_button_clicked(self, widget): + log.debug('on_sounds_edit_button_clicked') + selection = self.sounds_treeview.get_selection() + model, selected_iter = selection.get_selected() + if selected_iter: + path = model.get(selected_iter, SND_PATH)[0] + dialog = Gtk.FileChooserDialog( + title=_('Choose Sound File'), + buttons=( + Gtk.STOCK_CANCEL, + Gtk.ResponseType.CANCEL, + Gtk.STOCK_OPEN, + Gtk.ResponseType.OK, + ), + ) + dialog.set_filename(path) + + def update_model(response): + if response == Gtk.ResponseType.OK: + new_filename = dialog.get_filename() + dialog.destroy() + log.debug(new_filename) + model.set( + selected_iter, + SND_PATH, + new_filename, + SND_NAME, + basename(new_filename), + ) + + d = defer.maybeDeferred(dialog.run) + d.addCallback(update_model) + + log.debug('dialog should have been shown') + + def on_enabled_toggled(self, widget): + for widget_name in ( + 'smtp_host', + 'smtp_port', + 'smtp_user', + 'smtp_pass', + 'smtp_pass', + 'smtp_tls', + 'smtp_from', + 'smtp_recipients', + ): + self.builder.get_object(widget_name).set_property( + 'sensitive', widget.get_active() + ) + + def on_sound_enabled_toggled(self, widget): + if widget.get_active(): + self.builder.get_object('sound_path').set_property('sensitive', True) + self.builder.get_object('sounds_page').set_property('sensitive', True) + self.builder.get_object('sounds_page_label').set_property('sensitive', True) + else: + self.builder.get_object('sound_path').set_property('sensitive', False) + self.builder.get_object('sounds_page').set_property('sensitive', False) + self.builder.get_object('sounds_page_label').set_property( + 'sensitive', False + ) + + # for widget_name in ('sounds_path', 'sounds_page', 'sounds_page_label'): + # self.builder.get_object(widget_name).set_property('sensitive', + # widget.get_active()) + + def _on_email_col_toggled(self, cell, path): + self.subscriptions_model[path][SUB_NOT_EMAIL] = not self.subscriptions_model[ + path + ][SUB_NOT_EMAIL] + return + + def _on_popup_col_toggled(self, cell, path): + self.subscriptions_model[path][SUB_NOT_POPUP] = not self.subscriptions_model[ + path + ][SUB_NOT_POPUP] + return + + def _on_blink_col_toggled(self, cell, path): + self.subscriptions_model[path][SUB_NOT_BLINK] = not self.subscriptions_model[ + path + ][SUB_NOT_BLINK] + return + + def _on_sound_col_toggled(self, cell, path): + self.subscriptions_model[path][SUB_NOT_SOUND] = not self.subscriptions_model[ + path + ][SUB_NOT_SOUND] + return |