KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > pde > internal > core > text > DocumentHandler


1 /*******************************************************************************
2  * Copyright (c) 2003, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.pde.internal.core.text;
12
13 import java.io.StringReader JavaDoc;
14 import java.util.ArrayList JavaDoc;
15 import java.util.Stack JavaDoc;
16
17 import org.eclipse.jface.text.BadLocationException;
18 import org.eclipse.jface.text.FindReplaceDocumentAdapter;
19 import org.eclipse.jface.text.IDocument;
20 import org.eclipse.jface.text.IRegion;
21 import org.eclipse.jface.text.Position;
22 import org.eclipse.jface.text.Region;
23 import org.eclipse.pde.internal.core.util.PDEXMLHelper;
24 import org.xml.sax.Attributes JavaDoc;
25 import org.xml.sax.InputSource JavaDoc;
26 import org.xml.sax.Locator JavaDoc;
27 import org.xml.sax.SAXException JavaDoc;
28 import org.xml.sax.SAXParseException JavaDoc;
29 import org.xml.sax.helpers.DefaultHandler JavaDoc;
30
31 public abstract class DocumentHandler extends DefaultHandler JavaDoc {
32
33     protected FindReplaceDocumentAdapter fFindReplaceAdapter;
34     protected Stack JavaDoc fDocumentNodeStack = new Stack JavaDoc();
35     protected int fHighestOffset = 0;
36     private Locator JavaDoc fLocator;
37     private IDocumentNode fLastError;
38     private boolean fReconciling;
39     
40     public DocumentHandler(boolean reconciling) {
41         fReconciling = reconciling;
42     }
43
44     /* (non-Javadoc)
45      * @see org.xml.sax.helpers.DefaultHandler#startDocument()
46      */

47     public void startDocument() throws SAXException JavaDoc {
48         fDocumentNodeStack.clear();
49         fHighestOffset = 0;
50         fLastError = null;
51         fFindReplaceAdapter = new FindReplaceDocumentAdapter(getDocument());
52     }
53     
54     /* (non-Javadoc)
55      * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
56      */

57     public void startElement(String JavaDoc uri, String JavaDoc localName, String JavaDoc qName,
58             Attributes JavaDoc attributes) throws SAXException JavaDoc {
59         IDocumentNode parent = fDocumentNodeStack.isEmpty() ? null : (IDocumentNode)fDocumentNodeStack.peek();
60         IDocumentNode node = getDocumentNode(qName, parent);
61         try {
62             int nodeOffset = getStartOffset(qName);
63             node.setOffset(nodeOffset);
64             IDocument doc = getDocument();
65             int line = doc.getLineOfOffset(nodeOffset);
66             node.setLineIndent(node.getOffset() - doc.getLineOffset(line));
67             // create attributes
68
for (int i = 0; i < attributes.getLength(); i++) {
69                 String JavaDoc attName = attributes.getQName(i);
70                 String JavaDoc attValue = attributes.getValue(i);
71                 IDocumentAttribute attribute = getDocumentAttribute(attName, attValue, node);
72                 if (attribute != null) {
73                     IRegion region = getAttributeRegion(attName, attValue, nodeOffset);
74                     if (region == null) {
75                         attValue = PDEXMLHelper.getWritableString(attValue);
76                         region = getAttributeRegion(attName, attValue, nodeOffset);
77                     }
78                     if (region != null) {
79                         attribute.setNameOffset(region.getOffset());
80                         attribute.setNameLength(attName.length());
81                         attribute.setValueOffset(region.getOffset() + region.getLength() - 1 - attValue.length());
82                         attribute.setValueLength(attValue.length());
83                     }
84                     node.setXMLAttribute(attribute);
85                 }
86             }
87             removeOrphanAttributes(node);
88         } catch (BadLocationException e) {
89         }
90         if (parent != null && node != null && node.getParentNode() == null) {
91             if (fReconciling) {
92                 // find right place for the child
93
// this is necessary to save as much as possible from the model
94
// we do not want an xml element with one tag to overwrite an element
95
// with a different tag
96
int position = 0;
97                 IDocumentNode[] children = parent.getChildNodes();
98                 for (; position < children.length; position++) {
99                     if (children[position].getOffset() == -1)
100                         break;
101                 }
102                 parent.addChildNode(node, position);
103             } else {
104                 parent.addChildNode(node);
105             }
106         }
107         fDocumentNodeStack.push(node);
108     }
109     
110     protected abstract IDocumentNode getDocumentNode(String JavaDoc name, IDocumentNode parent);
111     
112     protected abstract IDocumentAttribute getDocumentAttribute(String JavaDoc name, String JavaDoc value, IDocumentNode parent);
113     
114     private int getStartOffset(String JavaDoc elementName) throws BadLocationException {
115         int line = fLocator.getLineNumber();
116         int col = fLocator.getColumnNumber();
117         IDocument doc = getDocument();
118         if (col < 0)
119             col = doc.getLineLength(line);
120         String JavaDoc text = doc.get(fHighestOffset + 1, doc.getLineOffset(line) - fHighestOffset - 1);
121
122         ArrayList JavaDoc commentPositions = new ArrayList JavaDoc();
123         for (int idx = 0; idx < text.length();) {
124             idx = text.indexOf("<!--", idx); //$NON-NLS-1$
125
if (idx == -1)
126                 break;
127             int end = text.indexOf("-->", idx); //$NON-NLS-1$
128
if (end == -1)
129                 break;
130             
131             commentPositions.add(new Position(idx, end - idx));
132             idx = end + 1;
133         }
134
135         int idx = 0;
136         for (; idx < text.length(); idx += 1) {
137             idx = text.indexOf("<" + elementName, idx); //$NON-NLS-1$
138
if (idx == -1)
139                 break;
140             boolean valid = true;
141             for (int i = 0; i < commentPositions.size(); i++) {
142                 Position pos = (Position)commentPositions.get(i);
143                 if (pos.includes(idx)) {
144                     valid = false;
145                     break;
146                 }
147             }
148             if (valid)
149                 break;
150         }
151         if (idx > -1)
152             fHighestOffset += idx + 1;
153         return fHighestOffset;
154     }
155     
156     private int getElementLength(IDocumentNode node, int line, int column) throws BadLocationException {
157         int endIndex = node.getOffset();
158         IDocument doc = getDocument();
159         int start = Math.max(doc.getLineOffset(line), node.getOffset());
160         column = doc.getLineLength(line);
161         String JavaDoc lineText= doc.get(start, column - start + doc.getLineOffset(line));
162         
163         int index = lineText.indexOf("</" + node.getXMLTagName() + ">"); //$NON-NLS-1$ //$NON-NLS-2$
164
if (index == -1) {
165             index= lineText.indexOf(">"); //$NON-NLS-1$
166
if (index == -1 ) {
167                 endIndex = column;
168             } else {
169                 endIndex = index + 1;
170             }
171         } else{
172             endIndex = index + node.getXMLTagName().length() + 3;
173         }
174         return start + endIndex - node.getOffset();
175     }
176     
177     private IRegion getAttributeRegion(String JavaDoc name, String JavaDoc value, int offset) throws BadLocationException{
178         IRegion nameRegion = fFindReplaceAdapter.find(offset, name+"\\s*=\\s*\"", true, true, false, true); //$NON-NLS-1$
179
if (nameRegion != null) {
180             if (getDocument().get(nameRegion.getOffset() + nameRegion.getLength(), value.length()).equals(value))
181                 return new Region(nameRegion.getOffset(), nameRegion.getLength() + value.length() + 1);
182         }
183         return null;
184     }
185
186     
187     /* (non-Javadoc)
188      * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
189      */

190     public void endElement(String JavaDoc uri, String JavaDoc localName, String JavaDoc qName)
191             throws SAXException JavaDoc {
192         if (fDocumentNodeStack.isEmpty())
193             return;
194         
195         IDocumentNode node = (IDocumentNode)fDocumentNodeStack.pop();
196         try {
197             node.setLength(getElementLength(node, fLocator.getLineNumber() - 1, fLocator.getColumnNumber()));
198             setTextNodeOffset(node);
199         } catch (BadLocationException e) {
200         }
201         removeOrphanElements(node);
202     }
203     
204     protected void setTextNodeOffset(IDocumentNode node) throws BadLocationException {
205         IDocumentTextNode textNode = node.getTextNode();
206         if (textNode != null && textNode.getText() != null) {
207             if (textNode.getText().trim().length() == 0) {
208                 node.removeTextNode();
209                 return;
210             }
211             IDocument doc = getDocument();
212             String JavaDoc text = doc.get(node.getOffset(), node.getLength());
213             // 1st char of text node
214
int relativeStartOffset = text.indexOf('>') + 1;
215             // last char of text node
216
int relativeEndOffset = text.lastIndexOf('<') - 1;
217             
218             if ((relativeStartOffset < 0) ||
219                     (relativeStartOffset >= text.length())) {
220                 return;
221             } else if ((relativeEndOffset < 0) ||
222                     (relativeEndOffset >= text.length())) {
223                 return;
224             }
225             
226             // trim whitespace
227
while (Character.isWhitespace(text.charAt(relativeStartOffset)))
228                 relativeStartOffset += 1;
229             while (Character.isWhitespace(text.charAt(relativeEndOffset)))
230                 relativeEndOffset -= 1;
231             
232             textNode.setOffset(node.getOffset() + relativeStartOffset);
233             textNode.setLength(relativeEndOffset - relativeStartOffset + 1);
234             textNode.setText(textNode.getText().trim());
235         }
236     }
237     
238     /* (non-Javadoc)
239      * @see org.xml.sax.helpers.DefaultHandler#fatalError(org.xml.sax.SAXParseException)
240      */

241     public void fatalError(SAXParseException JavaDoc e) throws SAXException JavaDoc {
242         generateErrorElementHierarchy();
243     }
244     
245     /**
246      *
247      */

248     private void generateErrorElementHierarchy() {
249         while (!fDocumentNodeStack.isEmpty()) {
250             IDocumentNode node = (IDocumentNode)fDocumentNodeStack.pop();
251             node.setIsErrorNode(true);
252             removeOrphanAttributes(node);
253             removeOrphanElements(node);
254             if (fLastError == null)
255                 fLastError = node;
256         }
257     }
258
259     /* (non-Javadoc)
260      * @see org.xml.sax.helpers.DefaultHandler#error(org.xml.sax.SAXParseException)
261      */

262     public void error(SAXParseException JavaDoc e) throws SAXException JavaDoc {
263         generateErrorElementHierarchy();
264     }
265     
266     /* (non-Javadoc)
267      * @see org.xml.sax.helpers.DefaultHandler#setDocumentLocator(org.xml.sax.Locator)
268      */

269     public void setDocumentLocator(Locator JavaDoc locator) {
270         fLocator = locator;
271     }
272     
273     protected abstract IDocument getDocument();
274     
275     public InputSource JavaDoc resolveEntity(String JavaDoc publicId, String JavaDoc systemId) throws SAXException JavaDoc {
276         // Prevent the resolution of external entities in order to
277
// prevent the parser from accessing the Internet
278
// This will prevent huge workbench performance degradations and hangs
279
return new InputSource JavaDoc(new StringReader JavaDoc("")); //$NON-NLS-1$
280
}
281     
282     public IDocumentNode getLastErrorNode() {
283         return fLastError;
284     }
285     
286     /* (non-Javadoc)
287      * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
288      */

289     public void characters(char[] ch, int start, int length) throws SAXException JavaDoc {
290         if (!fReconciling || fDocumentNodeStack.isEmpty())
291             return;
292         
293         IDocumentNode parent = (IDocumentNode)fDocumentNodeStack.peek();
294         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
295         buffer.append(ch, start, length);
296         IDocumentTextNode textNode = parent.getTextNode();
297         if (textNode == null) {
298             if (buffer.toString().trim().length() > 0) {
299                 textNode = new DocumentTextNode();
300                 textNode.setEnclosingElement(parent);
301                 parent.addTextNode(textNode);
302                 textNode.setText(buffer.toString().trim());
303             }
304         } else {
305             textNode.setText(buffer.insert(0, textNode.getText()).toString());
306         }
307     }
308     
309     private void removeOrphanAttributes(IDocumentNode node) {
310         // when typing by hand, one element may overwrite a different existing one
311
// remove all attributes from previous element, if any.
312
if (fReconciling) {
313             IDocumentAttribute[] attrs = node.getNodeAttributes();
314             for (int i = 0; i < attrs.length; i++) {
315                 if (attrs[i].getNameOffset() == -1)
316                     node.removeDocumentAttribute(attrs[i]);
317             }
318         }
319     }
320
321     private void removeOrphanElements(IDocumentNode node) {
322         // when typing by hand, one element may overwrite a different existing one
323
// remove all excess children elements, if any.
324
if (fReconciling) {
325             IDocumentNode[] children = node.getChildNodes();
326             for (int i = 0; i < children.length; i++) {
327                 if (children[i].getOffset() == -1) {
328                     node.removeChildNode(children[i]);
329                 }
330             }
331         }
332     }
333     
334     protected boolean isReconciling() {
335         return fReconciling;
336     }
337     
338 }
339
Popular Tags