blob: 43e49c97555d105be34e355c3380471cd724292f [file] [log] [blame]
/*
* 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;
}