/******************************************************************************* * Copyright (c) 2001, 2009 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.navigation; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.eclipse.emf.common.notify.Adapter; import org.eclipse.emf.ecore.EObject; import org.eclipse.gef.GraphicalViewer; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IMemento; import org.eclipse.ui.INavigationLocation; import org.eclipse.ui.NavigationLocation; import org.eclipse.wst.xsd.ui.internal.adapters.XSDAdapterFactory; import org.eclipse.wst.xsd.ui.internal.adapters.XSDVisitor; import org.eclipse.wst.xsd.ui.internal.adt.design.DesignViewGraphicalViewer; import org.eclipse.wst.xsd.ui.internal.adt.facade.IADTObject; import org.eclipse.xsd.XSDAttributeGroupDefinition; import org.eclipse.xsd.XSDConcreteComponent; import org.eclipse.xsd.XSDElementDeclaration; import org.eclipse.xsd.XSDModelGroupDefinition; import org.eclipse.xsd.XSDRedefine; import org.eclipse.xsd.XSDSchema; import org.eclipse.xsd.XSDTypeDefinition; import com.ibm.icu.util.StringTokenizer; /** * This class exists to support navigation in a context where there is no text * editor page. In these cases we can't rely on the TextSelectionNavigationLocations * so we this class which is designed to work with just the design view. */ public class DesignViewNavigationLocation extends NavigationLocation { protected Path path; private static final String PATH_TAG = "path"; //$NON-NLS-1$ public DesignViewNavigationLocation(IEditorPart part) { super(part); this.path = new Path(); } public DesignViewNavigationLocation(IEditorPart part, XSDConcreteComponent component) { super(part); this.path = Path.computePath(component); } public boolean mergeInto(INavigationLocation currentLocation) { boolean result = false; if (currentLocation instanceof DesignViewNavigationLocation) { DesignViewNavigationLocation loc = (DesignViewNavigationLocation) currentLocation; result = loc.path.toString().equals(path.toString()); } else { } return result; } public void restoreLocation() { XSDSchema schema = (XSDSchema) getEditorPart().getAdapter(XSDSchema.class); Object viewer = getEditorPart().getAdapter(GraphicalViewer.class); if (viewer instanceof DesignViewGraphicalViewer) { DesignViewGraphicalViewer graphicalViewer = (DesignViewGraphicalViewer) viewer; XSDConcreteComponent component = Path.computeComponent(schema, path); if (component != null) { Adapter adapter = XSDAdapterFactory.getInstance().adapt(component); if (adapter instanceof IADTObject) { graphicalViewer.setInput((IADTObject)adapter); } } else if (path.segments.isEmpty()) { Adapter adapter = XSDAdapterFactory.getInstance().adapt(schema); if (adapter instanceof IADTObject) { graphicalViewer.setInput((IADTObject)adapter); } } } } public void restoreState(IMemento memento) { String string = memento.getString(PATH_TAG); path = Path.createPath(string); } public void saveState(IMemento memento) { memento.putString(PATH_TAG, path.toString()); } public void update() { // TODO (cs) not sure what needs to be done here } static class PathSegment { final static int ELEMENT = 1; final static int TYPE = 2; final static int MODEL_GROUP = 3; final static int ATTRIBUTE_GROUP = 4; final static int REDEFINE = 5; int kind; String name; PathSegment() { } PathSegment(int kind, String name) { this.kind = kind; this.name = name; } } protected static class Path { private static final String REDEFINE_TOKEN = "redefine"; //$NON-NLS-1$ private static final String MODEL_GROUP_TOKEN = "modelGroup"; //$NON-NLS-1$ private static final String ATTRIBUTE_GROUP_TOKEN = "attributeGroup"; //$NON-NLS-1$ private static final String TYPE_TOKEN = "type"; //$NON-NLS-1$ private static final String ELEMENT_TOKEN = "element"; //$NON-NLS-1$ List segments = new ArrayList(); public static XSDConcreteComponent computeComponent(XSDSchema schema, Path path) { PathResolvingXSDVisitor visitor = new PathResolvingXSDVisitor(path); visitor.visitSchema(schema); if (visitor.isDone()) { return visitor.result; } return null; } static Path createPath(String pathString) { Path path = new Path(); PathSegment segment = null; for (StringTokenizer st = new StringTokenizer(pathString, "/"); st.hasMoreTokens();) { String token = st.nextToken(); int kind = -1; if (token.startsWith(ELEMENT_TOKEN)) { kind = PathSegment.ELEMENT; } else if (token.startsWith(TYPE_TOKEN)) { kind = PathSegment.TYPE; } else if (token.startsWith(ATTRIBUTE_GROUP_TOKEN)) { kind = PathSegment.ATTRIBUTE_GROUP; } else if (token.startsWith(MODEL_GROUP_TOKEN)) { kind = PathSegment.MODEL_GROUP; } else if (token.startsWith(REDEFINE_TOKEN)) { kind = PathSegment.REDEFINE; } if (kind != -1) { segment = new PathSegment(); segment.kind = kind; path.segments.add(segment); String namePattern = "[@name='"; int startIndex = token.indexOf(namePattern); if (startIndex != -1) { startIndex += namePattern.length(); int endIndex = token.indexOf("']"); if (endIndex != -1) { segment.name = token.substring(startIndex, endIndex); } } } } return path; } public static Path computePath(XSDConcreteComponent component) { Path path = new Path(); for (EObject c = component; c != null; c = c.eContainer()) { if (c instanceof XSDConcreteComponent) { PathSegment segment = computePathSegment((XSDConcreteComponent) c); if (segment != null) { path.segments.add(0, segment); } } } return path; } static PathSegment computePathSegment(XSDConcreteComponent component) { PathSegment pathSegment = null; if (component instanceof XSDElementDeclaration) { XSDElementDeclaration elementDeclaration = (XSDElementDeclaration) component; pathSegment = new PathSegment(PathSegment.ELEMENT, elementDeclaration.getResolvedElementDeclaration().getName()); } else if (component instanceof XSDTypeDefinition) { XSDTypeDefinition typeDefinition = (XSDTypeDefinition) component; pathSegment = new PathSegment(PathSegment.TYPE, typeDefinition.getName()); } else if (component instanceof XSDModelGroupDefinition) { XSDModelGroupDefinition modelGroupDefinition = (XSDModelGroupDefinition) component; pathSegment = new PathSegment(PathSegment.MODEL_GROUP, modelGroupDefinition.getName()); } else if (component instanceof XSDAttributeGroupDefinition) { XSDAttributeGroupDefinition attributeGroupDefinition = (XSDAttributeGroupDefinition) component; pathSegment = new PathSegment(PathSegment.ATTRIBUTE_GROUP, attributeGroupDefinition.getResolvedAttributeGroupDefinition().getName()); } else if (component instanceof XSDRedefine) { XSDRedefine redefine = (XSDRedefine) component; pathSegment = new PathSegment(PathSegment.REDEFINE, redefine.getSchemaLocation()); } return pathSegment; } public String toString() { StringBuffer b = new StringBuffer(); for (Iterator i = segments.iterator(); i.hasNext();) { PathSegment segment = (PathSegment) i.next(); String kind = ""; if (segment.kind == PathSegment.ELEMENT) { kind = ELEMENT_TOKEN; } else if (segment.kind == PathSegment.TYPE) { kind = TYPE_TOKEN; } else if (segment.kind == PathSegment.MODEL_GROUP) { kind = MODEL_GROUP_TOKEN; } else if (segment.kind == PathSegment.ATTRIBUTE_GROUP) { kind = ATTRIBUTE_GROUP_TOKEN; } else if (segment.kind == PathSegment.REDEFINE) { kind = REDEFINE_TOKEN; } b.append(kind); if (segment.name != null) { b.append("[@name='" + segment.name + "']"); } if (i.hasNext()) { b.append("/"); } } return b.toString(); } } static class PathResolvingXSDVisitor extends XSDVisitor { Path path; int index = -1; PathSegment segment; XSDConcreteComponent result = null; PathResolvingXSDVisitor(Path path) { this.path = path; incrementSegment(); } boolean isDone() { return index >= path.segments.size(); } void incrementSegment() { index++; if (index < path.segments.size()) { segment = (PathSegment) path.segments.get(index); } else { segment = null; } } public void visitSchema(XSDSchema schema) { if (segment != null) { if (segment.kind == PathSegment.ELEMENT) { XSDElementDeclaration elementDeclaration = schema.resolveElementDeclaration(segment.name); if (elementDeclaration != null) { visitElementDeclaration(elementDeclaration); } } else if (segment.kind == PathSegment.TYPE) { XSDTypeDefinition typeDefinition = schema.resolveTypeDefinition(segment.name); if (typeDefinition != null) { visitTypeDefinition(typeDefinition); } } else if (segment.kind == PathSegment.MODEL_GROUP) { XSDModelGroupDefinition modelGroupDefinition = schema.resolveModelGroupDefinition(segment.name); if (modelGroupDefinition != null) { visitModelGroupDefinition(modelGroupDefinition); } } else if (segment.kind == PathSegment.ATTRIBUTE_GROUP) { XSDAttributeGroupDefinition attributeGroupDefinition = schema.resolveAttributeGroupDefinition(segment.name); if (attributeGroupDefinition != null) { visitAttributeGroupDefinition(attributeGroupDefinition); } } else if (segment.kind == PathSegment.REDEFINE) { Iterator iterator = schema.getContents().iterator(); while (iterator.hasNext()) { Object object = iterator.next(); if (object instanceof XSDRedefine) { XSDRedefine redefine = (XSDRedefine)object; visitRedefine(redefine); } } } } } public void visitElementDeclaration(XSDElementDeclaration element) { if (segment != null) { String name = element.getResolvedElementDeclaration().getName(); if (segment.kind == PathSegment.ELEMENT && isMatch(segment.name, name)) { result = element; incrementSegment(); if (!isDone()) { super.visitElementDeclaration(element); } } } } public void visitTypeDefinition(XSDTypeDefinition type) { if (segment != null) { String name = type.getName(); if (segment.kind == PathSegment.TYPE && isMatch(segment.name, name)) { result = type; incrementSegment(); if (!isDone()) { super.visitTypeDefinition(type); } } } } public void visitModelGroupDefinition(XSDModelGroupDefinition modelGroup) { if (segment != null) { String name = modelGroup.getName(); if (segment.kind == PathSegment.MODEL_GROUP && isMatch(segment.name, name)) { result = modelGroup; incrementSegment(); if (!isDone()) { super.visitModelGroupDefinition(modelGroup); } } } } public void visitAttributeGroupDefinition(XSDAttributeGroupDefinition attributeGroup) { if (segment != null) { String name = attributeGroup.getName(); if (segment.kind == PathSegment.ATTRIBUTE_GROUP && isMatch(segment.name, name)) { result = attributeGroup; incrementSegment(); if (!isDone()) { super.visitAttributeGroupDefinition(attributeGroup); } } } } public void visitRedefine(XSDRedefine redefine) { if (segment != null) { String name = redefine.getSchemaLocation(); if (segment.kind == PathSegment.REDEFINE && isMatch(segment.name, name)) { result = redefine; incrementSegment(); if (!isDone()) { visitSchema(redefine.getSchema()); } } } } protected boolean isMatch(String name1, String name2) { return name1 != null ? name1.equals(name2) : name1 == name2; } } }