diff -r 000000000000 -r 47700a43ef3f src/pyams_thesaurus/zmi/term.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_thesaurus/zmi/term.py Tue Apr 14 17:52:05 2015 +0200 @@ -0,0 +1,252 @@ +# +# Copyright (c) 2008-2015 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces +from pyams_skin.interfaces.viewlet import IToolbarViewletManager +from pyams_skin.layer import IPyAMSLayer +from pyams_thesaurus.interfaces.term import IThesaurusTerm +from pyams_thesaurus.interfaces.thesaurus import IThesaurus +from pyams_zmi.layer import IAdminLayer +from z3c.form.interfaces import IDataExtractedEvent, DISPLAY_MODE + +# import packages +from pyams_form.form import AJAXAddForm, AJAXEditForm +from pyams_pagelet.pagelet import pagelet_config +from pyams_skin.viewlet.toolbar import ToolbarAction +from pyams_thesaurus.term import ThesaurusTerm +from pyams_thesaurus.zmi.thesaurus import ThesaurusTermsView +from pyams_utils.traversing import get_parent +from pyams_utils.url import absolute_url +from pyams_viewlet.viewlet import viewlet_config +from pyams_zmi.form import AdminDialogAddForm, AdminDialogEditForm +from pyramid.events import subscriber +from pyramid.view import view_config +from z3c.form import field +from zope.interface import Invalid + +from pyams_thesaurus import _ + + +@viewlet_config(name='thesaurus.term.adding', context=IThesaurus, view=ThesaurusTermsView, + layer=IAdminLayer, manager=IToolbarViewletManager, permission='thesaurus.manage') +class ThesaurusTermAddAction(ToolbarAction): + """Thesaurus term add action""" + + label = _("Add term") + url = 'add-term.html' + modal_target = True + + +@pagelet_config(name='add-term.html', context=IThesaurus, layer=IPyAMSLayer, permission='thesaurus.manage') +class ThesaurusTermAddForm(AdminDialogAddForm): + """Thesaurus term add form""" + + @property + def title(self): + return self.context.title + + legend = _("Add new term") + icon_css_class = 'fa fa-fw fa-tag' + + fields = field.Fields(IThesaurusTerm).select('label', 'alt', 'definition', 'note', 'generic', 'associations', + 'usage', 'extensions', 'status', 'created') + + ajax_handler = 'add-term.json' + edit_permission = None + + def updateWidgets(self, prefix=None): + super(ThesaurusTermAddForm, self).updateWidgets(prefix) + for name in ('definition', 'note'): + self.widgets[name].label_css_class = 'input textarea' + for name in ('generic', 'associations', 'usage'): + self.widgets[name].thesaurus_name = self.context.name + + def create(self, data): + return ThesaurusTerm() + + def update_content(self, content, data): + super(ThesaurusTermAddForm, self).update_content(content, data) + generic = content.generic + usage = content.usage + if (generic is None) and (usage is None): + IThesaurus(self.context).top_terms += [content, ] + else: + if generic is not None: + generic.specifics += [content, ] + elif usage is not None: + usage.used_for += [content, ] + + def add(self, object): + self.context.terms[object.label] = object + + def nextURL(self): + return absolute_url(self.context, self.request, 'terms.html') + + +@subscriber(IDataExtractedEvent, form_selector=ThesaurusTermAddForm) +def handle_new_term_data_extraction(event): + """Handle new term data extraction""" + data = event.data + if data.get('label') in event.form.context.terms: + event.form.widgets.errors += (Invalid(_("Specified label is already used!")), ) + + +@view_config(name='add-term.json', context=IThesaurus, request_type=IPyAMSLayer, + permission='thesaurus.manage', renderer='json', xhr=True) +class ThesaurusTermAJAXAddForm(AJAXAddForm, ThesaurusTermAddForm): + """Thesaurus term add form, AJAX view""" + + def get_ajax_output(self, changes): + if changes.generic is not None: + return super(ThesaurusTermAJAXAddForm, self).get_ajax_output(changes) + else: + label = changes.label.replace("'", "'") + return {'callback': 'PyAMS_thesaurus.tree.findTerm', + 'options': {'term': label}} + + +@pagelet_config(name='properties.html', context=IThesaurusTerm, layer=IPyAMSLayer, permission='view') +class ThesaurusTermEditForm(AdminDialogEditForm): + """Thesaurus term edit form""" + + @property + def title(self): + return self.context.label + + legend = _("Edit term properties") + icon_css_class = 'fa fa-fw fa-tag' + + fields = field.Fields(IThesaurusTerm).select('label', 'alt', 'definition', 'note', 'generic', 'specifics', + 'associations', 'usage', 'used_for', 'extracts', 'extensions', + 'status', 'level', 'created', 'modified') + + ajax_handler = 'properties.json' + edit_permission = 'thesaurus.manage' + + generic_changed = False + usage_changed = False + + def updateWidgets(self, prefix=None): + super(ThesaurusTermEditForm, self).updateWidgets(prefix) + thesaurus = get_parent(self.context, IThesaurus) + for name in ('definition', 'note'): + self.widgets[name].label_css_class = 'input textarea' + for name in ('generic', 'specifics', 'associations', 'usage', 'used_for'): + self.widgets[name].thesaurus_name = thesaurus.name + for name in ('specifics', 'used_for', 'extracts', 'created'): + self.widgets[name].mode = DISPLAY_MODE + + def update_content(self, content, data): + term = self.context + thesaurus = get_parent(term, IThesaurus) + old_label = term.label + old_generic = term.generic + old_usage = term.usage + changes = super(ThesaurusTermEditForm, self).update_content(content, data) + # Move term if label changed + if 'label' in changes.get(IThesaurusTerm, ()): + terms = thesaurus.terms + del terms[old_label] + terms[term.label] = term + # Check modifications + self.generic_changed = old_generic != term.generic + self.usage_changed = old_usage != term.usage + # Check generic change + if self.generic_changed: + if old_generic is not None: + # Add a previous generic? + # => remove term from list of previous term's specifics + specifics = old_generic.specifics + if term in specifics: + specifics.remove(term) + old_generic.specifics = specifics + else: + # No previous generic? + # => remove term from thesaurus top terms + top_terms = thesaurus.top_terms + if term in top_terms: + top_terms.remove(term) + thesaurus.top_terms = top_terms + # Check new value + if term.generic is None: + # No generic and not a synonym? + # => add term to top terms + if (term.usage is None) and (term not in thesaurus.top_terms): + thesaurus.top_terms += [term, ] + else: + # New generic? + # => add term to generic specific terms + if term not in term.generic.specifics: + term.generic.specifics += [term, ] + # Check usage change + if self.usage_changed: + if old_usage is not None: + # Add previous usage term? + # => update used_for + used_for = old_usage.used_for + if term in used_for: + used_for.remove(term) + old_usage.used_for = used_for + # Check new term usage + if term.usage is None: + # No usage + # => maybe a top term... + if (term.generic is None) and (term not in thesaurus.top_terms): + thesaurus.top_terms += [term, ] + else: + # Term usage? + # => remove term from top terms + top_terms = thesaurus.top_terms + if term in top_terms: + top_terms.remove(term) + thesaurus.top_terms = top_terms + # Add term to usage synonyms + if term not in term.usage.used_for: + term.usage.used_for += [term, ] + return changes + + +@subscriber(IDataExtractedEvent, form_selector=ThesaurusTermEditForm) +def handle_term_properties_data_extraction(event): + """Handle term properties data extraction""" + context = event.form.context + thesaurus = get_parent(context, IThesaurus) + label = event.data.get('label') + if (label != context.label) and (label in thesaurus.terms): + event.form.widgets.errors += (Invalid(_("Specified new label is already used!")), ) + + +@pagelet_config(name='properties.json', context=IThesaurusTerm, request_type=IPyAMSLayer, + permission='thesaurus.manage', renderer='json', xhr=True) +class ThesaurusTermAJAXEditForm(AJAXEditForm, ThesaurusTermEditForm): + """Thesaurus term edit form, AJAX view""" + + def get_ajax_output(self, changes): + if self.generic_changed: + label = self.context.label.replace("'", "'") + return {'status': 'reload', + 'callback': 'PyAMS_thesaurus.tree.findTerm', + 'options': {'term': label}} + else: + term_changes = changes.get(IThesaurusTerm, ()) + if ('status' in term_changes) or ('label' in term_changes): + label = self.context.generic.label.replace("'", "'") + return {'status': 'callback', + 'callback': 'PyAMS_thesaurus.tree.updateTerm', + 'options': {'term': label}} + else: + return super(ThesaurusTermAJAXEditForm, self).get_ajax_output(changes)