| /* |
| * 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; |
| } |
| } |