src/pyams_thesaurus/zmi/term.py
changeset 0 47700a43ef3f
child 5 86ddb444d0a9
equal deleted inserted replaced
-1:000000000000 0:47700a43ef3f
       
     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 
       
    18 # import interfaces
       
    19 from pyams_skin.interfaces.viewlet import IToolbarViewletManager
       
    20 from pyams_skin.layer import IPyAMSLayer
       
    21 from pyams_thesaurus.interfaces.term import IThesaurusTerm
       
    22 from pyams_thesaurus.interfaces.thesaurus import IThesaurus
       
    23 from pyams_zmi.layer import IAdminLayer
       
    24 from z3c.form.interfaces import IDataExtractedEvent, DISPLAY_MODE
       
    25 
       
    26 # import packages
       
    27 from pyams_form.form import AJAXAddForm, AJAXEditForm
       
    28 from pyams_pagelet.pagelet import pagelet_config
       
    29 from pyams_skin.viewlet.toolbar import ToolbarAction
       
    30 from pyams_thesaurus.term import ThesaurusTerm
       
    31 from pyams_thesaurus.zmi.thesaurus import ThesaurusTermsView
       
    32 from pyams_utils.traversing import get_parent
       
    33 from pyams_utils.url import absolute_url
       
    34 from pyams_viewlet.viewlet import viewlet_config
       
    35 from pyams_zmi.form import AdminDialogAddForm, AdminDialogEditForm
       
    36 from pyramid.events import subscriber
       
    37 from pyramid.view import view_config
       
    38 from z3c.form import field
       
    39 from zope.interface import Invalid
       
    40 
       
    41 from pyams_thesaurus import _
       
    42 
       
    43 
       
    44 @viewlet_config(name='thesaurus.term.adding', context=IThesaurus, view=ThesaurusTermsView,
       
    45                 layer=IAdminLayer, manager=IToolbarViewletManager, permission='thesaurus.manage')
       
    46 class ThesaurusTermAddAction(ToolbarAction):
       
    47     """Thesaurus term add action"""
       
    48 
       
    49     label = _("Add term")
       
    50     url = 'add-term.html'
       
    51     modal_target = True
       
    52 
       
    53 
       
    54 @pagelet_config(name='add-term.html', context=IThesaurus, layer=IPyAMSLayer, permission='thesaurus.manage')
       
    55 class ThesaurusTermAddForm(AdminDialogAddForm):
       
    56     """Thesaurus term add form"""
       
    57 
       
    58     @property
       
    59     def title(self):
       
    60         return self.context.title
       
    61 
       
    62     legend = _("Add new term")
       
    63     icon_css_class = 'fa fa-fw fa-tag'
       
    64 
       
    65     fields = field.Fields(IThesaurusTerm).select('label', 'alt', 'definition', 'note', 'generic', 'associations',
       
    66                                                  'usage', 'extensions', 'status', 'created')
       
    67 
       
    68     ajax_handler = 'add-term.json'
       
    69     edit_permission = None
       
    70 
       
    71     def updateWidgets(self, prefix=None):
       
    72         super(ThesaurusTermAddForm, self).updateWidgets(prefix)
       
    73         for name in ('definition', 'note'):
       
    74             self.widgets[name].label_css_class = 'input textarea'
       
    75         for name in ('generic', 'associations', 'usage'):
       
    76             self.widgets[name].thesaurus_name = self.context.name
       
    77 
       
    78     def create(self, data):
       
    79         return ThesaurusTerm()
       
    80 
       
    81     def update_content(self, content, data):
       
    82         super(ThesaurusTermAddForm, self).update_content(content, data)
       
    83         generic = content.generic
       
    84         usage = content.usage
       
    85         if (generic is None) and (usage is None):
       
    86             IThesaurus(self.context).top_terms += [content, ]
       
    87         else:
       
    88             if generic is not None:
       
    89                 generic.specifics += [content, ]
       
    90             elif usage is not None:
       
    91                 usage.used_for += [content, ]
       
    92 
       
    93     def add(self, object):
       
    94         self.context.terms[object.label] = object
       
    95 
       
    96     def nextURL(self):
       
    97         return absolute_url(self.context, self.request, 'terms.html')
       
    98 
       
    99 
       
   100 @subscriber(IDataExtractedEvent, form_selector=ThesaurusTermAddForm)
       
   101 def handle_new_term_data_extraction(event):
       
   102     """Handle new term data extraction"""
       
   103     data = event.data
       
   104     if data.get('label') in event.form.context.terms:
       
   105         event.form.widgets.errors += (Invalid(_("Specified label is already used!")), )
       
   106 
       
   107 
       
   108 @view_config(name='add-term.json', context=IThesaurus, request_type=IPyAMSLayer,
       
   109              permission='thesaurus.manage', renderer='json', xhr=True)
       
   110 class ThesaurusTermAJAXAddForm(AJAXAddForm, ThesaurusTermAddForm):
       
   111     """Thesaurus term add form, AJAX view"""
       
   112 
       
   113     def get_ajax_output(self, changes):
       
   114         if changes.generic is not None:
       
   115             return super(ThesaurusTermAJAXAddForm, self).get_ajax_output(changes)
       
   116         else:
       
   117             label = changes.label.replace("'", "&#039;")
       
   118             return {'callback': 'PyAMS_thesaurus.tree.findTerm',
       
   119                     'options': {'term': label}}
       
   120 
       
   121 
       
   122 @pagelet_config(name='properties.html', context=IThesaurusTerm, layer=IPyAMSLayer, permission='view')
       
   123 class ThesaurusTermEditForm(AdminDialogEditForm):
       
   124     """Thesaurus term edit form"""
       
   125 
       
   126     @property
       
   127     def title(self):
       
   128         return self.context.label
       
   129 
       
   130     legend = _("Edit term properties")
       
   131     icon_css_class = 'fa fa-fw fa-tag'
       
   132 
       
   133     fields = field.Fields(IThesaurusTerm).select('label', 'alt', 'definition', 'note', 'generic', 'specifics',
       
   134                                                  'associations', 'usage', 'used_for', 'extracts', 'extensions',
       
   135                                                  'status', 'level', 'created', 'modified')
       
   136 
       
   137     ajax_handler = 'properties.json'
       
   138     edit_permission = 'thesaurus.manage'
       
   139 
       
   140     generic_changed = False
       
   141     usage_changed = False
       
   142 
       
   143     def updateWidgets(self, prefix=None):
       
   144         super(ThesaurusTermEditForm, self).updateWidgets(prefix)
       
   145         thesaurus = get_parent(self.context, IThesaurus)
       
   146         for name in ('definition', 'note'):
       
   147             self.widgets[name].label_css_class = 'input textarea'
       
   148         for name in ('generic', 'specifics', 'associations', 'usage', 'used_for'):
       
   149             self.widgets[name].thesaurus_name = thesaurus.name
       
   150         for name in ('specifics', 'used_for', 'extracts', 'created'):
       
   151             self.widgets[name].mode = DISPLAY_MODE
       
   152 
       
   153     def update_content(self, content, data):
       
   154         term = self.context
       
   155         thesaurus = get_parent(term, IThesaurus)
       
   156         old_label = term.label
       
   157         old_generic = term.generic
       
   158         old_usage = term.usage
       
   159         changes = super(ThesaurusTermEditForm, self).update_content(content, data)
       
   160         # Move term if label changed
       
   161         if 'label' in changes.get(IThesaurusTerm, ()):
       
   162             terms = thesaurus.terms
       
   163             del terms[old_label]
       
   164             terms[term.label] = term
       
   165         # Check modifications
       
   166         self.generic_changed = old_generic != term.generic
       
   167         self.usage_changed = old_usage != term.usage
       
   168         # Check generic change
       
   169         if self.generic_changed:
       
   170             if old_generic is not None:
       
   171                 # Add a previous generic?
       
   172                 # => remove term from list of previous term's specifics
       
   173                 specifics = old_generic.specifics
       
   174                 if term in specifics:
       
   175                     specifics.remove(term)
       
   176                     old_generic.specifics = specifics
       
   177             else:
       
   178                 # No previous generic?
       
   179                 # => remove term from thesaurus top terms
       
   180                 top_terms = thesaurus.top_terms
       
   181                 if term in top_terms:
       
   182                     top_terms.remove(term)
       
   183                     thesaurus.top_terms = top_terms
       
   184             # Check new value
       
   185             if term.generic is None:
       
   186                 # No generic and not a synonym?
       
   187                 # => add term to top terms
       
   188                 if (term.usage is None) and (term not in thesaurus.top_terms):
       
   189                     thesaurus.top_terms += [term, ]
       
   190             else:
       
   191                 # New generic?
       
   192                 # => add term to generic specific terms
       
   193                 if term not in term.generic.specifics:
       
   194                     term.generic.specifics += [term, ]
       
   195         # Check usage change
       
   196         if self.usage_changed:
       
   197             if old_usage is not None:
       
   198                 # Add previous usage term?
       
   199                 # => update used_for
       
   200                 used_for = old_usage.used_for
       
   201                 if term in used_for:
       
   202                     used_for.remove(term)
       
   203                     old_usage.used_for = used_for
       
   204             # Check new term usage
       
   205             if term.usage is None:
       
   206                 # No usage
       
   207                 # => maybe a top term...
       
   208                 if (term.generic is None) and (term not in thesaurus.top_terms):
       
   209                     thesaurus.top_terms += [term, ]
       
   210             else:
       
   211                 # Term usage?
       
   212                 # => remove term from top terms
       
   213                 top_terms = thesaurus.top_terms
       
   214                 if term in top_terms:
       
   215                     top_terms.remove(term)
       
   216                     thesaurus.top_terms = top_terms
       
   217                 # Add term to usage synonyms
       
   218                 if term not in term.usage.used_for:
       
   219                     term.usage.used_for += [term, ]
       
   220         return changes
       
   221 
       
   222 
       
   223 @subscriber(IDataExtractedEvent, form_selector=ThesaurusTermEditForm)
       
   224 def handle_term_properties_data_extraction(event):
       
   225     """Handle term properties data extraction"""
       
   226     context = event.form.context
       
   227     thesaurus = get_parent(context, IThesaurus)
       
   228     label = event.data.get('label')
       
   229     if (label != context.label) and (label in thesaurus.terms):
       
   230         event.form.widgets.errors += (Invalid(_("Specified new label is already used!")), )
       
   231 
       
   232 
       
   233 @pagelet_config(name='properties.json', context=IThesaurusTerm, request_type=IPyAMSLayer,
       
   234                 permission='thesaurus.manage', renderer='json', xhr=True)
       
   235 class ThesaurusTermAJAXEditForm(AJAXEditForm, ThesaurusTermEditForm):
       
   236     """Thesaurus term edit form, AJAX view"""
       
   237 
       
   238     def get_ajax_output(self, changes):
       
   239         if self.generic_changed:
       
   240             label = self.context.label.replace("'", "&#039;")
       
   241             return {'status': 'reload',
       
   242                     'callback': 'PyAMS_thesaurus.tree.findTerm',
       
   243                     'options': {'term': label}}
       
   244         else:
       
   245             term_changes = changes.get(IThesaurusTerm, ())
       
   246             if ('status' in term_changes) or ('label' in term_changes):
       
   247                 label = self.context.generic.label.replace("'", "&#039;")
       
   248                 return {'status': 'callback',
       
   249                         'callback': 'PyAMS_thesaurus.tree.updateTerm',
       
   250                         'options': {'term': label}}
       
   251             else:
       
   252                 return super(ThesaurusTermAJAXEditForm, self).get_ajax_output(changes)