| /* |
| * 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 org.netbeans.modules.xml.axi.impl; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| import org.netbeans.modules.xml.axi.AXIComponent; |
| import org.netbeans.modules.xml.axi.AXIModel; |
| import org.netbeans.modules.xml.axi.AXIType; |
| import org.netbeans.modules.xml.axi.AbstractAttribute; |
| import org.netbeans.modules.xml.axi.Compositor; |
| import org.netbeans.modules.xml.axi.ContentModel; |
| import org.netbeans.modules.xml.axi.Element; |
| import org.netbeans.modules.xml.axi.datatype.Datatype; |
| import org.netbeans.modules.xml.axi.visitor.AXIVisitor; |
| import org.netbeans.modules.xml.schema.model.Form; |
| import org.netbeans.modules.xml.schema.model.GlobalElement; |
| import org.netbeans.modules.xml.schema.model.SchemaComponent; |
| import org.netbeans.modules.xml.schema.model.SimpleType; |
| import org.netbeans.modules.xml.xam.dom.NamedComponentReference; |
| |
| /** |
| * Element implementation. |
| * @author Samaresh (Samaresh.Panda@Sun.Com) |
| */ |
| public final class ElementImpl extends Element { |
| |
| /** |
| * Creates a new instance of ElementImpl |
| */ |
| public ElementImpl(AXIModel model) { |
| super(model); |
| } |
| |
| /** |
| * Creates a new instance of ElementImpl |
| */ |
| public ElementImpl(AXIModel model, SchemaComponent schemaComponent) { |
| super(model, schemaComponent); |
| } |
| |
| /** |
| * Returns true if it is a reference, false otherwise. |
| */ |
| public boolean isReference() { |
| return false; |
| } |
| |
| /** |
| * Returns the referent if isReference() is true. |
| */ |
| public Element getReferent() { |
| return null; |
| } |
| |
| /** |
| * Returns abstract property. |
| */ |
| public boolean getAbstract() { |
| return isAbstract; |
| } |
| |
| /** |
| * Sets the abstract property. |
| */ |
| public void setAbstract(boolean value) { |
| boolean oldValue = getAbstract(); |
| if(oldValue != value) { |
| this.isAbstract = value; |
| firePropertyChangeEvent(PROP_ABSTRACT, oldValue, value); |
| } |
| } |
| |
| /** |
| * Returns the block. |
| */ |
| public String getBlock() { |
| return block; |
| } |
| |
| /** |
| * Sets the block property. |
| */ |
| public void setBlock(String value) { |
| String oldValue = getBlock(); |
| if( (oldValue == null && value == null) || |
| (oldValue != null && oldValue.equals(value)) ) { |
| return; |
| } |
| this.block = value; |
| firePropertyChangeEvent(PROP_BLOCK, oldValue, value); |
| } |
| |
| /** |
| * Returns the final property. |
| */ |
| public String getFinal() { |
| return finalValue; |
| } |
| |
| /** |
| * Sets the final property. |
| */ |
| public void setFinal(String value) { |
| String oldValue = getFinal(); |
| if( (oldValue == null && value == null) || |
| (oldValue != null && oldValue.equals(value)) ) { |
| return; |
| } |
| this.finalValue = value; |
| firePropertyChangeEvent(PROP_FINAL, oldValue, value); |
| } |
| |
| /** |
| * Returns the fixed value. |
| */ |
| public String getFixed() { |
| return fixedValue; |
| } |
| |
| /** |
| * Sets the fixed value. |
| */ |
| public void setFixed(String value) { |
| String oldValue = getFixed(); |
| if( (oldValue == null && value == null) || |
| (oldValue != null && oldValue.equals(value)) ) { |
| return; |
| } |
| this.fixedValue = value; |
| firePropertyChangeEvent(PROP_FIXED, oldValue, value); |
| } |
| |
| /** |
| * Returns the default value. |
| */ |
| public String getDefault() { |
| return defaultValue; |
| } |
| |
| /** |
| * Sets the default value. |
| */ |
| public void setDefault(String value) { |
| String oldValue = getDefault(); |
| if( (oldValue == null && value == null) || |
| (oldValue != null && oldValue.equals(value)) ) { |
| return; |
| } |
| this.defaultValue = value; |
| firePropertyChangeEvent(PROP_DEFAULT, oldValue, value); |
| } |
| |
| /** |
| * Returns the form. |
| */ |
| public Form getForm() { |
| return form; |
| } |
| |
| /** |
| * Sets the form. |
| */ |
| public void setForm(Form value) { |
| Form oldValue = getForm(); |
| if(oldValue != value) { |
| this.form = value; |
| firePropertyChangeEvent(PROP_FORM, oldValue, value); |
| } |
| } |
| |
| /** |
| * Returns the nillable. |
| */ |
| public boolean getNillable() { |
| return isNillable; |
| } |
| |
| /** |
| * Sets the nillable property. |
| */ |
| public void setNillable(boolean value) { |
| boolean oldValue = getNillable(); |
| if(oldValue != value) { |
| this.isNillable = value; |
| firePropertyChangeEvent(PROP_NILLABLE, oldValue, value); |
| } |
| } |
| |
| /** |
| * Returns the AXIType. |
| */ |
| public AXIType getType() { |
| if(axiType != null) |
| return axiType; |
| if(getTypeSchemaComponent() == null) { |
| SchemaComponent type = Util.getSchemaType((AXIModelImpl)getModel(), getPeer()); |
| setTypeSchemaComponent(type); |
| } |
| |
| this.axiType = Util.getAXIType(this, getTypeSchemaComponent()); |
| return axiType; |
| } |
| |
| /** |
| * Sets the AXIType. |
| */ |
| public void setType(AXIType newValue) { |
| if( (this == newValue) || |
| (this.isGlobal() && (newValue instanceof Element)) ) |
| return; |
| |
| if(newValue instanceof Element) { |
| setElementAsType(newValue); |
| return; |
| } |
| |
| AXIType oldValue = getType(); |
| if(!Util.canSetType(oldValue, newValue)) |
| return; |
| |
| updateChildren(oldValue, newValue); |
| this.axiType = newValue; |
| firePropertyChangeEvent(PROP_TYPE, oldValue, newValue); |
| setTypeSchemaComponent(getSchemaType(newValue)); |
| } |
| |
| private void setElementAsType(final AXIType newValue) { |
| if(newValue == this) |
| return; |
| int index = this.getIndex(); |
| AXIComponent parent = getParent(); |
| Element ref = getModel().getComponentFactory().createElementReference((Element)newValue); |
| parent.removeChild(this); |
| parent.insertAtIndex(Element.PROP_ELEMENT_REF, ref, index); |
| } |
| |
| /** |
| * Overwrites populateChildren of AXIComponent. |
| * |
| * An AXI element can keep LocalElement, GlobalElement or |
| * ElementReference as its peer. For the local and global, |
| * element, the element type's children becomes this AXI |
| * element's children. For ElementReference, the global element's |
| * type becomes this AXI element's children. |
| */ |
| public void populateChildren(List<AXIComponent> children) { |
| if(getPeer() == null) { |
| return; |
| } |
| |
| //populate children from the element's type |
| SchemaComponent type = Util.getSchemaType((AXIModelImpl)getModel(), getPeer()); |
| setTypeSchemaComponent(type); |
| |
| if(type == null || type instanceof SimpleType) { |
| if(this.isGlobal()) { |
| handleSubstitutionGroup(getPeer(), children); |
| } |
| return; |
| } |
| |
| AXIModelBuilder builder = new AXIModelBuilder(this); |
| builder.populateChildren(type, false, children); |
| } |
| |
| private void handleSubstitutionGroup(SchemaComponent sc, List<AXIComponent> children) { |
| if(!(sc instanceof GlobalElement)) |
| return; |
| GlobalElement ge = (GlobalElement)sc; |
| NamedComponentReference<GlobalElement> ncr = ge.getSubstitutionGroup(); |
| if(ncr == null || ncr.get() ==null) |
| return; |
| GlobalElement head = ncr.get(); |
| Element axiHead = (Element)((AXIModelImpl)getModel()).findChild(head); |
| Util.addProxyChildren(this, axiHead, children); |
| } |
| |
| /** |
| * Returns the last value for the element's type. |
| */ |
| SchemaComponent getTypeSchemaComponent() { |
| return typeSchemaComponent; |
| } |
| |
| /** |
| * Sets the new value for the element's type. |
| */ |
| void setTypeSchemaComponent(SchemaComponent type) { |
| this.typeSchemaComponent = type; |
| } |
| |
| private SchemaComponent getSchemaType(AXIType axiType) { |
| if(axiType instanceof Datatype) |
| return null; |
| if(axiType instanceof ContentModel) |
| return ((ContentModel)axiType).getPeer(); |
| if(axiType instanceof AnonymousType) |
| return ((AnonymousType)axiType).getPeer(); |
| |
| return null; |
| } |
| |
| /** |
| * OLD VALUE NEW VALUE RESULT |
| * SType LCT return |
| * SType GCT add proxy children |
| * LCT SType remove all and return |
| * LCT GCT remove all and add proxy children |
| * GCT SType remove all and return |
| * GCT LCT not allowed |
| */ |
| private void updateChildren(AXIType oldValue, AXIType newValue) { |
| //do not remove children if the old type was SimpleType and |
| //user added children on top of it, that makes the type as anonymous. |
| if(oldValue instanceof Datatype && newValue instanceof AnonymousType) { |
| return; |
| } |
| |
| //remove all children anyway |
| removeAllChildren(); |
| if( (newValue == null) || (newValue instanceof Datatype) ) { |
| return; |
| } |
| |
| //remove listener from old content model |
| if(oldValue != null && oldValue instanceof ContentModel) { |
| ContentModel cm = (ContentModel)oldValue; |
| cm.removeListener(this); |
| } |
| |
| //add proxy children for the new content model |
| if(newValue instanceof ContentModel) |
| Util.addProxyChildren(this, (ContentModel)newValue, null); |
| |
| if(newValue instanceof AnonymousType) { |
| List<AXIComponent> children = new ArrayList<AXIComponent>(); |
| AXIModelBuilder builder = new AXIModelBuilder(this); |
| builder.populateChildren( ((AnonymousType)newValue).getPeer(), false, children); |
| for(AXIComponent child : children) { |
| this.appendChild(child); |
| } |
| } |
| } |
| |
| /** |
| * Represents a local complex type. |
| */ |
| public static class AnonymousType implements AXIType { |
| private SchemaComponent schemaComponent; |
| public AnonymousType(SchemaComponent schemaComponent) { |
| this.schemaComponent = schemaComponent; |
| } |
| public String getName() { |
| return null; |
| } |
| public void accept(AXIVisitor visitor) { |
| } |
| public SchemaComponent getPeer() { |
| return schemaComponent; |
| } |
| } |
| |
| /** |
| * Overwrites addCompositor of AXIContainer. |
| */ |
| public void addCompositor(Compositor compositor) { |
| if( getType() != null && getType() instanceof ContentModel && |
| getModel() != ((ContentModel)getType()).getModel() ) { |
| //no drops allowed when the element's type |
| //belongs to some other model |
| return; |
| } |
| |
| if(getType() instanceof Datatype) { |
| setType(new AnonymousType(null)); |
| } |
| super.addCompositor(compositor); |
| } |
| |
| /** |
| * Overwrites addAttribute of AXIContainer. |
| */ |
| public void addAttribute(AbstractAttribute attribute) { |
| AXIType type = getType(); |
| if(type != null && type instanceof ContentModel) { |
| ((ContentModel)type).addAttribute(attribute); |
| return; |
| } |
| |
| if(type instanceof Datatype) { |
| setType(new AnonymousType(null)); |
| } |
| |
| super.addAttribute(attribute); |
| } |
| |
| |
| private AXIType axiType; |
| private SchemaComponent typeSchemaComponent; |
| } |