From f1cd5071da5915ffa5a9187424e2f2b0634358ed Mon Sep 17 00:00:00 2001 From: Martijn Voncken Date: Mon, 17 Mar 2008 19:42:44 +0000 Subject: [PATCH] webui-refactor:use deluge.component for components/prepare for plugins --- .../ui/webui/{config.py => config_forms.py} | 24 +- deluge/ui/webui/config_page_manager.py | 58 ++++ deluge/ui/webui/config_tabs_deluge.py | 46 +-- deluge/ui/webui/config_tabs_webui.py | 43 ++- deluge/ui/webui/dbus_interface.py | 283 ------------------ deluge/ui/webui/deluge_webserver.py | 31 +- deluge/ui/webui/menu_manager.py | 76 ++--- deluge/ui/webui/page_manager.py | 69 +++++ deluge/ui/webui/pages.py | 67 +---- .../{pluginmanager.py => plugin_manager.py} | 40 +-- deluge/ui/webui/register_menu.py | 58 ++++ deluge/ui/webui/render.py | 3 +- .../templates/advanced/part_torrent_list.html | 2 +- deluge/ui/webui/templates/deluge/config.html | 2 +- deluge/ui/webui/templates/deluge/connect.html | 3 +- deluge/ui/webui/templates/deluge/login.html | 2 + .../webui/templates/deluge/torrent_add.html | 1 + deluge/ui/webui/templates/white/index.html | 9 +- deluge/ui/webui/templates/white/login.html | 34 --- .../webui/templates/white/part_organize.html | 4 +- .../webui/templates/white/template_style.css | 32 +- deluge/ui/webui/webserver_common.py | 8 + 22 files changed, 377 insertions(+), 518 deletions(-) rename deluge/ui/webui/{config.py => config_forms.py} (88%) create mode 100644 deluge/ui/webui/config_page_manager.py delete mode 100644 deluge/ui/webui/dbus_interface.py create mode 100644 deluge/ui/webui/page_manager.py rename deluge/ui/webui/{pluginmanager.py => plugin_manager.py} (62%) create mode 100644 deluge/ui/webui/register_menu.py delete mode 100644 deluge/ui/webui/templates/white/login.html diff --git a/deluge/ui/webui/config.py b/deluge/ui/webui/config_forms.py similarity index 88% rename from deluge/ui/webui/config.py rename to deluge/ui/webui/config_forms.py index 6d0c9c062..472b274d4 100644 --- a/deluge/ui/webui/config.py +++ b/deluge/ui/webui/config_forms.py @@ -40,9 +40,9 @@ from lib.webpy022.http import seeother import sys import os import utils +from deluge import component -groups = [] -blocks = forms.utils.datastructures.SortedDict() +config_page_manager = component.get("ConfigPageManager") class WebCfgForm(forms.Form): "config base for webui" @@ -76,9 +76,9 @@ class config_page: """ def get_form_class(self,name): try: - return blocks[name] + return config_page_manager.blocks[name] except KeyError: - raise Exception('no config page named:"%s"') + raise Exception('no config page named:"%s"' % name) @deco.deluge_page def GET(self, name): @@ -109,18 +109,4 @@ class config_page: error= _('Correct the errors above and try again')) def render(self, f , name , message = '' , error=''): - return render.config(groups, blocks, f, name , message , error) - -def register_block(group, name, form): - if not group in groups: - groups.append(group) - form.group = group - blocks[name] = form - -def unregister_block(name): - del blocks[name] - - - - - + return render.config(config_page_manager.groups, config_page_manager.blocks, f, name , message , error) diff --git a/deluge/ui/webui/config_page_manager.py b/deluge/ui/webui/config_page_manager.py new file mode 100644 index 000000000..5c22e303f --- /dev/null +++ b/deluge/ui/webui/config_page_manager.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright (C) Martijn Voncken 2008 +# +# This program is free software; you can 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, or (at your option) +# any later version. +# +# This program 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 this program. 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. + + +from utils import logcall +from render import template +from deluge import component +import lib.newforms_plus as forms + +class ConfigPageManager(component.Component): + def __init__(self): + component.Component.__init__(self, "ConfigPageManager") + self.groups = [] + self.blocks = forms.utils.datastructures.SortedDict() + + def register(self, group, name, form): + if not group in self.groups: + self.groups.append(group) + form.group = group + self.blocks[name] = form + + def unregister(self, name): + del self.blocks[name] + +__config_page_manager = ConfigPageManager() + + + + + diff --git a/deluge/ui/webui/config_tabs_deluge.py b/deluge/ui/webui/config_tabs_deluge.py index 0c9ef5ce4..170178374 100644 --- a/deluge/ui/webui/config_tabs_deluge.py +++ b/deluge/ui/webui/config_tabs_deluge.py @@ -31,13 +31,16 @@ # 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 lib.newforms_plus as forms -import config import utils from webserver_common import ws, proxy , log +import lib.newforms_plus as forms +import config_forms +from deluge import component + +config_page = component.get("ConfigPageManager") -class NetworkPorts(config.CfgForm ): +class NetworkPorts(config_forms.CfgForm ): title = _("Ports") info = _("Restart daemon after changing these values.") _port_from = forms.IntegerField(_("From")) @@ -45,7 +48,7 @@ class NetworkPorts(config.CfgForm ): random_port = forms.CheckBox(_("Random")) def initial_data(self): - data = config.CfgForm.initial_data(self) + data = config_forms.CfgForm.initial_data(self) data['_port_from'] , data['_port_to'] = data['listen_ports'] return data @@ -53,15 +56,15 @@ class NetworkPorts(config.CfgForm ): data['listen_ports'] = [data['_port_from'] , data['_port_to'] ] del(data['_port_from']) del(data['_port_to']) - config.CfgForm.save(self, data) + config_forms.config.CfgForm.save(self, data) def validate(self, data): if (data['_port_to'] < data['_port_from']): raise ValidationError('"Port from" must be greater than "Port to"') -config.register_block('network','ports', NetworkPorts) +config_page.register('network','ports', NetworkPorts) -class NetworkExtra(config.CfgForm ): +class NetworkExtra(config_forms.CfgForm ): title = _("Extra's") dht = forms.CheckBox(_("Mainline DHT")) upnp = forms.CheckBox(_("UpNP")) @@ -69,9 +72,9 @@ class NetworkExtra(config.CfgForm ): utpex = forms.CheckBox(_("Peer-Exchange")) lsd = forms.CheckBox(_("LSD")) -config.register_block('network','extra', NetworkExtra) +config_page.register('network','extra', NetworkExtra) -class NetworkEnc(config.CfgForm ): +class NetworkEnc(config_forms.CfgForm ): title = _("Encryption") _enc_choices = list(enumerate([_("Forced"),_("Enabled"),_("Disabled")])) @@ -82,10 +85,10 @@ class NetworkEnc(config.CfgForm ): enc_level = forms.IntChoiceField(_("Level"), _level_choices) enc_prefer_rc4 = forms.CheckBox("Prefer to encrypt entire stream") -config.register_block('network','encryption', NetworkEnc) +config_page.register('network','encryption', NetworkEnc) -class BandwithGlobal(config.CfgForm): +class BandwithGlobal(config_forms.CfgForm): title = _("Global") info = _("-1 = Unlimited") max_connections_global = forms.DelugeInt(_("Maximum Connections")) @@ -93,18 +96,18 @@ class BandwithGlobal(config.CfgForm): max_upload_speed = forms.DelugeFloat(_("Maximum Upload Speed (Kib/s)")) max_upload_slots_global = forms.DelugeInt(_("Maximum Upload Slots")) -config.register_block('bandwidth','global', BandwithGlobal) +config_page.register('bandwidth','global', BandwithGlobal) -class BandwithTorrent(config.CfgForm): +class BandwithTorrent(config_forms.CfgForm): title = _("Per Torrent") info = _("-1 = Unlimited") max_connections_per_torrent = forms.DelugeInt(_("Maximum Connections")) max_upload_slots_per_torrent = forms.DelugeInt(_("Maximum Upload Slots")) -config.register_block('bandwidth','torrent', BandwithTorrent) +config_page.register('bandwidth','torrent', BandwithTorrent) -class Download(config.CfgForm): +class Download(config_forms.CfgForm): title = _("Download") download_location = forms.ServerFolder(_("Store all downoads in")) torrentfiles_location = forms.ServerFolder(_("Save .torrent files to")) @@ -113,15 +116,15 @@ class Download(config.CfgForm): prioritize_first_last_pieces = forms.CheckBox( _('Prioritize first and last pieces')) -config.register_block('deluge','download', Download) +config_page.register('deluge','download', Download) -class Daemon(config.CfgForm): +class Daemon(config_forms.CfgForm): title = _("Daemon") info = _("Restart daemon and webui after changing these settings") daemon_port = forms.IntegerField(_("Port")) allow_remote = forms.CheckBox(_("Allow Remote Connections")) -config.register_block('deluge','daemon', Daemon) +config_page.register('deluge','daemon', Daemon) class Plugins(forms.Form): title = _("Enabled Plugins") @@ -139,9 +142,9 @@ class Plugins(forms.Form): def save(self, value): raise forms.ValidationError("SAVE:TODO") -config.register_block('deluge','plugins', Plugins) - +config_page.register('deluge','plugins', Plugins) +""" class Queue(forms.Form): title = _("Queue") info = _("queue-cfg not finished") @@ -159,4 +162,5 @@ class Queue(forms.Form): def save(self, value): raise forms.ValidationError("SAVE:TODO") -config.register_block('plugins','queue', Queue) \ No newline at end of file +config_page.register('plugins','queue', Queue) +""" \ No newline at end of file diff --git a/deluge/ui/webui/config_tabs_webui.py b/deluge/ui/webui/config_tabs_webui.py index f61aa8fa1..62d25efd5 100644 --- a/deluge/ui/webui/config_tabs_webui.py +++ b/deluge/ui/webui/config_tabs_webui.py @@ -31,13 +31,17 @@ # 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 lib.newforms_plus as forms -import config + import utils -from webserver_common import ws +from webserver_common import ws, log +import lib.newforms_plus as forms +import config_forms +from deluge import component +config_page = component.get("ConfigPageManager") +plugins = component.get("WebPluginManager") -class Template(config.WebCfgForm): +class Template(config_forms.WebCfgForm): title = _("Template") _templates = [(t,t) for t in ws.get_templates()] @@ -52,20 +56,16 @@ class Template(config.WebCfgForm): from render import render render.apply_cfg() - -class Server(config.WebCfgForm): +class Server(config_forms.WebCfgForm): title = _("Server") + port = forms.IntegerField(label = _("Port"),min_value=80) + use_https = forms.CheckBox(_("Use https")) try: import OpenSSL except ImportError: info = _("pyopenssl not installed, install this for https.") - port = forms.IntegerField(label = _("Port"),min_value=80) - - use_https = forms.CheckBox(_("Use https")) - - def post_save(self): pass #raise forms.ValidationError( @@ -93,6 +93,21 @@ class Password(forms.Form): utils.end_session() #raise forms.ValidationError(_("Password changed,please login again")) -config.register_block('webui','template', Template) -config.register_block('webui','server',Server) -config.register_block('webui','password',Password) +class WebUiPlugins(forms.Form): + title = _("WebUi Plugins") + + _choices = [(p,p) for p in plugins.get_available_plugins()] + enabled_plugins = forms.MultipleChoice(_(""), _choices) + + def initial_data(self): + return {'enabled_plugins':plugins.get_enabled_plugins()} + + def save(self, data): + log.debug() + for plugin_name in data['enabled_plugins']: + plugins.enable_plugin(plugin_name) + +config_page.register('webui','template', Template) +config_page.register('webui','server',Server) +config_page.register('webui','password',Password) +config_page.register('webui','webuiplugins',WebUiPlugins) diff --git a/deluge/ui/webui/dbus_interface.py b/deluge/ui/webui/dbus_interface.py deleted file mode 100644 index 4743b77a0..000000000 --- a/deluge/ui/webui/dbus_interface.py +++ /dev/null @@ -1,283 +0,0 @@ -# -*- coding: utf-8 -*- -# Dbus Ipc for experimental web interface -# -# dbus_interface.py -# -# Copyright (C) Martijn Voncken 2007 -# Contains copy and pasted code from other parts of deluge,see deluge AUTHORS -# -# This program is free software; you can 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, or (at your option) -# any later version. -# -# This program 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 this program. 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 gtk -import dbus -import deluge.common as common -from lib.pythonize import pythonize -import base64 -import random -random.seed() - -dbus_interface="org.deluge_torrent.dbusplugin" -dbus_service="/org/deluge_torrent/DelugeDbusPlugin" - -dbus_manager = None -def get_dbus_manager(*args): - #another way to make a singleton. - global dbus_manager - if not dbus_manager: - dbus_manager = DbusManager(*args) - return dbus_manager - -class DbusManager(dbus.service.Object): - def __init__(self, core, interface,config,config_file): - self.core = core - self.interface = interface - self.config = config - self.config_file = config_file - self.bus = dbus.SessionBus() - bus_name = dbus.service.BusName(dbus_interface,bus=self.bus) - dbus.service.Object.__init__(self, bus_name,dbus_service) - - # - #todo : add: get_interface_version in=i,get_config_value in=s out=s - # - - @dbus.service.method(dbus_interface=dbus_interface, - in_signature="",out_signature="as") - def get_session_state(self): - """Returns a list of torrent_ids in the session. - same as 0.6, but returns type "as" instead of a pickle - """ - torrent_list = [str(key) for key in self.core.unique_IDs] - return torrent_list - - @dbus.service.method(dbus_interface=dbus_interface, - in_signature="sas",out_signature="a{sv}") - def get_torrent_status(self, torrent_id, keys): - """return torrent metadata of a single torrent as a dict - 0.6 returns a pickle, this returns a dbus-type. - +added some more values to the dict - """ - - torrent_id = int(torrent_id) - # Convert the array of strings to a python list of strings - nkeys = [str(key) for key in keys] - - state = self.core.get_torrent_state(torrent_id) - torrent = self.core.unique_IDs[torrent_id] - - status = { - "name": state["name"], - "total_size": state["total_size"], - "num_pieces": state["num_pieces"], - "state": state['state'], - "user_paused": self.core.is_user_paused(torrent_id), - "paused":state['is_paused'], - "progress": int(state["progress"] * 100), - "next_announce": state["next_announce"], - "total_payload_download":state["total_payload_download"], - "total_payload_upload": state["total_payload_upload"], - "download_payload_rate": state["download_rate"], - "upload_payload_rate": state["upload_rate"], - "num_peers": state["num_peers"], - "num_seeds": state["num_seeds"], - "total_wanted": state["total_wanted"], - "eta": common.estimate_eta(state), - "ratio": self.interface.manager.calc_ratio(torrent_id,state), - #non 0.6 values follow here: - "tracker_status": state.get("tracker_status","?"), - "uploaded_memory": torrent.uploaded_memory, - } - #more non 0.6 values - for key in ["total_seeds", "total_peers","is_seed", "total_done", - "total_download", "total_upload" - #, "download_rate","upload_rate" - , "num_files", "piece_length", "distributed_copies" - ,"next_announce","tracker","queue_pos"]: - status[key] = state[key] - - #print 'all_keys:',sorted(status.keys()) - - status_subset = {} - for key in keys: - if key in status: - status_subset[key] = status[key] - else: - print 'mbus error,no key named:', key - return status_subset - - @dbus.service.method(dbus_interface=dbus_interface, - in_signature="as",out_signature="") - def pause_torrent(self, torrents): - """same as 0.6 interface""" - for torrent_id in torrents: - torrent_id = int(torrent_id) - self.core.set_user_pause(torrent_id, True) - - @dbus.service.method(dbus_interface=dbus_interface, - in_signature="as", out_signature="") - def resume_torrent(self, torrents): - """same as 0.6 interface""" - for torrent_id in torrents: - torrent_id = int(torrent_id) - self.core.set_user_pause(torrent_id, False) - - @dbus.service.method(dbus_interface=dbus_interface, - in_signature="as", out_signature="") - def force_reannounce(self, torrents): - """same as 0.6 interface""" - for torrent_id in torrents: - torrent_id = int(torrent_id) - self.core.update_tracker(torrent_id) - - @dbus.service.method(dbus_interface=dbus_interface, - in_signature="asbb", out_signature="") - def remove_torrent(self, torrent_ids, data_also, torrent_also): - """remove a torrent,and optionally data and torrent - additions compared to 0.6 interface: (data_also, torrent_also) - """ - for torrent_id in torrent_ids: - torrent_id = int(torrent_id) - self.core.remove_torrent(torrent_id, bool(data_also) - ,bool( torrent_also)) - - #this should not be needed: - gtk.gdk.threads_enter() - try: - self.interface.torrent_model_remove(torrent_id) - except: - pass - - @dbus.service.method(dbus_interface=dbus_interface, - in_signature="s", out_signature="b") - def add_torrent_url(self, url): - filename = fetch_url(url) - self._add_torrent(filename) - return True - - @dbus.service.method(dbus_interface=dbus_interface, - in_signature="s", out_signature="b") - def queue_up(self, torrent_id): - self.core.queue_up(int(torrent_id)) - return True - - @dbus.service.method(dbus_interface=dbus_interface, - in_signature="s", out_signature="b") - def queue_down(self, torrent_id): - self.core.queue_down(int(torrent_id)) - return True - - @dbus.service.method(dbus_interface=dbus_interface, - in_signature="ss", out_signature="b") - def add_torrent_filecontent(self, name, filecontent_b64): - """not available in deluge 0.6 interface""" - #name = fillename without directory - name = name.replace('\\','/') - name = 'deluge_' + str(random.random()) + '_' + name.split('/')[-1] - filename = os.path.join(self.core.config.get("default_download_path"), name) - - filecontent = base64.b64decode(filecontent_b64) - f = open(filename,"wb") #no with statement, that's py 2.5+ - f.write(filecontent) - f.close() - print 'write:',filename - self._add_torrent(filename) - return True - - - @dbus.service.method(dbus_interface=dbus_interface, - in_signature="", out_signature="a{sv}") - def get_config(self): - return self.core.config.mapping - - @dbus.service.method(dbus_interface=dbus_interface, - in_signature="s", out_signature="v") - def get_config_value(self,key): - return self.core.config.mapping[pythonize(key)] #ugly! - - @dbus.service.method(dbus_interface=dbus_interface, - in_signature="a{sv}", out_signature="") - def set_config(self, config): - """Set the config with values from dictionary""" - config = deluge.common.pythonize(config) - # Load all the values into the configuration - for key in self.core.config.keys(): - self.core.config[key] = config[key] - self.core.apply_prefs() - - @dbus.service.method(dbus_interface=dbus_interface, - in_signature="", out_signature="v") - def get_download_rate(self): - return self.core.get_state()['download_rate'] - - @dbus.service.method(dbus_interface=dbus_interface, - in_signature="", out_signature="v") - def get_upload_rate(self): - return self.core.get_state()['upload_rate'] - - @dbus.service.method(dbus_interface=dbus_interface, - in_signature="", out_signature="v") - def get_num_connections(self): - core_state = self.core.get_state() - return core_state['num_connections'] - - #internal - def _add_torrent(self, filename): - filename = unicode(filename) - target = self.core.config.get("default_download_path") - - torrent_id = self.core.add_torrent(filename, target, - self.interface.config.get("use_compact_storage")) - - #update gtk-ui This should not be needed!! - gtk.gdk.threads_enter() - try: - self.interface.torrent_model_append(torrent_id) - except: - pass - #finally is 2.5 only! - gtk.gdk.threads_leave() - - return True - -def fetch_url(url): - import urllib - - try: - filename, headers = urllib.urlretrieve(url) - except IOError: - raise Exception( "Network error while trying to fetch torrent from %s" - % url) - else: - if (filename.endswith(".torrent") or - headers["content-type"]=="application/x-bittorrent"): - return filename - else: - raise Exception("URL doesn't appear to be a valid torrent file:%s" - % url) - - return None diff --git a/deluge/ui/webui/deluge_webserver.py b/deluge/ui/webui/deluge_webserver.py index aab520033..5f7c847a4 100644 --- a/deluge/ui/webui/deluge_webserver.py +++ b/deluge/ui/webui/deluge_webserver.py @@ -29,16 +29,28 @@ # this exception statement from your version. If you delete this exception # statement from all source files in the program, then also delete it here. +#initialize components: +import menu_manager #registers as "MenuManager" +import config_page_manager #registers as "ConfigPageManager" +import plugin_manager #registers as "WebPluginManager" +import page_manager #registers as "PageManager" -from webserver_common import ws +#self registering pages etc. +import pages +import config_tabs_webui #auto registers in ConfigUiManager +import config_tabs_deluge #auto registers in ConfigUiManager +import register_menu + +from webserver_common import ws #todo: remove ws. -from lib.webpy022.request import webpyfunc -from lib.webpy022 import webapi -from lib.gtk_cherrypy_wsgiserver import CherryPyWSGIServer -import lib.webpy022 as web -import os def create_webserver(urls, methods, middleware): + from webserver_common import ws + from lib.webpy022.request import webpyfunc + from lib.webpy022 import webapi + from lib.gtk_cherrypy_wsgiserver import CherryPyWSGIServer + import os + func = webapi.wsgifunc(webpyfunc(urls, methods, False), *middleware) server_address=("0.0.0.0", int(ws.config.get('port'))) @@ -51,13 +63,14 @@ def create_webserver(urls, methods, middleware): return server def WebServer(debug = False): + import lib.webpy022 as web + from deluge import component if debug: middleware = [web.reloader] else: middleware = [] - - import pages - return create_webserver(pages.urls, pages.page_classes, middleware) + pagemanager = component.get("PageManager") + return create_webserver(pagemanager.urls, pagemanager.page_classes, middleware) def run(debug = False): server = WebServer(debug) diff --git a/deluge/ui/webui/menu_manager.py b/deluge/ui/webui/menu_manager.py index d3404045e..b3df3ae22 100644 --- a/deluge/ui/webui/menu_manager.py +++ b/deluge/ui/webui/menu_manager.py @@ -37,52 +37,56 @@ future : required for plugin-api. """ from utils import logcall from render import template +from deluge import component -admin_pages = [] #[(title, url),..] -detail_tabs = [] #[(title, url),..] -toolbar_items = [] #((id,title ,flag ,method ,url ,image ),.. ) - -#a storage+sorteddict == evildict. - -#toolbar: - -class TB: +class TOOLBAR_FLAGS: generic = 0 torrent = 1 torrent_list = 2 -def register_toolbar_item(id, title, image, flag, method, url, important): - toolbar_items.append((id, title, image, flag, method, url, important)) - #todo: remove lower hack. +class MenuManager(component.Component): + TOOLBAR_FLAGS = TOOLBAR_FLAGS + def __init__(self): + component.Component.__init__(self, "MenuManager") + self.admin_pages = [] #[(title, url),..] + self.detail_tabs = [] #[(title, url),..] + self.toolbar_items = [] #((id,title ,flag ,method ,url ,image ),.. ) -def unregister_toolbar_item(item_id): - for (i, toolbar) in enumerate(admin_pages): - if toolbar[0] == item_id: - del toolbar_items[i] -#admin: + #register vars in template. + template.Template.globals["admin_pages"] = self.admin_pages + template.Template.globals["detail_tabs"] = self.detail_tabs + template.Template.globals["toolbar_items"] = self.toolbar_items -def register_admin_page(id, title, url): - admin_pages.append((id, title, url)) -def unregister_admin_page(page_id): - for (i, (id, title, url)) in list(enumerate(admin_pages)): - if id == page_id: - del admin_pages[i] - return + def register_toolbar_item(self, id, title, image, flag, method, url, important): + self.toolbar_items.append((id, title, image, flag, method, url, important)) + #todo: remove lower hack. -#detail: + def unregister_toolbar_item(self, item_id): + for (i, toolbar) in enumerate(admin_pages): + if toolbar[0] == item_id: + del self.toolbar_items[i] -def register_detail_tab(id, title, page): - detail_tabs.append((id, title, page)) + #admin: + def register_admin_page(self, id, title, url): + self.admin_pages.append((id, title, url)) -def unregister_detail_tab(tab_id): - for (i, (id, title, tab)) in list(enumerate(detail_tabs)): - if id == tab_id: - del detail_tabs[i] - return + def unregister_admin_page(page_id): + for (i, (id, title, url)) in list(enumerate(admin_pages)): + if id == page_id: + del self.admin_pages[i] + return + + #detail: + def register_detail_tab(self, id, title, page): + self.detail_tabs.append((id, title, page)) + + def unregister_detail_tab(self, tab_id): + for (i, (id, title, tab)) in list(enumerate(detail_tabs)): + if id == tab_id: + del self.detail_tabs[i] + return + +__menu_manager = MenuManager() -#register vars in template. -template.Template.globals["admin_pages"] = admin_pages -template.Template.globals["detail_tabs"] = detail_tabs -template.Template.globals["toolbar_items"] = toolbar_items diff --git a/deluge/ui/webui/page_manager.py b/deluge/ui/webui/page_manager.py new file mode 100644 index 000000000..6e6dd345c --- /dev/null +++ b/deluge/ui/webui/page_manager.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# +# Copyright (C) Martijn Voncken 2007 +# +# This program is free software; you can 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, or (at your option) +# any later version. +# +# This program 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 this program. 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. +# + +from deluge import component + +class PageManager(component.Component): + """ + web,py 0.2 mapping hack.. + see deluge_webserver.py + """ + def __init__(self): + component.Component.__init__(self, "PageManager") + self.page_classes = {} + self.urls = [] + + def register_pages(self, url_list, class_list): + self.urls += url_list + self.page_classes.update(class_list) + + def register_page(self, url, klass): + self.urls.append(url) + self.urls.append(klass.__name__) + self.page_classes[klass.__name__] = klass + + def unregister_page(self, url): + raise NotImplemenetedError() + #self.page_classes[klass.__name__] = None + +__page_manager = PageManager() + + + + + + + + + + diff --git a/deluge/ui/webui/pages.py b/deluge/ui/webui/pages.py index bf5a10257..e5837b521 100644 --- a/deluge/ui/webui/pages.py +++ b/deluge/ui/webui/pages.py @@ -30,12 +30,16 @@ # this exception statement from your version. If you delete this exception # statement from all source files in the program, then also delete it here. # + + +#todo: remove useless imports. + from webserver_common import ws, proxy, log from utils import * import utils #todo remove the line above. from render import render, error_page import page_decorators as deco -from config import config_page +from config_forms import config_page from torrent_options import torrent_options from torrent_move import torrent_move @@ -48,55 +52,16 @@ web.webapi.internalerror = deluge_debugerror import lib.webpy022 as web from lib.webpy022.http import seeother, url from lib.static_handler import static_handler - +from torrent_add import torrent_add from operator import attrgetter import os +from deluge import component + +page_manager = component.get("PageManager") #from json_api import json_api #secuity leak, todo:fix -#self registering pages: -import config_tabs_webui #auto registers -import config_tabs_deluge #auto registers -from torrent_add import torrent_add #todo: self-register. - -#plugin like api's -import menu_manager -from menu_manager import TB - -#plugin-like api's : register - -menu_manager.register_admin_page("config", _("Config"), "/config/") -menu_manager.register_admin_page("connect", _("Connect"), "/connect") -menu_manager.register_admin_page("about", _("About"), "/about") -menu_manager.register_admin_page("logout", _("Logout"), "/logout") - -menu_manager.register_detail_tab("details", _("Details"), "tab_meta") -menu_manager.register_detail_tab("files", _("Files"), "tab_files") -menu_manager.register_detail_tab("options", _("Options"), "tab_options") -menu_manager.register_detail_tab("trackers", _("Trackers"), "tab_trackers") - -menu_manager.register_toolbar_item("add", _("Add"), "list-add.png" , TB.generic, - "GET","/torrent/add/", True) -menu_manager.register_toolbar_item("delete",_("Delete"), "list-remove.png" ,TB.torrent_list, - "GET","/torrent/delete/" , True) -menu_manager.register_toolbar_item("stop",_("Stop"), "pause.png" ,TB.torrent_list, - "POST","/torrent/stop/", True) -menu_manager.register_toolbar_item("start",_("Start"), "start.png" ,TB.torrent_list, - "POST","/torrent/start/", True) -menu_manager.register_toolbar_item("queue_up",_("Up"), "queue-up.png" ,TB.torrent_list, - "POST","/torrent/queue/up/", True) -menu_manager.register_toolbar_item("queue_down",_("Down"), "queue-down.png" ,TB.torrent_list, - "POST","/torrent/queue/down/", True) -menu_manager.register_toolbar_item("details",_("Details"), "details.png" ,TB.torrent, - "GET","/torrent/info/", True) -menu_manager.register_toolbar_item("move",_("Move"), "move.png" ,TB.torrent_list, - "POST","/torrent/move/", True) - -menu_manager.register_toolbar_item("reannounce",_("Reannounce"), "view-refresh.png" ,TB.torrent_list, - "POST","'/torrent/reannounce/", False) -menu_manager.register_toolbar_item("recheck",_("Recheck"), "view-refresh.png" ,TB.torrent_list, - "POST","'/torrent/recheck/", False) #routing: urls = [ @@ -142,7 +107,6 @@ urls = [ #/routing - #pages: class login: @deco.deluge_page_noauth @@ -495,15 +459,4 @@ class pixmaps: #/pages -#for plugins: -page_classes = dict(globals()) - -def register_page(url, klass): - urls.append(url) - urls.append(klass.__name__) - page_classes[klass.__name__] = klass - -def unregister_page(url): - raise NotImplemenetedError() - #page_classes[klass.__name__] = None - +page_manager.register_pages(urls,globals()) diff --git a/deluge/ui/webui/pluginmanager.py b/deluge/ui/webui/plugin_manager.py similarity index 62% rename from deluge/ui/webui/pluginmanager.py rename to deluge/ui/webui/plugin_manager.py index ca191c75f..d05ba0b0e 100644 --- a/deluge/ui/webui/pluginmanager.py +++ b/deluge/ui/webui/plugin_manager.py @@ -31,29 +31,16 @@ # statement from all source files in the program, then also delete it here. # -import deluge.component as component -import deluge.pluginmanagerbase +from deluge import component, pluginmanagerbase from deluge.configmanager import ConfigManager from deluge.log import LOG as log -import lib.webpy022 as web -import lib.newforms_plus as forms -from render import render -from utils import logcall -import page_decorators as deco - -import pages -import config - -from menu_manager import TB -import menu_manager - -class PluginManager(deluge.pluginmanagerbase.PluginManagerBase, +class PluginManager(pluginmanagerbase.PluginManagerBase, component.Component): def __init__(self): - component.Component.__init__(self, "PluginManager") - self.config = ConfigManager("gtkui.conf") - deluge.pluginmanagerbase.PluginManagerBase.__init__( + component.Component.__init__(self, "WebPluginManager") + self.config = ConfigManager("webui.conf") + pluginmanagerbase.PluginManagerBase.__init__( self, "webui.conf", "deluge.plugin.webui") def start(self): @@ -73,22 +60,7 @@ class PluginManager(deluge.pluginmanagerbase.PluginManagerBase, self.enable_plugins() - register_template_path = staticmethod(render.register_template_path) - unregister_template_path = staticmethod(render.unregister_template_path) - - register_admin_page = staticmethod(menu_manager.register_admin_page) - unregister_admin_page = staticmethod(menu_manager.unregister_admin_page) - - register_toolbar_item = staticmethod(menu_manager.register_toolbar_item) - unregister_toolbar_item = staticmethod(menu_manager.register_toolbar_item) - - register_page = staticmethod(pages.register_page) - unregister_page = staticmethod(pages.unregister_page) - - register_config_form = staticmethod(config.register_block) - unregister_config_form = staticmethod(config.unregister_block) +__plugin_manager = PluginManager() -__all__ = ['PluginManager','web','forms','render','logcall','deco','TB'] - diff --git a/deluge/ui/webui/register_menu.py b/deluge/ui/webui/register_menu.py new file mode 100644 index 000000000..a2c620fe6 --- /dev/null +++ b/deluge/ui/webui/register_menu.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# +# Copyright (C) Martijn Voncken 2008 +# +# This program is free software; you can 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, or (at your option) +# any later version. +# +# This program 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 this program. 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. +# + +from deluge import component + +menu = component.get("MenuManager") +TB = menu.TOOLBAR_FLAGS + +menu.register_admin_page("config", _("Config"), "/config/") +menu.register_admin_page("connect", _("Connect"), "/connect") +menu.register_admin_page("about", _("About"), "/about") +menu.register_admin_page("logout", _("Logout"), "/logout") + +menu.register_detail_tab("details", _("Details"), "tab_meta") +menu.register_detail_tab("files", _("Files"), "tab_files") +menu.register_detail_tab("options", _("Options"), "tab_options") +menu.register_detail_tab("trackers", _("Trackers"), "tab_trackers") + +menu.register_toolbar_item("add", _("Add"), "list-add.png" , TB.generic, "GET","/torrent/add/", True) +menu.register_toolbar_item("delete",_("Delete"), "list-remove.png" ,TB.torrent_list, "GET","/torrent/delete/" , True) +menu.register_toolbar_item("stop",_("Stop"), "pause.png" ,TB.torrent_list, "POST","/torrent/stop/", True) +menu.register_toolbar_item("start",_("Start"), "start.png" ,TB.torrent_list, "POST","/torrent/start/", True) +menu.register_toolbar_item("queue_up",_("Up"), "queue-up.png" ,TB.torrent_list, "POST","/torrent/queue/up/", True) +menu.register_toolbar_item("queue_down",_("Down"), "queue-down.png" ,TB.torrent_list, "POST","/torrent/queue/down/", True) +menu.register_toolbar_item("details",_("Details"), "details.png" ,TB.torrent, "GET","/torrent/info/", True) +menu.register_toolbar_item("move",_("Move"), "move.png" ,TB.torrent_list,"POST","/torrent/move/", True) +menu.register_toolbar_item("reannounce",_("Reannounce"), "view-refresh.png" ,TB.torrent_list, "POST","'/torrent/reannounce/", False) +menu.register_toolbar_item("recheck",_("Recheck"), "view-refresh.png" ,TB.torrent_list, "POST","'/torrent/recheck/", False) diff --git a/deluge/ui/webui/render.py b/deluge/ui/webui/render.py index 671be34e1..ea15d55b9 100644 --- a/deluge/ui/webui/render.py +++ b/deluge/ui/webui/render.py @@ -54,6 +54,8 @@ class subclassed_render(object): #load template-meta-data cfg_template = ws.config.get('template') template_path = os.path.join(ws.webui_path, 'templates/%s/' % cfg_template) + if not os.path.exists(template_path): + template_path = os.path.join(ws.webui_path, 'templates/deluge/') self.meta = Storage(eval(open(os.path.join(template_path,'meta.cfg')).read())) #load renerders @@ -186,5 +188,4 @@ template.Template.globals.update({ }) #/template-defs - __all__ = ['render'] diff --git a/deluge/ui/webui/templates/advanced/part_torrent_list.html b/deluge/ui/webui/templates/advanced/part_torrent_list.html index 906636431..5017a5dde 100644 --- a/deluge/ui/webui/templates/advanced/part_torrent_list.html +++ b/deluge/ui/webui/templates/advanced/part_torrent_list.html @@ -84,7 +84,7 @@ $for torrent in torrent_list: $ftime(torrent.eta) $("%.3f" % torrent.distributed_copies) - $("%.3f" % torrent.ratio) + $("%.3f" % torrent.ratio) diff --git a/deluge/ui/webui/templates/deluge/config.html b/deluge/ui/webui/templates/deluge/config.html index 4a4b00e44..a5f2d3671 100644 --- a/deluge/ui/webui/templates/deluge/config.html +++ b/deluge/ui/webui/templates/deluge/config.html @@ -19,7 +19,7 @@ $for group in groups:

$form.group / $form.title

-
$form.info
+
$form.info
$:form.as_table() diff --git a/deluge/ui/webui/templates/deluge/connect.html b/deluge/ui/webui/templates/deluge/connect.html index 9524f3354..8215a65dd 100644 --- a/deluge/ui/webui/templates/deluge/connect.html +++ b/deluge/ui/webui/templates/deluge/connect.html @@ -1,10 +1,11 @@ $def with (connect_list, connected) -$:render.header(_("Connect to Daemon"), 'connect') +$:render.header(_("Connect to Daemon"), 'Connect') $:render.admin_toolbar('connect')
+

$_("Connect")

$if connected:
diff --git a/deluge/ui/webui/templates/deluge/login.html b/deluge/ui/webui/templates/deluge/login.html index 3aecccfd1..0e5b24dfa 100644 --- a/deluge/ui/webui/templates/deluge/login.html +++ b/deluge/ui/webui/templates/deluge/login.html @@ -1,6 +1,8 @@ $def with (error) $:render.header(_('Login'))
+

$_("Deluge Login")

+ $if error > 0:
$_("Password is invalid,try again")
diff --git a/deluge/ui/webui/templates/deluge/torrent_add.html b/deluge/ui/webui/templates/deluge/torrent_add.html index 849b171f9..f9d999c02 100644 --- a/deluge/ui/webui/templates/deluge/torrent_add.html +++ b/deluge/ui/webui/templates/deluge/torrent_add.html @@ -1,6 +1,7 @@ $def with (add_form, options_form, error) $:render.header(_("Add Torrent"))
+

$_("Add Torrent")

diff --git a/deluge/ui/webui/templates/white/index.html b/deluge/ui/webui/templates/white/index.html index b49f333fa..fd5434a52 100644 --- a/deluge/ui/webui/templates/white/index.html +++ b/deluge/ui/webui/templates/white/index.html @@ -1,4 +1,6 @@ $def with (torrent_list, organize_filters) + + Deluge:$_('Torrent list') @@ -34,6 +36,7 @@ $if organize_filters: $:render.part_organize(organize_filters) +
@@ -44,12 +47,11 @@ $if organize_filters:
- +
-