blob: 1f2236709653542304517d3980ade19e8fc71bc0 [file] [log] [blame]
/*******************************************************************************
* 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;
}
}