[146333] F3/Hyperlink navigation does not work between XSD components in an inline
diff --git a/bundles/org.eclipse.wst.xsd.ui/src-adt-xsd/org/eclipse/wst/xsd/ui/internal/editor/XSDHyperlinkDetector.java b/bundles/org.eclipse.wst.xsd.ui/src-adt-xsd/org/eclipse/wst/xsd/ui/internal/editor/XSDHyperlinkDetector.java
index 5c553a9..8e27f14 100644
--- a/bundles/org.eclipse.wst.xsd.ui/src-adt-xsd/org/eclipse/wst/xsd/ui/internal/editor/XSDHyperlinkDetector.java
+++ b/bundles/org.eclipse.wst.xsd.ui/src-adt-xsd/org/eclipse/wst/xsd/ui/internal/editor/XSDHyperlinkDetector.java
@@ -12,8 +12,6 @@
 
 package org.eclipse.wst.xsd.ui.internal.editor;
 
-import java.util.List;
-
 import org.eclipse.jface.text.IDocument;
 import org.eclipse.jface.text.IRegion;
 import org.eclipse.jface.text.hyperlink.IHyperlink;
@@ -23,17 +21,8 @@
 import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;
 import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode;
 import org.eclipse.wst.xsd.ui.internal.text.XSDModelAdapter;
-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.w3c.dom.Attr;
 
@@ -106,157 +95,19 @@
    */
   private XSDConcreteComponent getTargetXSDComponent(XSDSchema xsdSchema, IDOMNode node)
   {
-    XSDConcreteComponent component = null;
+    XSDConcreteComponent xsdComponent = xsdSchema.getCorrespondingComponent(node);
 
-    XSDConcreteComponent xsdComp = xsdSchema.getCorrespondingComponent(node);
-    if (xsdComp instanceof XSDElementDeclaration)
-    {
-      XSDElementDeclaration elementDecl = (XSDElementDeclaration) xsdComp;
-      if (elementDecl.isElementDeclarationReference())
-      {
-        component = elementDecl.getResolvedElementDeclaration();
-      }
-      else
-      {
-        XSDConcreteComponent typeDef = null;
-        if (elementDecl.getAnonymousTypeDefinition() == null)
-        {
-          typeDef = elementDecl.getTypeDefinition();
-        }
-
-        XSDConcreteComponent subGroupAffiliation = elementDecl.getSubstitutionGroupAffiliation();
-
-        if (typeDef != null && subGroupAffiliation != null)
-        {
-          // we have 2 things we can navigate to, if the
-          // cursor is anywhere on the substitution
-          // attribute
-          // then jump to that, otherwise just go to the
-          // typeDef.
-          if (node instanceof Attr && ((Attr) node).getLocalName().equals(XSDConstants.SUBSTITUTIONGROUP_ATTRIBUTE))
-          {
-            component = subGroupAffiliation;
-          }
-          else
-          {
-            // try to reveal the type now. On success,
-            // then we return true.
-            // if we fail, set the substitution group
-            // as
-            // the object to reveal as a backup plan.
-            // ISSUE: how to set backup?
-            // if (revealObject(typeDef)) {
-            component = typeDef;
-            // }
-            // else {
-            // objectToReveal = subGroupAffiliation;
-            // }
-          }
-        }
-        else
-        {
-          // one or more of these is null. If the
-          // typeDef is
-          // non-null, use it. Otherwise
-          // try and use the substitution group
-          component = typeDef != null ? typeDef : subGroupAffiliation;
-        }
-      }
-    }
-    else if (xsdComp instanceof XSDModelGroupDefinition)
-    {
-      XSDModelGroupDefinition elementDecl = (XSDModelGroupDefinition) xsdComp;
-      if (elementDecl.isModelGroupDefinitionReference())
-      {
-        component = elementDecl.getResolvedModelGroupDefinition();
-      }
-    }
-    else if (xsdComp instanceof XSDAttributeDeclaration)
-    {
-      XSDAttributeDeclaration attrDecl = (XSDAttributeDeclaration) xsdComp;
-      if (attrDecl.isAttributeDeclarationReference())
-      {
-        component = attrDecl.getResolvedAttributeDeclaration();
-      }
-      else if (attrDecl.getAnonymousTypeDefinition() == null)
-      {
-        component = attrDecl.getTypeDefinition();
-      }
-    }
-    else if (xsdComp instanceof XSDAttributeGroupDefinition)
-    {
-      XSDAttributeGroupDefinition attrGroupDef = (XSDAttributeGroupDefinition) xsdComp;
-      if (attrGroupDef.isAttributeGroupDefinitionReference())
-      {
-        component = attrGroupDef.getResolvedAttributeGroupDefinition();
-      }
-    }
-    else if (xsdComp instanceof XSDIdentityConstraintDefinition)
-    {
-      XSDIdentityConstraintDefinition idConstraintDef = (XSDIdentityConstraintDefinition) xsdComp;
-      if (idConstraintDef.getReferencedKey() != null)
-      {
-        component = idConstraintDef.getReferencedKey();
-      }
-    }
-    else if (xsdComp instanceof XSDSimpleTypeDefinition)
-    {
-      XSDSimpleTypeDefinition typeDef = (XSDSimpleTypeDefinition) xsdComp;
-
-      // Simple types can be one of restriction, list or union.
-
-      XSDVariety variety = typeDef.getVariety();
-      int varietyType = variety.getValue();
-      
-      switch (varietyType)
-      {
-        case XSDVariety.ATOMIC : 
-          {
-            component = typeDef.getBaseTypeDefinition();
-          }
-          break;
-        case XSDVariety.LIST : 
-          {
-            component = typeDef.getItemTypeDefinition();
-          }
-          break;
-        case XSDVariety.UNION : 
-          {
-            List memberTypes = typeDef.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.
-              component = (XSDConcreteComponent) memberTypes.get(0);
-            }
-          }
-          break;
-      }
-    }
-    else if (xsdComp instanceof XSDTypeDefinition)
-    {
-      XSDTypeDefinition typeDef = (XSDTypeDefinition) xsdComp;
-      component = typeDef.getBaseType();
-    }
-    else if (xsdComp instanceof XSDSchemaDirective)
-    {
-      XSDSchemaDirective directive = (XSDSchemaDirective) xsdComp;
-      component = directive.getResolvedSchema();
-    }
-
-    // Avoid types located in the schema for schema (the built in XSD types) 
-    // as we don't want to navigate to their definition.
+    String attributeName = null;
     
-    if (component != null)
+    if (node instanceof Attr)
     {
-      XSDSchema schema =  component.getSchema();
-
-      if (schema != null && schema.equals(schema.getSchemaForSchema())) {
-        component = null;
-      }
+      Attr attribute = (Attr)node;
+      attributeName = attribute != null ? attribute.getName(): null;
     }
     
+    XSDHyperlinkTargetLocator xsdHyperlinkTargetLocator = new XSDHyperlinkTargetLocator();
+    XSDConcreteComponent component = xsdHyperlinkTargetLocator.locate(xsdComponent, attributeName); 
+    
     return component;
   }
 
diff --git a/bundles/org.eclipse.wst.xsd.ui/src-adt-xsd/org/eclipse/wst/xsd/ui/internal/editor/XSDHyperlinkTargetLocator.java b/bundles/org.eclipse.wst.xsd.ui/src-adt-xsd/org/eclipse/wst/xsd/ui/internal/editor/XSDHyperlinkTargetLocator.java
new file mode 100644
index 0000000..c04aebd
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsd.ui/src-adt-xsd/org/eclipse/wst/xsd/ui/internal/editor/XSDHyperlinkTargetLocator.java
@@ -0,0 +1,301 @@
+/*******************************************************************************
+ * 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);
+  }
+}
diff --git a/bundles/org.eclipse.wst.xsd.ui/src-adt-xsd/org/eclipse/wst/xsd/ui/internal/utils/OpenOnSelectionHelper.java b/bundles/org.eclipse.wst.xsd.ui/src-adt-xsd/org/eclipse/wst/xsd/ui/internal/utils/OpenOnSelectionHelper.java
index d25ee7c..9d5ca46 100644
--- a/bundles/org.eclipse.wst.xsd.ui/src-adt-xsd/org/eclipse/wst/xsd/ui/internal/utils/OpenOnSelectionHelper.java
+++ b/bundles/org.eclipse.wst.xsd.ui/src-adt-xsd/org/eclipse/wst/xsd/ui/internal/utils/OpenOnSelectionHelper.java
@@ -182,6 +182,10 @@
     {
       objects = schema.getModelGroupDefinitions();
     }
+    else if (comp instanceof XSDAttributeDeclaration)
+    {
+      objects = schema.getAttributeDeclarations();
+    }
 
     if (objects != null)
     {