Checkpoint:

* Custom notification providers working for email.
  * Configuration through the GtkUI working.
This commit is contained in:
Pedro Algarvio 2009-11-22 02:35:02 +00:00
parent 8a6ec7232d
commit 1b7a50f88b
6 changed files with 939 additions and 504 deletions

View File

@ -17,9 +17,9 @@
#
# You should have received a copy of the GNU General Public License
# along with deluge. If not, write to:
# The Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor
# Boston, MA 02110-1301, USA.
# The Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor
# Boston, MA 02110-1301, USA.
#
# In addition, as a special exception, the copyright holders give
# permission to link the code of portions of this program with the OpenSSL
@ -41,15 +41,15 @@ and subsequently emitted to the clients.
"""
event_list = []
known_events = {}
class DelugeEventMetaClass(type):
"""
This metaclass simply keeps a list of all events classes created.
"""
def __init__(cls, name, bases, dct):
event_list.append(name)
super(DelugeEventMetaClass, cls).__init__(name, bases, dct)
known_events[name] = cls
class DelugeEvent(object):
"""

View File

@ -22,9 +22,9 @@
#
# You should have received a copy of the GNU General Public License
# along with deluge. If not, write to:
# The Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor
# Boston, MA 02110-1301, USA.
# The Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor
# Boston, MA 02110-1301, USA.
#
# In addition, as a special exception, the copyright holders give
# permission to link the code of portions of this program with the OpenSSL
@ -39,4 +39,35 @@
def get_resource(filename):
import pkg_resources, os
return pkg_resources.resource_filename("notifications", os.path.join("data", filename))
return pkg_resources.resource_filename("notifications",
os.path.join("data", filename))
DEFAULT_PREFS = {
# Core -------------------------------------------------------------------------
"smtp_enabled": False,
"smtp_host": "",
"smtp_port": 25,
"smtp_user": "",
"smtp_pass": "",
"smtp_from": "",
"smtp_tls": False, # SSL or TLS
"smtp_recipients": [],
# GTK UI -----------------------------------------------------------------------
# BLINK
"blink_enabled": False,
# FLASH
"flash_enabled": False,
# POPUP
"popup_enabled": False,
# SOUND
"sound_enabled": False,
"sound_path": "",
# Subscriptions ----------------------------------------------------------------
"subscriptions": {
"popup": [],
"blink": [],
"sound": [],
"email": [],
}
}

View File

@ -39,20 +39,16 @@
import smtplib
from twisted.internet import defer, threads
from deluge.event import known_events, DelugeEvent
from deluge.log import LOG as log
from deluge.plugins.pluginbase import CorePluginBase
import deluge.component as component
import deluge.configmanager
from deluge.core.rpcserver import export
# Relative imports
from manager import Notifications
import events
from test import TestEmailNotifications
DEFAULT_PREFS = {
# BLINK
"blink_enabled": False,
# EMAIL
"smtp_enabled": False,
"smtp_host": "",
"smtp_port": 25,
@ -61,29 +57,36 @@ DEFAULT_PREFS = {
"smtp_from": "",
"smtp_tls": False, # SSL or TLS
"smtp_recipients": [],
# FLASH
"flash_enabled": False,
# POPUP
"popup_enabled": False,
# SOUND
"sound_enabled": False,
"sound_path": ""
# Subscriptions
"subscriptions": {
"email": []
}
}
class Core(CorePluginBase, component.Component):
def __init__(self, plugin_name):
CorePluginBase.__init__(self, plugin_name)
component.Component.__init__(self, "Notifications")
self.email_message_providers = {}
self.tn = TestEmailNotifications()
class Core(CorePluginBase, Notifications):
def enable(self):
Notifications.enable(self)
self.config = deluge.configmanager.ConfigManager("notifications.conf",
DEFAULT_PREFS)
self.config = deluge.configmanager.ConfigManager(
"notifications-core.conf", DEFAULT_PREFS)
component.get("EventManager").register_event_handler(
"TorrentFinishedEvent", self._on_torrent_finished_event
)
log.debug("\n\nENABLING CORE NOTIFICATIONS\n\n")
self.tn.enable()
# import sys
# print '\n\n', [(n, k.__module__) for n, k in known_events.items()]
# print [f for f in sys.modules.keys() if f.startswith("deluge.event")]
def disable(self):
Notifications.disable(self)
self.tn.disable()
log.debug("\n\nDISABLING CORE NOTIFICATIONS\n\n")
for eventtype in self.email_message_providers.keys():
self.deregister_email_message_provider(eventtype)
def update(self):
pass
@ -100,65 +103,87 @@ class Core(CorePluginBase, Notifications):
"returns the config dictionary"
return self.config.config
# Notification methods
@export
def notify_blink(self):
if not self.config["blink_enabled"]:
return defer.succeed("Blink notification not enabled")
return defer.maybeDeferred(
component.get("EventManager").emit, events.NotificationBlinkEvent())
def get_handled_events(self):
handled_events = []
for evt in sorted(known_events.keys()):
if known_events[evt].__module__.startswith('deluge.event'):
if evt not in ('TorrentFinishedEvent',):
# Skip the base class for all events
continue
classdoc = known_events[evt].__doc__.strip()
handled_events.append((evt, classdoc))
log.debug("Handled Notification Events: %s", handled_events)
return handled_events
@export
def notify_email(self, title='', message='', smtp_from='', recipients=[]):
def register_email_message_provider(self, eventtype, handler):
"""This is used to register email formatters for custom event types.
:param event: str, the event name
:param handler: function, to be called when `:param:event` is emitted
You're handler should return a tuple of (subject, email_contents).
"""
if eventtype not in known_events:
raise Exception("The event \"%s\" is not known" % eventtype)
if known_events[eventtype].__module__.startswith('deluge.event'):
raise Exception("You cannot register email message providers for "
"built-in event types.")
if eventtype not in self.email_message_providers:
def wrapper(*args, **kwargs):
return self._handle_custom_email_message_providers(eventtype,
*args,
**kwargs)
self.email_message_providers[eventtype] = (wrapper, handler)
else:
wrapper, handler = self.email_message_providers[eventtype]
component.get("EventManager").register_event_handler(
eventtype, wrapper
)
def deregister_email_message_provider(self, eventtype):
wrapper, handler = self.email_message_providers[eventtype]
component.get("EventManager").deregister_event_handler(
eventtype, wrapper
)
self.email_message_providers.pop(eventtype)
def _handle_custom_email_message_providers(self, event, *args, **kwargs):
if not self.config['smtp_enabled']:
return defer.succeed("SMTP notification not enabled")
d = threads.deferToThread(self._notify_email, title, message, smtp_from,
recipients)
d.addCallback(self._on_notify_sucess, 'email')
d.addErrback(self._on_notify_failure, 'email')
return d
return defer.succeed("SMTP notification not enabled.")
@export
def notify_flash(self, title='', message=''):
if not self.config["flash_enabled"]:
return defer.succeed("Flash notification not enabled")
d = defer.maybeDeferred(component.get("EventManager").emit,
events.NotificationFlashEvent(title, message))
d.addCallback(self._on_notify_event_sucess, 'flash')
d.addErrback(self._on_notify_event_failure, 'flash')
return d
log.debug("\n\nCalling CORE's custom email providers for %s: %s %s",
event, args, kwargs)
if event in self.config["subscriptions"]["email"]:
wrapper, handler = self.email_message_providers[event]
log.debug("Found handler: %s", handler)
d = defer.maybeDeferred(handler, *args, **kwargs)
d.addCallback(self._prepare_email)
d.addCallback(self._on_notify_sucess)
d.addErrback(self._on_notify_failure)
return d
@export
def notify_popup(self, title='', message=''):
if not self.config["popup_enabled"]:
return defer.succeed("Popup notification not enabled")
d = defer.maybeDeferred(component.get("EventManager").emit,
events.NotificationPopupEvent(title, message))
d.addCallback(self._on_notify_event_sucess, 'popup')
d.addErrback(self._on_notify_event_failure, 'popup')
return d
@export
def notify_sound(self, sound_path=''):
if not self.config["sound_enabled"]:
return defer.succeed("Sound notification not enabled")
d = defer.maybeDeferred(component.get("EventManager").emit,
events.NotificationSoundEvent(sound_path))
d.addCallback(self._on_notify_event_sucess, 'sound')
d.addErrback(self._on_notify_event_failure, 'sound')
return d
def _prepare_email(self, result):
if not self.config['smtp_enabled']:
return defer.succeed("SMTP notification not enabled.")
subject, message = result
log.debug("\n\nSending email with subject: %s: %s", subject, message)
return threads.deferToThread(self._notify_email, subject, message)
def _notify_email(self, title='', message='', smtp_from='', recipients=[]):
def _notify_email(self, subject='', message=''):
log.debug("Email prepared")
config = self.config
to_addrs = '; '.join(config['smtp_recipients']+recipients)
to_addrs = '; '.join(config['smtp_recipients'])
headers = """\
From: %(smtp_from)s
To: %(smtp_recipients)s
Subject: %(title)s
Subject: %(subject)s
""" % {'smtp_from': smtp_from and smtp_from or config['smtp_from'],
'title': title,
""" % {'smtp_from': config['smtp_from'],
'subject': subject,
'smtp_recipients': to_addrs}
message = '\r\n'.join((headers + message).splitlines())
@ -169,7 +194,7 @@ Subject: %(title)s
err_msg = _("There was an error sending the notification email:"
" %s") % err
log.error(err_msg)
raise err
return err
security_enabled = config['smtp_tls']
@ -188,12 +213,12 @@ Subject: %(title)s
err_msg = _("The server didn't reply properly to the helo "
"greeting: %s") % err
log.error(err_msg)
raise err
return err
except smtplib.SMTPAuthenticationError, err:
err_msg = _("The server didn't accept the username/password "
"combination: %s") % err
log.error(err_msg)
raise err
return err
try:
try:
@ -202,7 +227,7 @@ Subject: %(title)s
err_msg = _("There was an error sending the notification email:"
" %s") % err
log.error(err_msg)
raise err
return err
finally:
if security_enabled:
# avoid false failure detection when the server closes
@ -216,12 +241,13 @@ Subject: %(title)s
server.quit()
return _("Notification email sent.")
def _on_torrent_finished_event(self, torrent_id):
log.debug("\n\nhandler for TorrentFinishedEvent called for CORE")
log.debug("\n\nHandler for TorrentFinishedEvent called for CORE")
torrent = component.get("TorrentManager")[torrent_id]
torrent_status = torrent.get_status({})
# Email
title = _("Finished Torrent \"%(name)s\"") % torrent_status
subject = _("Finished Torrent \"%(name)s\"") % torrent_status
message = _(
"This email is to inform you that Deluge has finished "
"downloading \"%(name)s\", which includes %(num_files)i files."
@ -230,7 +256,17 @@ Subject: %(title)s
"Thank you,\nDeluge."
) % torrent_status
d = defer.maybeDeferred(self.notify_email, title, message)
d.addCallback(self._on_notify_sucess, 'email')
d.addErrback(self._on_notify_failure, 'email')
log.debug("Email notification callback yielded")
d = defer.maybeDeferred(self._prepare_email, [subject, message])
d.addCallback(self._on_notify_sucess)
d.addErrback(self._on_notify_failure)
return d
def _on_notify_sucess(self, result):
log.debug("\n\nEMAIL Notification success: %s", result)
return result
def _on_notify_failure(self, failure):
log.debug("\n\nEMAIL Notification failure: %s", failure)
return failure

View File

@ -8,390 +8,537 @@
<property name="visible">True</property>
<property name="orientation">vertical</property>
<child>
<widget class="GtkFrame" id="frame2">
<widget class="GtkViewport" id="viewport1">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<property name="resize_mode">queue</property>
<child>
<widget class="GtkAlignment" id="alignment2">
<widget class="GtkVBox" id="vbox4">
<property name="visible">True</property>
<property name="left_padding">12</property>
<property name="orientation">vertical</property>
<child>
<widget class="GtkVBox" id="vbox1">
<widget class="GtkVBox" id="vbox3">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<child>
<widget class="GtkCheckButton" id="blink_enabled">
<property name="label" translatable="yes">Blink tray icon</property>
<widget class="GtkLabel" id="label22">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="xalign">0</property>
<property name="xpad">10</property>
<property name="ypad">10</property>
<property name="label" translatable="yes">&lt;b&gt;&lt;i&gt;&lt;big&gt;Notifications&lt;/big&gt;&lt;/i&gt;&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="popup_enabled">
<property name="label" translatable="yes">Show popup</property>
<widget class="GtkHSeparator" id="hseparator1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="yalign">0</property>
<property name="bottom_padding">2</property>
<property name="left_padding">2</property>
<property name="right_padding">2</property>
<child>
<widget class="GtkHBox" id="hbox2">
<widget class="GtkNotebook" id="notebook1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<child>
<widget class="GtkCheckButton" id="sound_enabled">
<property name="label" translatable="yes">Play sound</property>
<widget class="GtkVBox" id="vbox2">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_sound_enabled_toggled"/>
<property name="orientation">vertical</property>
<child>
<widget class="GtkFrame" id="frame2">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<widget class="GtkAlignment" id="alignment2">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<child>
<widget class="GtkCheckButton" id="blink_enabled">
<property name="label" translatable="yes">Tray icon blinks enabled</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="popup_enabled">
<property name="label" translatable="yes">Popups enabled</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkHBox" id="hbox2">
<property name="visible">True</property>
<child>
<widget class="GtkCheckButton" id="sound_enabled">
<property name="label" translatable="yes">Sound enabled</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_sound_enabled_toggled"/>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkFileChooserButton" id="sound_path">
<property name="visible">True</property>
<property name="create_folders">False</property>
</widget>
<packing>
<property name="padding">2</property>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="position">2</property>
</packing>
</child>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkLabel" id="label6">
<property name="visible">True</property>
<property name="xpad">5</property>
<property name="label" translatable="yes">&lt;b&gt;UI Notifications&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="type">label_item</property>
</packing>
</child>
</widget>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkFrame" id="frame3">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<widget class="GtkAlignment" id="alignment3">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkTable" id="prefs_table">
<property name="visible">True</property>
<property name="n_rows">7</property>
<property name="n_columns">4</property>
<property name="column_spacing">2</property>
<property name="row_spacing">2</property>
<child>
<widget class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="label" translatable="yes">Hostname:</property>
<property name="justify">right</property>
</widget>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="smtp_host">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="label" translatable="yes">Port:</property>
<property name="justify">right</property>
</widget>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<widget class="GtkSpinButton" id="smtp_port">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="max_length">65535</property>
<property name="invisible_char">&#x25CF;</property>
<property name="width_chars">5</property>
<property name="adjustment">25 1 100 1 10 0</property>
<property name="climb_rate">1</property>
<property name="snap_to_ticks">True</property>
<property name="numeric">True</property>
</widget>
<packing>
<property name="left_attach">3</property>
<property name="right_attach">4</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="label" translatable="yes">Username:</property>
<property name="justify">right</property>
</widget>
<packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="smtp_user">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">4</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="label" translatable="yes">Password:</property>
</widget>
<packing>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="smtp_pass">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="visibility">False</property>
<property name="invisible_char">&#x25CF;</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">4</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
</packing>
</child>
<child>
<widget class="GtkFrame" id="frame1">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<widget class="GtkAlignment" id="alignment4">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkHBox" id="hbox1">
<property name="visible">True</property>
<property name="spacing">2</property>
<child>
<widget class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">automatic</property>
<property name="vscrollbar_policy">automatic</property>
<child>
<widget class="GtkTreeView" id="smtp_recipients">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="headers_visible">False</property>
<property name="enable_grid_lines">horizontal</property>
</widget>
</child>
</widget>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkVButtonBox" id="vbuttonbox1">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="spacing">5</property>
<property name="layout_style">start</property>
<child>
<widget class="GtkButton" id="add_button">
<property name="label">gtk-add</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_add_button_clicked"/>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="delete_button">
<property name="label">gtk-delete</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_delete_button_clicked"/>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="padding">3</property>
<property name="position">1</property>
</packing>
</child>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkLabel" id="label5">
<property name="visible">True</property>
<property name="label" translatable="yes">&lt;b&gt;Recipients&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="type">label_item</property>
</packing>
</child>
</widget>
<packing>
<property name="right_attach">4</property>
<property name="top_attach">6</property>
<property name="bottom_attach">7</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="smtp_tls">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<child>
<widget class="GtkLabel" id="label9">
<property name="visible">True</property>
<property name="label" translatable="yes">Server requires TLS/SSL</property>
</widget>
</child>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">4</property>
<property name="top_attach">5</property>
<property name="bottom_attach">6</property>
<property name="x_padding">10</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label8">
<property name="visible">True</property>
<property name="label" translatable="yes">From:</property>
<property name="justify">right</property>
</widget>
<packing>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="smtp_from">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">4</property>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="smtp_enabled">
<property name="label" translatable="yes">Enabled</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_enabled_toggled"/>
</widget>
<packing>
<property name="right_attach">4</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkLabel" id="label7">
<property name="visible">True</property>
<property name="xpad">5</property>
<property name="label" translatable="yes">&lt;b&gt;Email Notifications&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="type">label_item</property>
</packing>
</child>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
</child>
<child>
<widget class="GtkLabel" id="label10">
<property name="visible">True</property>
<property name="label" translatable="yes">Settings</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
<property name="tab_fill">False</property>
<property name="type">tab</property>
</packing>
</child>
<child>
<widget class="GtkFileChooserButton" id="sound_path">
<widget class="GtkVBox" id="vbox5">
<property name="visible">True</property>
<property name="create_folders">False</property>
<property name="orientation">vertical</property>
<child>
<placeholder/>
</child>
<child>
<widget class="GtkScrolledWindow" id="scrolledwindow2">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">automatic</property>
<property name="vscrollbar_policy">automatic</property>
<child>
<widget class="GtkTreeView" id="subscriptions_treeview">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="enable_grid_lines">horizontal</property>
</widget>
</child>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label12">
<property name="visible">True</property>
<property name="label" translatable="yes">This configuration does not mean that you'll actually receive notifications for all these events.</property>
<property name="justify">fill</property>
<property name="wrap">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="padding">2</property>
<property name="position">2</property>
</packing>
</child>
</widget>
<packing>
<property name="padding">2</property>
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label11">
<property name="visible">True</property>
<property name="label" translatable="yes">Subscriptions</property>
</widget>
<packing>
<property name="position">1</property>
<property name="tab_fill">False</property>
<property name="type">tab</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
<packing>
<property name="type">tab</property>
</packing>
</child>
</widget>
<packing>
<property name="position">2</property>
</packing>
</child>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
</child>
<child>
<widget class="GtkLabel" id="label6">
<property name="visible">True</property>
<property name="label" translatable="yes">&lt;b&gt;UI Notifications&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="type">label_item</property>
</packing>
</child>
</widget>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkFrame" id="frame3">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<widget class="GtkAlignment" id="alignment3">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkTable" id="prefs_table">
<property name="visible">True</property>
<property name="n_rows">7</property>
<property name="n_columns">4</property>
<property name="column_spacing">2</property>
<property name="row_spacing">2</property>
<child>
<widget class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="label" translatable="yes">Hostname:</property>
<property name="justify">right</property>
</widget>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="smtp_host">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="label" translatable="yes">Port:</property>
<property name="justify">right</property>
</widget>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<widget class="GtkSpinButton" id="smtp_port">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="max_length">65535</property>
<property name="invisible_char">&#x25CF;</property>
<property name="width_chars">5</property>
<property name="adjustment">25 1 100 1 10 10</property>
<property name="climb_rate">1</property>
<property name="snap_to_ticks">True</property>
<property name="numeric">True</property>
</widget>
<packing>
<property name="left_attach">3</property>
<property name="right_attach">4</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="label" translatable="yes">Username:</property>
<property name="justify">right</property>
</widget>
<packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="smtp_user">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">4</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="label" translatable="yes">Password:</property>
</widget>
<packing>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="smtp_pass">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="visibility">False</property>
<property name="invisible_char">&#x25CF;</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">4</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
</packing>
</child>
<child>
<widget class="GtkFrame" id="frame1">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<widget class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkHBox" id="hbox1">
<property name="visible">True</property>
<property name="spacing">2</property>
<child>
<widget class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">automatic</property>
<property name="vscrollbar_policy">automatic</property>
<child>
<widget class="GtkTreeView" id="smtp_recipients">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="headers_visible">False</property>
<property name="enable_grid_lines">horizontal</property>
</widget>
</child>
</widget>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkVButtonBox" id="vbuttonbox1">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="spacing">5</property>
<property name="layout_style">start</property>
<child>
<widget class="GtkButton" id="add_button">
<property name="label">gtk-add</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_add_button_clicked"/>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="delete_button">
<property name="label">gtk-delete</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_delete_button_clicked"/>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="padding">3</property>
<property name="position">1</property>
</packing>
</child>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkLabel" id="label5">
<property name="visible">True</property>
<property name="label" translatable="yes">&lt;b&gt;Recipients&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="type">label_item</property>
</packing>
</child>
</widget>
<packing>
<property name="right_attach">4</property>
<property name="top_attach">6</property>
<property name="bottom_attach">7</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="smtp_tls">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<child>
<widget class="GtkLabel" id="label9">
<property name="visible">True</property>
<property name="label" translatable="yes">Server requires TLS/SSL</property>
</widget>
</child>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">4</property>
<property name="top_attach">5</property>
<property name="bottom_attach">6</property>
<property name="x_padding">10</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label8">
<property name="visible">True</property>
<property name="label" translatable="yes">From:</property>
<property name="justify">right</property>
</widget>
<packing>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="smtp_from">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">4</property>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="smtp_enabled">
<property name="label" translatable="yes">Enabled</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_enabled_toggled"/>
</widget>
<packing>
<property name="right_attach">4</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkLabel" id="label7">
<property name="visible">True</property>
<property name="label" translatable="yes">&lt;b&gt;Email Notifications&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="type">label_item</property>
</packing>
</child>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
</child>
</widget>

View File

@ -40,11 +40,13 @@
import gtk
from twisted.internet import defer
from deluge.event import known_events, DelugeEvent
from deluge.log import LOG as log
from deluge.ui.client import client
from deluge.plugins.pluginbase import GtkPluginBase
import deluge.component as component
import deluge.common
import deluge.configmanager
try:
import pygame
@ -60,44 +62,148 @@ except ImportError:
# Relative imports
from common import get_resource
from manager import Notifications
DEFAULT_PREFS = {
# BLINK
"blink_enabled": False,
# FLASH
"flash_enabled": False,
# POPUP
"popup_enabled": False,
# SOUND
"sound_enabled": False,
"sound_path": "",
# Subscriptions
"subscriptions": {
"popup": [],
"blink": [],
"sound": [],
}
}
RECIPIENT_FIELD, RECIPIENT_EDIT = range(2)
(SUB_EVENT, SUB_EVENT_DOC, SUB_NOT_EMAIL, SUB_NOT_POPUP, SUB_NOT_BLINK,
SUB_NOT_SOUND) = range(6)
class GtkUI(GtkPluginBase, component.Component):
def __init__(self, plugin_name):
GtkPluginBase.__init__(self, plugin_name)
component.Component.__init__(self, "Notifications")
class GtkUI(GtkPluginBase, Notifications):
def enable(self):
Notifications.enable(self)
self.config = deluge.configmanager.ConfigManager(
"notifications-gtk.conf", DEFAULT_PREFS
)
self.glade = gtk.glade.XML(get_resource("config.glade"))
self.glade.get_widget("smtp_port").set_value(25)
self.prefs = self.glade.get_widget("prefs_box")
self.prefs.show_all()
self.treeview = self.glade.get_widget("smtp_recipients")
treeview_selection = self.treeview.get_selection()
treeview_selection.connect("changed", self.on_treeview_selection_changed)
self.model = gtk.ListStore(str, bool)
# SMTP Recipients treeview/model
self.recipients_treeview = self.glade.get_widget("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.model)
renderer.connect("edited", self.on_cell_edited, self.recipients_model)
renderer.set_data("recipient", RECIPIENT_FIELD)
column = gtk.TreeViewColumn("Recipients", renderer,
text=RECIPIENT_FIELD,
editable=RECIPIENT_EDIT)
column.set_expand(True)
self.treeview.append_column(column)
self.treeview.set_model(self.model)
self.recipients_treeview.append_column(column)
self.recipients_treeview.set_model(self.recipients_model)
deluge.common.get_default_download_dir()
# Notification Subscriptions treeview/model
self.subscriptions_treeview = self.glade.get_widget("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()
renderer.set_data("event", SUB_EVENT)
column = gtk.TreeViewColumn("Event", renderer, text=SUB_EVENT)
column.set_expand(True)
self.subscriptions_treeview.append_column(column)
renderer = gtk.CellRendererText()
renderer.set_data("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)
# column.add_attribute(renderer, "active", False)
# column.set_expand(True)
self.subscriptions_treeview.append_column(column)
renderer = gtk.CellRendererToggle()
# renderer.connect("edited", self.on_cell_edited, self.recipients_model)
# renderer.set_data("popup", SUB_NOT_POPUP)
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)
# column.add_attribute(renderer, "active", False)
# column.set_expand(True)
self.subscriptions_treeview.append_column(column)
renderer = gtk.CellRendererToggle()
# renderer.connect("edited", self.on_cell_edited, self.recipients_model)
# renderer.set_data("blink", SUB_NOT_BLINK)
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)
# column.add_attribute(renderer, "active", False)
# column.set_expand(True)
self.subscriptions_treeview.append_column(column)
renderer = gtk.CellRendererToggle()
# renderer.connect("edited", self.on_cell_edited, self.recipients_model)
renderer.set_property('activatable', True)
renderer.connect('toggled', self._on_sound_col_toggled)
# renderer.set_data("sound", SUB_NOT_SOUND)
column = gtk.TreeViewColumn("Sound", renderer, active=SUB_NOT_SOUND)
column.set_clickable(True)
# column.add_attribute(renderer, "active", False)
# column.set_expand(True)
self.subscriptions_treeview.append_column(column)
self.subscriptions_treeview.set_model(self.subscriptions_model)
client.notifications.get_handled_events().addCallback(
self.popuplate_subscriptions
)
self.glade.signal_autoconnect({
'on_add_button_clicked': (self.on_add_button_clicked,
self.treeview),
self.recipients_treeview),
'on_delete_button_clicked': (self.on_delete_button_clicked,
self.treeview),
self.recipients_treeview),
'on_enabled_toggled': self.on_enabled_toggled,
'on_sound_enabled_toggled': self.on_sound_enabled_toggled
})
component.get("Preferences").add_page("Notifications", self.prefs)
# component.get("Preferences").add_page("Notifications", self.prefs)
prefs = component.get("Preferences")
parent = self.prefs.get_parent()
if parent:
parent.remove(self.prefs)
index = prefs.notebook.append_page(self.prefs)
prefs.liststore.append([index, "Notifications"])
component.get("PluginManager").register_hook("on_apply_prefs",
self.on_apply_prefs)
component.get("PluginManager").register_hook("on_show_prefs",
@ -106,38 +212,93 @@ class GtkUI(GtkPluginBase, Notifications):
if not POPUP_AVAILABLE:
self.glade.get_widget("popup_enabled").set_property('sensitive',
False)
else:
client.register_event_handler("NotificationPopupEvent",
self.notify_popup)
client.register_event_handler("NotificationBlinkEvent",
self.notify_blink)
self.tray = component.get("SystemTray")
if not SOUND_AVAILABLE:
self.glade.get_widget("sound_enabled").set_property('sensitive',
False)
self.glade.get_widget('sound_path').set_property('sensitive', False)
else:
client.register_event_handler("NotificationSoundEvent",
self.notify_sound)
self.systray = component.get("SystemTray")
if not hasattr(self.systray, 'tray'):
# Tray is not beeing used
self.glade.get_widget('blink_enabled').set_property('sensitive',
False)
client.register_event_handler("TorrentFinishedEvent",
self._on_torrent_finished_event)
# Force config populate
client.notifications.get_config().addCallback(self.cb_get_config)
def disable(self):
Notifications.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 popuplate_subscriptions(self, handled_events, 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")
config = {
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)
# saved_popup_subscriptions = self.config['subscriptions']['popup']
# saved_blink_subscriptions = self.config['subscriptions']['blink']
# saved_sound_subscriptions = self.config['subscriptions']['sound']
# for event in current_popup_subscriptions:
# saved_popup_subscriptions.remove(event)
# for event in saved_blink_subscriptions:
# # De register
# pass
# for event in current_blink_subscriptions:
# saved_blink_subscriptions.remove(event)
# for event in saved_blink_subscriptions:
# # De register
# pass
# for event in current_sound_subscriptions:
# saved_sound_subscriptions.remove(event)
# for event in saved_sound_subscriptions:
# # De register
# pass
self.config.config.update({
"popup_enabled": self.glade.get_widget("popup_enabled").get_active(),
"blink_enabled": self.glade.get_widget("blink_enabled").get_active(),
"sound_enabled": self.glade.get_widget("sound_enabled").get_active(),
"sound_path": self.glade.get_widget("sound_path").get_filename(),
"subscriptions": {
"popup": current_popup_subscriptions,
"blink": current_blink_subscriptions,
"sound": current_sound_subscriptions
}
})
self.config.save()
core_config = {
"smtp_enabled": self.glade.get_widget("smtp_enabled").get_active(),
"smtp_host": self.glade.get_widget("smtp_host").get_text(),
"smtp_port": self.glade.get_widget("smtp_port").get_value(),
@ -145,45 +306,42 @@ class GtkUI(GtkPluginBase, Notifications):
"smtp_pass": self.glade.get_widget("smtp_pass").get_text(),
"smtp_from": self.glade.get_widget("smtp_from").get_text(),
"smtp_tls": self.glade.get_widget("smtp_tls").get_active(),
"smtp_recipients": [dest[0] for dest in self.model if
"smtp_recipients": [dest[0] for dest in self.recipients_model if
dest[0]!='USER@HOST'],
"blink_enabled": self.glade.get_widget("blink_enabled").get_active(),
"sound_enabled": self.glade.get_widget("sound_enabled").get_active(),
"sound_path": self.glade.get_widget("sound_path").get_filename(),
"popup_enabled": self.glade.get_widget("popup_enabled").get_active()
"subscriptions": {"email": current_email_subscriptions}
}
client.notifications.set_config(config)
client.notifications.set_config(core_config)
def on_show_prefs(self):
client.notifications.get_config().addCallback(self.cb_get_config)
def cb_get_config(self, config):
def cb_get_config(self, core_config):
"callback for on show_prefs"
self.config = config
self.glade.get_widget("smtp_host").set_text(config["smtp_host"])
self.glade.get_widget("smtp_port").set_value(config["smtp_port"])
self.glade.get_widget("smtp_user").set_text(config["smtp_user"])
self.glade.get_widget("smtp_pass").set_text(config["smtp_pass"])
self.glade.get_widget("smtp_from").set_text(config["smtp_from"])
self.glade.get_widget("smtp_tls").set_active(config["smtp_tls"])
self.model.clear()
for recipient in config['smtp_recipients']:
self.model.set(self.model.append(),
RECIPIENT_FIELD, recipient,
RECIPIENT_EDIT, False)
self.glade.get_widget("smtp_enabled").set_active(config['smtp_enabled'])
self.glade.get_widget("smtp_host").set_text(core_config["smtp_host"])
self.glade.get_widget("smtp_port").set_value(core_config["smtp_port"])
self.glade.get_widget("smtp_user").set_text(core_config["smtp_user"])
self.glade.get_widget("smtp_pass").set_text(core_config["smtp_pass"])
self.glade.get_widget("smtp_from").set_text(core_config["smtp_from"])
self.glade.get_widget("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.glade.get_widget("smtp_enabled").set_active(
core_config['smtp_enabled']
)
self.glade.get_widget("sound_enabled").set_active(
config['sound_enabled']
self.config['sound_enabled']
)
self.glade.get_widget("popup_enabled").set_active(
config['popup_enabled']
self.config['popup_enabled']
)
self.glade.get_widget("blink_enabled").set_active(
config['blink_enabled']
self.config['blink_enabled']
)
if config['sound_path']:
sound_path = config['sound_path']
if self.config['sound_path']:
sound_path = self.config['sound_path']
else:
sound_path = deluge.common.get_default_download_dir()
self.glade.get_widget("sound_path").set_filename(sound_path)
@ -191,6 +349,11 @@ class GtkUI(GtkPluginBase, Notifications):
self.on_enabled_toggled(self.glade.get_widget("smtp_enabled"))
self.on_sound_enabled_toggled(self.glade.get_widget('sound_enabled'))
client.notifications.get_handled_events().addCallback(
self.popuplate_subscriptions, core_config['subscriptions']['email']
)
def on_add_button_clicked(self, widget, treeview):
model = treeview.get_model()
model.set(model.append(),
@ -210,7 +373,7 @@ class GtkUI(GtkPluginBase, Notifications):
path = model.get_path(iter)[0]
model.set(iter, RECIPIENT_FIELD, new_text)
def on_treeview_selection_changed(self, selection):
def on_recipients_treeview_selection_changed(self, selection):
model, selected_connection_iter = selection.get_selected()
if selected_connection_iter:
self.glade.get_widget("delete_button").set_property('sensitive',
@ -218,6 +381,16 @@ class GtkUI(GtkPluginBase, Notifications):
else:
self.glade.get_widget("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.glade.get_widget("delete_button").set_property('sensitive',
True)
else:
self.glade.get_widget("delete_button").set_property('sensitive',
False)
def on_enabled_toggled(self, widget):
if widget.get_active():
for widget in ('smtp_host', 'smtp_port', 'smtp_user', 'smtp_pass',
@ -237,24 +410,14 @@ class GtkUI(GtkPluginBase, Notifications):
else:
self.glade.get_widget('sound_path').set_property('sensitive', False)
def notify_blink(self):
defer.maybeDeferred(self.tray.blink, True)
return defer.succeed("blink notification shown.")
def notify_email(self, title='', message='', smtp_from='', recipients=[]):
d = client.notifications.notify_email(title, message, smtp_from,
recipients)
d.addCallback(self._on_notify_sucess, "email")
d.addCallback(self._on_notify_failure, "email")
# Notification methods
def blink(self):
d = defer.maybeDeferred(self.systray.blink, True)
d.addCallback(self._on_notify_sucess, "blink")
d.addCallback(self._on_notify_failure, "blink")
return d
def notify_flash(self, title='', message=''):
d = client.notifications.notify_flash(title, message)
d.addCallback(self._on_notify_sucess, "flash")
d.addCallback(self._on_notify_failure, "flash")
return d
def notify_popup(self, title='', message=''):
def popup(self, title='', message=''):
if not self.config['popup_enabled']:
return defer.succeed(_("Popup notification is not enabled."))
if not POPUP_AVAILABLE:
@ -271,7 +434,7 @@ class GtkUI(GtkPluginBase, Notifications):
return defer.fail(err_msg)
return defer.succeed(_("Notification popup shown"))
def notify_sound(self, sound_path=''):
def play_sound(self, sound_path=''):
if not self.config['sound_enabled']:
return defer.succeed(_("Sound notification not enabled"))
if not SOUND_AVAILABLE:
@ -295,15 +458,16 @@ class GtkUI(GtkPluginBase, Notifications):
log.info(msg)
return defer.succeed(msg)
# Internal methods
def _on_torrent_finished_event(self, torrent_id):
log.debug("\n\nhandler for TorrentFinishedEvent GTKUI called")
# Blink
d0 = defer.maybeDeferred(self.notify_blink)
d0 = defer.maybeDeferred(self.blink)
d0.addCallback(self._on_notify_sucess, 'blink')
d0.addErrback(self._on_notify_failure, 'blink')
log.debug("Blink notification callback yielded")
# Sound
d1 = defer.maybeDeferred(self.notify_sound)
d1 = defer.maybeDeferred(self.play_sound)
d1.addCallback(self._on_notify_sucess, 'sound')
d1.addErrback(self._on_notify_failure, 'sound')
log.debug("Sound notification callback yielded")
@ -311,6 +475,7 @@ class GtkUI(GtkPluginBase, Notifications):
d2 = client.core.get_torrent_status(torrent_id, ["name", "num_files"])
d2.addCallback(self._on_torrent_finished_event_got_torrent_status)
d2.addErrback(self._on_torrent_finished_event_torrent_status_failure)
return defer.succeed("\n\nGtkUI on torrent finished")
def _on_torrent_finished_event_torrent_status_failure(self, failure):
log.debug("Failed to get torrent status to be able to show the popup")
@ -320,8 +485,36 @@ class GtkUI(GtkPluginBase, Notifications):
title = _("Finished Torrent")
message = _("The torrent \"%(name)s\" including %(num_files)i "
"has finished downloading.") % torrent_status
d2 = defer.maybeDeferred(self.notify_popup, title, message)
d2.addCallback(self._on_notify_sucess, 'popup')
d2.addErrback(self._on_notify_failure, 'popup')
log.debug("Popup notification callback yielded")
d = defer.maybeDeferred(self.popup, title, message)
d.addCallback(self._on_notify_sucess, 'popup')
d.addErrback(self._on_notify_failure, 'popup')
return d
def _on_notify_sucess(self, result, kind):
log.debug("\n\nNotification success using %s: %s", kind, result)
return result
def _on_notify_failure(self, failure, kind):
log.debug("\n\nNotification failure using %s: %s", kind, failure)
return failure
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

View File

@ -37,21 +37,49 @@
# statement from all source files in the program, then also delete it here.
#
from twisted.internet import defer
from deluge.log import LOG as log
from deluge.ui.client import client
from deluge import component
from deluge.plugins.pluginbase import WebPluginBase
import deluge.configmanager
# Relative imports
from common import get_resource
from manager import Notifications
class WebUI(WebPluginBase, Notifications):
DEFAULT_PREFS = {
# FLASH
"flash_enabled": False,
# Subscriptions
"subscriptions": {
"flash": []
}
}
class WebUI(WebPluginBase, component.Component):
scripts = [get_resource("notifications.js")]
def __init__(self, plugin_name):
WebPluginBase.__init__(self, plugin_name)
component.Component.__init__(self, "Notifications")
def enable(self):
Notifications.enable(self)
self.config = deluge.configmanager.ConfigManager(
"notifications-web.conf", DEFAULT_PREFS
)
log.debug("Enabling Web UI notifications")
def disable(self):
Notifications.disable(self)
log.debug("Disabling Web UI notifications")
def flash(self, title, message):
return defer.succeed("Web Flash Notifications not implemented yet")
def _on_notify_sucess(self, result, kind):
log.debug("\n\nNotification success using %s: %s", kind, result)
return result
def _on_notify_failure(self, failure, kind):
log.debug("\n\nNotification failure using %s: %s", kind, failure)
return failure