From 8cacacb3bbbeccaa547ad9499e4300e9e0afb19a Mon Sep 17 00:00:00 2001 From: Zach Tibbitts Date: Wed, 14 Feb 2007 22:43:48 +0000 Subject: [PATCH] plugins --- glade/dgtkpref.glade | 374 ++++++++++++++++---------------- plugins/ExamplePlugin/plugin.py | 15 +- src/dcommon.py | 3 + src/delugegtk.py | 132 ++++++----- src/delugeplugins.py | 44 +++- src/dgtk.py | 2 +- 6 files changed, 316 insertions(+), 254 deletions(-) diff --git a/glade/dgtkpref.glade b/glade/dgtkpref.glade index f5d298428..7a804ae21 100644 --- a/glade/dgtkpref.glade +++ b/glade/dgtkpref.glade @@ -44,18 +44,6 @@ - - - True - Enable system tray icon - True - True - - - - 2 - - True @@ -69,6 +57,18 @@ 12 + + + True + Enable system tray icon + True + True + + + + 2 + + @@ -95,15 +95,13 @@ 2 2 - + True - GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER + Ask me where to save each download + True - 1 2 - 1 - 2 @@ -119,13 +117,15 @@ - + True - Ask me where to save each download - True + GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER + 1 2 + 1 + 2 @@ -154,6 +154,14 @@ True 1 2 + + + True + Stop seeding torrents when +their share ratio reaches: + True + + True @@ -171,14 +179,6 @@ - - - True - Stop seeding torrents when -their share ratio reaches: - True - - @@ -272,53 +272,13 @@ their share ratio reaches: - + True - Try from: - - - - - True - to: - - - 2 - 3 - - - - - True - True - 0.5 - 0 0 65535 1 10 10 - - - 1 - 2 - - - - - True - True - 0.5 - 0 0 65535 1 10 10 + Test Port 3 4 - - - - - True - Active port: - - - 1 - 2 1 2 @@ -336,17 +296,57 @@ their share ratio reaches: - + True - Test Port + Active port: + + + 1 + 2 + 1 + 2 + + + + + True + True + 0.5 + 0 0 65535 1 10 10 3 4 - 1 - 2 + + + True + True + 0.5 + 0 0 65535 1 10 10 + + + 1 + 2 + + + + + True + to: + + + 2 + 3 + + + + + True + Try from: + + @@ -373,94 +373,62 @@ their share ratio reaches: 5 3 - + True - <i>(0 is unlimited)</i> - True + 0 + Maximum Upload Rate: - 3 - - - - - True - KB/s - - - 2 - 3 - 3 - 4 - - - - - - True - - - 2 - 3 - 2 - 3 - - - - - - True - KB/s - - - 2 - 3 1 2 - - + True + 0 + Maximum number of Uploads: - 2 - 3 - 4 - 5 - + 2 + 3 - + True - True - 10 - 1 - 0 0 100 1 10 10 + 0 + Maximum Download Rate: - 1 - 2 - 4 - 5 - - - - - - True - True - 10 - 1 - 0 0 100 1 10 10 - - - 1 - 2 3 4 + + + + + True + 0 + Maximum number of Downloads: + + + 4 + 5 + + + + + True + True + 10 + 1 + 0 0 100 1 10 10 + + + 1 + 2 + 1 + 2 @@ -481,7 +449,7 @@ their share ratio reaches: - + True True 10 @@ -491,53 +459,85 @@ their share ratio reaches: 1 2 + 3 + 4 + + + + + + True + True + 10 + 1 + 0 0 100 1 10 10 + + + 1 + 2 + 4 + 5 + + + + + + True + + + 2 + 3 + 4 + 5 + + + + + + True + KB/s + + + 2 + 3 1 2 - + True - 0 - Maximum number of Downloads: - - - 4 - 5 - - - - - True - 0 - Maximum Download Rate: - - - 3 - 4 - - - - - True - 0 - Maximum number of Uploads: + 2 + 3 2 3 + - + True - 0 - Maximum Upload Rate: + KB/s - 1 - 2 + 2 + 3 + 3 + 4 + + + + + + True + <i>(0 is unlimited)</i> + True + + + 3 @@ -640,16 +640,11 @@ their share ratio reaches: 2 2 - + True - False - GTK_WRAP_WORD - 1 - 2 - 10 - 10 + 2 @@ -684,11 +679,16 @@ their share ratio reaches: - + True + False + GTK_WRAP_WORD - 2 + 1 + 2 + 10 + 10 @@ -718,16 +718,12 @@ their share ratio reaches: GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK GTK_BUTTONBOX_END - - True - gtk-cancel - True - + True - gtk-ok + gtk-close True diff --git a/plugins/ExamplePlugin/plugin.py b/plugins/ExamplePlugin/plugin.py index fa31ddb1d..980d13315 100644 --- a/plugins/ExamplePlugin/plugin.py +++ b/plugins/ExamplePlugin/plugin.py @@ -4,16 +4,23 @@ class plugin_Example: def __init__(self, deluge_core, deluge_interface): self.core = deluge_core self.interface = deluge_interface + print "Example Plugin loaded" def unload(self): - pass + print "Example Plugin unloaded" def update(self): - pass + print "Hello World, from Example Plugin" + + -register_plugin("Example", +register_plugin("Example Plugin", plugin_Example, "0.2", "An example plugin", - requires="0.5.0") \ No newline at end of file + config=True, + default=False, + requires="0.5.0", + interface="gtk", + required_plugins=None) diff --git a/src/dcommon.py b/src/dcommon.py index 53016bce1..8bbb78d10 100644 --- a/src/dcommon.py +++ b/src/dcommon.py @@ -19,10 +19,13 @@ # Boston, MA 02110-1301, USA. import sys, os, os.path, webbrowser +import xdg, xdg.BaseDirectory PROGRAM_NAME = "Deluge" PROGRAM_VERSION = "0.4.9.0" +CONFIG_DIR = xdg.BaseDirectory.save_config_path('deluge-svn') + GLADE_DIR = sys.prefix + '/share/deluge/glade' PIXMAP_DIR = sys.prefix + '/share/deluge/pixmaps' PLUGIN_DIR = sys.prefix + '/share/deluge/plugins' diff --git a/src/delugegtk.py b/src/delugegtk.py index 3bc4b7ff3..fe6a734dc 100755 --- a/src/delugegtk.py +++ b/src/delugegtk.py @@ -21,7 +21,7 @@ # Boston, MA 02110-1301, USA. import sys, os, os.path, gettext, urllib -import deluge, dcommon, dgtk +import deluge, dcommon, dgtk, delugeplugins import pygtk pygtk.require('2.0') import gtk, gtk.glade, gobject @@ -33,13 +33,27 @@ if getattr(dbus, 'version', (0,0,0)) >= (0,41,0): _ = gettext.gettext class DelugeGTK(dbus.service.Object): + ## external_add_torrent should only be called from outside the class + @dbus.service.method('org.deluge_torrent.DelugeInterface') + def external_add_torrent(self, torrent_file): + print "Ding!" + print "Got torrent externally:", os.path.basename(torrent_file) + print "\tNow, what to do with it?" + if self.is_running: + print "\t\tthe client seems to already be running, i'll try and add the torrent" + uid = self.manager.add_torrent(torrent_file, ".", True) + self.store.append(self.get_list_from_unique_id(uid)) + else: + print "\t\tthe client hasn't started yet, I'll queue the torrent" + self.torrent_file_queue.append(torrent_file) + def __init__(self, bus_name=dbus.service.BusName('org.deluge_torrent.Deluge', bus=dbus.SessionBus()), object_path='/org/deluge_torrent/DelugeObject'): dbus.service.Object.__init__(self, bus_name, object_path) self.is_running = False self.torrent_file_queue = [] #Load up a config file: - self.conf_file = xdg.BaseDirectory.save_config_path("deluge-svn") + '/deluge.conf' + self.conf_file = dcommon.CONFIG_DIR + '/deluge.conf' if os.path.isdir(self.conf_file): print 'Weird, the file I was trying to write to, %s, is an existing directory'%(self.conf_file) sys.exit(0) @@ -51,8 +65,7 @@ class DelugeGTK(dbus.service.Object): self.load_default_settings() self.pref.load_from_file(self.conf_file) #Start the Deluge Manager: - self.manager = deluge.Manager("DE", "0490", "Deluge 0.4.9", - xdg.BaseDirectory.save_config_path("deluge-svn")) + self.manager = deluge.Manager("DE", "0490", "Deluge 0.4.9", dcommon.CONFIG_DIR) #Set up the interface: self.wtree = gtk.glade.XML(dcommon.get_glade_file("delugegtk.glade")) self.window = self.wtree.get_widget("main_window") @@ -63,11 +76,16 @@ class DelugeGTK(dbus.service.Object): self.window.set_title('%s %s'%(dcommon.PROGRAM_NAME, dcommon.PROGRAM_VERSION)) self.window.set_icon_from_file(dcommon.get_pixmap("deluge32.png")) + self.plugins = delugeplugins.PluginManager(self.manager, self) + self.plugins.add_plugin_dir(dcommon.PLUGIN_DIR) + if os.path.isdir(dcommon.CONFIG_DIR + '/plugins'): + self.plugins.add_plugin_dir(dcommon.CONFIG_DIR + '/plugins') + self.plugins.scan_for_plugins() + ## Construct the Interface self.build_tray_icon() self.build_about_dialog() self.build_pref_dialog() - self.build_plugin_dialog() self.build_torrent_table() self.build_summary_tab() self.build_file_tab() @@ -164,9 +182,14 @@ class DelugeGTK(dbus.service.Object): self.prf = self.prf_glade.get_widget("pref_dialog") self.prf.set_icon_from_file(dcommon.get_pixmap("deluge32.png")) self.prf_glade.signal_autoconnect({"tray_toggle": self.tray_toggle,}) - - def build_plugin_dialog(self): - pass + self.plugin_dlg = self.prf_glade.get_widget("plugin_dialog") + self.plugin_dlg.set_icon_from_file(dcommon.get_pixmap("deluge32.png")) + self.plugin_view = self.prf_glade.get_widget("plugin_view") + self.plugin_store = gtk.ListStore(str, bool) + self.plugin_view.set_model(self.plugin_store) + dgtk.add_text_column(self.plugin_view, "Name", 0) + dgtk.add_toggle_column(self.plugin_view, "Enabled", 1, toggled_signal=self.plugin_toggled) + def build_torrent_table(self): ## Create the torrent listview @@ -312,8 +335,26 @@ class DelugeGTK(dbus.service.Object): self.apply_prefs() def show_plugin_dialog(self, arg=None): - pass - + self.plugin_store.clear() + for plugin in self.plugins.get_available_plugins(): + self.plugin_store.append( (plugin, False) ) + self.plugin_dlg.show() + self.plugin_dlg.run() + self.plugin_dlg.hide() + + def plugin_toggled(self, renderer, path): + plugin_iter = self.plugin_store.get_iter_from_string(path) + plugin_name = self.plugin_store.get_value(plugin_iter, 0) + plugin_value = not self.plugin_store.get_value(plugin_iter, 1) + self.plugin_store.set_value(plugin_iter, 1, plugin_value) + print "Plugin:", plugin_name, renderer.get_active() + if plugin_value: + self.plugins.enable_plugin(plugin_name) + else: + self.plugins.disable_plugin(plugin_name) + + + def tray_toggle(self, obj): if obj.get_active(): self.prf_glade.get_widget("chk_min_on_close").set_sensitive(True) @@ -321,22 +362,28 @@ class DelugeGTK(dbus.service.Object): self.prf_glade.get_widget("chk_min_on_close").set_sensitive(False) + def apply_prefs(self): + pass + - ## external_add_torrent should only be called from outside the class - @dbus.service.method('org.deluge_torrent.DelugeInterface') - def external_add_torrent(self, torrent_file): - print "Ding!" - print "Got torrent externally:", os.path.basename(torrent_file) - print "\tNow, what to do with it?" - if self.is_running: - print "\t\tthe client seems to already be running, i'll try and add the torrent" - uid = self.manager.add_torrent(torrent_file, ".", True) - self.store.append(self.get_list_from_unique_id(uid)) - else: - print "\t\tthe client hasn't started yet, I'll queue the torrent" - self.torrent_file_queue.append(torrent_file) - - + # UID, Q#, Name, Size, Progress, Message, Seeders, Peers, DL, UL, ETA, Share + def get_list_from_unique_id(self, unique_id): + state = self.manager.get_torrent_state(unique_id) + queue = int(state['queue_pos']) + 1 + name = state['name'] + size = dcommon.fsize(state['total_size']) + progress = float(state['progress'] * 100) + message = '%s %d%%'%(deluge.STATE_MESSAGES[state['state']], int(state['progress'] * 100)) + seeds = dcommon.fseed(state) + peers = dcommon.fpeer(state) + dlrate = dcommon.frate(state['download_rate']) + ulrate = dcommon.frate(state['upload_rate']) + eta = dcommon.estimate_eta(state) + share = self.calc_share_ratio(unique_id, state) + return [unique_id, queue, name, size, progress, message, + seeds, peers, dlrate, ulrate, eta, share] + + ## Start the timer that updates the interface def start(self, hidden=False): if not hidden: @@ -360,34 +407,7 @@ class DelugeGTK(dbus.service.Object): gtk.main() except KeyboardInterrupt: self.manager.quit() - - def show_pref(self, o=None): - self.pref = self.prf.show_dlg(self.pref) - - def show_plugins(self, o=None): - pass - - def apply_prefs(self): - for k in self.pref.keys(): - print k, self.pref.get(k) - - - # UID, Q#, Name, Size, Progress, Message, Seeders, Peers, DL, UL, ETA, Share - def get_list_from_unique_id(self, unique_id): - state = self.manager.get_torrent_state(unique_id) - queue = int(state['queue_pos']) + 1 - name = state['name'] - size = dcommon.fsize(state['total_size']) - progress = float(state['progress'] * 100) - message = '%s %d%%'%(deluge.STATE_MESSAGES[state['state']], int(state['progress'] * 100)) - seeds = dcommon.fseed(state) - peers = dcommon.fpeer(state) - dlrate = dcommon.frate(state['download_rate']) - ulrate = dcommon.frate(state['upload_rate']) - eta = dcommon.estimate_eta(state) - share = self.calc_share_ratio(unique_id, state) - return [unique_id, queue, name, size, progress, message, - seeds, peers, dlrate, ulrate, eta, share] + ## Call via a timer to update the interface def update(self): @@ -396,6 +416,9 @@ class DelugeGTK(dbus.service.Object): tab = self.wtree.get_widget("torrent_info").get_current_page() except AttributeError: return False + + self.plugins.update_active_plugins() + # If no torrent is selected, select the first torrent: (temp, selection) = self.view.get_selection().get_selected() if selection is None: @@ -404,6 +427,7 @@ class DelugeGTK(dbus.service.Object): itr = self.store.get_iter_first() if itr is None: return True + while itr is not None: uid = self.store.get_value(itr, 0) try: @@ -419,6 +443,8 @@ class DelugeGTK(dbus.service.Object): self.saved_peer_info = None + + if tab == 0: #Details Pane try: state = self.manager.get_torrent_state(self.get_selected_torrent()) diff --git a/src/delugeplugins.py b/src/delugeplugins.py index 143bb09e8..911659ec8 100644 --- a/src/delugeplugins.py +++ b/src/delugeplugins.py @@ -23,9 +23,12 @@ import os class PluginManager: - def __init__(self): + def __init__(self, deluge_core, deluge_interface): self.plugin_dirs = [] - self.plugins = {} + self.available_plugins = {} + self.enabled_plugins = {} + self.core = deluge_core + self.interface = deluge_interface def add_plugin_dir(self, directory): self.plugin_dirs.append(directory) @@ -33,11 +36,30 @@ class PluginManager: def scan_for_plugins(self): register_plugin = self.register_plugin for folder in self.plugin_dirs: - print "Looking in", folder plugin_folders = os.listdir(folder) for plugin in plugin_folders: - if os.path.isfile(folder + plugin + "/plugin.py"): - execfile(folder + plugin + "/plugin.py") + if os.path.isfile(folder + "/" + plugin + "/plugin.py"): + execfile(folder + "/" + plugin + "/plugin.py") + + def get_available_plugins(self): + return self.available_plugins.keys() + + def get_plugin(self, name): + return self.available_plugins[name] + + def enable_plugin(self, name): + self.enabled_plugins[name] = self.available_plugins[name]['class'](self.core, self.interface) + + def get_enabled_plugins(self): + return self.enabled_plugins.keys() + + def disable_plugin(self, name): + self.enabled_plugins[name].unload() + self.enabled_plugins.pop(name) + + def update_active_plugins(self): + for name in self.enabled_plugins.keys(): + self.enabled_plugins[name].update() def register_plugin(self, name, @@ -49,7 +71,15 @@ class PluginManager: requires=None, interface=None, required_plugins=None): - self.plugins[name] = (plugin_class, version, description, config, default, requires, interface, required_plugins) + self.available_plugins[name] = {'class': plugin_class, + 'version': version, + 'description': description, + 'config': config, + 'default': default, + 'requires': requires, + 'interface': interface, + 'req plugins': required_plugins + } ## Few lines of code to test functionality if __name__ == "__main__": @@ -59,4 +89,4 @@ if __name__ == "__main__": for x in p.plugins: print x for y in p.plugins[x]: - print "\t", y \ No newline at end of file + print "\t", y diff --git a/src/dgtk.py b/src/dgtk.py index 938f0169b..c519d9e5a 100644 --- a/src/dgtk.py +++ b/src/dgtk.py @@ -91,5 +91,5 @@ def add_toggle_column(view, header, cid, toggled_signal=None): column.set_expand(False) view.append_column(column) if toggled_signal is not None: - render.connect("toggled", toggled_signal, cid) + render.connect("toggled", toggled_signal) return column