Checkpoint:
* Custom notification providers working for email. * Configuration through the GtkUI working.
This commit is contained in:
parent
8a6ec7232d
commit
1b7a50f88b
|
@ -17,9 +17,9 @@
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with deluge. If not, write to:
|
# along with deluge. If not, write to:
|
||||||
# The Free Software Foundation, Inc.,
|
# The Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor
|
# 51 Franklin Street, Fifth Floor
|
||||||
# Boston, MA 02110-1301, USA.
|
# Boston, MA 02110-1301, USA.
|
||||||
#
|
#
|
||||||
# In addition, as a special exception, the copyright holders give
|
# In addition, as a special exception, the copyright holders give
|
||||||
# permission to link the code of portions of this program with the OpenSSL
|
# 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):
|
class DelugeEventMetaClass(type):
|
||||||
"""
|
"""
|
||||||
This metaclass simply keeps a list of all events classes created.
|
This metaclass simply keeps a list of all events classes created.
|
||||||
"""
|
"""
|
||||||
def __init__(cls, name, bases, dct):
|
def __init__(cls, name, bases, dct):
|
||||||
event_list.append(name)
|
|
||||||
super(DelugeEventMetaClass, cls).__init__(name, bases, dct)
|
super(DelugeEventMetaClass, cls).__init__(name, bases, dct)
|
||||||
|
known_events[name] = cls
|
||||||
|
|
||||||
class DelugeEvent(object):
|
class DelugeEvent(object):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -22,9 +22,9 @@
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with deluge. If not, write to:
|
# along with deluge. If not, write to:
|
||||||
# The Free Software Foundation, Inc.,
|
# The Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor
|
# 51 Franklin Street, Fifth Floor
|
||||||
# Boston, MA 02110-1301, USA.
|
# Boston, MA 02110-1301, USA.
|
||||||
#
|
#
|
||||||
# In addition, as a special exception, the copyright holders give
|
# In addition, as a special exception, the copyright holders give
|
||||||
# permission to link the code of portions of this program with the OpenSSL
|
# permission to link the code of portions of this program with the OpenSSL
|
||||||
|
@ -39,4 +39,35 @@
|
||||||
|
|
||||||
def get_resource(filename):
|
def get_resource(filename):
|
||||||
import pkg_resources, os
|
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": [],
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -39,20 +39,16 @@
|
||||||
|
|
||||||
import smtplib
|
import smtplib
|
||||||
from twisted.internet import defer, threads
|
from twisted.internet import defer, threads
|
||||||
|
from deluge.event import known_events, DelugeEvent
|
||||||
from deluge.log import LOG as log
|
from deluge.log import LOG as log
|
||||||
from deluge.plugins.pluginbase import CorePluginBase
|
from deluge.plugins.pluginbase import CorePluginBase
|
||||||
import deluge.component as component
|
import deluge.component as component
|
||||||
import deluge.configmanager
|
import deluge.configmanager
|
||||||
from deluge.core.rpcserver import export
|
from deluge.core.rpcserver import export
|
||||||
|
|
||||||
# Relative imports
|
from test import TestEmailNotifications
|
||||||
from manager import Notifications
|
|
||||||
import events
|
|
||||||
|
|
||||||
DEFAULT_PREFS = {
|
DEFAULT_PREFS = {
|
||||||
# BLINK
|
|
||||||
"blink_enabled": False,
|
|
||||||
# EMAIL
|
|
||||||
"smtp_enabled": False,
|
"smtp_enabled": False,
|
||||||
"smtp_host": "",
|
"smtp_host": "",
|
||||||
"smtp_port": 25,
|
"smtp_port": 25,
|
||||||
|
@ -61,29 +57,36 @@ DEFAULT_PREFS = {
|
||||||
"smtp_from": "",
|
"smtp_from": "",
|
||||||
"smtp_tls": False, # SSL or TLS
|
"smtp_tls": False, # SSL or TLS
|
||||||
"smtp_recipients": [],
|
"smtp_recipients": [],
|
||||||
# FLASH
|
# Subscriptions
|
||||||
"flash_enabled": False,
|
"subscriptions": {
|
||||||
# POPUP
|
"email": []
|
||||||
"popup_enabled": False,
|
}
|
||||||
# SOUND
|
|
||||||
"sound_enabled": False,
|
|
||||||
"sound_path": ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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):
|
def enable(self):
|
||||||
Notifications.enable(self)
|
self.config = deluge.configmanager.ConfigManager(
|
||||||
self.config = deluge.configmanager.ConfigManager("notifications.conf",
|
"notifications-core.conf", DEFAULT_PREFS)
|
||||||
DEFAULT_PREFS)
|
|
||||||
component.get("EventManager").register_event_handler(
|
component.get("EventManager").register_event_handler(
|
||||||
"TorrentFinishedEvent", self._on_torrent_finished_event
|
"TorrentFinishedEvent", self._on_torrent_finished_event
|
||||||
)
|
)
|
||||||
log.debug("\n\nENABLING CORE NOTIFICATIONS\n\n")
|
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):
|
def disable(self):
|
||||||
Notifications.disable(self)
|
self.tn.disable()
|
||||||
log.debug("\n\nDISABLING CORE NOTIFICATIONS\n\n")
|
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):
|
def update(self):
|
||||||
pass
|
pass
|
||||||
|
@ -100,65 +103,87 @@ class Core(CorePluginBase, Notifications):
|
||||||
"returns the config dictionary"
|
"returns the config dictionary"
|
||||||
return self.config.config
|
return self.config.config
|
||||||
|
|
||||||
# Notification methods
|
|
||||||
@export
|
@export
|
||||||
def notify_blink(self):
|
def get_handled_events(self):
|
||||||
if not self.config["blink_enabled"]:
|
handled_events = []
|
||||||
return defer.succeed("Blink notification not enabled")
|
for evt in sorted(known_events.keys()):
|
||||||
return defer.maybeDeferred(
|
if known_events[evt].__module__.startswith('deluge.event'):
|
||||||
component.get("EventManager").emit, events.NotificationBlinkEvent())
|
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 register_email_message_provider(self, eventtype, handler):
|
||||||
def notify_email(self, title='', message='', smtp_from='', recipients=[]):
|
"""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']:
|
if not self.config['smtp_enabled']:
|
||||||
return defer.succeed("SMTP notification not 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
|
|
||||||
|
|
||||||
@export
|
log.debug("\n\nCalling CORE's custom email providers for %s: %s %s",
|
||||||
def notify_flash(self, title='', message=''):
|
event, args, kwargs)
|
||||||
if not self.config["flash_enabled"]:
|
if event in self.config["subscriptions"]["email"]:
|
||||||
return defer.succeed("Flash notification not enabled")
|
wrapper, handler = self.email_message_providers[event]
|
||||||
d = defer.maybeDeferred(component.get("EventManager").emit,
|
log.debug("Found handler: %s", handler)
|
||||||
events.NotificationFlashEvent(title, message))
|
d = defer.maybeDeferred(handler, *args, **kwargs)
|
||||||
d.addCallback(self._on_notify_event_sucess, 'flash')
|
d.addCallback(self._prepare_email)
|
||||||
d.addErrback(self._on_notify_event_failure, 'flash')
|
d.addCallback(self._on_notify_sucess)
|
||||||
return d
|
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 _prepare_email(self, result):
|
||||||
def notify_sound(self, sound_path=''):
|
if not self.config['smtp_enabled']:
|
||||||
if not self.config["sound_enabled"]:
|
return defer.succeed("SMTP notification not enabled.")
|
||||||
return defer.succeed("Sound notification not enabled")
|
subject, message = result
|
||||||
d = defer.maybeDeferred(component.get("EventManager").emit,
|
log.debug("\n\nSending email with subject: %s: %s", subject, message)
|
||||||
events.NotificationSoundEvent(sound_path))
|
return threads.deferToThread(self._notify_email, subject, message)
|
||||||
d.addCallback(self._on_notify_event_sucess, 'sound')
|
|
||||||
d.addErrback(self._on_notify_event_failure, 'sound')
|
|
||||||
return d
|
|
||||||
|
|
||||||
def _notify_email(self, title='', message='', smtp_from='', recipients=[]):
|
|
||||||
|
def _notify_email(self, subject='', message=''):
|
||||||
|
log.debug("Email prepared")
|
||||||
config = self.config
|
config = self.config
|
||||||
to_addrs = '; '.join(config['smtp_recipients']+recipients)
|
to_addrs = '; '.join(config['smtp_recipients'])
|
||||||
headers = """\
|
headers = """\
|
||||||
From: %(smtp_from)s
|
From: %(smtp_from)s
|
||||||
To: %(smtp_recipients)s
|
To: %(smtp_recipients)s
|
||||||
Subject: %(title)s
|
Subject: %(subject)s
|
||||||
|
|
||||||
|
|
||||||
""" % {'smtp_from': smtp_from and smtp_from or config['smtp_from'],
|
""" % {'smtp_from': config['smtp_from'],
|
||||||
'title': title,
|
'subject': subject,
|
||||||
'smtp_recipients': to_addrs}
|
'smtp_recipients': to_addrs}
|
||||||
|
|
||||||
message = '\r\n'.join((headers + message).splitlines())
|
message = '\r\n'.join((headers + message).splitlines())
|
||||||
|
@ -169,7 +194,7 @@ Subject: %(title)s
|
||||||
err_msg = _("There was an error sending the notification email:"
|
err_msg = _("There was an error sending the notification email:"
|
||||||
" %s") % err
|
" %s") % err
|
||||||
log.error(err_msg)
|
log.error(err_msg)
|
||||||
raise err
|
return err
|
||||||
|
|
||||||
security_enabled = config['smtp_tls']
|
security_enabled = config['smtp_tls']
|
||||||
|
|
||||||
|
@ -188,12 +213,12 @@ Subject: %(title)s
|
||||||
err_msg = _("The server didn't reply properly to the helo "
|
err_msg = _("The server didn't reply properly to the helo "
|
||||||
"greeting: %s") % err
|
"greeting: %s") % err
|
||||||
log.error(err_msg)
|
log.error(err_msg)
|
||||||
raise err
|
return err
|
||||||
except smtplib.SMTPAuthenticationError, err:
|
except smtplib.SMTPAuthenticationError, err:
|
||||||
err_msg = _("The server didn't accept the username/password "
|
err_msg = _("The server didn't accept the username/password "
|
||||||
"combination: %s") % err
|
"combination: %s") % err
|
||||||
log.error(err_msg)
|
log.error(err_msg)
|
||||||
raise err
|
return err
|
||||||
|
|
||||||
try:
|
try:
|
||||||
try:
|
try:
|
||||||
|
@ -202,7 +227,7 @@ Subject: %(title)s
|
||||||
err_msg = _("There was an error sending the notification email:"
|
err_msg = _("There was an error sending the notification email:"
|
||||||
" %s") % err
|
" %s") % err
|
||||||
log.error(err_msg)
|
log.error(err_msg)
|
||||||
raise err
|
return err
|
||||||
finally:
|
finally:
|
||||||
if security_enabled:
|
if security_enabled:
|
||||||
# avoid false failure detection when the server closes
|
# avoid false failure detection when the server closes
|
||||||
|
@ -216,12 +241,13 @@ Subject: %(title)s
|
||||||
server.quit()
|
server.quit()
|
||||||
return _("Notification email sent.")
|
return _("Notification email sent.")
|
||||||
|
|
||||||
|
|
||||||
def _on_torrent_finished_event(self, torrent_id):
|
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 = component.get("TorrentManager")[torrent_id]
|
||||||
torrent_status = torrent.get_status({})
|
torrent_status = torrent.get_status({})
|
||||||
# Email
|
# Email
|
||||||
title = _("Finished Torrent \"%(name)s\"") % torrent_status
|
subject = _("Finished Torrent \"%(name)s\"") % torrent_status
|
||||||
message = _(
|
message = _(
|
||||||
"This email is to inform you that Deluge has finished "
|
"This email is to inform you that Deluge has finished "
|
||||||
"downloading \"%(name)s\", which includes %(num_files)i files."
|
"downloading \"%(name)s\", which includes %(num_files)i files."
|
||||||
|
@ -230,7 +256,17 @@ Subject: %(title)s
|
||||||
"Thank you,\nDeluge."
|
"Thank you,\nDeluge."
|
||||||
) % torrent_status
|
) % torrent_status
|
||||||
|
|
||||||
d = defer.maybeDeferred(self.notify_email, title, message)
|
d = defer.maybeDeferred(self._prepare_email, [subject, message])
|
||||||
d.addCallback(self._on_notify_sucess, 'email')
|
d.addCallback(self._on_notify_sucess)
|
||||||
d.addErrback(self._on_notify_failure, 'email')
|
d.addErrback(self._on_notify_failure)
|
||||||
log.debug("Email notification callback yielded")
|
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
|
||||||
|
|
|
@ -8,390 +8,537 @@
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="orientation">vertical</property>
|
<property name="orientation">vertical</property>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkFrame" id="frame2">
|
<widget class="GtkViewport" id="viewport1">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="label_xalign">0</property>
|
<property name="resize_mode">queue</property>
|
||||||
<property name="shadow_type">none</property>
|
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkAlignment" id="alignment2">
|
<widget class="GtkVBox" id="vbox4">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="left_padding">12</property>
|
<property name="orientation">vertical</property>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkVBox" id="vbox1">
|
<widget class="GtkVBox" id="vbox3">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="orientation">vertical</property>
|
<property name="orientation">vertical</property>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkCheckButton" id="blink_enabled">
|
<widget class="GtkLabel" id="label22">
|
||||||
<property name="label" translatable="yes">Blink tray icon</property>
|
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">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="receives_default">False</property>
|
<property name="xalign">0</property>
|
||||||
<property name="draw_indicator">True</property>
|
<property name="xpad">10</property>
|
||||||
|
<property name="ypad">10</property>
|
||||||
|
<property name="label" translatable="yes"><b><i><big>Notifications</big></i></b></property>
|
||||||
|
<property name="use_markup">True</property>
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
<property name="position">0</property>
|
<property name="position">0</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkCheckButton" id="popup_enabled">
|
<widget class="GtkHSeparator" id="hseparator1">
|
||||||
<property name="label" translatable="yes">Show popup</property>
|
|
||||||
<property name="visible">True</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>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
<property name="position">1</property>
|
<property name="position">1</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</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>
|
<child>
|
||||||
<widget class="GtkHBox" id="hbox2">
|
<widget class="GtkNotebook" id="notebook1">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkCheckButton" id="sound_enabled">
|
<widget class="GtkVBox" id="vbox2">
|
||||||
<property name="label" translatable="yes">Play sound</property>
|
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="orientation">vertical</property>
|
||||||
<property name="receives_default">False</property>
|
<child>
|
||||||
<property name="draw_indicator">True</property>
|
<widget class="GtkFrame" id="frame2">
|
||||||
<signal name="toggled" handler="on_sound_enabled_toggled"/>
|
<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"><b>UI Notifications</b></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">●</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">●</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">●</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">●</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"><b>Recipients</b></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">●</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"><b>Email Notifications</b></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>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="tab_fill">False</property>
|
||||||
<property name="position">0</property>
|
<property name="type">tab</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkFileChooserButton" id="sound_path">
|
<widget class="GtkVBox" id="vbox5">
|
||||||
<property name="visible">True</property>
|
<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>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="padding">2</property>
|
|
||||||
<property name="position">1</property>
|
<property name="position">1</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</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>
|
</widget>
|
||||||
<packing>
|
|
||||||
<property name="position">2</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
</child>
|
||||||
</widget>
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
</widget>
|
</widget>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
|
||||||
<widget class="GtkLabel" id="label6">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="label" translatable="yes"><b>UI Notifications</b></property>
|
|
||||||
<property name="use_markup">True</property>
|
|
||||||
</widget>
|
|
||||||
<packing>
|
|
||||||
<property name="type">label_item</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="position">0</property>
|
<property name="position">0</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</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">●</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">●</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">●</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">●</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"><b>Recipients</b></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">●</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"><b>Email Notifications</b></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>
|
</widget>
|
||||||
</child>
|
</child>
|
||||||
</widget>
|
</widget>
|
||||||
|
|
|
@ -40,11 +40,13 @@
|
||||||
import gtk
|
import gtk
|
||||||
|
|
||||||
from twisted.internet import defer
|
from twisted.internet import defer
|
||||||
|
from deluge.event import known_events, DelugeEvent
|
||||||
from deluge.log import LOG as log
|
from deluge.log import LOG as log
|
||||||
from deluge.ui.client import client
|
from deluge.ui.client import client
|
||||||
from deluge.plugins.pluginbase import GtkPluginBase
|
from deluge.plugins.pluginbase import GtkPluginBase
|
||||||
import deluge.component as component
|
import deluge.component as component
|
||||||
import deluge.common
|
import deluge.common
|
||||||
|
import deluge.configmanager
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import pygame
|
import pygame
|
||||||
|
@ -60,44 +62,148 @@ except ImportError:
|
||||||
|
|
||||||
# Relative imports
|
# Relative imports
|
||||||
from common import get_resource
|
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)
|
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):
|
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 = gtk.glade.XML(get_resource("config.glade"))
|
||||||
self.glade.get_widget("smtp_port").set_value(25)
|
self.glade.get_widget("smtp_port").set_value(25)
|
||||||
self.prefs = self.glade.get_widget("prefs_box")
|
self.prefs = self.glade.get_widget("prefs_box")
|
||||||
self.prefs.show_all()
|
self.prefs.show_all()
|
||||||
self.treeview = self.glade.get_widget("smtp_recipients")
|
|
||||||
treeview_selection = self.treeview.get_selection()
|
# SMTP Recipients treeview/model
|
||||||
treeview_selection.connect("changed", self.on_treeview_selection_changed)
|
self.recipients_treeview = self.glade.get_widget("smtp_recipients")
|
||||||
self.model = gtk.ListStore(str, bool)
|
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 = 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)
|
renderer.set_data("recipient", RECIPIENT_FIELD)
|
||||||
column = gtk.TreeViewColumn("Recipients", renderer,
|
column = gtk.TreeViewColumn("Recipients", renderer,
|
||||||
text=RECIPIENT_FIELD,
|
text=RECIPIENT_FIELD,
|
||||||
editable=RECIPIENT_EDIT)
|
editable=RECIPIENT_EDIT)
|
||||||
column.set_expand(True)
|
column.set_expand(True)
|
||||||
self.treeview.append_column(column)
|
self.recipients_treeview.append_column(column)
|
||||||
self.treeview.set_model(self.model)
|
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({
|
self.glade.signal_autoconnect({
|
||||||
'on_add_button_clicked': (self.on_add_button_clicked,
|
'on_add_button_clicked': (self.on_add_button_clicked,
|
||||||
self.treeview),
|
self.recipients_treeview),
|
||||||
'on_delete_button_clicked': (self.on_delete_button_clicked,
|
'on_delete_button_clicked': (self.on_delete_button_clicked,
|
||||||
self.treeview),
|
self.recipients_treeview),
|
||||||
'on_enabled_toggled': self.on_enabled_toggled,
|
'on_enabled_toggled': self.on_enabled_toggled,
|
||||||
'on_sound_enabled_toggled': self.on_sound_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",
|
component.get("PluginManager").register_hook("on_apply_prefs",
|
||||||
self.on_apply_prefs)
|
self.on_apply_prefs)
|
||||||
component.get("PluginManager").register_hook("on_show_prefs",
|
component.get("PluginManager").register_hook("on_show_prefs",
|
||||||
|
@ -106,38 +212,93 @@ class GtkUI(GtkPluginBase, Notifications):
|
||||||
if not POPUP_AVAILABLE:
|
if not POPUP_AVAILABLE:
|
||||||
self.glade.get_widget("popup_enabled").set_property('sensitive',
|
self.glade.get_widget("popup_enabled").set_property('sensitive',
|
||||||
False)
|
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:
|
if not SOUND_AVAILABLE:
|
||||||
self.glade.get_widget("sound_enabled").set_property('sensitive',
|
self.glade.get_widget("sound_enabled").set_property('sensitive',
|
||||||
False)
|
False)
|
||||||
self.glade.get_widget('sound_path').set_property('sensitive', False)
|
self.glade.get_widget('sound_path').set_property('sensitive', False)
|
||||||
else:
|
|
||||||
client.register_event_handler("NotificationSoundEvent",
|
self.systray = component.get("SystemTray")
|
||||||
self.notify_sound)
|
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",
|
client.register_event_handler("TorrentFinishedEvent",
|
||||||
self._on_torrent_finished_event)
|
self._on_torrent_finished_event)
|
||||||
# Force config populate
|
|
||||||
client.notifications.get_config().addCallback(self.cb_get_config)
|
|
||||||
|
|
||||||
def disable(self):
|
def disable(self):
|
||||||
Notifications.disable(self)
|
|
||||||
component.get("Preferences").remove_page("Notifications")
|
component.get("Preferences").remove_page("Notifications")
|
||||||
component.get("PluginManager").deregister_hook("on_apply_prefs",
|
component.get("PluginManager").deregister_hook("on_apply_prefs",
|
||||||
self.on_apply_prefs)
|
self.on_apply_prefs)
|
||||||
component.get("PluginManager").deregister_hook("on_show_prefs",
|
component.get("PluginManager").deregister_hook("on_show_prefs",
|
||||||
self.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):
|
def on_apply_prefs(self):
|
||||||
log.debug("applying prefs for Notifications")
|
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_enabled": self.glade.get_widget("smtp_enabled").get_active(),
|
||||||
"smtp_host": self.glade.get_widget("smtp_host").get_text(),
|
"smtp_host": self.glade.get_widget("smtp_host").get_text(),
|
||||||
"smtp_port": self.glade.get_widget("smtp_port").get_value(),
|
"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_pass": self.glade.get_widget("smtp_pass").get_text(),
|
||||||
"smtp_from": self.glade.get_widget("smtp_from").get_text(),
|
"smtp_from": self.glade.get_widget("smtp_from").get_text(),
|
||||||
"smtp_tls": self.glade.get_widget("smtp_tls").get_active(),
|
"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'],
|
dest[0]!='USER@HOST'],
|
||||||
"blink_enabled": self.glade.get_widget("blink_enabled").get_active(),
|
"subscriptions": {"email": current_email_subscriptions}
|
||||||
"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()
|
|
||||||
}
|
}
|
||||||
|
client.notifications.set_config(core_config)
|
||||||
client.notifications.set_config(config)
|
|
||||||
|
|
||||||
def on_show_prefs(self):
|
def on_show_prefs(self):
|
||||||
client.notifications.get_config().addCallback(self.cb_get_config)
|
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"
|
"callback for on show_prefs"
|
||||||
self.config = config
|
self.glade.get_widget("smtp_host").set_text(core_config["smtp_host"])
|
||||||
self.glade.get_widget("smtp_host").set_text(config["smtp_host"])
|
self.glade.get_widget("smtp_port").set_value(core_config["smtp_port"])
|
||||||
self.glade.get_widget("smtp_port").set_value(config["smtp_port"])
|
self.glade.get_widget("smtp_user").set_text(core_config["smtp_user"])
|
||||||
self.glade.get_widget("smtp_user").set_text(config["smtp_user"])
|
self.glade.get_widget("smtp_pass").set_text(core_config["smtp_pass"])
|
||||||
self.glade.get_widget("smtp_pass").set_text(config["smtp_pass"])
|
self.glade.get_widget("smtp_from").set_text(core_config["smtp_from"])
|
||||||
self.glade.get_widget("smtp_from").set_text(config["smtp_from"])
|
self.glade.get_widget("smtp_tls").set_active(core_config["smtp_tls"])
|
||||||
self.glade.get_widget("smtp_tls").set_active(config["smtp_tls"])
|
self.recipients_model.clear()
|
||||||
self.model.clear()
|
for recipient in core_config['smtp_recipients']:
|
||||||
for recipient in config['smtp_recipients']:
|
self.recipients_model.set(self.recipients_model.append(),
|
||||||
self.model.set(self.model.append(),
|
RECIPIENT_FIELD, recipient,
|
||||||
RECIPIENT_FIELD, recipient,
|
RECIPIENT_EDIT, False)
|
||||||
RECIPIENT_EDIT, False)
|
self.glade.get_widget("smtp_enabled").set_active(
|
||||||
self.glade.get_widget("smtp_enabled").set_active(config['smtp_enabled'])
|
core_config['smtp_enabled']
|
||||||
|
)
|
||||||
self.glade.get_widget("sound_enabled").set_active(
|
self.glade.get_widget("sound_enabled").set_active(
|
||||||
config['sound_enabled']
|
self.config['sound_enabled']
|
||||||
)
|
)
|
||||||
self.glade.get_widget("popup_enabled").set_active(
|
self.glade.get_widget("popup_enabled").set_active(
|
||||||
config['popup_enabled']
|
self.config['popup_enabled']
|
||||||
)
|
)
|
||||||
self.glade.get_widget("blink_enabled").set_active(
|
self.glade.get_widget("blink_enabled").set_active(
|
||||||
config['blink_enabled']
|
self.config['blink_enabled']
|
||||||
)
|
)
|
||||||
if config['sound_path']:
|
if self.config['sound_path']:
|
||||||
sound_path = config['sound_path']
|
sound_path = self.config['sound_path']
|
||||||
else:
|
else:
|
||||||
sound_path = deluge.common.get_default_download_dir()
|
sound_path = deluge.common.get_default_download_dir()
|
||||||
self.glade.get_widget("sound_path").set_filename(sound_path)
|
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_enabled_toggled(self.glade.get_widget("smtp_enabled"))
|
||||||
self.on_sound_enabled_toggled(self.glade.get_widget('sound_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):
|
def on_add_button_clicked(self, widget, treeview):
|
||||||
model = treeview.get_model()
|
model = treeview.get_model()
|
||||||
model.set(model.append(),
|
model.set(model.append(),
|
||||||
|
@ -210,7 +373,7 @@ class GtkUI(GtkPluginBase, Notifications):
|
||||||
path = model.get_path(iter)[0]
|
path = model.get_path(iter)[0]
|
||||||
model.set(iter, RECIPIENT_FIELD, new_text)
|
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()
|
model, selected_connection_iter = selection.get_selected()
|
||||||
if selected_connection_iter:
|
if selected_connection_iter:
|
||||||
self.glade.get_widget("delete_button").set_property('sensitive',
|
self.glade.get_widget("delete_button").set_property('sensitive',
|
||||||
|
@ -218,6 +381,16 @@ class GtkUI(GtkPluginBase, Notifications):
|
||||||
else:
|
else:
|
||||||
self.glade.get_widget("delete_button").set_property('sensitive',
|
self.glade.get_widget("delete_button").set_property('sensitive',
|
||||||
False)
|
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):
|
def on_enabled_toggled(self, widget):
|
||||||
if widget.get_active():
|
if widget.get_active():
|
||||||
for widget in ('smtp_host', 'smtp_port', 'smtp_user', 'smtp_pass',
|
for widget in ('smtp_host', 'smtp_port', 'smtp_user', 'smtp_pass',
|
||||||
|
@ -237,24 +410,14 @@ class GtkUI(GtkPluginBase, Notifications):
|
||||||
else:
|
else:
|
||||||
self.glade.get_widget('sound_path').set_property('sensitive', False)
|
self.glade.get_widget('sound_path').set_property('sensitive', False)
|
||||||
|
|
||||||
def notify_blink(self):
|
# Notification methods
|
||||||
defer.maybeDeferred(self.tray.blink, True)
|
def blink(self):
|
||||||
return defer.succeed("blink notification shown.")
|
d = defer.maybeDeferred(self.systray.blink, True)
|
||||||
|
d.addCallback(self._on_notify_sucess, "blink")
|
||||||
def notify_email(self, title='', message='', smtp_from='', recipients=[]):
|
d.addCallback(self._on_notify_failure, "blink")
|
||||||
d = client.notifications.notify_email(title, message, smtp_from,
|
|
||||||
recipients)
|
|
||||||
d.addCallback(self._on_notify_sucess, "email")
|
|
||||||
d.addCallback(self._on_notify_failure, "email")
|
|
||||||
return d
|
return d
|
||||||
|
|
||||||
def notify_flash(self, title='', message=''):
|
def popup(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=''):
|
|
||||||
if not self.config['popup_enabled']:
|
if not self.config['popup_enabled']:
|
||||||
return defer.succeed(_("Popup notification is not enabled."))
|
return defer.succeed(_("Popup notification is not enabled."))
|
||||||
if not POPUP_AVAILABLE:
|
if not POPUP_AVAILABLE:
|
||||||
|
@ -271,7 +434,7 @@ class GtkUI(GtkPluginBase, Notifications):
|
||||||
return defer.fail(err_msg)
|
return defer.fail(err_msg)
|
||||||
return defer.succeed(_("Notification popup shown"))
|
return defer.succeed(_("Notification popup shown"))
|
||||||
|
|
||||||
def notify_sound(self, sound_path=''):
|
def play_sound(self, sound_path=''):
|
||||||
if not self.config['sound_enabled']:
|
if not self.config['sound_enabled']:
|
||||||
return defer.succeed(_("Sound notification not enabled"))
|
return defer.succeed(_("Sound notification not enabled"))
|
||||||
if not SOUND_AVAILABLE:
|
if not SOUND_AVAILABLE:
|
||||||
|
@ -295,15 +458,16 @@ class GtkUI(GtkPluginBase, Notifications):
|
||||||
log.info(msg)
|
log.info(msg)
|
||||||
return defer.succeed(msg)
|
return defer.succeed(msg)
|
||||||
|
|
||||||
|
# Internal methods
|
||||||
def _on_torrent_finished_event(self, torrent_id):
|
def _on_torrent_finished_event(self, torrent_id):
|
||||||
log.debug("\n\nhandler for TorrentFinishedEvent GTKUI called")
|
log.debug("\n\nhandler for TorrentFinishedEvent GTKUI called")
|
||||||
# Blink
|
# Blink
|
||||||
d0 = defer.maybeDeferred(self.notify_blink)
|
d0 = defer.maybeDeferred(self.blink)
|
||||||
d0.addCallback(self._on_notify_sucess, 'blink')
|
d0.addCallback(self._on_notify_sucess, 'blink')
|
||||||
d0.addErrback(self._on_notify_failure, 'blink')
|
d0.addErrback(self._on_notify_failure, 'blink')
|
||||||
log.debug("Blink notification callback yielded")
|
log.debug("Blink notification callback yielded")
|
||||||
# Sound
|
# Sound
|
||||||
d1 = defer.maybeDeferred(self.notify_sound)
|
d1 = defer.maybeDeferred(self.play_sound)
|
||||||
d1.addCallback(self._on_notify_sucess, 'sound')
|
d1.addCallback(self._on_notify_sucess, 'sound')
|
||||||
d1.addErrback(self._on_notify_failure, 'sound')
|
d1.addErrback(self._on_notify_failure, 'sound')
|
||||||
log.debug("Sound notification callback yielded")
|
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 = client.core.get_torrent_status(torrent_id, ["name", "num_files"])
|
||||||
d2.addCallback(self._on_torrent_finished_event_got_torrent_status)
|
d2.addCallback(self._on_torrent_finished_event_got_torrent_status)
|
||||||
d2.addErrback(self._on_torrent_finished_event_torrent_status_failure)
|
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):
|
def _on_torrent_finished_event_torrent_status_failure(self, failure):
|
||||||
log.debug("Failed to get torrent status to be able to show the popup")
|
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")
|
title = _("Finished Torrent")
|
||||||
message = _("The torrent \"%(name)s\" including %(num_files)i "
|
message = _("The torrent \"%(name)s\" including %(num_files)i "
|
||||||
"has finished downloading.") % torrent_status
|
"has finished downloading.") % torrent_status
|
||||||
d2 = defer.maybeDeferred(self.notify_popup, title, message)
|
d = defer.maybeDeferred(self.popup, title, message)
|
||||||
d2.addCallback(self._on_notify_sucess, 'popup')
|
d.addCallback(self._on_notify_sucess, 'popup')
|
||||||
d2.addErrback(self._on_notify_failure, 'popup')
|
d.addErrback(self._on_notify_failure, 'popup')
|
||||||
log.debug("Popup notification callback yielded")
|
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
|
||||||
|
|
||||||
|
|
|
@ -37,21 +37,49 @@
|
||||||
# statement from all source files in the program, then also delete it here.
|
# 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.log import LOG as log
|
||||||
from deluge.ui.client import client
|
from deluge.ui.client import client
|
||||||
from deluge import component
|
from deluge import component
|
||||||
from deluge.plugins.pluginbase import WebPluginBase
|
from deluge.plugins.pluginbase import WebPluginBase
|
||||||
|
import deluge.configmanager
|
||||||
|
|
||||||
# Relative imports
|
# Relative imports
|
||||||
from common import get_resource
|
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")]
|
scripts = [get_resource("notifications.js")]
|
||||||
|
|
||||||
|
def __init__(self, plugin_name):
|
||||||
|
WebPluginBase.__init__(self, plugin_name)
|
||||||
|
component.Component.__init__(self, "Notifications")
|
||||||
|
|
||||||
def enable(self):
|
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):
|
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
|
||||||
|
|
Loading…
Reference in New Issue