| /******************************************************************************* |
| * Copyright (c) 2001, 2005 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 |
| * Jens Lukowski/Innoopract - initial renaming/restructuring |
| * |
| *******************************************************************************/ |
| package org.eclipse.wst.dtd.core.internal; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.List; |
| |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.wst.dtd.core.internal.document.DTDModelImpl; |
| import org.eclipse.wst.dtd.core.internal.parser.DTDRegionTypes; |
| import org.eclipse.wst.dtd.core.internal.text.RegionIterator; |
| import org.eclipse.wst.sse.core.internal.model.FactoryRegistry; |
| import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion; |
| import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion; |
| import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion; |
| import org.eclipse.wst.sse.core.internal.text.TextRegionListImpl; |
| import org.eclipse.wst.xml.core.internal.document.NodeContainer; |
| import org.w3c.dom.Node; |
| |
| |
| public abstract class DTDNode extends NodeContainer implements IndexedRegion { |
| |
| // these are characteroffsets |
| protected DTDFile dtdFile; |
| |
| // flat node that contains this node |
| protected IStructuredDocumentRegion flatNode; |
| |
| protected TextRegionListImpl regions = new TextRegionListImpl(); |
| |
| protected TextRegionListImpl whitespace = new TextRegionListImpl(); |
| |
| public DTDNode(DTDFile dtdFile, IStructuredDocumentRegion flatNode) { |
| this.dtdFile = dtdFile; |
| this.flatNode = flatNode; |
| } |
| |
| public void addRegion(ITextRegion region) { |
| /* |
| * if (startRegion == null) { startRegion = region; } endRegion = |
| * region; |
| */ |
| regions.add(region); |
| } |
| |
| public void addWhitespaceRegion(ITextRegion region) { |
| whitespace.add(region); |
| } |
| |
| public void beginRecording(Object requestor, String label) { |
| getDTDFile().getDTDModel().beginRecording(requestor, label); |
| } |
| |
| public Node cloneNode(boolean deepest) { |
| return null; |
| } |
| |
| public boolean contains(int testPosition) { |
| return containsRange(testPosition, testPosition); |
| } |
| |
| public boolean containsRange(int start, int end) { |
| return getStartOffset() <= start && end <= getEndOffset(); |
| } |
| |
| public void delete(DTDNode child) { |
| beginRecording(this, DTDCoreMessages._UI_LABEL_DTD_NODE_DELETE); //$NON-NLS-1$ |
| delete(this, child); |
| endRecording(this); |
| } |
| |
| public void delete(Object requestor, DTDNode child) { |
| replaceText(requestor, child.getStartOffset(), child.getFullNodeLength(), ""); //$NON-NLS-1$ |
| } |
| |
| public void endRecording(Object requestor) { |
| getDTDFile().getDTDModel().endRecording(requestor); |
| } |
| |
| public Object[] getChildren() { |
| return getChildrenList().toArray(); |
| } |
| |
| public List getChildrenList() { |
| Node child = getFirstChild(); |
| if (child != null) { |
| List children = new ArrayList(); |
| for (; child != null; child = child.getNextSibling()) { |
| children.add(child); |
| } |
| return children; |
| } |
| else { |
| return Collections.EMPTY_LIST; |
| } |
| } |
| |
| public DTDNode getDeepestNode(int offset) { |
| if (contains(offset)) { |
| // now see if a child contains this offset |
| Object[] children = getChildren(); |
| for (int i = 0; i < children.length; i++) { |
| DTDNode child = (DTDNode) children[i]; |
| DTDNode deepest = child.getDeepestNode(offset); |
| if (deepest != null) { |
| return deepest; |
| } |
| } // end of for () |
| return this; |
| } |
| return null; |
| } |
| |
| public DTDNode getDeepestNode(int start, int end) { |
| if (containsRange(start, end)) { |
| // now see if a child contains this offset |
| Object[] children = getChildren(); |
| for (int i = 0; i < children.length; i++) { |
| DTDNode child = (DTDNode) children[i]; |
| DTDNode deepest = child.getDeepestNode(start, end); |
| if (deepest != null) { |
| return deepest; |
| } |
| } // end of for () |
| return this; |
| } |
| return null; |
| } |
| |
| public DTDFile getDTDFile() { |
| return dtdFile; |
| } |
| |
| public int getEndOffset() { |
| return getStructuredDTDDocumentRegion().getEndOffset(getEndRegion()); |
| } |
| |
| public ITextRegion getEndRegion() { |
| return regions.get(regions.size() - 1);// endRegion; |
| } |
| |
| /** |
| */ |
| public FactoryRegistry getFactoryRegistry() { |
| DTDModelImpl model = dtdFile.getDTDModel(); |
| if (model != null) { |
| FactoryRegistry reg = model.getFactoryRegistry(); |
| if (reg != null) |
| return reg; |
| } |
| return null; |
| } |
| |
| public int getFullNodeLength() { |
| return getWhitespaceEndOffset() - getStartOffset(); |
| } |
| |
| public String getFullNodeText() { |
| String text = getNodeText(); |
| if (whitespace.size() > 0) { |
| RegionIterator iter = new RegionIterator(whitespace); |
| while (iter.hasNext()) { |
| ITextRegion region = iter.next(); |
| text += getStructuredDTDDocumentRegion().getText(region); |
| } |
| } |
| return text; |
| } |
| |
| abstract public Image getImage(); |
| |
| public String getName() { |
| ITextRegion region = getNameRegion(); |
| if (region != null) { |
| return getStructuredDTDDocumentRegion().getText(region); |
| } |
| return ""; //$NON-NLS-1$ |
| } |
| |
| public ITextRegion getNameRegion() { |
| RegionIterator iter = iterator(); |
| while (iter.hasNext()) { |
| ITextRegion region = iter.next(); |
| if (region.getType() == DTDRegionTypes.NAME) { |
| return region; |
| } |
| } |
| return null; |
| } |
| |
| // return the first token containing the specified token type |
| public ITextRegion getNextRegion(RegionIterator iter, String type) { |
| while (iter.hasNext()) { |
| ITextRegion region = iter.next(); |
| if (region.getType().equals(type)) { |
| return region; |
| } |
| } |
| return null; |
| } |
| |
| public int getNodeLength() { |
| return getEndOffset() - getStartOffset(); |
| } |
| |
| public String getNodeName() { |
| return getName(); |
| } |
| |
| public String getNodeText() { |
| StringBuffer sb = new StringBuffer(); |
| |
| RegionIterator iter = iterator(); |
| while (iter.hasNext()) { |
| ITextRegion region = iter.next(); |
| sb.append(getStructuredDTDDocumentRegion().getText(region)); |
| } |
| return sb.toString(); |
| } |
| |
| public short getNodeType() { |
| return -1; |
| } |
| |
| public int getStartOffset() { |
| return getStructuredDTDDocumentRegion().getStartOffset(getStartRegion()); |
| } |
| |
| // private Region startRegion,endRegion; |
| public ITextRegion getStartRegion() { |
| return regions.get(0); |
| // return startRegion; |
| } |
| |
| /** |
| * Get the value of flatNode. |
| * |
| * @return value of flatNode. |
| * |
| * ISSUE:named changed not to be confused with default access protected |
| * super class method, but should re-think if this is correct technique. |
| * Perhaps getFirstRegion? |
| */ |
| public IStructuredDocumentRegion getStructuredDTDDocumentRegion() { |
| return flatNode; |
| } |
| |
| // return end offset including whitespace |
| // or just the end offset if there is no whitespace |
| public int getWhitespaceEndOffset() { |
| if (whitespace.size() > 0) { |
| ITextRegion region = whitespace.get(whitespace.size() - 1); |
| return getStructuredDTDDocumentRegion().getEndOffset(region); |
| } |
| |
| return getEndOffset(); |
| } |
| |
| public boolean hasTrailingWhitespace() { |
| return whitespace.size() > 0; |
| } |
| |
| public RegionIterator iterator() { |
| // System.out.println("create region iter " + this.getClass() + " with |
| // start , end = " + getStartOffset() + ", " +getEndOffset()); |
| return new RegionIterator(regions); |
| } |
| |
| public void replaceText(Object requestor, int start, int length, String newText) { |
| getDTDFile().getStructuredDocument().replaceText(requestor, start, length, newText); |
| } |
| |
| public void resolveRegions() { |
| } |
| |
| public void setName(Object requestor, String name) { |
| if (!getName().equals(name)) { |
| ITextRegion nameRegion = getNameRegion(); |
| if (nameRegion != null) { |
| // nameToken.updateText(name); |
| getDTDFile().getDTDModel().getReferenceUpdater().nameAboutToChange(requestor, this, name); |
| replaceText(requestor, getStructuredDTDDocumentRegion().getStartOffset(nameRegion), nameRegion.getLength(), name); |
| } |
| } |
| } |
| |
| public void setName(String name) { |
| beginRecording(this, DTDCoreMessages._UI_LABEL_DTD_NODE_NAME_CHG); //$NON-NLS-1$ |
| setName(this, name); |
| endRecording(this); |
| } |
| |
| /** |
| * Set the value of flatNode. |
| * |
| * @param v |
| * Value to assign to flatNode. ISSUE:named changed not to be |
| * confused with default access protected super class method, |
| * but should re-think if this is correct technique |
| */ |
| void setStructuredDTDDocumentRegion(IStructuredDocumentRegion v) { |
| this.flatNode = v; |
| } |
| |
| // skips past next name token in the iterator |
| protected void skipPastName(RegionIterator iter) { |
| while (iter.hasNext()) { |
| ITextRegion currentRegion = iter.next(); |
| if (currentRegion.getType() == DTDRegionTypes.NAME) { |
| break; |
| } |
| } |
| } |
| |
| public boolean supports(java.lang.String feature, java.lang.String version) { |
| return false; |
| } |
| |
| } |