blob: 27bbabbee7efd29200995f8320b794d52b55e2aa [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2001, 2004 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.wst.xsd.ui.internal.actions;
import java.util.ArrayList;
import java.util.Iterator;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.wst.sse.core.format.IStructuredFormatProcessor;
import org.eclipse.wst.xml.core.document.XMLModel;
import org.eclipse.wst.xml.core.document.XMLNode;
import org.eclipse.wst.xml.core.format.FormatProcessorXML;
import org.eclipse.wst.xml.core.internal.document.DocumentImpl;
import org.eclipse.wst.xsd.ui.internal.XSDEditorPlugin;
import org.eclipse.wst.xsd.ui.internal.util.TypesHelper;
import org.eclipse.wst.xsd.ui.internal.util.XSDDOMHelper;
import org.eclipse.wst.xsd.ui.internal.widgets.SetBaseTypeDialog;
import org.eclipse.xsd.XSDComplexTypeDefinition;
import org.eclipse.xsd.XSDConcreteComponent;
import org.eclipse.xsd.XSDSchema;
import org.eclipse.xsd.XSDTypeDefinition;
import org.eclipse.xsd.util.XSDConstants;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class SetBaseTypeAction extends Action
{
XSDSchema xsdSchema;
Element element;
String type = "";
String derivedByString = "";
XSDDOMHelper domHelper;
/**
* Constructor for SetBaseTypeAction.
*/
public SetBaseTypeAction()
{
super();
domHelper = new XSDDOMHelper();
}
/**
* Constructor for SetBaseTypeAction.
* @param arg0
*/
public SetBaseTypeAction(String arg0)
{
super(arg0);
domHelper = new XSDDOMHelper();
}
/**
* Constructor for SetBaseTypeAction.
* @param arg0
* @param arg1
*/
public SetBaseTypeAction(String arg0, ImageDescriptor arg1)
{
super(arg0, arg1);
domHelper = new XSDDOMHelper();
}
/**
* Constructor for SetBaseTypeAction.
* @param arg0
* @param arg1
*/
public SetBaseTypeAction(String arg0, int arg1)
{
super(arg0, arg1);
domHelper = new XSDDOMHelper();
}
public void setXSDSchema(XSDSchema schema)
{
this.xsdSchema = schema;
}
public void setComplexTypeElement(Element element)
{
this.element = element;
}
public void setType(String type)
{
this.type = type;
}
public void setDerivedBy(String derivedByString)
{
this.derivedByString = derivedByString;
}
public void run()
{
Display display = Display.getCurrent();
// if it is null, get the default one
display = display == null ? Display.getDefault() : display;
Shell parentShell = display.getActiveShell();
SetBaseTypeDialog dialog = new SetBaseTypeDialog(parentShell, xsdSchema, element);
dialog.setBlockOnOpen(true);
Element contentModelElement = domHelper.getContentModelFromParent(element);
if (contentModelElement != null)
{
// to set the current values to show in the dialog
if (XSDDOMHelper.inputEquals(contentModelElement, XSDConstants.COMPLEXCONTENT_ELEMENT_TAG, false) ||
XSDDOMHelper.inputEquals(contentModelElement, XSDConstants.SIMPLECONTENT_ELEMENT_TAG, false))
{
Element derivedByElement = domHelper.getDerivedByElementFromComplexType(element);
if (derivedByElement != null)
{
String currentBaseType = derivedByElement.getAttribute(XSDConstants.BASE_ATTRIBUTE);
dialog.setCurrentBaseType(currentBaseType);
dialog.setCurrentDerivedBy(derivedByElement.getLocalName());
}
else
{
dialog.setCurrentBaseType("");
dialog.setCurrentDerivedBy("");
}
}
}
int result = dialog.open();
if (result == Window.OK)
{
type = dialog.getBaseType();
derivedByString = dialog.getDerivedBy();
performAction();
}
}
XSDTypeDefinition newTypeDefinition = null;
public XSDTypeDefinition getXSDTypeDefinition()
{
return newTypeDefinition;
}
public void performAction()
{
TypesHelper helper = new TypesHelper(xsdSchema);
XSDConcreteComponent xsdComp = xsdSchema.getCorrespondingComponent(element);
Element contentModelElement = domHelper.getContentModelFromParent(element);
boolean contentModelExists = true;
if (contentModelElement == null)
{
contentModelExists = false;
}
// get XSD component of the new type chosen
newTypeDefinition = null;
for (Iterator i = xsdSchema.getTypeDefinitions().iterator(); i.hasNext(); )
{
XSDTypeDefinition typeDef = (XSDTypeDefinition)i.next();
if (typeDef.getQName().equals(type))
{
newTypeDefinition = typeDef;
break;
}
}
boolean needsComplexContent = false;
boolean needsSimpleContent = false;
if (helper.getBuiltInTypeNamesList().contains(type) ||
helper.getUserSimpleTypeNamesList().contains(type))
// if (newTypeDefinition instanceof XSDSimpleTypeDefinition)
{
needsSimpleContent = true;
}
else if (newTypeDefinition instanceof XSDComplexTypeDefinition)
{
needsComplexContent = true;
// XSDComplexTypeDefinition newCTObj = (XSDComplexTypeDefinition)newTypeDefinition;
// XSDContentTypeCategory category = newCTObj.getContentTypeCategory();
}
beginRecording(XSDEditorPlugin.getXSDString("_UI_LABEL_SET_BASE_TYPE"), element);
String prefix = element.getPrefix();
prefix = (prefix == null) ? "" : (prefix + ":");
DOMAttribute attr = new DOMAttribute(XSDConstants.BASE_ATTRIBUTE, type);
boolean hasChildrenElements = domHelper.hasElementChildren(element);
if (!contentModelExists) // if no content model exists, then add the new nodes
{
if (helper.getBuiltInTypeNamesList().contains(type) ||
helper.getUserSimpleTypeNamesList().contains(type))
{
updateModelAndDerivedByKind(prefix + XSDConstants.SIMPLECONTENT_ELEMENT_TAG, prefix + XSDConstants.EXTENSION_ELEMENT_TAG, attr);
}
else if (helper.getUserComplexTypeNamesList().contains(type))
{
if (derivedByString.equals("")) // default
{
derivedByString = XSDConstants.EXTENSION_ELEMENT_TAG;
}
Element derivedByElement = updateModelAndDerivedByKind(prefix + XSDConstants.COMPLEXCONTENT_ELEMENT_TAG, prefix + derivedByString, attr);
Element newModelGroupElement = element.getOwnerDocument().createElementNS(XSDConstants.SCHEMA_FOR_SCHEMA_URI_2001, prefix + XSDConstants.SEQUENCE_ELEMENT_TAG);
derivedByElement.appendChild(newModelGroupElement);
formatChild(derivedByElement);
}
}
else // else there is a content model
{
if (type.equals("")) // the chosen type is blank, ie. there is no base type
{
Element derivedByElement = domHelper.getDerivedByElementFromComplexType(element);
Element sourceContentModelElement = domHelper.getContentModelFromParent(derivedByElement);
// Retain the content model if there is one from the complex or simple content derive by element
if (XSDDOMHelper.inputEquals(sourceContentModelElement, XSDConstants.SEQUENCE_ELEMENT_TAG, false) ||
XSDDOMHelper.inputEquals(sourceContentModelElement, XSDConstants.CHOICE_ELEMENT_TAG, false) ||
XSDDOMHelper.inputEquals(sourceContentModelElement, XSDConstants.ALL_ELEMENT_TAG, false))
{
Element newNode = domHelper.cloneElement(element, sourceContentModelElement);
element.replaceChild(newNode, contentModelElement);
formatChild(element);
}
else // otherwise just add the nodes
{
XSDDOMHelper.removeNodeAndWhitespace(contentModelElement);
Element newSequenceElement = element.getOwnerDocument().createElementNS(XSDConstants.SCHEMA_FOR_SCHEMA_URI_2001, prefix + XSDConstants.SEQUENCE_ELEMENT_TAG);
element.appendChild(newSequenceElement);
formatChild(newSequenceElement);
}
}
else // a base type is specified
{
Element sequenceChoiceOrAllElement = null; // copy the model to reposition it off of the new derived by element
if (XSDDOMHelper.inputEquals(contentModelElement, XSDConstants.SEQUENCE_ELEMENT_TAG, false) ||
XSDDOMHelper.inputEquals(contentModelElement, XSDConstants.CHOICE_ELEMENT_TAG, false) ||
XSDDOMHelper.inputEquals(contentModelElement, XSDConstants.ALL_ELEMENT_TAG, false))
{
sequenceChoiceOrAllElement = domHelper.cloneElement(element, contentModelElement);
}
if (needsComplexContent)
{
if (!(XSDDOMHelper.inputEquals(contentModelElement, XSDConstants.COMPLEXCONTENT_ELEMENT_TAG, false)))
{
domHelper.changeContentModel(element, XSDConstants.COMPLEXCONTENT_ELEMENT_TAG, sequenceChoiceOrAllElement);
contentModelElement = domHelper.getContentModelFromParent(element);
}
}
if (needsSimpleContent)
{
if (!(XSDDOMHelper.inputEquals(contentModelElement, XSDConstants.SIMPLECONTENT_ELEMENT_TAG, false)))
{
// we don't want to append the element content to a simple content
sequenceChoiceOrAllElement = null;
domHelper.changeContentModel(element, XSDConstants.SIMPLECONTENT_ELEMENT_TAG, sequenceChoiceOrAllElement);
contentModelElement = domHelper.getContentModelFromParent(element);
}
}
Element derivedByElement = domHelper.getDerivedByElementFromComplexType(element);
if (derivedByElement == null)
{
if (derivedByString == null || (derivedByString != null && derivedByString.equals("")))
{
derivedByString = XSDConstants.EXTENSION_ELEMENT_TAG; // since there is no derivedByElement
}
derivedByElement = element.getOwnerDocument().createElementNS(XSDConstants.SCHEMA_FOR_SCHEMA_URI_2001, derivedByString);
contentModelElement.appendChild(derivedByElement);
formatChild(contentModelElement);
if (sequenceChoiceOrAllElement != null)
{
derivedByElement.appendChild(sequenceChoiceOrAllElement);
formatChild(derivedByElement);
}
}
else
{
if (helper.getBuiltInTypeNamesList().contains(type) ||
helper.getUserSimpleTypeNamesList().contains(type))
{
derivedByString = XSDConstants.EXTENSION_ELEMENT_TAG;
Element aContentModelElement = domHelper.getContentModelFromParent(derivedByElement);
if (aContentModelElement != null)
{
XSDDOMHelper.removeNodeAndWhitespace(aContentModelElement);
}
}
domHelper.changeDerivedByType(contentModelElement, derivedByString, type);
}
derivedByElement.setAttribute(attr.getName(), attr.getValue());
}
}
xsdComp.setElement(element);
endRecording(element);
}
private Element updateModelAndDerivedByKind(String modelType, String derivedByKind, DOMAttribute attr)
{
Element newContentModelElement = element.getOwnerDocument().createElementNS(XSDConstants.SCHEMA_FOR_SCHEMA_URI_2001, modelType);
element.appendChild(newContentModelElement);
Element newDerivedByElement = element.getOwnerDocument().createElementNS(XSDConstants.SCHEMA_FOR_SCHEMA_URI_2001, derivedByKind);
newContentModelElement.appendChild(newDerivedByElement);
newDerivedByElement.setAttribute(attr.getName(), attr.getValue());
NodeList children = element.getChildNodes();
int length = children.getLength();
ArrayList nodesToRemove = new ArrayList();
for (int i = 0; i < length; i++)
{
Node node = children.item(i);
if (XSDDOMHelper.inputEquals(node, XSDConstants.ATTRIBUTE_ELEMENT_TAG, false) ||
XSDDOMHelper.inputEquals(node, XSDConstants.ATTRIBUTE_ELEMENT_TAG, true) ||
XSDDOMHelper.inputEquals(node, XSDConstants.ATTRIBUTEGROUP_ELEMENT_TAG, true) ||
XSDDOMHelper.inputEquals(node, XSDConstants.ANYATTRIBUTE_ELEMENT_TAG, false))
{
newDerivedByElement.appendChild(node.cloneNode(true));
nodesToRemove.add(node);
}
}
for (Iterator i = nodesToRemove.iterator(); i.hasNext(); )
{
XSDDOMHelper.removeNodeAndWhitespace((Node)i.next());
}
formatChild(newContentModelElement);
return newDerivedByElement;
}
protected void formatChild(Element child)
{
if (child instanceof XMLNode)
{
XMLModel model = ((XMLNode)child).getModel();
try
{
// tell the model that we are about to make a big model change
model.aboutToChangeModel();
IStructuredFormatProcessor formatProcessor = new FormatProcessorXML();
formatProcessor.formatNode(child);
}
finally
{
// tell the model that we are done with the big model change
model.changedModel();
}
}
}
public DocumentImpl getDocument(Element element)
{
return (DocumentImpl) element.getOwnerDocument();
}
public void beginRecording(String description, Element element)
{
getDocument(element).getModel().beginRecording(this, description);
}
public void endRecording(Element element)
{
DocumentImpl doc = (DocumentImpl) getDocument(element);
doc.getModel().endRecording(this);
}
}