From 9df4492083395616bc21138cf0fc2131abb522ae Mon Sep 17 00:00:00 2001
From: Martijn Voncken
Date: Mon, 11 Feb 2008 16:59:29 +0000
Subject: [PATCH] refactor forms
---
deluge/ui/webui/webui_plugin/config.py | 110 +----------
.../webui/webui_plugin/config_tabs_deluge.py | 73 +++----
.../webui/webui_plugin/config_tabs_webui.py | 19 +-
.../webui/webui_plugin/lib/newforms/forms.py | 2 +-
.../webui/webui_plugin/lib/newforms_plus.py | 178 ++++++++++++++++++
.../templates/advanced/index.html | 2 +-
6 files changed, 231 insertions(+), 153 deletions(-)
create mode 100644 deluge/ui/webui/webui_plugin/lib/newforms_plus.py
diff --git a/deluge/ui/webui/webui_plugin/config.py b/deluge/ui/webui/webui_plugin/config.py
index d8b6f5ae1..b590e9b25 100644
--- a/deluge/ui/webui/webui_plugin/config.py
+++ b/deluge/ui/webui/webui_plugin/config.py
@@ -31,7 +31,7 @@
# 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 as forms
+import lib.newforms_plus as forms
import page_decorators as deco
import lib.webpy022 as web
from webserver_common import ws
@@ -43,37 +43,7 @@ import os
groups = []
blocks = forms.utils.datastructures.SortedDict()
-class Form(forms.Form):
- info = ""
- title = "No Title"
- def __init__(self,data = None):
- if data == None:
- data = self.initial_data()
- forms.Form.__init__(self,data)
-
- def initial_data(self):
- "override in subclass"
- return None
-
- def start_save(self):
- "called by config_page"
- data = web.Storage(self.clean_data)
- self.validate(data)
- self.save(data)
- self.post_save()
-
- def save(self, vars):
- "override in subclass"
- raise NotImplementedError()
-
- def post_save(self):
- pass
-
- def validate(self, data):
- pass
-
-
-class WebCfgForm(Form):
+class WebCfgForm(forms.Form):
"config base for webui"
def initial_data(self):
return ws.config
@@ -82,7 +52,7 @@ class WebCfgForm(Form):
ws.config.update(data)
ws.save_config()
-class CookieCfgForm(Form):
+class CookieCfgForm(forms.Form):
"config base for webui"
def initial_data(self):
return ws.config
@@ -92,85 +62,13 @@ class CookieCfgForm(Form):
ws.save_config()
-class CfgForm(Form):
+class CfgForm(forms.Form):
"config base for deluge-cfg"
def initial_data(self):
return ws.proxy.get_config()
def save(self, data):
ws.proxy.set_config(dict(data))
-
-#convenience Input Fields.
-class _IntInput(forms.TextInput):
- """
- because deluge-floats are edited as ints.
- """
- def render(self, name, value, attrs=None):
- try:
- value = int(float(value))
- if value == -1:
- value = _("Unlimited")
- except:
- pass
- return forms.TextInput.render(self, name, value, attrs)
-
-class CheckBox(forms.BooleanField):
- "Non Required ChoiceField"
- def __init__(self,label, **kwargs):
- forms.BooleanField.__init__(self,label=label,required=False,**kwargs)
-
-class IntCombo(forms.ChoiceField):
- """
- choices are the display-values
- returns int for the chosen display-value.
- """
- def __init__(self, label, choices, **kwargs):
- forms.ChoiceField.__init__(self, label=label,
- choices=enumerate(choices), **kwargs)
-
- def clean(self, value):
- return int(forms.ChoiceField.clean(self, value))
-
-class DelugeInt(forms.IntegerField):
- def __init__(self, label , **kwargs):
- forms.IntegerField.__init__(self, label=label, min_value=-1,
- max_value=sys.maxint, widget=_IntInput, **kwargs)
-
- def clean(self, value):
- if str(value).lower() == _('Unlimited').lower():
- value = -1
- return int(forms.IntegerField.clean(self, value))
-
-class DelugeFloat(DelugeInt):
- def clean(self, value):
- return int(DelugeInt.clean(self, value))
-
-class MultipleChoice(forms.MultipleChoiceField):
- #temp/test
- def __init__(self, label, choices, **kwargs):
- forms.MultipleChoiceField.__init__(self, label=label, choices=choices,
- widget=forms.CheckboxSelectMultiple, required=False)
-
-class ServerFolder(forms.CharField):
- def __init__(self, label, **kwargs):
- forms.CharField.__init__(self, label=label,**kwargs)
-
- def clean(self, value):
- value = value.rstrip('/').rstrip('\\')
- self.validate(value)
- return forms.CharField.clean(self, value)
-
- def validate(self, value):
- if (value and not os.path.isdir(value)):
- raise forms.ValidationError(_("This folder does not exist."))
-
-class Password(forms.CharField):
- def __init__(self, label, **kwargs):
- forms.CharField.__init__(self, label=label, widget=forms.PasswordInput,
- **kwargs)
-
-#/fields
-
class config_page:
"""
web.py config page
diff --git a/deluge/ui/webui/webui_plugin/config_tabs_deluge.py b/deluge/ui/webui/webui_plugin/config_tabs_deluge.py
index e8489e79b..092732db8 100644
--- a/deluge/ui/webui/webui_plugin/config_tabs_deluge.py
+++ b/deluge/ui/webui/webui_plugin/config_tabs_deluge.py
@@ -31,7 +31,7 @@
# 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 as forms
+import lib.newforms_plus as forms
import config
import utils
from webserver_common import ws
@@ -42,7 +42,7 @@ class NetworkPorts(config.CfgForm ):
info = _("Restart daemon after changing these values.")
_port_from = forms.IntegerField(_("From"))
_port_to = forms.IntegerField(_("To"))
- random_port = config.CheckBox(_("Random"))
+ random_port = forms.CheckBox(_("Random"))
def initial_data(self):
data = config.CfgForm.initial_data(self)
@@ -63,24 +63,24 @@ config.register_block('network','ports', NetworkPorts)
class NetworkExtra(config.CfgForm ):
title = _("Extra's")
- dht = config.CheckBox(_("Mainline DHT"))
- upnp = config.CheckBox(_("UpNP"))
- natpmp = config.CheckBox(_("NAT-PMP"))
- utpex = config.CheckBox(_("Peer-Exchange"))
- lsd = config.CheckBox(_("LSD"))
+ dht = forms.CheckBox(_("Mainline DHT"))
+ upnp = forms.CheckBox(_("UpNP"))
+ natpmp = forms.CheckBox(_("NAT-PMP"))
+ utpex = forms.CheckBox(_("Peer-Exchange"))
+ lsd = forms.CheckBox(_("LSD"))
config.register_block('network','extra', NetworkExtra)
class NetworkEnc(config.CfgForm ):
title = _("Encryption")
- _enc_choices = [_("Forced"),_("Enabled"),_("Disabled")]
- _level_choices = [_("Handshake"), _("Full") , _("Either")]
+ _enc_choices = list(enumerate([_("Forced"),_("Enabled"),_("Disabled")]))
+ _level_choices = list(enumerate([_("Handshake"), _("Full") , _("Either")]))
- enc_in_policy = config.IntCombo(_("Inbound"), _enc_choices)
- enc_out_policy = config.IntCombo(_("Outbound"), _enc_choices)
- enc_level = config.IntCombo(_("Level"), _level_choices)
- enc_prefer_rc4 = config.CheckBox("Prefer to encrypt entire stream")
+ enc_in_policy = forms.IntChoiceField(_("Inbound"), _enc_choices)
+ enc_out_policy = forms.IntChoiceField(_("Outbound"), _enc_choices)
+ enc_level = forms.IntChoiceField(_("Level"), _level_choices)
+ enc_prefer_rc4 = forms.CheckBox("Prefer to encrypt entire stream")
config.register_block('network','encryption', NetworkEnc)
@@ -88,44 +88,45 @@ config.register_block('network','encryption', NetworkEnc)
class BandwithGlobal(config.CfgForm):
title = _("Global")
info = _("-1 = Unlimited")
- max_connections_global = config.DelugeInt(_("Maximum Connections"))
- max_download_speed = config.DelugeFloat(_("Maximum Download Speed (Kib/s)"))
- max_upload_speed = config.DelugeFloat(_("Maximum Upload Speed (Kib/s)"))
- max_upload_slots_global = config.DelugeInt(_("Maximum Upload Slots"))
+ max_connections_global = 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_global = forms.DelugeInt(_("Maximum Upload Slots"))
config.register_block('bandwidth','global', BandwithGlobal)
class BandwithTorrent(config.CfgForm):
title = _("Per Torrent")
info = _("-1 = Unlimited")
- max_connections_per_torrent = config.DelugeInt(_("Maximum Connections"))
- max_upload_slots_per_torrent = config.DelugeInt(_("Maximum Upload Slots"))
+ max_connections_per_torrent = forms.DelugeInt(_("Maximum Connections"))
+ max_upload_slots_per_torrent = forms.DelugeInt(_("Maximum Upload Slots"))
config.register_block('bandwidth','torrent', BandwithTorrent)
class Download(config.CfgForm):
title = _("Download")
- download_location = config.ServerFolder(_("Store all downoads in"))
- torrentfiles_location = config.ServerFolder(_("Save .torrent files to"))
- autoadd_location = config.ServerFolder(_("Auto Add folder"), required=False)
- compact_allocation = config.CheckBox(_('Use Compact Allocation'))
- prioritize_first_last_pieces = config.CheckBox(
+ download_location = forms.ServerFolder(_("Store all downoads in"))
+ torrentfiles_location = forms.ServerFolder(_("Save .torrent files to"))
+ autoadd_location = forms.ServerFolder(_("Auto Add folder"), required=False)
+ compact_allocation = forms.CheckBox(_('Use Compact Allocation'))
+ prioritize_first_last_pieces = forms.CheckBox(
_('Prioritize first and last pieces'))
config.register_block('deluge','download', Download)
class Daemon(config.CfgForm):
title = _("Daemon")
+ info = _("Restart daemon and webui after changing these settings")
daemon_port = forms.IntegerField(_("Port"))
- allow_remote = config.CheckBox(_("Allow Remote Connections"))
+ allow_remote = forms.CheckBox(_("Allow Remote Connections"))
config.register_block('deluge','daemon', Daemon)
-class Plugins(config.Form):
+class Plugins(forms.Form):
title = _("Enabled Plugins")
_choices = [(p,p) for p in ws.proxy.get_available_plugins()]
- enabled_plugins = config.MultipleChoice(_(""), _choices)
+ enabled_plugins = forms.MultipleChoice(_(""), _choices)
def initial_data(self):
return {'enabled_plugins':ws.proxy.get_enabled_plugins()}
@@ -136,19 +137,19 @@ class Plugins(config.Form):
config.register_block('deluge','plugins', Plugins)
-class Queue(config.Form):
+class Queue(forms.Form):
title = _("Queue")
info = _("queue-cfg not finished")
- queue_top = config.CheckBox(_("Queue new torrents to top"))
- total_active = config.DelugeInt(_("Total active torrents"))
- total_seeding = config.DelugeInt(_("Total active seeding"))
- total_downloading = config.DelugeInt(_("Total active downloading"))
+ queue_top = forms.CheckBox(_("Queue new torrents to top"))
+ total_active = forms.DelugeInt(_("Total active torrents"))
+ total_seeding = forms.DelugeInt(_("Total active seeding"))
+ total_downloading = forms.DelugeInt(_("Total active downloading"))
- queue_bottom = config.CheckBox(_("Queue completed torrents to bottom"))
- stop_on_ratio = config.CheckBox(_("Stop seeding when ratio reaches"))
- stop_ratio = config.DelugeInt(_("TODO:float-edit-box"))
- remove_after_stop = config.CheckBox(_("Remve torrent when ratio reached"))
+ queue_bottom = forms.CheckBox(_("Queue completed torrents to bottom"))
+ stop_on_ratio = forms.CheckBox(_("Stop seeding when ratio reaches"))
+ stop_ratio = forms.DelugeInt(_("TODO:float-edit-box"))
+ remove_after_stop = forms.CheckBox(_("Remve torrent when ratio reached"))
def save(self, value):
raise forms.ValidationError("SAVE:TODO")
diff --git a/deluge/ui/webui/webui_plugin/config_tabs_webui.py b/deluge/ui/webui/webui_plugin/config_tabs_webui.py
index 5937ca699..f61aa8fa1 100644
--- a/deluge/ui/webui/webui_plugin/config_tabs_webui.py
+++ b/deluge/ui/webui/webui_plugin/config_tabs_webui.py
@@ -31,7 +31,7 @@
# 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 as forms
+import lib.newforms_plus as forms
import config
import utils
from webserver_common import ws
@@ -41,11 +41,12 @@ class Template(config.WebCfgForm):
title = _("Template")
_templates = [(t,t) for t in ws.get_templates()]
- _button_choices = [_('Text and image'), _('Image Only'), _('Text Only')]
+ _button_choices = enumerate([_('Text and image'), _('Image Only')
+ , _('Text Only')])
template = forms.ChoiceField( label=_("Template"), choices = _templates)
- button_style = config.IntCombo(_("Button style"),_button_choices)
- cache_templates = config.CheckBox(_("Cache templates"))
+ button_style = forms.IntChoiceField(_("Button style"),_button_choices)
+ cache_templates = forms.CheckBox(_("Cache templates"))
def post_save(self):
from render import render
@@ -62,7 +63,7 @@ class Server(config.WebCfgForm):
port = forms.IntegerField(label = _("Port"),min_value=80)
- use_https = config.CheckBox(_("Use https"))
+ use_https = forms.CheckBox(_("Use https"))
def post_save(self):
@@ -70,12 +71,12 @@ class Server(config.WebCfgForm):
#raise forms.ValidationError(
# _("Manually restart server to apply these changes."))
-class Password(config.Form):
+class Password(forms.Form):
title = _("Password")
- old_pwd = config.Password(_("Current Password"))
- new1 = config.Password(_("New Password"))
- new2 = config.Password(_("New Password (Confirm)"))
+ old_pwd = forms.Password(_("Current Password"))
+ new1 = forms.Password(_("New Password"))
+ new2 = forms.Password(_("New Password (Confirm)"))
def save(self,data):
ws.update_pwd(data.new1)
diff --git a/deluge/ui/webui/webui_plugin/lib/newforms/forms.py b/deluge/ui/webui/webui_plugin/lib/newforms/forms.py
index 97f0efcb6..df4af3b54 100644
--- a/deluge/ui/webui/webui_plugin/lib/newforms/forms.py
+++ b/deluge/ui/webui/webui_plugin/lib/newforms/forms.py
@@ -9,7 +9,7 @@ from widgets import TextInput, Textarea, HiddenInput, MultipleHiddenInput
from util import flatatt, StrAndUnicode, ErrorDict, ErrorList, ValidationError
import copy
-__all__ = ('BaseForm', 'Form')
+#__all__ = ('BaseForm', 'Form')
NON_FIELD_ERRORS = '__all__'
diff --git a/deluge/ui/webui/webui_plugin/lib/newforms_plus.py b/deluge/ui/webui/webui_plugin/lib/newforms_plus.py
new file mode 100644
index 000000000..e11c56b4d
--- /dev/null
+++ b/deluge/ui/webui/webui_plugin/lib/newforms_plus.py
@@ -0,0 +1,178 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) Martijn Voncken 2008
+# Django Lisence, see ./newforms/LICENCE
+#
+
+from newforms import *
+import newforms
+from newforms.forms import BoundField
+
+import sys, os
+
+
+import webpy022 as web #todo:remove this dependency.
+
+#Form
+class FilteredForm(newforms.Form):
+ """
+ used to enable more complex layouts.
+ the filter argument contains the names of the fields to render.
+ """
+ def _html_output_filtered(self, normal_row, error_row, row_ender, help_text_html, errors_on_separate_row, filter):
+ """
+ Helper function for outputting HTML. Used by as_table(), as_ul(), as_p().
+ newforms_plus: 99% c&p from newforms, added filter.
+ """
+ top_errors = self.non_field_errors() # Errors that should be displayed above all fields.
+ output, hidden_fields = [], []
+ for name, field in self.fields.items():
+ #FilteredForm
+ if (filter != None) and (not name in filter):
+ continue
+ #/FilteredForm
+ bf = BoundField(self, field, name)
+ bf_errors = ErrorList([escape(error) for error in bf.errors]) # Escape and cache in local variable.
+ if bf.is_hidden:
+ if bf_errors:
+ top_errors.extend(['(Hidden field %s) %s' % (name, e) for e in bf_errors])
+ hidden_fields.append(unicode(bf))
+ else:
+ if errors_on_separate_row and bf_errors:
+ output.append(error_row % bf_errors)
+ label = bf.label and bf.label_tag(escape(bf.label + ':')) or ''
+ if field.help_text:
+ help_text = help_text_html % field.help_text
+ else:
+ help_text = u''
+ output.append(normal_row % {'errors': bf_errors, 'label': label, 'field': unicode(bf), 'help_text': help_text})
+ if top_errors:
+ output.insert(0, error_row % top_errors)
+ if hidden_fields: # Insert any hidden fields in the last row.
+ str_hidden = u''.join(hidden_fields)
+ if output:
+ last_row = output[-1]
+ # Chop off the trailing row_ender (e.g. '') and insert the hidden fields.
+ output[-1] = last_row[:-len(row_ender)] + str_hidden + row_ender
+ else: # If there aren't any rows in the output, just append the hidden fields.
+ output.append(str_hidden)
+ return u'\n'.join(output)
+
+ def as_table(self , filter = None):
+ "Returns this form rendered as HTML s -- excluding the ."
+ return self._html_output_filtered(u'
| %(label)s | %(errors)s%(field)s%(help_text)s |
', u'| %s |
', '', u'
%s', False, filter)
+
+ def as_ul(self, filter = None):
+ "Returns this form rendered as HTML s -- excluding the ."
+ return self._html_output_filtered(u'%(errors)s%(label)s %(field)s%(help_text)s', u'%s', '', u' %s', False , filter)
+
+ def as_p(self , filter = None):
+ "Returns this form rendered as HTML s."
+ return self._html_output_filtered(u'
%(label)s %(field)s%(help_text)s
', u'%s
', '
', u' %s', True, filter)
+
+class Form(newforms.Form):
+ info = ""
+ title = "No Title"
+ def __init__(self,data = None):
+ if data == None:
+ data = self.initial_data()
+ newforms.Form.__init__(self,data)
+
+ def initial_data(self):
+ "override in subclass"
+ return None
+
+ def start_save(self):
+ "called by config_page"
+ data = web.Storage(self.clean_data)
+ self.validate(data)
+ self.save(data)
+ self.post_save()
+
+ def save(self, vars):
+ "override in subclass"
+ raise NotImplementedError()
+
+ def post_save(self):
+ pass
+
+ def validate(self, data):
+ pass
+
+
+#convenience Input Fields.
+class CheckBox(newforms.BooleanField):
+ "Non Required BooleanField,why the f is it required by default?"
+ def __init__(self,label, **kwargs):
+ newforms.BooleanField.__init__(self,label=label,required=False,**kwargs)
+
+class IntChoiceField(newforms.ChoiceField):
+ """same as ChoiceField, but returns an int
+ hint : Use IntChoiceField(choices=enumerate("list","of","strings"]))
+ for index-based values on a list of strings.
+ """
+ def __init__(self, label, choices, **kwargs):
+ newforms.ChoiceField.__init__(self, label=label, choices=choices,**kwargs)
+
+ def clean(self, value):
+ return int(newforms.ChoiceField.clean(self, value))
+
+class MultipleChoice(newforms.MultipleChoiceField):
+ #temp/test/debug!!
+ "Non Required MultipleChoiceField,why the f is it required by default?"
+ def __init__(self, label, choices, **kwargs):
+ newforms.MultipleChoiceField.__init__(self, label=label, choices=choices,
+ widget=newforms.CheckboxSelectMultiple, required=False)
+
+class ServerFolder(newforms.CharField):
+ def __init__(self, label, **kwargs):
+ newforms.CharField.__init__(self, label=label,**kwargs)
+
+ def clean(self, value):
+ value = value.rstrip('/').rstrip('\\')
+ self.validate(value)
+ return newforms.CharField.clean(self, value)
+
+ def validate(self, value):
+ if (value and not os.path.isdir(value)):
+ raise newforms.ValidationError(_("This folder does not exist."))
+
+class Password(newforms.CharField):
+ def __init__(self, label, **kwargs):
+ newforms.CharField.__init__(self, label=label, widget=newforms.PasswordInput,
+ **kwargs)
+
+#Deluge specific:
+class _DelugeIntInput(newforms.TextInput):
+ """
+ because deluge-floats are edited as ints.
+ """
+ def render(self, name, value, attrs=None):
+ try:
+ value = int(float(value))
+ if value == -1:
+ value = _("Unlimited")
+ except:
+ pass
+ return newforms.TextInput.render(self, name, value, attrs)
+
+class DelugeInt(newforms.IntegerField):
+ def __init__(self, label , **kwargs):
+ newforms.IntegerField.__init__(self, label=label, min_value=-1,
+ max_value=sys.maxint, widget=_DelugeIntInput, **kwargs)
+
+ def clean(self, value):
+ if str(value).lower() == _('Unlimited').lower():
+ value = -1
+ return int(newforms.IntegerField.clean(self, value))
+
+class DelugeFloat(DelugeInt):
+ def clean(self, value):
+ return int(DelugeInt.clean(self, value))
+
+#/fields
+
+
+
+
+
diff --git a/deluge/ui/webui/webui_plugin/templates/advanced/index.html b/deluge/ui/webui/webui_plugin/templates/advanced/index.html
index a77d31073..e5684560e 100644
--- a/deluge/ui/webui/webui_plugin/templates/advanced/index.html
+++ b/deluge/ui/webui/webui_plugin/templates/advanced/index.html
@@ -55,7 +55,7 @@ $for t in torrent_list: