src/pyams_thesaurus/zmi/widget/__init__.py
changeset 77 5eb2f0ff9ba3
parent 73 6eaae503e35d
child 78 8bab1101f4ef
equal deleted inserted replaced
76:1d0d13ab5665 77:5eb2f0ff9ba3
       
     1 #
       
     2 # Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
       
     3 # All Rights Reserved.
       
     4 #
       
     5 # This software is subject to the provisions of the Zope Public License,
       
     6 # Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
       
     7 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
       
     8 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
       
     9 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
       
    10 # FOR A PARTICULAR PURPOSE.
       
    11 #
       
    12 
       
    13 __docformat__ = 'restructuredtext'
       
    14 
       
    15 
       
    16 # import standard library
       
    17 import json
       
    18 import re
       
    19 
       
    20 # import interfaces
       
    21 from pyams_form.interfaces.form import IFormLayer
       
    22 from pyams_thesaurus.interfaces.term import IThesaurusTerm
       
    23 from pyams_thesaurus.interfaces.thesaurus import IThesaurus
       
    24 from pyams_thesaurus.schema import IThesaurusTermField, IThesaurusTermsListField
       
    25 from pyams_thesaurus.zmi.widget.interfaces import IThesaurusTermWidget, IThesaurusTermsListWidget
       
    26 from z3c.form.interfaces import IDataConverter, IFieldWidget
       
    27 
       
    28 # import packages
       
    29 from pyams_form.widget import widgettemplate_config
       
    30 from pyams_utils.adapter import adapter_config
       
    31 from pyams_utils.registry import get_utility, query_utility
       
    32 from pyams_utils.traversing import get_parent
       
    33 from z3c.form.browser.widget import HTMLInputWidget
       
    34 from z3c.form.converter import BaseDataConverter
       
    35 from z3c.form.widget import Widget, FieldWidget
       
    36 from zope.interface import implementer_only
       
    37 from zope.schema.fieldproperty import FieldProperty
       
    38 
       
    39 
       
    40 SYNONYM = re.compile('(.*)\ \[\ .*\ \]')
       
    41 
       
    42 
       
    43 #
       
    44 # Term widget
       
    45 #
       
    46 
       
    47 @adapter_config(context=(IThesaurusTermField, IThesaurusTermWidget), provides=IDataConverter)
       
    48 class ThesaurusTermDataConverter(BaseDataConverter):
       
    49     """Thesaurus term data converter"""
       
    50 
       
    51     def toWidgetValue(self, value):
       
    52         # Widget expects term label or caption
       
    53         if value is self.field.missing_value:
       
    54             return ''
       
    55         if IThesaurusTerm.providedBy(self.widget.context):
       
    56             return value.label
       
    57         else:
       
    58             return value.title
       
    59 
       
    60     def toFieldValue(self, value):
       
    61         # Field expects thesaurus term instance
       
    62         if not value:
       
    63             return self.field.missing_value
       
    64         match = SYNONYM.match(value)
       
    65         if match:
       
    66             value = match.groups()[0]
       
    67         thesaurus_name = self.widget.thesaurus_name or self.field.thesaurus_name
       
    68         if thesaurus_name:
       
    69             thesaurus = get_utility(IThesaurus, name=thesaurus_name)
       
    70         else:
       
    71             thesaurus = get_parent(self.widget.context, IThesaurus)
       
    72             if thesaurus is None:
       
    73                 thesaurus = query_utility(IThesaurus, name=thesaurus_name)
       
    74         if thesaurus is None:
       
    75             return None
       
    76         else:
       
    77             return thesaurus.terms.get(value)
       
    78 
       
    79 
       
    80 @widgettemplate_config(mode='input', template='templates/term-input.pt', layer=IFormLayer)
       
    81 @widgettemplate_config(mode='display', template='templates/term-display.pt', layer=IFormLayer)
       
    82 @implementer_only(IThesaurusTermWidget)
       
    83 class ThesaurusTermWidget(HTMLInputWidget, Widget):
       
    84     """Thesaurus term widget"""
       
    85 
       
    86     thesaurus_name = FieldProperty(IThesaurusTermWidget['thesaurus_name'])
       
    87     extract_name = FieldProperty(IThesaurusTermWidget['extract_name'])
       
    88 
       
    89     @property
       
    90     def query_params(self):
       
    91         return json.dumps({'thesaurus_name': self.thesaurus_name,
       
    92                            'extract_name': self.extract_name})
       
    93 
       
    94     @property
       
    95     def values_map(self):
       
    96         return json.dumps({self.value: self.value})
       
    97 
       
    98 
       
    99 @adapter_config(context=(IThesaurusTermField, IFormLayer), provides=IFieldWidget)
       
   100 def ThesaurusTermFieldWidget(field, request):
       
   101     """Thesaurus term field widget factory"""
       
   102     return FieldWidget(field, ThesaurusTermWidget(request))
       
   103 
       
   104 
       
   105 #
       
   106 # Terms list widget
       
   107 #
       
   108 
       
   109 @adapter_config(context=(IThesaurusTermsListField, IThesaurusTermsListWidget), provides=IDataConverter)
       
   110 class ThesaurusTermsListDataConverter(BaseDataConverter):
       
   111     """Thesaurus terms list data converter"""
       
   112 
       
   113     def __init__(self, field, widget):
       
   114         super(ThesaurusTermsListDataConverter, self).__init__(field, widget)
       
   115 
       
   116     def toWidgetValue(self, value):
       
   117         # Widget expects a list of thesaurus terms labels or captions
       
   118         if value is self.field.missing_value:
       
   119             return []
       
   120         if IThesaurusTerm.providedBy(self.widget.context):
       
   121             return [term.label for term in value]
       
   122         else:
       
   123             return [term.title for term in value]
       
   124 
       
   125     def toFieldValue(self, value):
       
   126         # Field expects a list of thesaurus terms
       
   127         if not value:
       
   128             return self.field.missing_value
       
   129         thesaurus_name = self.widget.thesaurus_name or self.field.thesaurus_name
       
   130         if thesaurus_name:
       
   131             thesaurus = get_utility(IThesaurus, name=thesaurus_name)
       
   132         else:
       
   133             thesaurus = get_parent(self.widget.context, IThesaurus)
       
   134             if thesaurus is None:
       
   135                 thesaurus = query_utility(IThesaurus, name=thesaurus_name)
       
   136         if thesaurus is None:
       
   137             return None
       
   138         if isinstance(value, str):
       
   139             value = value.split('|')
       
   140         for idx, val in enumerate(value):
       
   141             match = SYNONYM.match(val)
       
   142             if match:
       
   143                 value[idx] = match.groups()[0]
       
   144         terms = thesaurus.terms
       
   145         return [terms.get(term) for term in value]
       
   146 
       
   147 
       
   148 @widgettemplate_config(mode='input', template='templates/terms-list-input.pt', layer=IFormLayer)
       
   149 @widgettemplate_config(mode='display', template='templates/terms-list-display.pt', layer=IFormLayer)
       
   150 @implementer_only(IThesaurusTermsListWidget)
       
   151 class ThesaurusTermsListWidget(HTMLInputWidget, Widget):
       
   152     """Thesaurus terms list widget"""
       
   153 
       
   154     thesaurus_name = FieldProperty(IThesaurusTermsListWidget['thesaurus_name'])
       
   155     extract_name = FieldProperty(IThesaurusTermsListWidget['extract_name'])
       
   156 
       
   157     @property
       
   158     def query_params(self):
       
   159         return json.dumps({'thesaurus_name': self.thesaurus_name,
       
   160                            'extract_name': self.extract_name})
       
   161 
       
   162     @property
       
   163     def values_map(self):
       
   164         result = {}
       
   165         [result.update({value: value}) for value in (self.value or ())]
       
   166         return json.dumps(result)
       
   167 
       
   168 
       
   169 @adapter_config(context=(IThesaurusTermsListField, IFormLayer), provides=IFieldWidget)
       
   170 def ThesaurusTermsListFieldWidget(field, request):
       
   171     """Thesaurus terms list field widget factory"""
       
   172     return FieldWidget(field, ThesaurusTermsListWidget(request))
       
   173 
       
   174 
       
   175 @widgettemplate_config(mode='input', template='templates/terms-tree-input.pt', layer=IFormLayer)
       
   176 class ThesaurusTermsTreeWidget(ThesaurusTermsListWidget):
       
   177     """Thesaurus terms tree widget"""
       
   178 
       
   179     @property
       
   180     def top_terms(self):
       
   181         thesaurus = query_utility(IThesaurus, name=self.thesaurus_name)
       
   182         if thesaurus is not None:
       
   183             return sorted(thesaurus.get_top_terms(extract=self.extract_name),
       
   184                           key=lambda x: x.label)
       
   185         else:
       
   186             return ()
       
   187 
       
   188     def get_subterms(self, term):
       
   189         for subterm in term.specifics:
       
   190             if (not self.extract_name) or (self.extract_name in subterm.extracts):
       
   191                 yield subterm
       
   192                 for another in self.get_subterms(subterm):
       
   193                     yield another
       
   194 
       
   195 
       
   196 def ThesaurusTermsTreeFieldWidget(field, request):
       
   197     """Thesaurus terms tree field widget factory"""
       
   198     return FieldWidget(field, ThesaurusTermsTreeWidget(request))
       
   199 
       
   200 
       
   201 #
       
   202 # Terms list widget with selector
       
   203 #
       
   204 
       
   205 @widgettemplate_config(mode='input', template='templates/terms-list-selector-input.pt', layer=IFormLayer)
       
   206 class ThesaurusTermsListSelectorWidget(ThesaurusTermsListWidget):
       
   207     """Thesaurus terms list widget with selector"""
       
   208 
       
   209 
       
   210 def ThesaurusTermsListSelectorFieldWidget(field, request):
       
   211     """Thesaurus terms list field widget with selector factory"""
       
   212     return FieldWidget(field, ThesaurusTermsListSelectorWidget(request))