blob: f5ac358bec8ed24c625ca7e0363222e9e209740d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.ant.internal.ui.editor.outline;
import java.io.IOException;
import java.io.StringReader;
import org.apache.xerces.parsers.SAXParser;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentListener;
import org.eclipse.ant.internal.ui.editor.xml.XmlElement;
import org.eclipse.ant.internal.ui.model.AntUIPlugin;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
/**
* AntModel.java
*/
public class AntModel {
private XMLCore fCore;
private IDocument fDocument;
private IProblemRequestor fProblemRequestor;
private ILocationProvider fLocationProvider;
private XmlElement[] fRootElements= new XmlElement[0];
private Object fRootElementLock= new Object();
private final Object fDirtyLock= new Object();
private boolean fIsDirty= true;
private IDocumentListener fListener;
public AntModel(XMLCore core, IDocument document, IProblemRequestor problemRequestor, ILocationProvider locationProvider) {
fCore= core;
fDocument= document;
fProblemRequestor= problemRequestor;
fLocationProvider= locationProvider;
}
public void install() {
fListener= new IDocumentListener() {
public void documentAboutToBeChanged(DocumentEvent event) {
synchronized (fDirtyLock) {
fIsDirty= true;
}
}
public void documentChanged(DocumentEvent event) {}
};
fDocument.addDocumentListener(fListener);
reconcile();
}
public void dispose() {
if (fDocument != null) {
fDocument.removeDocumentListener(fListener);
}
synchronized (this) {
fDocument= null;
fCore= null;
}
}
public void reconcile() {
synchronized (fDirtyLock) {
if (!fIsDirty) {
return;
}
fIsDirty= false;
}
synchronized (this) {
if (fCore == null) {
// disposed
return;
}
XmlElement[] rootElements;
if (fDocument == null) {
rootElements= new XmlElement[0];
} else {
XmlElement rootElement= parseDocument(fDocument);
if (rootElement == null) {
rootElements= new XmlElement[0];
} else {
rootElements= new XmlElement[] { rootElement };
}
}
setRootElements(rootElements);
fCore.notifyDocumentModelListeners(new DocumentModelChangeEvent(this));
}
}
private void setRootElements(XmlElement[] rootElements) {
synchronized (fRootElementLock) {
fRootElements= rootElements;
}
}
public XmlElement[] getRootElements() {
synchronized (fRootElementLock) {
return fRootElements;
}
}
/**
* Gets the content outline for a given input element.
* Returns the root XmlElement, or null if the
* outline could not be generated.
*/
private XmlElement parseDocument(IDocument input) {
/*
* What happens here:
* The file is parsed by the SAX Parser.
* The Parser then creates the DOM Tree of the file.
* The root element is returned here.
*/
// Create the parser
SAXParser parser;
try {
parser = new SAXParser();
parser.setFeature("http://xml.org/sax/features/namespaces", false); //$NON-NLS-1$
} catch (SAXException e) {
AntUIPlugin.log(e);
return null;
}
// Create the handler
OutlinePreparingHandler handler = new OutlinePreparingHandler(fLocationProvider);
handler.setProblemRequestor(fProblemRequestor);
handler.setDocument(input);
parser.setContentHandler(handler);
parser.setDTDHandler(handler);
parser.setEntityResolver(handler);
parser.setErrorHandler(handler);
// parser.setLocale(...);
// Parse!
try {
handler.begin();
String wholeDocString= input.get();
InputSource inputSource = new InputSource(new StringReader(wholeDocString));
IPath location= fLocationProvider.getLocation();
if (location != null) {
//needed for resolving relative external entities
inputSource.setSystemId(location.toOSString());
}
parser.setProperty("http://xml.org/sax/properties/lexical-handler", handler); //$NON-NLS-1$
parser.parse(inputSource);
} catch(SAXParseException e) {
handler.fixEndLocations(e);
} catch (SAXException e) {
AntUIPlugin.log(e);
return null;
} catch (IOException e) {
handler.fixEndLocations();
generateExceptionOutline(handler.getLastOpenElement());
} finally {
handler.end();
}
return handler.getRootElement();
}
private void generateExceptionOutline(XmlElement openElement) {
while (openElement != null) {
openElement.setIsErrorNode(true);
openElement= openElement.getParentNode();
}
}
/**
* @return ILocationProvider
*/
public ILocationProvider getLocationProvider() {
return fLocationProvider;
}
}