/******************************************************************************* * Copyright (c) 2006 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.editor; import java.util.List; import org.eclipse.xsd.XSDAttributeDeclaration; import org.eclipse.xsd.XSDAttributeGroupDefinition; import org.eclipse.xsd.XSDConcreteComponent; import org.eclipse.xsd.XSDElementDeclaration; import org.eclipse.xsd.XSDIdentityConstraintDefinition; import org.eclipse.xsd.XSDModelGroupDefinition; import org.eclipse.xsd.XSDSchema; import org.eclipse.xsd.XSDSchemaDirective; import org.eclipse.xsd.XSDSimpleTypeDefinition; import org.eclipse.xsd.XSDTypeDefinition; import org.eclipse.xsd.XSDVariety; import org.eclipse.xsd.util.XSDConstants; import org.eclipse.xsd.util.XSDSwitch; /** * A custom XSDSwitch used to locate the "referenced" component. Used by the * hyperlink/F3 navigation mechanism. Made a separate class because it is used * from the WSDL editor as well. */ public class XSDHyperlinkTargetLocator extends XSDSwitch { /** * Holds the attribute name if the cursor/mouse is over an attribute. */ private String attributeName; /* * (non-Javadoc) * * @see org.eclipse.xsd.util.XSDSwitch#caseXSDAttributeDeclaration(org.eclipse.xsd.XSDAttributeDeclaration) */ public Object caseXSDAttributeDeclaration(XSDAttributeDeclaration attributeDeclaration) { XSDConcreteComponent target = null; if (attributeDeclaration.isAttributeDeclarationReference()) { target = attributeDeclaration.getResolvedAttributeDeclaration(); } else if (attributeDeclaration.getAnonymousTypeDefinition() == null) { target = attributeDeclaration.getTypeDefinition(); // Avoid navigating to built in data types. if (isFromSchemaForSchema(target)) { target = null; } } return target; } /* * (non-Javadoc) * * @see org.eclipse.xsd.util.XSDSwitch#caseXSDAttributeGroupDefinition(org.eclipse.xsd.XSDAttributeGroupDefinition) */ public Object caseXSDAttributeGroupDefinition(XSDAttributeGroupDefinition attributeGroupDefinition) { XSDConcreteComponent target = null; if (attributeGroupDefinition.isAttributeGroupDefinitionReference()) { target = attributeGroupDefinition.getResolvedAttributeGroupDefinition(); } return target; } /* * (non-Javadoc) * * @see org.eclipse.xsd.util.XSDSwitch#caseXSDElementDeclaration(org.eclipse.xsd.XSDElementDeclaration) */ public Object caseXSDElementDeclaration(XSDElementDeclaration elementDeclaration) { XSDConcreteComponent target = null; if (elementDeclaration.isElementDeclarationReference()) { target = elementDeclaration.getResolvedElementDeclaration(); } else { XSDConcreteComponent typeDefinition = null; if (elementDeclaration.getAnonymousTypeDefinition() == null) { typeDefinition = elementDeclaration.getTypeDefinition(); } XSDConcreteComponent substitutionGroupAffiliation = elementDeclaration.getSubstitutionGroupAffiliation(); if (typeDefinition != null && substitutionGroupAffiliation != null) { // There are 2 things we can navigate to: if the cursor is anywhere on // the // substitution attribute then jump to that, otherwise just go to the // base type. if (XSDConstants.SUBSTITUTIONGROUP_ATTRIBUTE.equals(attributeName)) { target = substitutionGroupAffiliation; } else { target = typeDefinition; } } else { target = typeDefinition != null ? typeDefinition : substitutionGroupAffiliation; } if (isFromSchemaForSchema(target)) { target = null; } } return target; } /* * (non-Javadoc) * * @see org.eclipse.xsd.util.XSDSwitch#caseXSDIdentityConstraintDefinition(org.eclipse.xsd.XSDIdentityConstraintDefinition) */ public Object caseXSDIdentityConstraintDefinition(XSDIdentityConstraintDefinition idConstraintDefinition) { Object target = null; XSDIdentityConstraintDefinition referencedKey = idConstraintDefinition.getReferencedKey(); if (referencedKey != null) { target = referencedKey; } return target; } /* * (non-Javadoc) * * @see org.eclipse.xsd.util.XSDSwitch#caseXSDModelGroupDefinition(org.eclipse.xsd.XSDModelGroupDefinition) */ public Object caseXSDModelGroupDefinition(XSDModelGroupDefinition modelGroupDefinition) { XSDConcreteComponent target = null; if (modelGroupDefinition.isModelGroupDefinitionReference()) { target = modelGroupDefinition.getResolvedModelGroupDefinition(); } return target; } /* * (non-Javadoc) * * @see org.eclipse.xsd.util.XSDSwitch#caseXSDSchemaDirective(org.eclipse.xsd.XSDSchemaDirective) */ public Object caseXSDSchemaDirective(XSDSchemaDirective directive) { XSDSchema schema = directive.getResolvedSchema(); return schema; } public Object caseXSDSimpleTypeDefinition(XSDSimpleTypeDefinition typeDefinition) { XSDConcreteComponent target = null; // Simple types can be one of: atomic, list or union. XSDVariety variety = typeDefinition.getVariety(); int varietyType = variety.getValue(); switch (varietyType) { case XSDVariety.ATOMIC: { target = typeDefinition.getBaseTypeDefinition(); } break; case XSDVariety.LIST: { target = typeDefinition.getItemTypeDefinition(); } break; case XSDVariety.UNION: { List memberTypes = typeDefinition.getMemberTypeDefinitions(); if (memberTypes != null && memberTypes.size() > 0) { // ISSUE: What if there are more than one type? // This could be a case for multiple hyperlinks at the same // location. target = (XSDConcreteComponent) memberTypes.get(0); } } break; } // Avoid navigating to built in data types. if (isFromSchemaForSchema(target)) { target = null; } return target; } /* * (non-Javadoc) * * @see org.eclipse.xsd.util.XSDSwitch#caseXSDTypeDefinition(org.eclipse.xsd.XSDTypeDefinition) */ public Object caseXSDTypeDefinition(XSDTypeDefinition typeDefinition) { XSDConcreteComponent target = null; XSDTypeDefinition baseType = typeDefinition.getBaseType(); if (baseType != null) { target = baseType; } // Avoid navigating to built in data types. if (isFromSchemaForSchema(target)) { target = null; } return target; } /** * Detects if a given schema component is from the schema for schema (built in * data types). Used to avoid navigating to this type of components as they * don't have an accessible physical location. * * @param component the component to check. * @return true if the component is from the schema for schema namespace, * false otherwise. */ public boolean isFromSchemaForSchema(XSDConcreteComponent component) { if (component == null) { return false; } XSDSchema schema = component.getSchema(); if (schema != null && schema.equals(schema.getSchemaForSchema())) { return true; } return false; } /** * Locates the target component - for example the element declaration pointed * to by an element reference, etc. * * @param component the current component. * @param attributeName the attribute name if the cursor/mouse is over an * attribute. This is used to provide fine grained navigation for * components with more than one "active" attribute. * @return the referenced XSD concrete component or null if none is found. */ public XSDConcreteComponent locate(XSDConcreteComponent component, String attributeName) { this.attributeName = attributeName; return (XSDConcreteComponent) doSwitch(component); } }