summaryrefslogtreecommitdiffstats
path: root/deluge/plugins/Notifications/deluge_notifications/gtkui.py
diff options
context:
space:
mode:
Diffstat (limited to 'deluge/plugins/Notifications/deluge_notifications/gtkui.py')
-rw-r--r--deluge/plugins/Notifications/deluge_notifications/gtkui.py741
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