diff --git a/deluge/plugins/label/TODO b/deluge/plugins/label/TODO
new file mode 100644
index 000000000..1724b1696
--- /dev/null
+++ b/deluge/plugins/label/TODO
@@ -0,0 +1,13 @@
+*grey bars in sidebar are ugly
+*label sub-menu is broken on 1'st popup.
+*replacing/restoring the sidebar model is a hack
+*config should save a label on bottom ok-button, not a seperate save-button per label
+*filters : add "Traffic" , use label-core for filtering ; needs hooks in torrentview.
+*torrentview: bugs/hacks in adding and removing columns
+*webui is functional but not polished.
+*move_torrent_to is not implemeted
+*no client-side validation (could be solved by a ui.aclient exception-plugin)
+
+
+
+
diff --git a/deluge/plugins/label/label/core.py b/deluge/plugins/label/label/core.py
index 6fefb0231..a4f751449 100644
--- a/deluge/plugins/label/label/core.py
+++ b/deluge/plugins/label/label/core.py
@@ -46,7 +46,7 @@ import re
RE_VALID = re.compile("[a-z0-9_-]*\Z")
RE_VALID = re.compile("[a-z0-9_-]*\Z")
-KNOWN_STATES = ['Downloading','Seeding','Paused','Checking','Allocating','Queued','Error']
+KNOWN_STATES = ['Downloading','Seeding','Paused','Checking','Queued','Error']
STATE = "state"
TRACKER = "tracker"
KEYWORD = "keyword"
@@ -58,7 +58,7 @@ CONFIG_DEFAULTS = {
"gtk_alfa":False
}
OPTIONS_KEYS = ["max_download_speed", "max_upload_speed",
- "max_connections", "max_upload_slots", "prioritize_first_last"]
+ "max_connections", "max_upload_slots", "prioritize_first_last","apply_max","move_completed_to"]
NO_LABEL = "No Label"
@@ -264,7 +264,7 @@ class Core(CorePluginBase):
label_id = label_id.lower()
CheckInput(RE_VALID.match(label_id) , _("Invalid label, valid characters:[a-z0-9_-]"))
CheckInput(label_id, _("Empty Label"))
- CheckInput(not (label_id in self.labels) , _("Unknown Label"))
+ CheckInput(not (label_id in self.labels) , _("Label already exists"))
#default to current global per-torrent settings.
@@ -273,7 +273,9 @@ class Core(CorePluginBase):
"max_upload_speed":self.core_cfg.config["max_upload_speed_per_torrent"],
"max_connections":self.core_cfg.config["max_connections_per_torrent"],
"max_upload_slots":self.core_cfg.config["max_upload_slots_per_torrent"],
- "prioritize_first_last":self.core_cfg.config["prioritize_first_last_pieces"]
+ "prioritize_first_last":self.core_cfg.config["prioritize_first_last_pieces"],
+ "apply_max":True,
+ "move_completed_to":None
}
def export_remove(self, label_id):
@@ -291,12 +293,14 @@ class Core(CorePluginBase):
"max_upload_speed":float(),
"max_connections":int(),
"max_upload_slots":int(),
- "prioritize_first_last":bool(),
+ #"prioritize_first_last":bool(),
+ "apply_max":bool(),
+ "move_completed_to":string() or None
}
apply : applies download-options to all torrents currently labelled by label_id
"""
- CheckInput(not (label_id in self.labels) , _("Unknown Label"))
+ CheckInput(label_id in self.labels , _("Unknown Label"))
for key in options_dict.keys():
if not key in OPTIONS_KEYS:
raise Exception("label: Invalid options_dict key:%s" % key)
@@ -339,12 +343,13 @@ class Core(CorePluginBase):
self.torrent_labels[torrent_id] = label_id
#set speeds, etc:
options = self.labels[label_id]
- torrent = self.torrents[torrent_id]
- torrent.set_max_download_speed(options["max_download_speed"])
- torrent.set_max_upload_speed(options["max_upload_speed"])
- torrent.set_max_connections(options["max_connections"])
- torrent.set_max_upload_slots(options["max_upload_slots"])
- torrent.set_prioritize_first_last(options["prioritize_first_last"])
+ if ("apply_max" in options) and options["apply_max"]:
+ torrent = self.torrents[torrent_id]
+ torrent.set_max_download_speed(options["max_download_speed"])
+ torrent.set_max_upload_speed(options["max_upload_speed"])
+ torrent.set_max_connections(options["max_connections"])
+ torrent.set_max_upload_slots(options["max_upload_slots"])
+ torrent.set_prioritize_first_last(options["prioritize_first_last"])
self.config.save()
diff --git a/deluge/plugins/label/label/data/label_pref.glade b/deluge/plugins/label/label/data/label_pref.glade
new file mode 100644
index 000000000..d4be23368
--- /dev/null
+++ b/deluge/plugins/label/label/data/label_pref.glade
@@ -0,0 +1,450 @@
+
+
+
+
+
+
+
+ True
+ 5
+
+
+ True
+ 0
+ GTK_SHADOW_NONE
+
+
+ True
+ 12
+
+
+ True
+ 5
+
+
+ True
+ 5
+
+
+ True
+
+
+ False
+ False
+
+
+
+
+ True
+ True
+ Hide zero hits
+ 0
+ True
+
+
+ 1
+
+
+
+
+ False
+ False
+
+
+
+
+
+
+
+
+ True
+ 5
+ <b>General</b>
+ True
+
+
+ label_item
+
+
+
+
+ False
+ False
+
+
+
+
+ True
+ 0
+ GTK_SHADOW_NONE
+
+
+ True
+ True
+ 150
+
+
+ True
+
+
+ True
+ 1
+ 2
+
+
+ True
+ True
+ True
+ add
+ 0
+
+
+ 1
+ 2
+ GTK_EXPAND
+
+
+
+
+ 100
+ True
+ True
+
+
+
+
+
+
+ 250
+ True
+ True
+ True
+
+
+ 1
+
+
+
+
+ True
+ True
+ True
+ Remove
+ 0
+
+
+ False
+ 2
+
+
+
+
+ False
+ False
+
+
+
+
+ True
+
+
+ 30
+ True
+ <b>label</b>
+ True
+
+
+
+
+ True
+ 12
+ 3
+ 5
+ 5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 50
+ True
+ True
+ True
+ Apply to all
+ 0
+
+
+ 1
+ 3
+ 5
+ 6
+
+
+
+
+ True
+ Select A Folder
+
+
+ 3
+ 7
+ 8
+ GTK_EXPAND
+
+
+
+
+ True
+ True
+ -1 -1 9999 1 10 10
+
+
+ 1
+ 2
+ 3
+ 4
+ GTK_EXPAND
+ GTK_EXPAND
+
+
+
+
+ True
+ True
+ Apply maximum limits on add:
+ 0
+ True
+
+
+ 3
+
+
+
+
+ True
+ True
+ Move completed to:
+ 0
+ True
+
+
+ 3
+ 6
+ 7
+
+
+
+
+ True
+ Kib/s
+
+
+ 2
+ 3
+ 2
+ 3
+ GTK_EXPAND | GTK_SHRINK | GTK_FILL
+ GTK_EXPAND
+
+
+
+
+ True
+ True
+ -1 -1 9999 1 10 10
+
+
+ 1
+ 2
+ 2
+ 3
+ GTK_EXPAND
+ GTK_EXPAND
+
+
+
+
+ True
+ True
+ -1 -1 9999 1 10 10
+ True
+
+
+ 1
+ 2
+ 1
+ 2
+
+ GTK_EXPAND
+
+
+
+
+ True
+ 0
+ Upload Slots:
+
+
+ 4
+ 5
+ GTK_FILL
+
+
+
+
+
+ True
+ 0
+ Upload Speed:
+
+
+ 3
+ 4
+ GTK_FILL
+
+
+
+
+
+ True
+ 0
+ Download Speed:
+ True
+
+
+ 2
+ 3
+ GTK_FILL
+
+
+
+
+
+ True
+ 0
+ Connections:
+
+
+ 1
+ 2
+ GTK_FILL
+
+
+
+
+
+ True
+ Kib/s
+
+
+ 2
+ 3
+ 3
+ 4
+ GTK_EXPAND
+
+
+
+
+ True
+ True
+ -1 -1 9999 1 10 10
+ True
+
+
+ 1
+ 2
+ 4
+ 5
+ GTK_EXPAND
+ GTK_EXPAND
+
+
+
+
+ True
+ True
+ True
+ Save Label Settings
+ 0
+
+
+ 3
+ 9
+ 10
+
+
+
+
+ 1
+
+
+
+
+
+
+
+ True
+ True
+
+
+
+
+
+
+ True
+ 5
+ <b>Labels</b>
+ True
+
+
+ label_item
+
+
+
+
+ False
+ False
+ 1
+
+
+
+
+
+
+
+
+
diff --git a/deluge/plugins/label/label/gtkui.py b/deluge/plugins/label/label/gtkui.py
deleted file mode 100644
index eab8d8ce4..000000000
--- a/deluge/plugins/label/label/gtkui.py
+++ /dev/null
@@ -1,366 +0,0 @@
-#
-# blocklist/gtkui.py
-#
-# Copyright (C) 2007 Andrew Resch ('andar')
-# Copyright (C) 2008 Mark Stahler ('kramed')
-#
-# Deluge is free software.
-#
-# You may redistribute it and/or modify it under the terms of the
-# GNU General Public License, as published by the Free Software
-# Foundation; either version 2 of the License, or (at your option)
-# any later version.
-#
-# deluge is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-# See the GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with deluge. If not, write to:
-# The Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor
-# Boston, MA 02110-1301, USA.
-#
-# In addition, as a special exception, the copyright holders give
-# permission to link the code of portions of this program with the OpenSSL
-# library.
-# You must obey the GNU General Public License in all respects for all of
-# the code used other than OpenSSL. If you modify file(s) with this
-# exception, you may extend this exception to your version of the file(s),
-# but you are not obligated to do so. If you do not wish to do so, delete
-# this exception statement from your version. If you delete this exception
-# statement from all source files in the program, then also delete it here.
-
-import os
-import pkg_resources # access plugin egg
-from deluge.log import LOG as log
-from deluge import component # for systray
-import ui
-import gtk, gobject
-from deluge.ui.client import aclient
-import gtk_sidebar
-
-from deluge.configmanager import ConfigManager
-config = ConfigManager("label.conf")
-GTK_ALFA = config.get("gtk_alfa")
-NO_LABEL = "No Label"
-
-
-def cell_data_label(column, cell, model, row, data):
- cell.set_property('text', str(model.get_value(row, data)))
-
-def cell_data_tracker_host(column, cell, model, row, data):
- cell.set_property('text', str(model.get_value(row, data)))
-
-class GtkUI(ui.UI):
- def __init__(self, plugin_api, plugin_name):
- log.debug("Calling UI init")
- # Call UI constructor
- ui.UI.__init__(self, plugin_api, plugin_name)
- log.debug("Label GtkUI plugin initalized..")
-
- def enable(self):
- self.plugin.register_hook("on_apply_prefs", self.apply_prefs)
- self.load_interface()
-
- def disable(self):
- #deluge.component.get("StatusBar").remove_item(self.blocklist_status)
- self.plugin.deregister_hook("on_apply_prefs", self.apply_prefs)
- self.plugin.remove_preferences_page("Label")
-
- def get_pixmap(self, fname):
- """Returns a pixmap file included with plugin"""
- return pkg_resources.resource_filename("blocklist", os.path.join("data", fname))
-
- def unload_interface(self):
- self.plugin.remove_preferences_page("Label")
-
-
- def load_interface(self):
- if not GTK_ALFA:
- self.plugin.add_preferences_page("Label", gtk.Label(
- "Sorry, the Gtk UI for the Label-plugin is still in development."))
- return
-
- log.debug("replace sidebar")
-
- try :
- labelsidebar = gtk_sidebar.LabelSideBar()
- #sidebar.hpaned.remove(sidebar.scrolled)
- except Exception, e:
- log.debug(e)
-
- log.debug("add items to torrentview-popup menu.")
-
- torrentmenu = component.get("MenuBar").torrentmenu
-
- self.label_menu = LabelMenu()
- torrentmenu.append(self.label_menu)
- self.label_menu.show_all()
-
- log.debug("add columns")
-
- component.get("TorrentView").add_func_column(_("Label"),
- cell_data_label,
- [str],
- status_field=["label"])
-
- component.get("TorrentView").add_func_column(_("Tracker"),
- cell_data_tracker_host,
- [str],
- status_field=["tracker_host"])
-
- component.get("TorrentView").create_model_filter() #todo:improve.
- #TODO!
- log.debug("Beginning gtk pane initialization")
- self.config_frame = LabelConfigFrame()
-
- self.blocklist_pref_page = gtk.VBox()
- self.blocklist_pref_page.set_spacing(6)
-
- self.blocklist_pref_page.pack_start(self.config_frame,True,True)
-
- # Add preferences page to preferences page
- log.debug('Adding Label Preferences page')
- self.plugin.add_preferences_page("Label", self.blocklist_pref_page)
-
- # Load settings from config and fill widgets with settings
- self.fetch_prefs()
- #log.debug('Finished loading Label preferences')
-
-
- def fetch_prefs(self): # Fetch settings dictionary from plugin core and pass it to GTK ui settings
- log.info('LABEL: Fetching and loading Preferences via GTK ui')
- #aclient.block_list_get_options(self.callback_load_prefs)
- self.config_frame.load_settings()
-
- def apply_prefs(self):
- log.info('Blocklist: Preferences saved via Gtk ui')
- """settings_dict = {
- "url": self.url.get_text(),
- "listtype": self.get_ltype(),
- "check_after_days": self.check_after_days.get_value_as_int(),
- "load_on_start":self.load_on_start.get_active(),
- "try_times": self.try_times.get_value_as_int(),
- "timeout": self.timeout.get_value_as_int()
- }
- aclient.block_list_set_options(None, settings_dict)
- # Needs to go in another thread or wait until window is closed
- #gobject.idle_add(self.call_critical_setting)
- """
-
-
- # GTK Gui Callback functions
- def callback_load_prefs(self, dict):
- self.config_frame.load_settings()
- log.info('Blocklist: Callback Load Prefs GTK ui')
- """self.settings_url(dict['url'])
- self.settings_listtype(dict['listtype'])
- self.settings_load(dict['load_on_start'])
- self.settings_check_after_days(dict['check_after_days'])
- self.settings_timeout(dict['timeout'])
- self.settings_try_times(dict['try_times'])
- """
-
-def cb_none(args):
- "hack for empty callbacks."
- pass
-
-"""
-class LabelList(gtk.TreeView):
- "a simple listbox is way too hard in gtk :(."
- def __init__(self):
- pass
-"""
-
-class LabelMenu(gtk.MenuItem):
- def __init__(self):
- gtk.MenuItem.__init__(self, "Label")
- self.show_all()
-
- #attach..
- torrentmenu = component.get("MenuBar").torrentmenu
- torrentmenu.connect("show", self.on_show, None)
-
- aclient.connect_on_new_core(self._on_new_core)
-
- def _on_new_core(self, data):
- self.on_show()
-
- def get_torrent_ids(self):
- return component.get("TorrentView").get_selected_torrents()
-
-
- def on_show(self, widget=None, data=None):
- log.debug("label-on-show")
- aclient.label_get_labels(self.cb_labels)
- aclient.force_call(block=True)
-
- def cb_labels(self , labels):
- log.debug("cb_labels-start")
- self.sub_menu = gtk.Menu()
- for label in [NO_LABEL] + labels:
- item = gtk.MenuItem(label)
- item.connect("activate", self.on_select_label, label)
- self.sub_menu.append(item)
- self.set_submenu(self.sub_menu)
- self.show_all()
- log.debug("cb_labels-end")
-
- def on_select_label(self, widget=None, label_id = None):
- log.debug("select label:%s,%s" % (label_id ,self.get_torrent_ids()) )
- for torrent_id in self.get_torrent_ids():
- aclient.label_set_torrent(cb_none, torrent_id, label_id)
- #aclient.force_call(block=True)
-
-class LabelConfigFrame(gtk.Frame):
- def __init__(self):
- gtk.Frame.__init__(self)
- self.build_label_view()
- self.build_label_options()
- self.build_ui()
- self.labels = []
- aclient.connect_on_new_core(self._on_new_core)
-
- def _on_new_core(self, data):
- log.debug("NEW CORE")
- self.load_settings()
-
- def load_settings(self ,widget=None ,data=None):
- aclient.label_get_labels(self.cb_update_labels)
-
- def cb_update_labels(self, labels):
- self.labels = labels
- self.label_store.clear()
- for label in labels:
- self.label_store.append([label])
-
- def on_add(self, widget, data=None):
- label = self.txt_add.get_text()
- self.txt_add.set_text("")
- if label in self.labels:
- return
- aclient.label_add(cb_none, label)
- aclient.label_get_labels(self.cb_update_labels)
- self.select_label(label)
-
- #aclient.force_call(block=True)
-
- def on_remove(self, widget, data=None):
- label = self.get_selected_label()
- aclient.label_remove(cb_none, label)
- aclient.label_get_labels(self.cb_update_labels)
- self.select_label(0)
-
- def get_selected_label(self):
- model , iter = self.label_view.get_selection().get_selected()
- return self.label_store.get_value(iter,0)
-
- def select_label(self, label):
- aclient.force_call(block=True) #sync..
- if label:
- it = self.label_store.iter_nth_child(None,self.labels.index(label))
- else:
- it = self.label_store.iter_nth_child(None,0)
- self.label_view.get_selection().select_iter(it)
-
- def build_label_view(self):
- "gtk should have a simple listbox widget..."
- self.label_store = gtk.ListStore(str)
-
- column = gtk.TreeViewColumn(_("Label"))
- renderer = gtk.CellRendererText()
- column.pack_start(renderer)
- column.set_attributes(renderer, text = 0)
-
- self.label_view = gtk.TreeView(self.label_store)
- self.label_view.append_column(column)
- self.label_view.set_headers_visible(False)
-
- #self.label_scroll = gtk.ScrolledWindow()
- #self.label_scroll.add_with_viewport(self.label_view)
-
-
- def build_label_options(self):
- self.label_options = gtk.Label("Per label options")
-
- def build_ui(self):
- #vbox
- #general
- #[x] stuff
- #labels:
- #hpaned : left-right
- #right: listbox with labels
- #left: label-options
- #---
- #label-add
- #--
-
- label = gtk.Label()
- label.set_markup('' + _('General') + '')
-
-
- self.set_shadow_type(gtk.SHADOW_NONE)
- self.set_label_widget(label)
-
- self.btn_load = gtk.Button("Load Settings")
- self.btn_load.connect("clicked", self.load_settings, None)
-
- self.btn_remove = gtk.Button("Remove")
- self.btn_remove.connect("clicked", self.on_remove, None)
-
- vb = gtk.VBox()
- self.add(vb)
- vb.add(self.btn_load)
- vb.add(gtk.Label("Label is in developent, you're testing pre-alfa!!!"))
-
-
- self.hide_zero_hits = gtk.CheckButton(_('Hide Zero Hits'))
- vb.add(self.hide_zero_hits)
-
- label = gtk.Label()
- label.set_markup('' + _('Labels') + '')
- vb.add(label)
-
- hp = gtk.HPaned()
- hp.add1(self.label_view)
-
-
- hp.add2(self.label_options)
-
- hp.set_position(100)
-
- hp.set_size_request(400, 200) #bug..
-
-
- hbAdd = gtk.HBox()
- hbAdd.add(gtk.Label("Label:"))
- self.txt_add = gtk.Entry()
- hbAdd.add(self.txt_add)
- btn_add = gtk.Button("Add")
- hbAdd.add(btn_add)
- btn_add.connect("clicked", self.on_add, None)
-
- vb.pack_end(hbAdd)
-
- label = gtk.Label()
- label.set_markup('' + _('Add') + '')
-
-
-
- vb.pack_end(label)
-
- vb.pack_end(self.btn_remove, True , True)
-
- vb.pack_end(hp,True , True)
-
-
-
-
-
-
-
-
-
-
diff --git a/deluge/plugins/label/label/gtkui/__init__.py b/deluge/plugins/label/label/gtkui/__init__.py
new file mode 100644
index 000000000..9e1a1004b
--- /dev/null
+++ b/deluge/plugins/label/label/gtkui/__init__.py
@@ -0,0 +1,130 @@
+#
+# blocklist/gtkui.py
+#
+# Copyright (C) 2008 Martijn Voncken
+#
+# Deluge is free software.
+#
+# You may redistribute it and/or modify it under the terms of the
+# GNU General Public License, as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option)
+# any later version.
+#
+# deluge is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with deluge. If not, write to:
+# The Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor
+# Boston, MA 02110-1301, USA.
+#
+# In addition, as a special exception, the copyright holders give
+# permission to link the code of portions of this program with the OpenSSL
+# library.
+# You must obey the GNU General Public License in all respects for all of
+# the code used other than OpenSSL. If you modify file(s) with this
+# exception, you may extend this exception to your version of the file(s),
+# but you are not obligated to do so. If you do not wish to do so, delete
+# this exception statement from your version. If you delete this exception
+# statement from all source files in the program, then also delete it here.
+
+import os
+import pkg_resources # access plugin egg
+from deluge.log import LOG as log
+from deluge import component # for systray
+import ui
+import gtk, gobject
+from deluge.ui.client import aclient
+
+import sidebar
+import label_config
+import submenu
+
+from deluge.configmanager import ConfigManager
+config = ConfigManager("label.conf")
+NO_LABEL = "No Label"
+
+
+def cell_data_label(column, cell, model, row, data):
+ cell.set_property('text', str(model.get_value(row, data)))
+
+def cell_data_tracker_host(column, cell, model, row, data):
+ cell.set_property('text', str(model.get_value(row, data)))
+
+class GtkUI(ui.UI):
+ def __init__(self, plugin_api, plugin_name):
+ log.debug("Calling UI init")
+ # Call UI constructor
+ ui.UI.__init__(self, plugin_api, plugin_name)
+ log.debug("Label GtkUI plugin initalized..")
+ self.labelcfg = None
+ self.sidebar = None
+
+ def enable(self):
+ self.load_interface()
+
+ def disable(self):
+ self.labelcfg.unload()
+ try:
+ component.get("TorrentView").remove_column(_("Label"))
+ log.debug(1.1)
+ component.get("TorrentView").remove_column(_("Tracker"))
+ log.debug(1.2)
+ except Exception, e:
+ log.debug(e) #fix this!
+ log.debug(1.2)
+ self.sidebar.unload()
+ log.debug(2)
+
+
+ def get_pixmap(self, fname):
+ """Returns a pixmap file included with plugin"""
+ return pkg_resources.resource_filename("blocklist", os.path.join("data", fname))
+
+
+ def load_interface(self):
+ #sidebar
+ log.debug("replace sidebar")
+ try :
+ if not self.sidebar:
+ self.sidebar = sidebar.LabelSideBar()
+ self.sidebar.load()
+ except Exception, e:
+ log.debug(e)
+
+ #menu:
+ log.debug("add items to torrentview-popup menu.")
+ torrentmenu = component.get("MenuBar").torrentmenu
+ self.label_menu = submenu.LabelMenu()
+ torrentmenu.append(self.label_menu)
+ self.label_menu.show_all()
+
+ #columns:
+ self.load_columns()
+
+ #config:
+ if not self.labelcfg:
+ self.labelcfg = label_config.LabelConfig(self.plugin)
+ self.labelcfg.load()
+
+ log.debug('Finished loading Label plugin')
+
+ def load_columns(self):
+ log.debug("add columns")
+
+ component.get("TorrentView").add_func_column(_("Label"),
+ cell_data_label,
+ [str],
+ status_field=["label"])
+
+ component.get("TorrentView").add_func_column(_("Tracker"),
+ cell_data_tracker_host,
+ [str],
+ status_field=["tracker_host"])
+
+ component.get("TorrentView").create_model_filter() #todo:improve.
+
+
diff --git a/deluge/plugins/label/label/gtkui/label_config.py b/deluge/plugins/label/label/gtkui/label_config.py
new file mode 100644
index 000000000..33ed868f5
--- /dev/null
+++ b/deluge/plugins/label/label/gtkui/label_config.py
@@ -0,0 +1,268 @@
+#
+# Copyright (C) 2008 Martijn Voncken
+#
+# Deluge is free software.
+#
+#
+# You may redistribute it and/or modify it under the terms of the
+# GNU General Public License, as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option)
+# any later version.
+#
+# deluge is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with deluge. If not, write to:
+# The Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor
+# Boston, MA 02110-1301, USA.
+#
+# In addition, as a special exception, the copyright holders give
+# permission to link the code of portions of this program with the OpenSSL
+# library.
+# You must obey the GNU General Public License in all respects for all of
+# the code used other than OpenSSL. If you modify file(s) with this
+# exception, you may extend this exception to your version of the file(s),
+# but you are not obligated to do so. If you do not wish to do so, delete
+# this exception statement from your version. If you delete this exception
+# statement from all source files in the program, then also delete it here.
+
+import gtk
+import gtk.glade
+import os
+import pkg_resources # access plugin egg
+import deluge.component as component
+import deluge.common
+from deluge.log import LOG as log
+from deluge.ui.client import aclient
+
+
+
+class LabelConfig(object):
+ def __init__(self, plugin):
+ self.plugin = plugin
+ self.labels = []
+
+ def load(self):
+ #self.glade = gtk.glade.XML(self.get_resource("label_pref.glade"))
+ log.debug('Adding Label Preferences page')
+
+
+
+ self.glade = gtk.glade.XML(self.get_resource("label_pref.glade"))
+ self.prefs_box = self.glade.get_widget("label_prefs_box")
+ self.label_view = self.glade.get_widget("label_view")
+ self.txt_add = self.glade.get_widget("txt_add")
+ self.btn_add = self.glade.get_widget("btn_add")
+ self.btn_remove = self.glade.get_widget("btn_remove")
+ self.label_view = self.glade.get_widget("label_view")
+
+
+ self.btn_remove.connect("clicked", self.on_remove, None)
+ self.btn_add.connect("clicked", self.on_add, None)
+
+ self.build_label_view()
+
+ self.plugin.add_preferences_page("Label", self.glade.get_widget("label_prefs_box"))
+ self.plugin.register_hook("on_show_prefs", self.load_settings)
+ self.plugin.register_hook("on_apply_prefs", self.on_apply_prefs)
+
+ self.glade.get_widget("chk_move_completed").connect("clicked",self.on_chk_move_changed)
+ self.glade.get_widget("apply_max").connect("clicked",self.on_apply_max_changed)
+ self.glade.get_widget("btn_save").connect("clicked",self.on_save_label)
+ self.glade.get_widget("btn_apply").connect("clicked",self.on_apply_label)
+
+
+ self.load_settings()
+
+ def unload(self):
+ self.plugin.remove_preferences_page("Label")
+ self.plugin.deregister_hook("on_show_prefs", self.load_settings)
+
+ def get_resource(self, filename):
+ return pkg_resources.resource_filename("label", os.path.join("data", filename))
+
+ def load_settings(self ,widget = None , data = None):
+ aclient.label_get_labels(self.cb_update_labels)
+ aclient.label_get_global_options(self.cb_global_options)
+
+ def cb_global_options(self, data):
+ self.glade.get_widget("hide_zero_hits").set_active(data["hide_zero_hits"])
+
+ def cb_update_labels(self, labels):
+ log.debug("update labels")
+ self.labels = labels
+ self.label_store.clear()
+ for label in labels:
+ self.label_store.append([label])
+ self.label_view.get_selection().select_iter(self.label_store.get_iter_first())
+
+ def cb_label_options(self, data):
+ for key in ["max_download_speed", "max_upload_speed", "max_connections" ,"max_upload_slots"]:
+ spin = self.glade.get_widget(key)
+ spin.set_value(data[key])
+
+ self.glade.get_widget("apply_max").set_active(data["apply_max"])
+ self.glade.get_widget("chk_move_completed").set_active(bool(data["move_completed_to"]))
+ self.glade.get_widget("move_completed_to").set_filename(data["move_completed_to"] or "")
+
+ self.on_apply_max_changed()
+ self.on_chk_move_changed()
+
+ def on_apply_prefs(self):
+ options = {"hide_zero_hits":self.glade.get_widget("hide_zero_hits").get_active()}
+ aclient.label_set_global_options(None, options)
+
+ def on_chk_move_changed(self, data = None):
+ self.glade.get_widget("move_completed_to").set_sensitive(
+ self.glade.get_widget("chk_move_completed").get_active())
+
+ def on_apply_max_changed(self, data = None):
+ active = self.glade.get_widget("apply_max").get_active()
+ for key in ["max_download_speed", "max_upload_speed", "max_connections" ,"max_upload_slots","btn_apply"]:
+ spin = self.glade.get_widget(key)
+ spin.set_sensitive(active)
+
+
+ def on_add(self, widget, data = None):
+ label = self.txt_add.get_text()
+ self.txt_add.set_text("")
+ if label in self.labels:
+ return
+ aclient.label_add(None , label)
+ aclient.label_get_labels(self.cb_update_labels)
+ aclient.force_call(block=True)
+ self.select_label(label)
+
+ def on_remove(self, widget, data=None):
+ label = self.get_selected_label()
+ aclient.label_remove(None, label)
+ aclient.label_get_labels(self.cb_update_labels)
+ self.select_label(0)
+
+ def on_save_label(self, arg = None, apply = False):
+ options = {}
+ for key in ["max_download_speed", "max_upload_speed", "max_connections" ,"max_upload_slots"]:
+ options[key] = self.glade.get_widget(key).get_value()
+ options["apply_max"] = self.glade.get_widget("apply_max").get_active()
+
+ if self.glade.get_widget("chk_move_completed").get_active():
+ options["move_completed_to"] = self.glade.get_widget("move_completed_to").get_filename()
+ else:
+ options["move_completed_to"] = None
+
+ aclient.label_set_options(None, self.label, options , apply)
+
+ def on_apply_label(self, arg = None):
+ self.on_save_label(apply = True)
+
+ def get_selected_label(self):
+ model , iter = self.label_view.get_selection().get_selected()
+ return self.label_store.get_value(iter,0)
+
+ def select_label(self, label):
+ aclient.force_call(block=True) #sync..
+ if label:
+ it = self.label_store.iter_nth_child(None,self.labels.index(label))
+ else:
+ it = self.label_store.iter_nth_child(None,0)
+ self.label_view.get_selection().select_iter(it)
+
+ def build_label_view(self):
+ "gtk should have a simple listbox widget..."
+ self.label_store = gtk.ListStore(str)
+
+ column = gtk.TreeViewColumn(_("Label"))
+ renderer = gtk.CellRendererText()
+ column.pack_start(renderer)
+ column.set_attributes(renderer, text = 0)
+
+
+ self.label_view.set_model(self.label_store)
+ self.label_view.append_column(column)
+ self.label_view.set_headers_visible(False)
+
+ self.label_view.get_selection().connect("changed", self.on_label_changed)
+
+ def on_label_changed(self, selection):
+ (model, row) = self.label_view.get_selection().get_selected()
+ self.label = model.get_value(row, 0)
+ self.glade.get_widget("txt_label").set_markup("%s" % self.label)
+ aclient.label_get_options(self.cb_label_options, self.label)
+
+
+
+
+
+
+
+
+
+
+
+
+
+"""
+
+ label = gtk.Label()
+ label.set_markup('' + _('General') + '')
+
+
+ self.set_shadow_type(gtk.SHADOW_NONE)
+ self.set_label_widget(label)
+
+ self.btn_load = gtk.Button("Load Settings")
+ self.btn_load.connect("clicked", self.load_settings, None)
+
+ self.btn_remove = gtk.Button("Remove")
+ self.btn_remove.connect("clicked", self.on_remove, None)
+
+ vb = gtk.VBox()
+ self.add(vb)
+ #vb.add(self.btn_load)
+ #vb.add(gtk.Label("Label is in developent, you're testing pre-alfa!!!"))
+
+
+ self.hide_zero_hits = gtk.CheckButton(_('Hide Zero Hits'))
+ vb.add(self.hide_zero_hits)
+
+ label = gtk.Label()
+ label.set_markup('' + _('Labels') + '')
+ vb.add(label)
+
+ hp = gtk.HPaned()
+ hp.add1(self.label_view)
+
+
+ hp.add2(self.label_options)
+
+ hp.set_position(100)
+
+ hp.set_size_request(400, 200) #bug..
+
+
+ hbAdd = gtk.HBox()
+ hbAdd.add(gtk.Label("Label:"))
+ self.txt_add = gtk.Entry()
+ hbAdd.add(self.txt_add)
+ btn_add = gtk.Button("Add")
+ hbAdd.add(btn_add)
+ btn_add.connect("clicked", self.on_add, None)
+
+ vb.pack_end(hbAdd)
+
+ label = gtk.Label()
+ label.set_markup('' + _('Add') + '')
+
+
+
+ vb.pack_end(label)
+
+ vb.pack_end(self.btn_remove, True , True)
+
+ vb.pack_end(hp,True , True)
+
+"""
diff --git a/deluge/plugins/label/label/gtk_sidebar.py b/deluge/plugins/label/label/gtkui/sidebar.py
similarity index 66%
rename from deluge/plugins/label/label/gtk_sidebar.py
rename to deluge/plugins/label/label/gtkui/sidebar.py
index b8f72e42d..fbef3ebfb 100644
--- a/deluge/plugins/label/label/gtk_sidebar.py
+++ b/deluge/plugins/label/label/gtkui/sidebar.py
@@ -62,11 +62,23 @@ class LabelSideBar(component.Component):
self.filters = {}
# Create the liststore
- #cat,value,count , pixmap.
- self.liststore = gtk.ListStore(str, str, int, gtk.gdk.Pixbuf)
- self.filters[("state", "All")] = self.liststore.append(["state","All",0,gtk.gdk.pixbuf_new_from_file(
- deluge.common.get_pixmap("dht16.png"))])
+ #cat,value,count , pixmap , visible
+ self.treestore = gtk.TreeStore(str, str, int, gtk.gdk.Pixbuf, bool)
+ #add Cat nodes:
+ self.cat_nodes = {}
+ self.cat_nodes["state"] = self.treestore.append(None, ["cat", "State", 0, None, True])
+ self.cat_nodes["tracker"] = self.treestore.append(None, ["cat","Tracker", 0,None, True])
+ self.cat_nodes["label"] = self.treestore.append(None, ["cat", "Label", 0, None, True])
+
+ #default node:
+ self.filters[("state", "All")] = self.treestore.append(self.cat_nodes["state"],
+ ["state", "All", 0, gtk.gdk.pixbuf_new_from_file(deluge.common.get_pixmap("dht16.png")), True])
+
+
+ #remove all old columns:
+ for c in self.label_view.get_columns():
+ self.label_view.remove_column(c)
# Create the column
column = gtk.TreeViewColumn(_("Filters"))
@@ -75,44 +87,80 @@ class LabelSideBar(component.Component):
column.pack_start(render, expand=False)
column.add_attribute(render, 'pixbuf', 3)
render = gtk.CellRendererText()
- column.pack_start(render, expand=True)
+ column.pack_start(render, expand=False)
column.set_cell_data_func(render, self.render_cell_data,None)
self.label_view.append_column(column)
+ self.label_view.set_show_expanders(False)
- self.label_view.set_model(self.liststore)
+ self.label_view.set_model(self.treestore)
self.label_view.get_selection().connect("changed",
self.on_selection_changed)
# Select the 'All' label on init
self.label_view.get_selection().select_iter(
- self.liststore.get_iter_first())
+ self.treestore.get_iter_first())
+ self.create_model_filter()
#init.....
self._start()
+ self.label_view.expand_all()
+ self.hpaned.set_position(170)
+ def load(self):
+ self.label_view.set_model(self.model_filter)
+
+ def unload(self):
+ #hacks!
+ old_sidebar = component.get("SideBar")
+ del old_sidebar
+ new_sidebar = deluge.ui.gtkui.sidebar.SideBar()
+
+
+ def create_model_filter(self):
+ self.model_filter = self.treestore.filter_new()
+ self.model_filter.set_visible_column(4)
+ self.label_view.set_model(self.model_filter)
def cb_update_filter_items(self, filter_items):
+ visible_filters = []
for cat,filters in filter_items.iteritems():
for value, count in filters:
self.update_row(cat, value , count)
+ visible_filters.append((cat, value))
- def update_row(self, cat, value , count ):
+ for f in self.filters:
+ if not f in visible_filters:
+ self.treestore.set_value(self.filters[f], 4, False)
+
+ self.label_view.expand_all()
+
+ def update_row(self, cat, value , count):
if (cat, value) in self.filters:
row = self.filters[(cat, value)]
- self.liststore.set_value(row, 2, count)
+ self.treestore.set_value(row, 2, count)
else:
pix = self.get_pixmap(cat, value)
- row = self.liststore.append([cat, value, count , pix])
+ row = self.treestore.append(self.cat_nodes[cat],[cat, value, count , pix, True])
self.filters[(cat, value)] = row
+ self.treestore.set_value(row, 4, True)
+
+
def render_cell_data(self, column, cell, model, row, data):
"cell renderer"
+ cat = model.get_value(row, 0)
value = model.get_value(row, 1)
count = model.get_value(row, 2)
- txt = "%s (%s)" % (value, count)
+ if cat == "cat":
+ txt = value
+ col = gtk.gdk.color_parse('gray')
+ else:
+ txt = "%s (%s)" % (value, count)
+ col = gtk.gdk.color_parse('white')
cell.set_property('text', txt)
+ cell.set_property("cell-background-gdk",col)
def get_pixmap(self, cat, value):
if cat == "state":
@@ -144,7 +192,7 @@ class LabelSideBar(component.Component):
cat = "tracker_host"
filter = (cat, value)
- if value == "All":
+ if value == "All" or cat == "cat":
filter = (None, None)
elif (cat == "label" and value == "No Label"):
filter = ("label","")
@@ -157,6 +205,9 @@ class LabelSideBar(component.Component):
return None
def update(self):
- aclient.label_filter_items(self.cb_update_filter_items)
+ try:
+ aclient.label_filter_items(self.cb_update_filter_items)
+ except Exception, e:
+ log.debug(e)
diff --git a/deluge/plugins/label/label/gtkui/submenu.py b/deluge/plugins/label/label/gtkui/submenu.py
new file mode 100644
index 000000000..e919fa206
--- /dev/null
+++ b/deluge/plugins/label/label/gtkui/submenu.py
@@ -0,0 +1,98 @@
+#
+# blocklist/gtkui.py
+#
+# Copyright (C) 2007 Andrew Resch ('andar')
+# Copyright (C) 2008 Mark Stahler ('kramed')
+#
+# Deluge is free software.
+#
+# You may redistribute it and/or modify it under the terms of the
+# GNU General Public License, as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option)
+# any later version.
+#
+# deluge is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with deluge. If not, write to:
+# The Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor
+# Boston, MA 02110-1301, USA.
+#
+# In addition, as a special exception, the copyright holders give
+# permission to link the code of portions of this program with the OpenSSL
+# library.
+# You must obey the GNU General Public License in all respects for all of
+# the code used other than OpenSSL. If you modify file(s) with this
+# exception, you may extend this exception to your version of the file(s),
+# but you are not obligated to do so. If you do not wish to do so, delete
+# this exception statement from your version. If you delete this exception
+# statement from all source files in the program, then also delete it here.
+
+import os
+import pkg_resources # access plugin egg
+from deluge.log import LOG as log
+from deluge import component # for systray
+import ui
+import gtk, gobject
+from deluge.ui.client import aclient
+
+from deluge.configmanager import ConfigManager
+config = ConfigManager("label.conf")
+GTK_ALFA = config.get("gtk_alfa")
+NO_LABEL = "No Label"
+
+def cb_none(args):
+ "hack for empty callbacks."
+ pass
+
+class LabelMenu(gtk.MenuItem):
+ def __init__(self):
+ gtk.MenuItem.__init__(self, "Label")
+ self.show_all()
+
+ #attach..
+ torrentmenu = component.get("MenuBar").torrentmenu
+ torrentmenu.connect("show", self.on_show, None)
+
+ aclient.connect_on_new_core(self._on_new_core)
+
+ def _on_new_core(self, data):
+ self.on_show()
+
+ def get_torrent_ids(self):
+ return component.get("TorrentView").get_selected_torrents()
+
+
+ def on_show(self, widget=None, data=None):
+ log.debug("label-on-show")
+ aclient.label_get_labels(self.cb_labels)
+ aclient.force_call(block=True)
+
+ def cb_labels(self , labels):
+ log.debug("cb_labels-start")
+ self.sub_menu = gtk.Menu()
+ for label in [NO_LABEL] + labels:
+ item = gtk.MenuItem(label)
+ item.connect("activate", self.on_select_label, label)
+ self.sub_menu.append(item)
+ self.set_submenu(self.sub_menu)
+ self.show_all()
+ log.debug("cb_labels-end")
+
+ def on_select_label(self, widget=None, label_id = None):
+ log.debug("select label:%s,%s" % (label_id ,self.get_torrent_ids()) )
+ for torrent_id in self.get_torrent_ids():
+ aclient.label_set_torrent(cb_none, torrent_id, label_id)
+ #aclient.force_call(block=True)
+
+
+
+
+
+
+
+
diff --git a/deluge/plugins/label/label/ui.py b/deluge/plugins/label/label/gtkui/ui.py
similarity index 100%
rename from deluge/plugins/label/label/ui.py
rename to deluge/plugins/label/label/gtkui/ui.py
diff --git a/deluge/plugins/label/label/webui.py b/deluge/plugins/label/label/webui/__init__.py
similarity index 91%
rename from deluge/plugins/label/label/webui.py
rename to deluge/plugins/label/label/webui/__init__.py
index 5bdc03f75..06c3f72dd 100644
--- a/deluge/plugins/label/label/webui.py
+++ b/deluge/plugins/label/label/webui/__init__.py
@@ -38,8 +38,8 @@ from deluge.ui.client import sclient
from deluge import component
import ui
-import webui_config
-import webui_pages
+import config
+import pages
class WebUI(ui.UI):
def __init__(self, plugin_api, plugin_name):
@@ -49,12 +49,12 @@ class WebUI(ui.UI):
log.debug("Label WebUI plugin initalized..")
def enable(self):
- webui_pages.register()
- webui_config.register()
+ pages.register()
+ config.register()
def disable(self):
- webui_pages.unregister()
- webui_config.unregister()
+ pages.unregister()
+ config.unregister()
diff --git a/deluge/plugins/label/label/webui_config.py b/deluge/plugins/label/label/webui/config.py
similarity index 96%
rename from deluge/plugins/label/label/webui_config.py
rename to deluge/plugins/label/label/webui/config.py
index c11c85650..435973c56 100644
--- a/deluge/plugins/label/label/webui_config.py
+++ b/deluge/plugins/label/label/webui/config.py
@@ -80,10 +80,12 @@ class LabelUpdateCfgForm(forms.Form):
sclient.label_set_options(label_id, dict(data), apply)
#input fields :
+ apply_max = forms.CheckBox(_("Apply Maximum settings on add"))
max_connections = forms.DelugeInt(_("Maximum Connections"))
max_download_speed = forms.DelugeFloat(_("Maximum Download Speed (Kib/s)"))
max_upload_speed = forms.DelugeFloat(_("Maximum Upload Speed (Kib/s)"))
max_upload_slots = forms.DelugeInt(_("Maximum Upload Slots"))
+ move_completed_to = forms.ServerFolder(_("Move completed to"), required=False)
apply = forms.CheckBox(_("Apply"))
delete = forms.CheckBox(_("Delete"))
diff --git a/deluge/plugins/label/label/webui_pages.py b/deluge/plugins/label/label/webui/pages.py
similarity index 100%
rename from deluge/plugins/label/label/webui_pages.py
rename to deluge/plugins/label/label/webui/pages.py
diff --git a/deluge/plugins/label/label/webui/ui.py b/deluge/plugins/label/label/webui/ui.py
new file mode 100644
index 000000000..94b5f4b9f
--- /dev/null
+++ b/deluge/plugins/label/label/webui/ui.py
@@ -0,0 +1,53 @@
+#
+# blocklist/ui.py
+#
+# Copyright (C) 2007 Andrew Resch ('andar')
+# Copyright (C) 2008 Mark Stahler ('kramed')
+
+#
+# Deluge is free software.
+#
+# You may redistribute it and/or modify it under the terms of the
+# GNU General Public License, as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option)
+# any later version.
+#
+# deluge is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with deluge. If not, write to:
+# The Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor
+# Boston, MA 02110-1301, USA.
+#
+# In addition, as a special exception, the copyright holders give
+# permission to link the code of portions of this program with the OpenSSL
+# library.
+# You must obey the GNU General Public License in all respects for all of
+# the code used other than OpenSSL. If you modify file(s) with this
+# exception, you may extend this exception to your version of the file(s),
+# but you are not obligated to do so. If you do not wish to do so, delete
+# this exception statement from your version. If you delete this exception
+# statement from all source files in the program, then also delete it here.
+
+import gettext
+import locale
+import pkg_resources
+import deluge.component
+from deluge.ui.client import aclient as client
+from deluge.log import LOG as log
+
+class UI:
+ def __init__(self, plugin_api, plugin_name):
+ self.plugin = plugin_api
+
+ def enable(self):
+ pass
+
+ def disable(self):
+ pass
+
+
\ No newline at end of file
diff --git a/deluge/plugins/label/setup.py b/deluge/plugins/label/setup.py
index 959b5c9cd..0923934f1 100644
--- a/deluge/plugins/label/setup.py
+++ b/deluge/plugins/label/setup.py
@@ -47,8 +47,8 @@ setup(
version="0.1",
description=__doc__,
author=__author__,
- packages=["label"],
- package_data = {"label": ["template/*"]},
+ packages=["label","label.gtkui","label.webui"],
+ package_data = {"label": ["template/*","data/*"]},
entry_points="""
[deluge.plugin.core]
Label = label:CorePlugin