label plugin (clean label/build dir)

This commit is contained in:
Martijn Voncken 2008-07-20 21:04:51 +00:00
parent 8f8b87987b
commit 99a5c07c8c
14 changed files with 1103 additions and 399 deletions

13
deluge/plugins/label/TODO Normal file
View File

@ -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)

View File

@ -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()

View File

@ -0,0 +1,450 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
<!--Generated with glade3 3.4.5 on Sun Jul 20 22:26:59 2008 -->
<glade-interface>
<widget class="GtkWindow" id="window1">
<child>
<widget class="GtkVBox" id="label_prefs_box">
<property name="visible">True</property>
<property name="spacing">5</property>
<child>
<widget class="GtkFrame" id="frame1">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="shadow_type">GTK_SHADOW_NONE</property>
<child>
<widget class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkVBox" id="vbox2">
<property name="visible">True</property>
<property name="spacing">5</property>
<child>
<widget class="GtkHBox" id="hbox1">
<property name="visible">True</property>
<property name="spacing">5</property>
<child>
<widget class="GtkLabel" id="label2">
<property name="visible">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="hide_zero_hits">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Hide zero hits</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="ypad">5</property>
<property name="label" translatable="yes">&lt;b&gt;General&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="type">label_item</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkFrame" id="frame2">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="shadow_type">GTK_SHADOW_NONE</property>
<child>
<widget class="GtkHPaned" id="hpaned1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="position">150</property>
<child>
<widget class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<child>
<widget class="GtkTable" id="table2">
<property name="visible">True</property>
<property name="n_rows">1</property>
<property name="n_columns">2</property>
<child>
<widget class="GtkButton" id="btn_add">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="label" translatable="yes">add</property>
<property name="response_id">0</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="y_options">GTK_EXPAND</property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="txt_add">
<property name="width_request">100</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkTreeView" id="label_view">
<property name="height_request">250</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="headers_clickable">True</property>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="btn_remove">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="label" translatable="yes">Remove</property>
<property name="response_id">0</property>
</widget>
<packing>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
</widget>
<packing>
<property name="resize">False</property>
<property name="shrink">False</property>
</packing>
</child>
<child>
<widget class="GtkVBox" id="vbox3">
<property name="visible">True</property>
<child>
<widget class="GtkLabel" id="txt_label">
<property name="height_request">30</property>
<property name="visible">True</property>
<property name="label" translatable="yes">&lt;b&gt;label&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
</child>
<child>
<widget class="GtkTable" id="table1">
<property name="visible">True</property>
<property name="n_rows">12</property>
<property name="n_columns">3</property>
<property name="column_spacing">5</property>
<property name="row_spacing">5</property>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<widget class="GtkButton" id="btn_apply">
<property name="width_request">50</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="label" translatable="yes">Apply to all</property>
<property name="response_id">0</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">3</property>
<property name="top_attach">5</property>
<property name="bottom_attach">6</property>
</packing>
</child>
<child>
<widget class="GtkFileChooserButton" id="move_completed_to">
<property name="visible">True</property>
<property name="title" translatable="yes">Select A Folder</property>
</widget>
<packing>
<property name="right_attach">3</property>
<property name="top_attach">7</property>
<property name="bottom_attach">8</property>
<property name="y_options">GTK_EXPAND</property>
</packing>
</child>
<child>
<widget class="GtkSpinButton" id="max_upload_speed">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="adjustment">-1 -1 9999 1 10 10</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="x_options">GTK_EXPAND</property>
<property name="y_options">GTK_EXPAND</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="apply_max">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Apply maximum limits on add:</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="right_attach">3</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="chk_move_completed">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Move completed to:</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="right_attach">3</property>
<property name="top_attach">6</property>
<property name="bottom_attach">7</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label9">
<property name="visible">True</property>
<property name="label" translatable="yes">Kib/s</property>
</widget>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_EXPAND | GTK_SHRINK | GTK_FILL</property>
<property name="y_options">GTK_EXPAND</property>
</packing>
</child>
<child>
<widget class="GtkSpinButton" id="max_download_speed">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="adjustment">-1 -1 9999 1 10 10</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_EXPAND</property>
<property name="y_options">GTK_EXPAND</property>
</packing>
</child>
<child>
<widget class="GtkSpinButton" id="max_connections">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="adjustment">-1 -1 9999 1 10 10</property>
<property name="numeric">True</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>
<property name="x_options"></property>
<property name="y_options">GTK_EXPAND</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Upload Slots: </property>
</widget>
<packing>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label6">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Upload Speed:</property>
</widget>
<packing>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label5">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Download Speed:</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Connections:</property>
</widget>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label8">
<property name="visible">True</property>
<property name="label" translatable="yes">Kib/s</property>
</widget>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="y_options">GTK_EXPAND</property>
</packing>
</child>
<child>
<widget class="GtkSpinButton" id="max_upload_slots">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="adjustment">-1 -1 9999 1 10 10</property>
<property name="numeric">True</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
<property name="x_options">GTK_EXPAND</property>
<property name="y_options">GTK_EXPAND</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="btn_save">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="label" translatable="yes">Save Label Settings</property>
<property name="response_id">0</property>
</widget>
<packing>
<property name="right_attach">3</property>
<property name="top_attach">9</property>
<property name="bottom_attach">10</property>
</packing>
</child>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</widget>
<packing>
<property name="resize">True</property>
<property name="shrink">True</property>
</packing>
</child>
</widget>
</child>
<child>
<widget class="GtkLabel" id="label10">
<property name="visible">True</property>
<property name="ypad">5</property>
<property name="label" translatable="yes">&lt;b&gt;Labels&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="type">label_item</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</widget>
</child>
</widget>
</glade-interface>

View File

@ -1,366 +0,0 @@
#
# blocklist/gtkui.py
#
# Copyright (C) 2007 Andrew Resch ('andar') <andrewresch@gmail.com>
# Copyright (C) 2008 Mark Stahler ('kramed') <markstahler@gmail.com>
#
# 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('<b>' + _('General') + '</b>')
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('<b>' + _('Labels') + '</b>')
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('<b>' + _('Add') + '</b>')
vb.pack_end(label)
vb.pack_end(self.btn_remove, True , True)
vb.pack_end(hp,True , True)

View File

@ -0,0 +1,130 @@
#
# blocklist/gtkui.py
#
# Copyright (C) 2008 Martijn Voncken <mvoncken@gmail.com>
#
# 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.

View File

@ -0,0 +1,268 @@
#
# Copyright (C) 2008 Martijn Voncken <mvoncken@gmail.com>
#
# 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("<b>%s</b>" % self.label)
aclient.label_get_options(self.cb_label_options, self.label)
"""
label = gtk.Label()
label.set_markup('<b>' + _('General') + '</b>')
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('<b>' + _('Labels') + '</b>')
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('<b>' + _('Add') + '</b>')
vb.pack_end(label)
vb.pack_end(self.btn_remove, True , True)
vb.pack_end(hp,True , True)
"""

View File

@ -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)

View File

@ -0,0 +1,98 @@
#
# blocklist/gtkui.py
#
# Copyright (C) 2007 Andrew Resch ('andar') <andrewresch@gmail.com>
# Copyright (C) 2008 Mark Stahler ('kramed') <markstahler@gmail.com>
#
# 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)

View File

@ -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()

View File

@ -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"))

View File

@ -0,0 +1,53 @@
#
# blocklist/ui.py
#
# Copyright (C) 2007 Andrew Resch ('andar') <andrewresch@gmail.com>
# Copyright (C) 2008 Mark Stahler ('kramed') <markstahler@gmail.com>
#
# 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

View File

@ -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