Package flex2.compiler.mxml.rep

Source Code of flex2.compiler.mxml.rep.Model

/*
*
*  Licensed to the Apache Software Foundation (ASF) under one or more
*  contributor license agreements.  See the NOTICE file distributed with
*  this work for additional information regarding copyright ownership.
*  The ASF licenses this file to You under the Apache License, Version 2.0
*  (the "License"); you may not use this file except in compliance with
*  the License.  You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*
*/

package flex2.compiler.mxml.rep;

import flex2.compiler.mxml.gen.CodeFragmentList;
import flex2.compiler.mxml.gen.TextGen;
import flex2.compiler.mxml.lang.StandardDefs;
import flex2.compiler.mxml.reflect.*;
import flex2.compiler.mxml.rep.init.*;
import flex2.compiler.util.IteratorList;
import flex2.compiler.util.NameFormatter;
import org.apache.commons.collections.Predicate;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.iterators.FilterIterator;
import org.apache.commons.collections.iterators.IteratorChain;
import org.apache.commons.collections.iterators.TransformIterator;

import java.util.*;

/**
* This class represents a non-language node in a MXML document.
*/
public class Model implements LineNumberMapped
{
    private Type type;

    /**
     * line number where this model occurred in xml.  -1 if this model
     * is synthetic and has no creation site in MXML.
     */
    private int xmlLineNumber;

    /**
     * this is the guaranteed-unique name used by the value initializer
     * TODO see below
     */
    private String definitionName;

    /**
     * this is the ID we have given this instance in mxml.  it will either be user assigned or
     * assigned automatically by the compiler.
     * NOTE: in anonymous cases (e.g. XML), this may be a child element name, thus not guaranteed unique.
     */
    // TODO id should be the guaranteed-unique one; childName or something for the other one.
    private String id;

    /**
     * this flag is true if the id (see above) was assigned automatically
     * by the compiler.  Conversely, this flag is false if the user
     * explicitly assigned the id
     */
    private boolean idIsAutogenerated = false;

    /**
     * indicates whether this Model is a child of an AnonymousObjectGraph
     */
    private boolean isAnonymous = false;

    private MxmlDocument document;
    protected final StandardDefs standardDefs;

    private Model parent;
    private String parentIndex;
    private String parentIndexState;

    private boolean inspectable = false;

    private List<Model> repeaterParents;

    private Map<String, Initializer> properties;
    private Map<String, Initializer> styles;
    private Map<String, Initializer> effects;
    private Map<String, Initializer> events;
    private Collection<String> states;

    /*
     * The DesignLayer associated with this model.
     */
    public DesignLayer layerParent;
   
    private boolean described;  //  TODO remove when DI is generalized
   
    /*
     * Denotes whether or not this node is state-specific.
     */
    private boolean stateSpecific = false;
   
    /*
     * Denotes whether or not this node is to be instantiated immediately
     * upon document instantiation (runtime).
     */
    public boolean earlyInit = false;
   
    /*
     * used to force declare a model, even when not normally applicable.
     */
    private boolean ensureDeclaration = false;
   
    /*
     * used to force a models property declaration to be bindable.
     */
    private boolean ensureBindable = false;
   
    /*
     * indicates whether this Model should be initialized within the document descriptor.
     */
    private boolean descriptorInit = true;

    /*
     * indicates that this model serves as the rvalue of an ITransientDeferredInstance type.
     */
    private boolean isTransient = false;
   
    public Model(MxmlDocument document, Type type, int line)
    {
        this(document, type, null, line);
    }

    public Model(MxmlDocument document, Type type, Model parent, int line)
    {
        assert (type != null);

        this.document = document;
        this.standardDefs = document.getStandardDefs();
        this.type = type;
        this.parent = parent;
        setXmlLineNumber(line);

        document.ensureId(this);
        setDefinitionName(getId());
    }

    public final boolean isDeclared()
    {
        //  TODO first clause is necessary due to id being abused in AOG case (see AOGBuilder ~line 85.
        //  This breaks meaning of id - need to find another way to enable correct databinding codegen in AOG case.
        return !isAnonymous && document.isDeclared(this);
    }

    public final StandardDefs getStandardDefs()
    {
        return standardDefs;
    }

    public final Type getType()
    {
        return type;
    }

    public final String getDefinitionName()
    {
        return definitionName;
    }

    public final void setDefinitionName(String definitionName)
    {
        this.definitionName = definitionName;
    }

    public final String getId()
    {
        return id;
    }

    public final void setId(String id, boolean idIsAutogenerated)
    {
        this.id = id;
        this.idIsAutogenerated = idIsAutogenerated;
    }

    public final boolean getIdIsAutogenerated()
    {
        return idIsAutogenerated;
    }

    public final void ensureBindable()
    {
      ensureBindable = true
    }
   
    public final boolean getBindabilityEnsured()
    {
      return ensureBindable;
    }
   
    public final boolean getIsAnonymous()
    {
        return isAnonymous;
    }

    public final void setIsAnonymous(boolean isAnonymous)
    {
        this.isAnonymous = isAnonymous;
    }

    public final boolean getIsTransient()
    {
        return isTransient;
    }

    public final void setIsTransient(boolean isTransient)
    {
        this.isTransient = isTransient;
    }
   
    public final MxmlDocument getDocument()
    {
        return document;
    }

    public final void setParent(Model parent)
    {
        this.parent = parent;
    }

    public final Model getParent()
    {
        return parent;
    }

    public final void setParentIndex(String index)
    {
        this.parentIndex = index;
    }
   
    public final void setParentIndex(String index, String state)
    {
        this.parentIndex = index;
        this.parentIndexState = state;
    }

    public final void setParentIndex(int index)
    {
        this.parentIndex = Integer.toString(index);
    }

    public final String getParentIndex()
    {
        return parentIndex;
    }
   
    public final String getParentIndexState()
    {
        return parentIndexState;
    }

    public final int getXmlLineNumber()
    {
        return xmlLineNumber;
    }

    public final void setXmlLineNumber(int xmlLineNumber)
    {
        this.xmlLineNumber = xmlLineNumber;
    }

    public final boolean getInspectable()
    {
        return inspectable;
    }

    public final void setInspectable(boolean inspectable)
        {
        this.inspectable = inspectable;
        }

    public final int getRepeaterLevel()
    {
        return getRepeaterParents().size();
    }

    public final List<Model> getRepeaterParents()
    {
        if (repeaterParents == null)
        {
            repeaterParents = new ArrayList<Model>();

            if (parent != null)
            {
                repeaterParents.addAll(parent.getRepeaterParents());

                if (standardDefs.isRepeater(parent.getType()))
                {
                    repeaterParents.add(parent);
                }
            }
        }

        return repeaterParents;
    }

    /**
     *
     */
    public void setProperty(String name, Model value)
    {
        setProperty(name, value, value.getXmlLineNumber());
    }

    /**
     *
     */
    public void setProperty(Property property, Object value, int line)
    {
        ValueInitializer initializer = new StaticPropertyInitializer(property, value, line, standardDefs);
       
        // Register this property and value as pertaining only to a specific state, otherwise
        // assign to this instance (base state).
        if (property.isStateSpecific())
        {
            document.registerStateSpecificProperty(this, property.getName(), initializer, property.getStateName());
        }
        else
        {
            (properties != null ? properties : (properties = new LinkedHashMap<String, Initializer>())).put(property.getName(), initializer);
        }
    }

    /**
     *
     */
    public void setDynamicProperty(Type type, String name, Object value, String state, int line)
    {
        ValueInitializer initializer = new DynamicPropertyInitializer(type, name, value, line, standardDefs);
       
        // Register this property and value as pertaining only to a specific state, otherwise
        // assign to this instance (base state).
        if (state != null)
        {
            document.registerStateSpecificProperty(this, name, initializer, state);
        }
        else
        {
            (properties != null ? properties : (properties = new LinkedHashMap<String, Initializer>())).put(name, initializer);
        }
    }

    /**
     * TODO legacy shim. Convert all callers to either setProperty(property, value) or setDynamicProperty(type, name, value)
     */
    public void setProperty(String name, Object value, int line)
    {
        Property property = type.getProperty(name);
        if (property != null)
        {
            setProperty(property, value, line);
        }
        else
        {
            setDynamicProperty(type.getTypeTable().objectType, name, value, null, line);
        }
    }

    /**
     *
     */
    public final boolean hasProperty(String name)
    {
        return getProperties().containsKey(name);
    }

    /**
     *
     */
    public boolean hasBindings()
    {
        return bindingsOnly(getProperties().values().iterator()).hasNext() ||
                bindingsOnly(getStyles().values().iterator()).hasNext() ||
                bindingsOnly(getEffects().values().iterator()).hasNext();
    }

    /**
     * Returns true if the specified property is the target of a binding.
     */
    public boolean hasDataBoundProperty(String name)
    {
        Initializer initializer = (Initializer) getProperties().get(name);
        return initializer != null ? initializer.isBinding() : false;
    }
   
    /**
     * Returns true if the specified style is the target of a binding.
     */
    public boolean hasDataBoundStyle(String name)
    {
        Initializer initializer = (Initializer) getStyles().get(name);
        return initializer != null ? initializer.isBinding() : false;
    }
   
    /**
     * Returns true if the specified event property is the target of a binding.
     */
    public boolean hasDataBoundEvent(String name)
    {
        Initializer initializer = (Initializer) getEvents().get(name);
        return initializer != null ? initializer.isBinding() : false;
    }
   
    /**
     * Returns true if the specified effect property is the target of a binding.
     */
    public boolean hasDataBoundEffect(String name)
    {
        Initializer initializer = (Initializer) getEffects().get(name);
        return initializer != null ? initializer.isBinding() : false;
    }
   
    /**
     * Note that we do *not* filter out bindings by default for property initializers.
     */
    public final Iterator<Initializer> getPropertyInitializerIterator()
    {
        return getPropertyInitializerIterator(true);
    }

    /**
     *
     */
    public final Iterator<Initializer> getPropertyInitializerIterator(boolean includeBindings)
    {
        return includeBindings ?
                getProperties().values().iterator() :
                excludeBindings(getProperties().values().iterator());
    }

    /**
     *
     */
    public boolean isEmpty()
    {
        return properties == null && styles == null && effects == null && events == null;
    }

    /**
     * TODO make this private once RemoteObjectBuilder usage has been removed
     */
    public final Map<String, Initializer> getProperties()
    {
        return properties != null ? properties : Collections.<String, Initializer>emptyMap();
    }

    /**
     * TODO legacy - delete once AnonymousObjectGraphBuilder usage has been removed
     */
    public Object getProperty(String name)
    {
        ValueInitializer initializer = (ValueInitializer)getProperties().get(name);
        return initializer != null ? initializer.getValue() : null;
    }

    /**
     *
     */
    public final void setStyle(String name, Object value, int line)
    {
        Style style = type.getStyle(name);
        assert style != null : "style '" + name + "' not defined on type '" + type.getName() + "'";
        setStyle(style,value, line);
    }
   
    /**
     *
     */
    public final void setStyle(Style style, Object value, int line)
    {
        StyleInitializer styleInitializer = new StyleInitializer(style, value, line, standardDefs);
       
        // Register this style and value as pertaining only to a specific state, otherwise
        // assign to this instance (base state).
        if (style.isStateSpecific())
        {
            document.registerStateSpecificStyle(this, style.getName(), styleInitializer, style.getStateName());
        }
        else
        {
            (styles != null ? styles : (styles = new LinkedHashMap<String, Initializer>())).put(style.getName(), styleInitializer);
        }
    }

    public final Iterator<Initializer> getStyleInitializerIterator()
    {
        return excludeBindings(getStyles().values().iterator());
    }

    public final boolean hasStyle(String name)
    {
        return getStyles().containsKey(name);
    }

    private Map<String, Initializer> getStyles()
    {
        return styles != null ? styles : Collections.<String, Initializer>emptyMap();
    }

    /**
     * Note: this is a little irregular; effect rvalues are either class names or bindings.
     */
    public final void setEffect(String name, Object value, Type effectType, int line)
    {
        Effect effect = type.getEffect(name);
        setEffect(effect, value, effectType, line);
    }
   
    /**
     * Note: this is a little irregular; effect rvalues are either class names or bindings.
     */
    public final void setEffect(Effect effect, Object value, Type effectType, int line)
    {
        EffectInitializer effectInitializer = new EffectInitializer(effect, value, effectType, line, standardDefs);
       
        // Register this effect and value as pertaining only to a specific state, otherwise
        // assign to this instance (base state).
        if (effect.isStateSpecific())
        {
            document.registerStateSpecificStyle(this, effect.getName(), effectInitializer, effect.getStateName());
        }
        else
        {
            (effects != null ? effects : (effects = new LinkedHashMap<String, Initializer>())).put(effect.getName(), effectInitializer);
        }
    }

    public final Iterator<Initializer> getEffectInitializerIterator()
    {
        return excludeBindings(getEffects().values().iterator());
    }

    public final boolean hasEffect(String name)
    {
        return getEffects().containsKey(name);
    }

    public final Map<String, Initializer> getEffects()
    {
        return effects != null ? effects : Collections.<String, Initializer>emptyMap();
    }

    public String getEffectNames()
    {
        Iterator eventNameIter = new TransformIterator(getEffectInitializerIterator(), new Transformer()
        {
            public Object transform(Object object)
            {
                return TextGen.quoteWord(((EffectInitializer)object).getName());
            }
        });

        return TextGen.toCommaList(eventNameIter);
    }

    public String getEffectEventNames()
    {
        Iterator eventNameIter = new TransformIterator(getEffectInitializerIterator(), new Transformer()
        {
            public Object transform(Object object)
            {
                return TextGen.quoteWord(((EffectInitializer)object).getEventName());
            }
        });

        return TextGen.toCommaList(eventNameIter);
    }

    /**
     *
     */
    public Iterator getStyleAndEffectInitializerIterator()
    {
        return new IteratorChain(getStyleInitializerIterator(), getEffectInitializerIterator());
    }

    /**
     *
     */
    public final void setEvent(Event event, String text, int line)
    {
        EventHandler handler;
       
        // If this handler will be only assigned for a state other than base (default),
        // ensure we generate a corresponding import.
        if (!event.isStateSpecific())
        {
            document.addImport(NameFormatter.toDot(event.getType().getName()), line);
            handler = new EventHandler(this, event, text);
        }
        else
        {
            handler = new EventHandler(this, event, text, event.getStateName());
        }

        handler.setXmlLineNumber(line);
        EventInitializer eventInitializer = new EventInitializer(handler);

        // Register this handler and value as pertaining only to a specific state, otherwise
        // assign to this instance (base state).
        if (event.isStateSpecific())
        {
            document.addStateSpecificEventInitializer(eventInitializer);
            document.registerStateSpecificEventHandler(this, event.getName(), eventInitializer, event.getStateName());
        }
        else
        {
            (events != null ? events : (events = new LinkedHashMap<String, Initializer>())).put(event.getName(), eventInitializer);
        }
    }
   
    public final Iterator<Initializer> getEventInitializerIterator()
    {
        return getEvents().values().iterator();
    }

    public final boolean hasEvent(String name)
    {
        return getEvents().containsKey(name);
    }
   
    public final Initializer getEventInitializer(String name)
    {
      return getEvents().get(name);
    }

    private final Map<String, Initializer> getEvents()
    {
        return events != null ? events : Collections.<String, Initializer>emptyMap();
    }

    /**
     *  iterator containing definitions from our initializers
     */
    public Iterator<CodeFragmentList> getSubDefinitionsIterator()
    {
        IteratorList iterList = new IteratorList();

        addDefinitionIterators(iterList, getPropertyInitializerIterator());
        addDefinitionIterators(iterList, getStyleInitializerIterator());
        addDefinitionIterators(iterList, getEffectInitializerIterator());
        addDefinitionIterators(iterList, getEventInitializerIterator());

        return iterList.toIterator();
    }

    /**
     *
     */
    protected static void addDefinitionIterators(IteratorList iterList, Iterator<? extends Initializer> initIter)
    {
        while (initIter.hasNext())
        {
            iterList.add(initIter.next().getDefinitionsIterator());
        }
    }

  /**
   *  iterator containing our initializers
   */
  public Iterator<Initializer> getSubInitializerIterator()
  {
    IteratorList iterList = new IteratorList();

    iterList.add(getPropertyInitializerIterator());
    iterList.add(getStyleInitializerIterator());
    iterList.add(getEffectInitializerIterator());
    iterList.add(getEventInitializerIterator());

    return iterList.toIterator();
  }

    /**
     *
     */
    protected Iterator<Initializer> excludeBindings(Iterator<? extends Initializer> iter)
    {
        return bindingFilter(iter, false);
    }

    /**
     *
     */
    protected Iterator<Initializer> bindingsOnly(Iterator<? extends Initializer> iter)
    {
        return bindingFilter(iter, true);
    }

    /**
     *
     */
    @SuppressWarnings("unchecked")
    protected Iterator<Initializer> bindingFilter(Iterator<? extends Initializer> iter, final boolean include)
    {
        return new FilterIterator(iter, new Predicate()
        {
            public boolean evaluate(Object object)
            {
                return (((Initializer) object).isBinding()) == include;
            }
        });
    }

    /**
     *
     */
    public final void setDescribed(boolean described)
    {
        this.described = described;
    }

    /**
     *
     */
    public final boolean isDescribed()
    {
        return described;
    }
   
    /**
     * Denotes whether or not this node is state-specific.
     */
    public final void setStateSpecific(boolean stateful)
    {
        this.stateSpecific = stateful;
    }

    /**
     * Denotes whether or not this node is state-specific.
     */
    public final boolean isStateSpecific()
    {
        return stateSpecific;
    }
   
    /**
     * Denotes whether or not this node is to be created immediate
     * upon document initialization (runtime).
     */
    public final void setEarlyInit(boolean earlyInit)
    {
        this.earlyInit = earlyInit;
    }

    /**
     * Denotes whether or not this node is to be created immediate
     * upon document initialization (runtime).
     */
    public final boolean isEarlyInit()
    {
        return earlyInit;
    }
   
    /**
     * Sets the list of states which this node is to apply.
     */
    public final void setStates(Collection<String> states)
    {
        this.states = states;
    }
   
    /**
     * Returns list of states for which this node applies.
     */
    public final Collection<String> getStates()
    {
        return states;
    }
   
    /**
     * Returns true if this object is to be applied for a given state.
     */
    public final boolean hasState(String state)
    {
        if (states != null)
        {
           return states.contains(state);
        }
        return false;
    }
   
    /**
     * used to force declare a model, even when not normally applicable.
     */
    public final void ensureDeclaration()
    {
        this.ensureDeclaration = true;
    }

    /**
     * used to force declare a model, even when not normally applicable.
     */
    public final boolean isDeclarationEnsured()
    {
        return ensureDeclaration;
    }
   
    /**
     * indicates whether this Model should be initialized within the document descriptor.
     */
    public final void setDescriptorInit(boolean descriptorInit)
    {
        this.descriptorInit = descriptorInit;
    }

    /**
     * indicates whether this Model should be initialized within the document descriptor.
     */
    public final boolean isDescriptorInit()
    {
        return descriptorInit;
    }
   
    /**
     * comment field for asdoc generation.
     */
    public String comment;
}
TOP

Related Classes of flex2.compiler.mxml.rep.Model

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.