Logo Search packages:      
Sourcecode: zope-linguaplone version File versions


# Plone Solutions AS <info@plonesolutions.com>
# http://www.plonesolutions.com

# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.


$Id: utils.py,v 2004/04/21 14:39:51 tesdal Exp $

__version__ = "$Revision: $"

from types import FunctionType as function

# Method generation for ITranslatable content with language independent fields
from Products.Archetypes.ClassGen import Generator as ATGenerator, ClassGenerator as ATClassGenerator, GeneratorError, _modes
from Products.Archetypes.ArchetypeTool import registerType as registerATType, getType

from Products.LinguaPlone.config import KWARGS_TRANSLATION_KEY, RELATIONSHIP

    't' : { 'prefix'   : 'setTranslation',
            'attr'     : 'translation_mutator',
            'security' : 'write_permission',

00043 class Generator(ATGenerator):
    """Generate methods for language independent fields"""
    def makeMethod(self, klass, field, mode, methodName):
        name = field.getName()
        method = None
        if mode == "r":
            def generatedAccessor(self, **kw):
                """Default Accessor."""
                if self.isCanonical():
                    if kw.has_key('schema'):
                        schema = kw['schema']
                        schema = self.Schema()
                        kw['schema'] = schema
                    return schema[name].get(self, **kw)
                    return getattr(self.getCanonical(), methodName)(**kw)
            method = generatedAccessor
        elif mode == "m":
            def generatedEditAccessor(self, **kw):
                """Default Edit Accessor."""
                if self.isCanonical():
                    if kw.has_key('schema'):
                        schema = kw['schema']
                        schema = self.Schema()
                        kw['schema'] = schema
                    return schema[name].getRaw(self, **kw)
                    return getattr(self.getCanonical(), methodName)(**kw)
            method = generatedEditAccessor
        elif mode == "w":
            # the generatedMutator doesn't actually mutate, but calls a
            # translation mutator on all translations, including self.
            def generatedMutator(self, value, **kw):
                """Default Mutator."""
                if kw.has_key('schema'):
                    schema = kw['schema']
                    schema = self.Schema()
                    kw['schema'] = schema
                translations = [t[0] for t in self.getTranslations().values()]
                # reverse to return the result of the canonical mutator
                translationMethodName = schema[name].translation_mutator
                res = None
                for t in translations:
                    res = getattr(t, translationMethodName)(value, **kw)
                return res
            method = generatedMutator
        elif mode == "t":
            # The translation mutator that changes data
            def generatedTranslationMutator(self, value, **kw):
                """ Delegated Mutator """
                if kw.has_key('schema'):
                    schema = kw['schema']
                    schema = self.Schema()
                    kw['schema'] = schema
                return schema[name].set(self, value, **kw)
            method = generatedTranslationMutator
            raise GeneratorError("""Unhandled mode for method creation:
            %s:%s -> %s:%s""" %(klass.__name__,

        # Zope security requires all security protected methods to have a
        # function name. It uses this name to determine which roles are allowed
        # to access the method.
        # This code is renaming the internal name from e.g. generatedAccessor to
        # methodName.
        method = function(method.func_code,
        setattr(klass, methodName, method)

00125 class ClassGenerator(ATClassGenerator):
    """Generate methods for language independent fields"""
    def generateClass(self, klass):
        # We are going to assert a few things about the class here
        # before we start, set meta_type, portal_type based on class
        # name, but only if they are not set yet
        if (not getattr(klass, 'meta_type', None) or
            'meta_type' not in klass.__dict__):
            klass.meta_type = klass.__name__
        if (not getattr(klass, 'portal_type', None) or
            'portal_type' not in klass.__dict__):
            klass.portal_type = klass.__name__
        klass.archetype_name = getattr(klass, 'archetype_name',

        fields = klass.schema.fields()
        # Find the languageIndependent fields.
        fields = [field for field in fields if field.languageIndependent]
        self.generateMethods(klass, fields)

    def generateMethods(self, klass, fields):
        generator = Generator()
        for field in fields:
            assert not 'm' in field.mode, 'm is an implicit mode'
            assert not 't' in field.mode, 't is an implicit mode'

            # Make sure we want to muck with the class for this field
            if "c" not in field.generateMode: continue
            type = getattr(klass, 'type')
            for mode in field.mode: #(r, w)
                self.handle_mode(klass, generator, type, field, mode)
                if mode == 'w':
                    self.handle_mode(klass, generator, type, field, 'm')
                    self.handle_mode(klass, generator, type, field, 't')

    def handle_mode(self, klass, generator, type, field, mode):
        attr = _modes[mode]['attr']
        # Did the field request a specific method name?
        methodName = getattr(field, attr, None)
        if not methodName:
            methodName = generator.computeMethodName(field, mode)

        # If there is already a mutator, make that the translation mutator
        if methodName in klass.__dict__.keys() and mode == 'w':
            setattr(klass, generator.computeMethodName(field, 't'), getattr(klass, methodName))
            delattr(klass, methodName)

        # Avoid name space conflicts
        if not methodName in klass.__dict__.keys() \
               or getattr(klass, methodName) is AT_GENERATE_METHOD:
            if type.has_key(methodName):
                raise GeneratorError("There is a conflict"
                                     "between the Field(%s) and the attempt"
                                     "to generate a method of the same name on"
                                     "class %s" % (

            # Make a method for this klass/field/mode
            generator.makeMethod(klass, field, mode, methodName)
            self.updateSecurity(klass, field, mode, methodName)

        # Note on the class what we did (even if the method existed)
        attr = _modes[mode]['attr']
        setattr(field, attr, methodName)

_cg = ClassGenerator()
generateClass = _cg.generateClass
generateMethods = _cg.generateMethods

def registerType(klass, package=None):
    """Overrides the AT registerType to enable method generation for language independent fields"""
    # Generate methods for language independent fields
    # Pass on to the regular AT registerType
    registerATType(klass, package)

def generateCtor(name, module):
    ctor = """
def add%(name)s(self, id, **kwargs):
    o = %(name)s(id)
    self._setObject(id, o)
    o = getattr(self, id)
    canonical = None
    if kwargs.has_key('%(KWARGS_TRANSLATION_KEY)s'):
        canonical = kwargs.get('%(KWARGS_TRANSLATION_KEY)s')
        del kwargs['%(KWARGS_TRANSLATION_KEY)s']
    if canonical is not None:
        o.addReference(canonical, '%(RELATIONSHIP)s')
    return id

    exec ctor in module.__dict__
    return getattr(module, "add%s" % name)

# Exact copy of ArchetypeTool.process_type, but with new generateCtor
import sys
from copy import deepcopy
from Products.Archetypes.ArchetypeTool import base_factory_type_information, modify_fti
def process_types(types, pkg_name):
    content_types = ()
    constructors  = ()
    ftis          = ()

    for rti in types:
        typeName = rti['name']
        klass  = rti['klass']
        module = rti['module']

        if hasattr(module, "factory_type_information"):
            fti = module.factory_type_information
            fti = deepcopy(base_factory_type_information)
            modify_fti(fti, klass, pkg_name)

        # Add a callback to modifty the fti
        if hasattr(module, "modify_fti"):
            m = None
            for k in klass.__bases__:
                base_module = sys.modules[k.__module__]
                if hasattr(base_module, "modify_fti"):
                    m = base_module
            if m is not None:

        ctor = getattr(module, "add%s" % typeName, None)
        if ctor is None:
            ctor = generateCtor(typeName, module)

        content_types += (klass,)
        constructors  += (ctor,)
        ftis   += fti

    return content_types, constructors, ftis

Generated by  Doxygen 1.6.0   Back to index