blob: be428e97fd5d838c61b365f9930c5fc97f8cb228 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.ant.debugger;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JEditorPane;
import javax.swing.SwingUtilities;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultEditorKit;
import javax.swing.text.EditorKit;
import javax.swing.text.StyledDocument;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.apache.tools.ant.module.api.support.TargetLister;
import org.apache.tools.ant.module.spi.AntEvent;
import org.openide.ErrorManager;
import org.openide.cookies.EditorCookie;
import org.openide.cookies.LineCookie;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.loaders.DataObject;
import org.openide.loaders.DataObjectNotFoundException;
import org.openide.text.Annotatable;
import org.openide.text.Line;
import org.openide.text.Line.ShowOpenType;
import org.openide.text.Line.ShowVisibilityType;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/*
* AntTest.java
*
* Created on 19. leden 2004, 20:03
*/
/**
*
* @author Honza
*/
public class Utils {
private static final Logger logger = Logger.getLogger(Utils.class.getName());
private static Object currentLine;
static synchronized void markCurrent (final Object line) {
unmarkCurrent ();
Annotatable[] annotatables = (Annotatable[]) line;
int i = 0, k = annotatables.length;
// first line with icon in gutter
DebuggerAnnotation[] annotations = new DebuggerAnnotation [k];
if (annotatables [i] instanceof Line.Part)
annotations [i] = new DebuggerAnnotation (
DebuggerAnnotation.CURRENT_LINE_PART_ANNOTATION_TYPE,
annotatables [i]
);
else
annotations [i] = new DebuggerAnnotation (
DebuggerAnnotation.CURRENT_LINE_ANNOTATION_TYPE,
annotatables [i]
);
// other lines
for (i = 1; i < k; i++)
if (annotatables [i] instanceof Line.Part)
annotations [i] = new DebuggerAnnotation (
DebuggerAnnotation.CURRENT_LINE_PART_ANNOTATION_TYPE2,
annotatables [i]
);
else
annotations [i] = new DebuggerAnnotation (
DebuggerAnnotation.CURRENT_LINE_ANNOTATION_TYPE2,
annotatables [i]
);
currentLine = annotations;
showLine (line);
}
static synchronized void unmarkCurrent () {
if (currentLine != null) {
// ((DebuggerAnnotation) currentLine).detach ();
int i, k = ((DebuggerAnnotation[]) currentLine).length;
for (i = 0; i < k; i++)
((DebuggerAnnotation[]) currentLine) [i].detach ();
currentLine = null;
}
}
static void showLine (final Object line) {
// SwingUtilities.invokeLater (new Runnable () {
// public void run () {
// ((Line) line).show (Line.SHOW_GOTO);
// }
// });
final Annotatable[] a = (Annotatable[]) line;
SwingUtilities.invokeLater (new Runnable () {
@Override
public void run () {
if (a [0] instanceof Line)
((Line) a [0]).show (ShowOpenType.OPEN, ShowVisibilityType.FOCUS);
else
if (a [0] instanceof Line.Part)
((Line.Part) a [0]).getLine ().show (ShowOpenType.OPEN, ShowVisibilityType.FOCUS);
else
throw new InternalError ();
}
});
}
static int getLineNumber (Object line) {
// return ((Line) line).getLineNumber ();
final Annotatable[] a = (Annotatable[]) line;
if (a [0] instanceof Line)
return ((Line) a [0]).getLineNumber ();
else
if (a [0] instanceof Line.Part)
return ((Line.Part) a [0]).getLine ().getLineNumber ();
else
throw new InternalError ();
}
public static boolean contains (Object currentLine, Line line) {
if (currentLine == null) return false;
final Annotatable[] a = (Annotatable[]) currentLine;
int i, k = a.length;
for (i = 0; i < k; i++) {
if (a [i].equals (line)) return true;
if ( a [i] instanceof Line.Part &&
((Line.Part) a [i]).getLine ().equals (line)
) return true;
}
return false;
}
static Object getLine (
final AntEvent event
) {
File file = event.getScriptLocation ();
final int lineNumber = event.getLine ();
if (file == null) return null;
if (lineNumber < 0) return null;
FileObject fileObject = FileUtil.toFileObject (file);
EditorCookie editor;
LineCookie lineCookie;
DataObject d;
try {
d = DataObject.find (fileObject);
} catch (DataObjectNotFoundException donfex) {
logger.log(Level.CONFIG, "No DataObject for "+fileObject, donfex);
return null;
}
editor = d.getLookup().lookup (EditorCookie.class);
lineCookie = d.getLookup().lookup (LineCookie.class);
assert editor != null;
assert lineCookie != null;
InputSource in = null;
try {
StyledDocument doc = editor.openDocument ();
in = createInputSource (fileObject, editor, doc);
} catch (IOException ioex) {
logger.log(Level.CONFIG, "A problem while opening "+fileObject, ioex);
} catch (BadLocationException blex) {
logger.log(Level.CONFIG, "A problem while opening "+fileObject, blex);
}
if (in == null) {
return null;
}
final int[] line = new int [4];
SAXParserFactory factory = SAXParserFactory.newInstance ();
try {
SAXParser parser = factory.newSAXParser ();
class Handler extends DefaultHandler {
private Locator locator;
@Override
public void setDocumentLocator (Locator l) {
locator = l;
}
@Override
public void startElement (
String uri,
String localname,
String qname,
Attributes attr
) throws SAXException {
if (line [0] == 0) {
if ( qname.equals (event.getTaskName ()) &&
locator.getLineNumber () == lineNumber
) {
line[0] = locator.getLineNumber ();
line[1] = locator.getColumnNumber () - 1;
}
}
}
@Override
public void endElement (
String uri,
String localname,
String qname
) throws SAXException {
if ( line [0] != 0 &&
line [2] == 0 &&
qname.equals (event.getTaskName ())
) {
line[2] = locator.getLineNumber ();
line[3] = locator.getColumnNumber () - 1;
}
}
}
parser.parse (in, new Handler ());
} catch (IOException ioex) {
logger.log(Level.CONFIG, "A problem while reading "+fileObject, ioex);
return null;
} catch (ParserConfigurationException pcex) {
logger.log(Level.CONFIG, "A problem while parsing "+fileObject, pcex);
return null;
} catch (SAXException saxex) {
logger.log(Level.CONFIG, "A problem while parsing "+fileObject, saxex);
return null;
}
if (line [0] == 0) return null;
Annotatable[] annotatables = new Annotatable [
line [2] - line [0] + 1
];
int i = 0;
for (int ln = line [0]; ln <= line [2]; ln ++) {
Line l = lineCookie.getLineSet ().getCurrent (ln - 1);
annotatables [i++] = l;
}
return annotatables;
}
static Object getLine (
final TargetLister.Target target,
String nextTargetName
) {
FileObject fileObject = target.getScript ().getFileObject ();
assert fileObject != null : "No build script for " + target.getName ();
EditorCookie editor;
LineCookie lineCookie;
DataObject d;
try {
d = DataObject.find (fileObject);
} catch (DataObjectNotFoundException donfex) {
logger.log(Level.CONFIG, "No DataObject for "+fileObject, donfex);
return null;
}
editor = d.getLookup().lookup (EditorCookie.class);
lineCookie = d.getLookup().lookup (LineCookie.class);
assert editor != null;
assert lineCookie != null;
InputSource in = null;
try {
StyledDocument doc = editor.openDocument ();
in = createInputSource (fileObject, editor, doc);
} catch (IOException ioex) {
logger.log(Level.CONFIG, "A problem while opening "+fileObject, ioex);
} catch (BadLocationException blex) {
logger.log(Level.CONFIG, "A problem while opening "+fileObject, blex);
}
if (in == null) {
return null;
}
final int[] line = new int [4];
SAXParserFactory factory = SAXParserFactory.newInstance ();
try {
SAXParser parser = factory.newSAXParser ();
class Handler extends DefaultHandler {
private Locator locator;
@Override
public void setDocumentLocator (Locator l) {
locator = l;
}
@Override
public void startElement (
String uri,
String localname,
String qname,
Attributes attr
) throws SAXException {
if (line [0] == 0) {
if (qname.equals ("target") && // NOI18N
target.getName ().equals (attr.getValue ("name")) // NOI18N
) {
line[0] = locator.getLineNumber ();
line[1] = locator.getColumnNumber ();
}
}
}
@Override
public void endElement (
String uri,
String localname,
String qname
) throws SAXException {
if ( line [0] != 0 &&
line [2] == 0 &&
qname.equals ("target")
) {
line[2] = locator.getLineNumber ();
line[3] = locator.getColumnNumber ();
}
}
}
parser.parse (in, new Handler ());
} catch (IOException ioex) {
logger.log(Level.CONFIG, "A problem while reading "+fileObject, ioex);
return null;
} catch (ParserConfigurationException pcex) {
logger.log(Level.CONFIG, "A problem while parsing "+fileObject, pcex);
return null;
} catch (SAXException saxex) {
logger.log(Level.CONFIG, "A problem while parsing "+fileObject, saxex);
return null;
}
if (line [0] == 0) return null;
int ln = line [0] - 1;
List annotatables = new ArrayList ();
if (nextTargetName != null) {
Line fLine = lineCookie.getLineSet ().getCurrent (ln);
int inx = findIndexOf(fLine.getText (), nextTargetName);
if (inx >= 0) {
annotatables.add (fLine.createPart (
inx, nextTargetName.length ()
));
ln ++;
}
}
if (annotatables.size () < 1)
for (; ln < line [2]; ln ++) {
Line l = lineCookie.getLineSet ().getCurrent (ln);
annotatables.add (l);
}
return annotatables.toArray (new Annotatable [annotatables.size ()]);
}
private static int findIndexOf(String text, String target) {
int index = 0;
while ((index = text.indexOf(target, index)) > 0) {
char c = text.charAt(index - 1);
if (!Character.isWhitespace(c) && c != ',' && c != '\"') {
// begins with some text => is not the target
index++;
continue;
}
if (text.length() > index + target.length()) {
c = text.charAt(index + target.length());
if (!Character.isWhitespace(c) && c != ',' && c != '\"') {
// ends with some text => is not the target
index++;
continue;
}
}
break;
}
return index;
}
/**
* Utility method to get a properly configured XML input source for a script.
*/
private static InputSource createInputSource (
FileObject fo,
EditorCookie editor,
final StyledDocument document
) throws IOException, BadLocationException {
final StringWriter w = new StringWriter (document.getLength ());
final EditorKit kit = findKit (editor);
if (kit == null) return null;
final IOException[] ioe = new IOException [1];
final BadLocationException[] ble = new BadLocationException [1];
document.render(new Runnable () {
@Override
public void run() {
try {
kit.write (w, document, 0, document.getLength ());
} catch (IOException e) {
ioe [0] = e;
} catch (BadLocationException e) {
ble [0] = e;
}
}
});
if (ioe[0] != null) {
throw ioe [0];
} else if (ble [0] != null) {
throw ble [0];
}
InputSource in = new InputSource (new StringReader (w.toString ()));
if (fo != null) { // #10348
in.setSystemId(fo.toURL().toExternalForm());
// [PENDING] Ant's ProjectHelper has an elaborate set of work-
// arounds for inconsistent parser behavior, e.g. file:foo.xml
// works in Ant but not with Xerces parser. You must use just foo.xml
// as the system ID. If necessary, Ant's algorithm could be copied
// here to make the behavior match perfectly, but it ought not be necessary.
}
return in;
}
private static EditorKit findKit(final EditorCookie editor) {
if (SwingUtilities.isEventDispatchThread()) {
return findKit_(editor);
} else {
final EditorKit[] ek = new EditorKit[1];
try {
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
ek[0] = findKit_(editor);
}
});
} catch (InvocationTargetException ex) {
ErrorManager.getDefault().notify(ex.getTargetException());
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
return ek[0];
}
}
private static EditorKit findKit_(EditorCookie editor) {
JEditorPane[] panes = editor.getOpenedPanes();
EditorKit kit;
if (panes != null) {
kit = panes[0].getEditorKit ();
} else {
kit = JEditorPane.createEditorKitForContentType ("text/xml"); // NOI18N
if (kit == null) {
// #39301: fallback; can happen if xml/text-edit is disabled
kit = new DefaultEditorKit ();
}
}
assert kit != null;
return kit;
}
}