| /******************************************************************************* |
| * Copyright (c) 2002, 2003 GEBIT Gesellschaft fuer EDV-Beratung |
| * und Informatik-Technologien mbH, |
| * Berlin, Duesseldorf, Frankfurt (Germany) and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Common Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/cpl-v10.html |
| * |
| * Contributors: |
| * GEBIT Gesellschaft fuer EDV-Beratung und Informatik-Technologien mbH - initial API and implementation |
| * IBM Corporation - bug fixes |
| *******************************************************************************/ |
| |
| package org.eclipse.ant.internal.ui.editor.xml; |
| |
| import java.io.File; |
| import java.text.MessageFormat; |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import org.apache.xerces.util.URI; |
| import org.apache.xerces.util.URI.MalformedURIException; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.runtime.IAdaptable; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.ant.internal.ui.editor.AntEditorException; |
| import org.eclipse.ant.internal.ui.model.AntUtil; |
| |
| /** |
| * General representation of an xml element. |
| * <P> |
| * Here an xml element is refered to as what is specified using like |
| * '<elementName>' in an xml file. |
| * |
| */ |
| public class XmlElement implements IAdaptable { |
| |
| /* |
| * (T) |
| * Eventually extract an interface XmlSourceRange in respect to |
| * ISourceReference that contains the two methods getOffset and |
| * getLength |
| */ |
| |
| |
| /** |
| * The offset of the corresponding source. |
| * @see #getOffset() |
| */ |
| protected int offset; |
| |
| |
| /** |
| * The length of the corresponding source. |
| * @see #getLength() |
| */ |
| protected int length; |
| |
| |
| /** |
| * The parent node. |
| */ |
| protected XmlElement parent; |
| |
| |
| /** |
| * The attributes. |
| */ |
| protected List attributes = new ArrayList(); |
| |
| |
| /** |
| * The child nodes. |
| */ |
| protected List childNodes = new ArrayList(); |
| |
| |
| /** |
| * The (tag-)name of the element. |
| */ |
| protected String name; |
| |
| |
| /** |
| * The startingRow where the element begins at. |
| * <P> |
| * The first startingRow has the index '1'. |
| */ |
| protected int startingRow; |
| |
| |
| /** |
| * The startingColumn where the element begins at. |
| * <P> |
| * The first startingColumn has the index '1'. |
| */ |
| protected int startingColumn; |
| |
| |
| /** |
| * The row where the element ends at. |
| * <P> |
| * The first ending row has the index '1'. |
| */ |
| protected int endingRow; |
| |
| |
| /** |
| * The column where the element ends at. |
| * <P> |
| * The first ending column has the index '1'. |
| * The ending column is actually the index on this line after '>'. |
| */ |
| protected int endingColumn; |
| |
| /** |
| * Whether this element has been generated as part of an element hierarchy |
| * this is not complete as a result of an error. |
| */ |
| private boolean isErrorNode; |
| |
| /** |
| * The absolute file system path of the file this element is |
| * defined within. |
| */ |
| private String filePath; |
| |
| /** |
| * Whether this element has been generated from an external entity definition |
| */ |
| private boolean isExternal = false; |
| |
| /** |
| * Whether this element is the root external element generated from an external entity definition |
| */ |
| private boolean isRootExternal = false; |
| |
| /** |
| * The unique (in the corresponding element tree) path of this element. |
| */ |
| private String fElementPath; |
| |
| /** |
| * The (not necessarily unique) identifier of this element. |
| */ |
| private String fElementIdentifier; |
| |
| |
| /** |
| * Creates an instance with the specified name. |
| */ |
| public XmlElement(String aName) { |
| name = aName; |
| } |
| |
| |
| /** |
| * Returns the name. |
| */ |
| public String getName() { |
| return name; |
| } |
| |
| |
| /** |
| * Returns the name that is used for display in outline view. |
| * <P> |
| * The default implementation returns just the same as the method <code>getName()</code>. |
| * Override this method in your own subclass for special elements in order to provide a |
| * custom display name. |
| */ |
| public String getDisplayName() { |
| return getName(); |
| } |
| |
| |
| /** |
| * Returns the child nodes. |
| */ |
| public List getChildNodes() { |
| return childNodes; |
| } |
| |
| |
| /** |
| * Returns the parent XmlElement. |
| * |
| * @return the parent or <code>null</code> if this element has no parent. |
| */ |
| public XmlElement getParentNode() { |
| return parent; |
| } |
| |
| |
| /** |
| * Adds the specified element as child. |
| * <P> |
| * The specified element will have this assigned as its parent. |
| * |
| * @throws AntEditorException if the specified child element allready |
| * has a parent. |
| */ |
| public void addChildNode(XmlElement aChildElement) { |
| if(aChildElement.getParentNode() != null) { |
| throw new AntEditorException(MessageFormat.format(AntEditorXMLMessages.getString("XmlElement.XmlElement_cannot_be_added_as_a_child"), new String[]{aChildElement.toString(), aChildElement.getParentNode().toString()})); //$NON-NLS-1$ |
| } |
| aChildElement.parent = this; |
| childNodes.add(aChildElement); |
| } |
| |
| |
| /** |
| * Returns all attributes. |
| */ |
| public List getAttributes() { |
| return attributes; |
| } |
| |
| |
| /** |
| * Adds the specified attribute. |
| */ |
| public void addAttribute(XmlAttribute anAttribute) { |
| attributes.add(anAttribute); |
| } |
| |
| |
| /** |
| * Returns the attribute with the specified name or <code>null</code>, |
| * if non existing. |
| */ |
| public XmlAttribute getAttributeNamed(String anAttributeName) { |
| for (Iterator i = attributes.iterator(); i.hasNext();) { |
| XmlAttribute anAttribute = (XmlAttribute) i.next(); |
| if(anAttributeName.equals(anAttribute.name)) { |
| return anAttribute; |
| } |
| } |
| return null; |
| } |
| |
| |
| /** |
| * Returns the startingColumn. |
| * <P> |
| * The first column has the index '1'. |
| */ |
| public int getStartingColumn() { |
| return startingColumn; |
| } |
| |
| |
| /** |
| * Returns the startingRow. |
| * <P> |
| * The first row has the index '1'. |
| */ |
| public int getStartingRow() { |
| return startingRow; |
| } |
| |
| |
| /** |
| * Returns the endingRow. |
| * <P> |
| * The first row has the index '1'. |
| */ |
| public int getEndingRow() { |
| return endingRow; |
| } |
| |
| |
| /** |
| * Sets the endingRow. |
| * <P> |
| * The first row has the index '1'. |
| */ |
| public void setEndingRow(int endingRow) { |
| this.endingRow = endingRow; |
| } |
| |
| |
| /** |
| * Returns the ending column. |
| * <P> |
| * The first column has the index '1'. |
| * The ending column is actually the index right after '>' on the ending |
| * line. |
| */ |
| public int getEndingColumn() { |
| return endingColumn; |
| } |
| |
| /** |
| * Sets the absolute file system path of the file this element is defined |
| * within. |
| */ |
| public void setFilePath(String path) { |
| URI uri= null; |
| try { |
| uri= new URI(path); |
| } catch (MalformedURIException e) { |
| filePath= path; |
| return; |
| } |
| filePath = new Path(new File(uri.getPath()).getAbsolutePath()).toString(); |
| } |
| |
| /** |
| * Returns the absolute file system path of the file this element is defined |
| * within. |
| */ |
| public String getFilePath() { |
| return filePath; |
| } |
| |
| /** |
| * Sets the endingColumn. |
| * <P> |
| * The first column has the index '1'. |
| * The ending column is actually the index right after '>' on the ending |
| * line. |
| */ |
| public void setEndingColumn(int endingColumn) { |
| this.endingColumn = endingColumn; |
| } |
| |
| |
| /** |
| * Sets the startingColumn. |
| * <P> |
| * The first column has the index '1'. |
| */ |
| public void setStartingColumn(int startingColumn) { |
| this.startingColumn = startingColumn; |
| } |
| |
| |
| /** |
| * Sets the startingRow. |
| * <P> |
| * The first row has the index '1'. |
| */ |
| public void setStartingRow(int startingRow) { |
| this.startingRow = startingRow; |
| } |
| |
| |
| /** |
| * Returns the 0-based index of the first character of the source code for this element, |
| * relative to the source buffer in which this element is contained. |
| * |
| * @return the 0-based index of the first character of the source code for this element, |
| * relative to the source buffer in which this element is contained |
| */ |
| public int getOffset() { |
| return offset; |
| } |
| |
| |
| /** |
| * Sets the offset. |
| * |
| * @see #getOffset() |
| */ |
| public void setOffset(int anOffset) { |
| offset = anOffset; |
| } |
| |
| |
| /** |
| * Returns the number of characters of the source code for this element, |
| * relative to the source buffer in which this element is contained. |
| * |
| * @return the number of characters of the source code for this element, |
| * relative to the source buffer in which this element is contained |
| */ |
| public int getLength() { |
| return length; |
| } |
| |
| |
| /** |
| * Sets the length. |
| * |
| * @see #getLength() |
| */ |
| public void setLength(int aLength) { |
| length = aLength; |
| } |
| |
| |
| /** |
| * Returns a string representation of this element. |
| */ |
| public String toString() { |
| return MessageFormat.format(AntEditorXMLMessages.getString("XmlElement.XmlElement_toString"), new String[]{name, Integer.toString(startingRow), Integer.toString(startingColumn), Integer.toString(endingRow), Integer.toString(endingColumn)}); //$NON-NLS-1$ |
| } |
| |
| /** |
| * Returns whether this element has been generated as part of an element |
| * hierarchy this is not complete as a result of an error. |
| */ |
| public boolean isErrorNode() { |
| return isErrorNode; |
| } |
| |
| /** |
| * Sets whether this element has been generated as part of an element |
| * hierarchy this is not complete as a result of an error. |
| */ |
| public void setIsErrorNode(boolean isErrorNode) { |
| this.isErrorNode= isErrorNode; |
| } |
| /** |
| * Returns whether this xml element is defined in an external entity. |
| * |
| * @return boolean |
| */ |
| public boolean isExternal() { |
| return isExternal; |
| } |
| |
| /** |
| * Sets whether this xml element is defined in an external entity. |
| */ |
| public void setExternal(boolean isExternal) { |
| this.isExternal = isExternal; |
| } |
| |
| /** |
| * Sets whether this xml element is the root external entity. |
| */ |
| public void setRootExternal(boolean isExternal) { |
| this.isRootExternal = isExternal; |
| } |
| |
| /** |
| * Returns whether this xml element is the root external entity. |
| */ |
| public boolean isRootExternal() { |
| return isRootExternal; |
| } |
| |
| public String getElementPath() { |
| if (fElementPath == null) { |
| StringBuffer buffer= new StringBuffer(getParentNode() != null ? getParentNode().getElementPath() : ""); //$NON-NLS-1$ |
| buffer.append('/'); |
| buffer.append(getElementIdentifier()); |
| buffer.append('['); |
| buffer.append(getParentNode() != null ? getParentNode().getElementIndexOf(this) : 0); |
| buffer.append(']'); |
| |
| fElementPath= buffer.toString(); |
| } |
| return fElementPath; |
| } |
| |
| private String getElementIdentifier() { |
| if (fElementIdentifier == null) { |
| StringBuffer buffer= escape(new StringBuffer(getName() != null ? getName() : ""), '\\', "$/[]\\"); //$NON-NLS-1$ //$NON-NLS-2$ |
| buffer.append('$'); |
| buffer.append(escape(new StringBuffer(getDisplayName() != null ? getDisplayName() : ""), '\\', "$/[]\\").toString()); //$NON-NLS-1$ //$NON-NLS-2$ |
| |
| fElementIdentifier= buffer.toString(); |
| } |
| return fElementIdentifier; |
| } |
| |
| private StringBuffer escape(StringBuffer sb, char esc, String special) { |
| for (int i= 0; i < sb.length(); i++) { |
| if (special.indexOf(sb.charAt(i)) >= 0) { |
| sb.insert(i++, esc); |
| } |
| } |
| |
| return sb; |
| } |
| |
| private int getElementIndexOf(XmlElement child) { |
| if (getChildNodes() == null) { |
| return -1; |
| } |
| |
| int result= -1; |
| |
| Iterator iter= getChildNodes().iterator(); |
| XmlElement current= null; |
| while (current != child && iter.hasNext()) { |
| current= (XmlElement) iter.next(); |
| if (child.getElementIdentifier().equals(current.getElementIdentifier())) |
| result++; |
| } |
| |
| if (current != child) { |
| return -1; |
| } |
| |
| return result; |
| } |
| |
| /* |
| * @see java.lang.Object#equals(java.lang.Object) |
| */ |
| public boolean equals(Object o2) { |
| // prepared to be used in an IElementComparer, depends on http://dev.eclipse.org/bugs/show_bug.cgi?id=32254 |
| Object o1= this; |
| |
| if (o1 == o2) { |
| return true; |
| } |
| if (o1 == null || o2 == null) { |
| return false; |
| } |
| if (!(o1 instanceof XmlElement || o2 instanceof XmlElement)) { |
| return o2.equals(o1); |
| } |
| if (!(o1 instanceof XmlElement && o2 instanceof XmlElement)) { |
| return false; |
| } |
| |
| XmlElement e1= (XmlElement) o1; |
| XmlElement e2= (XmlElement) o2; |
| |
| if (e1.getElementPath().equals(e2.getElementPath())) { |
| return true; |
| } |
| |
| return false; |
| } |
| |
| /* |
| * @see java.lang.Object#hashCode() |
| */ |
| public int hashCode() { |
| // prepared to be used in an IElementComparer, depends on http://dev.eclipse.org/bugs/show_bug.cgi?id=32254 |
| Object o1= this; |
| |
| if (o1 == null) { |
| return 0; |
| } |
| if (!(o1 instanceof XmlElement)) { |
| return o1.hashCode(); |
| } |
| |
| XmlElement e1= (XmlElement) o1; |
| |
| return e1.getElementPath().hashCode(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class) |
| */ |
| public Object getAdapter(Class adapter) { |
| if (adapter == IResource.class) { |
| if (getFilePath() != null) { |
| return AntUtil.getFile(getFilePath()); |
| } |
| } |
| return null; |
| } |
| |
| } |