blob: f3370377ece28546bf9a39ba8862c2187ecafeb7 [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 24108
*******************************************************************************/
package org.eclipse.ant.ui.internal.editor;
import java.io.File;
import javax.xml.parsers.ParserConfigurationException;
import org.eclipse.ant.ui.internal.model.AntUIPlugin;
import org.w3c.dom.Element;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
/**
* SAX Parsing Handler that determines the enclosing target task element in
* respect to a specified cursor position.
*
* @author Alf Schiefelbein
*/
public class EnclosingTargetSearchingHandler extends AntEditorSaxDefaultHandler {
/**
* Whether the enclosing target element has been determined.
* <P>
* This is the case if the method
* <code>determineEnclosingTargetTaskElement</code> has been called once.
*/
protected boolean enclosingTargetElementDetermined;
/**
* Creates an EnclosingTargetSearchingHandler, with the specified parameters.
*
* @param aRowOfCursorPosition the startingRow where the cursor is located in the
* document. The first startingRow is refered to with an index of '0'.
* @param aColumnOfCursorPosition the startingColumn where the cursor is located in
* the document. The first startingColumn is refered to with an index of '0'.
*/
public EnclosingTargetSearchingHandler(File mainFileContainer, int aRowOfCursorPosition, int aColumnOfCursorPosition) throws ParserConfigurationException {
super(mainFileContainer, aRowOfCursorPosition, aColumnOfCursorPosition);
}
/* (non-Javadoc)
* @see org.xml.sax.ContentHandler#endElement(String, String, String)
*/
public void endElement(String aUri, String aLocalName, String aQualifiedName)
throws SAXException {
if (AntUIPlugin.getDefault() != null && AntUIPlugin.getDefault().isDebugging()) {
AntUIPlugin.log("AntEditorSaxDefaultHandler.endElement(" +aUri+ ", " +aLocalName+ ", "+aQualifiedName+ ")", null); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
}
if(parsingFinished) {
return;
}
// Checks wether we know the parent for sure
boolean tempParentKnown = checkForParentElement();
String tempTagName = aLocalName.length() > 0 ? aLocalName : aQualifiedName;
if(tempTagName.equals("target")) { //$NON-NLS-1$
if(!stillOpenElements.isEmpty()) {
Element tempLastStillOpenElement = (Element)stillOpenElements.peek();
if(tempLastStillOpenElement != null && tempLastStillOpenElement.getTagName().equals(tempTagName)) {
stillOpenElements.pop();
if(!stillOpenElements.empty()) {
Element tempSecondLastStillOpenElement = (Element)stillOpenElements.peek();
tempSecondLastStillOpenElement.appendChild(tempLastStillOpenElement);
}
if(tempParentKnown && parentElement != null && parentElement.getTagName().equals(tempTagName)) {
parsingFinished = true;
}
}
}
}
}
/* (non-Javadoc)
* @see org.xml.sax.ContentHandler#startElement(String, String, String, Attributes)
*/
public void startElement(
String aUri,
String aLocalName,
String aQualifiedName,
Attributes anAttributes)
throws SAXException {
/*
* While the crimson parser passes the tag name as local name, apache's
* xerces parser, passes the tag name as qualilfied name and an empty
* string as local name.
*/
if (AntUIPlugin.getDefault() != null && AntUIPlugin.getDefault().isDebugging()) {
AntUIPlugin.log("AntEditorSaxDefaultHandler.startElement(" +aUri+ ", " +aLocalName+ ", "+aQualifiedName+ ", "+anAttributes+ ")", null); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
}
if(parsingFinished) {
return;
}
// Checks wether we know the parent for sure
checkForParentElement();
// Create a Dom Element
String tempTagName = aLocalName.length() > 0 ? aLocalName : aQualifiedName;
if(tempTagName == null || tempTagName.length() == 0) {
throw new AntEditorException(AntEditorMessages.getString("EnclosingTargetSearchingHandler.Error_parsing")); //$NON-NLS-1$
}
if(tempTagName.equals("target")) { //$NON-NLS-1$
Element tempElement = document.createElement(tempTagName);
String tempTargetName = anAttributes.getValue("name"); //$NON-NLS-1$
if(tempTargetName != null && tempTargetName.length() > 0) {
tempElement.setAttribute("name", tempTargetName); //$NON-NLS-1$
}
stillOpenElements.push(tempElement);
}
}
/**
* Checks whether the enclosing task element, that we are searching for can
* be or has already been determined.
* <P>
* This will be done by comparing the current parsing position with the
* cursor position. If we just passed the cursor position and the enclosing
* task element has not been set yet, it will be set.
*
* @return <code>true</code> if the enclosing task element is known
* otherwise <code>false</code>
*/
protected boolean checkForParentElement() {
if(parentElement == null && !enclosingTargetElementDetermined) {
if(locator != null) {
/*
* The locator's numbers are 1-based though, we do everything
* 0-based.
*/
int tempLineNr = locator.getLineNumber() -1;
int tempColumnNr = locator.getColumnNumber() -1;
if(tempLineNr> rowOfCursorPosition ||
(tempLineNr == rowOfCursorPosition && tempColumnNr > columnOfCursorPosition)) {
determineEnclosingTargetTaskElement();
return true;
}
}
return false;
}
// Parent element has been set already before
return true;
}
/**
* Determines the enclosing target task element.
* <P>
* This Method shall only be called if the parser has passed the cursor
* position allready.
*/
protected void determineEnclosingTargetTaskElement() {
while(parentElement == null && !stillOpenElements.empty()) {
Element tempElement = (Element)stillOpenElements.pop();
if(tempElement.getTagName().equals("target")) { //$NON-NLS-1$
parentElement = tempElement;
if (AntUIPlugin.getDefault() != null && AntUIPlugin.getDefault().isDebugging()) {
AntUIPlugin.log("EnclosingTargetSearchingHandler.checkForParentElement(): Enclosing target element found: " +parentElement, null); //$NON-NLS-1$
}
}
}
enclosingTargetElementDetermined = true;
}
/**
* Returns the enclosing target task element that has been determined
* during a prior parsing.
* <P>
* It is quite common that parsing stopped before the current cursor
* position. That happens when the parser finds an error within the parsed
* document before. In that case the parent element might be guessed to be
* the one that opened last. To tell the handler wether the parent should
* be guessed, <code>aGuessParentFlag</code> may be specified.
*
* @param aGuessParentFlag wether the parent should be guessed
* @return the parent element or <code>null</code> if not known.
*/
public Element getParentElement(boolean aGuessParentFlag) {
if(enclosingTargetElementDetermined) {
return parentElement;
}
if(aGuessParentFlag) {
if(!stillOpenElements.empty()) {
determineEnclosingTargetTaskElement();
return parentElement;
}
}
return null;
}
}