PageRenderTime 47ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/components/tools/OmeroWeb/omeroweb/webclient/custom_forms.py

https://github.com/will-moore/openmicroscopy
Python | 346 lines | 306 code | 16 blank | 24 comment | 7 complexity | 7c87b380cc7b78d1e92528a2659ae362 MD5 | raw file
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. #
  4. #
  5. # Copyright (C) 2011 University of Dundee & Open Microscopy Environment.
  6. # All rights reserved.
  7. #
  8. # This program is free software: you can redistribute it and/or modify
  9. # it under the terms of the GNU Affero General Public License as
  10. # published by the Free Software Foundation, either version 3 of the
  11. # License, or (at your option) any later version.
  12. #
  13. # This program is distributed in the hope that it will be useful,
  14. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. # GNU Affero General Public License for more details.
  17. #
  18. # You should have received a copy of the GNU Affero General Public License
  19. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. #
  21. import re
  22. from django import forms
  23. from django.forms.widgets import SelectMultiple, MultipleHiddenInput
  24. from django.forms.fields import Field, EMPTY_VALUES
  25. from django.forms import ModelChoiceField, ValidationError
  26. from django.utils.translation import ugettext_lazy as _
  27. from django.utils.encoding import smart_unicode
  28. from omero_model_FileAnnotationI import FileAnnotationI
  29. from omero_model_TagAnnotationI import TagAnnotationI
  30. from omero_model_LongAnnotationI import LongAnnotationI
  31. ##################################################################
  32. # Fields
  33. class MultiEmailField(forms.Field):
  34. def clean(self, value):
  35. if not value:
  36. raise forms.ValidationError('No email.')
  37. if value.count(' ') > 0:
  38. raise forms.ValidationError(
  39. 'Use only separator ";". Remove every space.')
  40. emails = value.split(';')
  41. for email in emails:
  42. if not self.is_valid_email(email):
  43. raise forms.ValidationError(
  44. '%s is not a valid e-mail address. Use separator ";"'
  45. % email)
  46. return emails
  47. def is_valid_email(self, email):
  48. email_pat = re.compile(
  49. r"(?:^|\s)[-a-z0-9_.]+@(?:[-a-z0-9]+\.)+[a-z]{2,6}(?:\s|$)",
  50. re.IGNORECASE)
  51. return email_pat.match(email) is not None
  52. class UrlField(forms.Field):
  53. def clean(self, value):
  54. if not value:
  55. raise forms.ValidationError('No url.')
  56. if not self.is_valid_url(value):
  57. raise forms.ValidationError('%s is not a valid url' % value)
  58. return value
  59. def is_valid_url(self, url):
  60. url_pat = re.compile(
  61. r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|'
  62. '(?:%[0-9a-fA-F][0-9a-fA-F]))+', re.IGNORECASE)
  63. return url_pat.match(url) is not None
  64. ##################################################################
  65. # Metadata queryset iterator for group form
  66. class MetadataQuerySetIterator(object):
  67. def __init__(self, queryset, empty_label):
  68. self.queryset = queryset
  69. self.empty_label = empty_label
  70. def __iter__(self):
  71. if self.empty_label is not None:
  72. yield (u"", self.empty_label)
  73. for obj in self.queryset:
  74. yield (obj.value, smart_unicode(obj.value))
  75. class MetadataModelChoiceField(ModelChoiceField):
  76. def _get_choices(self):
  77. # If self._choices is set, then somebody must have manually set
  78. # the property self.choices. In this case, just return self._choices.
  79. if hasattr(self, '_choices'):
  80. return self._choices
  81. # Otherwise, execute the QuerySet in self.queryset to determine the
  82. # choices dynamically. Return a fresh QuerySetIterator that has not
  83. # been consumed. Note that we're instantiating a new QuerySetIterator
  84. # *each* time _get_choices() is called (and, thus, each time
  85. # self.choices is accessed) so that we can ensure the QuerySet has not
  86. # been consumed.
  87. return MetadataQuerySetIterator(self.queryset, self.empty_label)
  88. def _set_choices(self, value):
  89. # This method is copied from ChoiceField._set_choices(). It's necessary
  90. # because property() doesn't allow a subclass to overwrite only
  91. # _get_choices without implementing _set_choices.
  92. self._choices = self.widget.choices = list(value)
  93. choices = property(_get_choices, _set_choices)
  94. def clean(self, value):
  95. Field.clean(self, value)
  96. if value in EMPTY_VALUES:
  97. return None
  98. res = False
  99. for q in self.queryset:
  100. if long(value) == q.id:
  101. res = True
  102. if not res:
  103. raise ValidationError(self.error_messages['invalid_choice'])
  104. return value
  105. class AnnotationQuerySetIterator(object):
  106. def __init__(self, queryset, empty_label):
  107. self.queryset = queryset
  108. self.empty_label = empty_label
  109. def __iter__(self):
  110. if self.empty_label is not None:
  111. yield (u"", self.empty_label)
  112. for obj in self.queryset:
  113. textValue = None
  114. if isinstance(obj._obj, FileAnnotationI):
  115. textValue = (
  116. (len(obj.getFileName()) < 45) and (obj.getFileName()) or
  117. (obj.getFileName()[:42]+"..."))
  118. elif isinstance(obj._obj, TagAnnotationI):
  119. if obj.textValue is not None:
  120. if obj.ns is not None and obj.ns != "":
  121. textValue = (
  122. (len(obj.textValue) < 45) and
  123. ("%s (tagset)" % obj.textValue) or
  124. ("%s (tagset)" % obj.textValue[:42]+"..."))
  125. else:
  126. textValue = (
  127. (len(obj.textValue) < 45) and (obj.textValue) or
  128. (obj.textValue[:42]+"..."))
  129. elif isinstance(obj._obj, LongAnnotationI):
  130. textValue = obj.longValue
  131. else:
  132. textValue = obj.textValue
  133. if isinstance(textValue, str):
  134. l = len(textValue)
  135. if l > 55:
  136. textValue = "%s..." % textValue[:55]
  137. oid = obj.id
  138. yield (oid, smart_unicode(textValue))
  139. class AnnotationModelChoiceField(ModelChoiceField):
  140. def _get_choices(self):
  141. # If self._choices is set, then somebody must have manually set
  142. # the property self.choices. In this case, just return self._choices.
  143. if hasattr(self, '_choices'):
  144. return self._choices
  145. # Otherwise, execute the QuerySet in self.queryset to determine the
  146. # choices dynamically. Return a fresh QuerySetIterator that has not
  147. # been consumed. Note that we're instantiating a new QuerySetIterator
  148. # *each* time _get_choices() is called (and, thus, each time
  149. # self.choices is accessed) so that we can ensure the QuerySet has not
  150. # been consumed.
  151. return AnnotationQuerySetIterator(self.queryset, self.empty_label)
  152. def _set_choices(self, value):
  153. # This method is copied from ChoiceField._set_choices(). It's
  154. # necessary because property() doesn't allow a subclass to overwrite
  155. # only _get_choices without implementing _set_choices.
  156. self._choices = self.widget.choices = list(value)
  157. choices = property(_get_choices, _set_choices)
  158. def clean(self, value):
  159. Field.clean(self, value)
  160. if value in EMPTY_VALUES:
  161. return None
  162. res = False
  163. for q in self.queryset:
  164. if long(value) == q.id:
  165. res = True
  166. if not res:
  167. raise ValidationError(self.error_messages['invalid_choice'])
  168. return value
  169. class AnnotationModelMultipleChoiceField(AnnotationModelChoiceField):
  170. """A MultipleChoiceField whose choices are a model QuerySet."""
  171. hidden_widget = MultipleHiddenInput
  172. default_error_messages = {
  173. 'list': _(u'Enter a list of values.'),
  174. 'invalid_choice': _(u'Select a valid choice. That choice is not one'
  175. u' of the available choices.')}
  176. def __init__(self, queryset, required=True,
  177. widget=SelectMultiple, label=None, initial=None,
  178. help_text=None, *args, **kwargs):
  179. super(AnnotationModelMultipleChoiceField, self).__init__(
  180. queryset=queryset, empty_label=None, required=required,
  181. widget=widget, label=label, initial=initial,
  182. help_text=help_text, *args, **kwargs)
  183. def clean(self, value):
  184. if self.required and not value:
  185. raise ValidationError(self.error_messages['required'])
  186. elif not self.required and not value:
  187. return []
  188. if not isinstance(value, (list, tuple)):
  189. raise ValidationError(self.error_messages['list'])
  190. final_values = []
  191. for val in value:
  192. try:
  193. long(val)
  194. except:
  195. raise ValidationError(self.error_messages['invalid_choice'])
  196. else:
  197. res = False
  198. for q in self.queryset:
  199. if long(val) == q.id:
  200. res = True
  201. if not res:
  202. raise ValidationError(
  203. self.error_messages['invalid_choice'])
  204. else:
  205. final_values.append(val)
  206. return final_values
  207. # Object queryset iterator for group form
  208. class ObjectQuerySetIterator(object):
  209. def __init__(self, queryset, empty_label):
  210. self.queryset = queryset
  211. self.empty_label = empty_label
  212. def __iter__(self):
  213. if self.empty_label is not None:
  214. yield (u"", self.empty_label)
  215. for obj in self.queryset:
  216. if hasattr(obj.id, 'val'):
  217. yield (obj.id.val, smart_unicode(obj.id.val))
  218. else:
  219. yield (obj.id, smart_unicode(obj.id))
  220. class ObjectModelChoiceField(ModelChoiceField):
  221. def _get_choices(self):
  222. # If self._choices is set, then somebody must have manually set
  223. # the property self.choices. In this case, just return self._choices.
  224. if hasattr(self, '_choices'):
  225. return self._choices
  226. # Otherwise, execute the QuerySet in self.queryset to determine the
  227. # choices dynamically. Return a fresh QuerySetIterator that has not
  228. # been consumed. Note that we're instantiating a new QuerySetIterator
  229. # *each* time _get_choices() is called (and, thus, each time
  230. # self.choices is accessed) so that we can ensure the QuerySet has not
  231. # been consumed.
  232. return ObjectQuerySetIterator(self.queryset, self.empty_label)
  233. def _set_choices(self, value):
  234. # This method is copied from ChoiceField._set_choices(). It's
  235. # necessary because property() doesn't allow a subclass to overwrite
  236. # only _get_choices without implementing _set_choices.
  237. self._choices = self.widget.choices = list(value)
  238. choices = property(_get_choices, _set_choices)
  239. def clean(self, value):
  240. Field.clean(self, value)
  241. if value in EMPTY_VALUES:
  242. return None
  243. res = False
  244. for q in self.queryset:
  245. if hasattr(q.id, 'val'):
  246. if long(value) == q.id.val:
  247. res = True
  248. else:
  249. if long(value) == q.id:
  250. res = True
  251. if not res:
  252. raise ValidationError(self.error_messages['invalid_choice'])
  253. return value
  254. class ObjectModelMultipleChoiceField(ObjectModelChoiceField):
  255. """A MultipleChoiceField whose choices are a model QuerySet."""
  256. hidden_widget = MultipleHiddenInput
  257. default_error_messages = {
  258. 'list': _(u'Enter a list of values.'),
  259. 'invalid_choice': _(u'Select a valid choice. That choice is not one'
  260. u' of the available choices.'),
  261. }
  262. def __init__(self, queryset, required=True,
  263. widget=SelectMultiple, label=None, initial=None,
  264. help_text=None, *args, **kwargs):
  265. super(ObjectModelMultipleChoiceField, self).__init__(
  266. queryset=queryset, empty_label=None, required=required,
  267. widget=widget, label=label, initial=initial,
  268. help_text=help_text, *args, **kwargs)
  269. def clean(self, value):
  270. if self.required and not value:
  271. raise ValidationError(self.error_messages['required'])
  272. elif not self.required and not value:
  273. return []
  274. if not isinstance(value, (list, tuple)):
  275. raise ValidationError(self.error_messages['list'])
  276. final_values = []
  277. for val in value:
  278. try:
  279. long(val)
  280. except:
  281. raise ValidationError(self.error_messages['invalid_choice'])
  282. else:
  283. res = False
  284. for q in self.queryset:
  285. if hasattr(q.id, 'val'):
  286. if long(val) == q.id.val:
  287. res = True
  288. else:
  289. if long(val) == q.id:
  290. res = True
  291. if not res:
  292. raise ValidationError(
  293. self.error_messages['invalid_choice'])
  294. else:
  295. final_values.append(val)
  296. return final_values